aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs56
-rw-r--r--crates/ide_assists/src/tests/generated.rs15
2 files changed, 56 insertions, 15 deletions
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index ed15f169e..4e75a7b14 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -11,37 +11,45 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
11// Converts an Iterator::for_each function into a for loop. 11// Converts an Iterator::for_each function into a for loop.
12// 12//
13// ``` 13// ```
14// # //- /lib.rs crate:core
15// # pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
16// # pub struct SomeIter;
17// # impl self::iter::traits::iterator::Iterator for SomeIter {}
18// # //- /lib.rs crate:main deps:core
19// # use core::SomeIter;
14// fn main() { 20// fn main() {
15// let vec = vec![(1, 2), (2, 3), (3, 4)]; 21// let iter = SomeIter;
16// x.iter().for_each(|(x, y)| { 22// iter.for_each$0(|(x, y)| {
17// println!("x: {}, y: {}", x, y); 23// println!("x: {}, y: {}", x, y);
18// }); 24// });
19// } 25// }
20// ``` 26// ```
21// -> 27// ->
22// ``` 28// ```
29// # use core::SomeIter;
23// fn main() { 30// fn main() {
24// let vec = vec![(1, 2), (2, 3), (3, 4)]; 31// let iter = SomeIter;
25// for (x, y) in x.iter() { 32// for (x, y) in iter {
26// println!("x: {}, y: {}", x, y); 33// println!("x: {}, y: {}", x, y);
27// } 34// }
28// } 35// }
29// ``` 36// ```
37
30pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 38pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
31 let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?; 39 let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?;
32 let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
33 40
34 let closure = match method.arg_list()?.args().next()? { 41 let closure = match method.arg_list()?.args().next()? {
35 ast::Expr::ClosureExpr(expr) => expr, 42 ast::Expr::ClosureExpr(expr) => expr,
36 _ => return None, 43 _ => return None,
37 }; 44 };
38 45
39 let (method, receiver) = validate_method_call_expr(&ctx.sema, method)?; 46 let (method, receiver) = validate_method_call_expr(ctx, method)?;
40 47
41 let param_list = closure.param_list()?; 48 let param_list = closure.param_list()?;
42 let param = param_list.params().next()?.pat()?; 49 let param = param_list.params().next()?.pat()?;
43 let body = closure.body()?; 50 let body = closure.body()?;
44 51
52 let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
45 let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax()); 53 let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());
46 54
47 acc.add( 55 acc.add(
@@ -65,13 +73,18 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex
65} 73}
66 74
67fn validate_method_call_expr( 75fn validate_method_call_expr(
68 sema: &hir::Semantics<ide_db::RootDatabase>, 76 ctx: &AssistContext,
69 expr: ast::MethodCallExpr, 77 expr: ast::MethodCallExpr,
70) -> Option<(ast::Expr, ast::Expr)> { 78) -> Option<(ast::Expr, ast::Expr)> {
71 if expr.name_ref()?.text() != "for_each" { 79 let name_ref = expr.name_ref()?;
80 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none()
81 || name_ref.text() != "for_each"
82 {
72 return None; 83 return None;
73 } 84 }
74 85
86 let sema = &ctx.sema;
87
75 let receiver = expr.receiver()?; 88 let receiver = expr.receiver()?;
76 let expr = ast::Expr::MethodCallExpr(expr); 89 let expr = ast::Expr::MethodCallExpr(expr);
77 90
@@ -85,7 +98,7 @@ fn validate_method_call_expr(
85 98
86#[cfg(test)] 99#[cfg(test)]
87mod tests { 100mod tests {
88 use crate::tests::{check_assist, check_assist_not_applicable}; 101 use crate::tests::{self, check_assist};
89 102
90 use super::*; 103 use super::*;
91 104
@@ -112,6 +125,16 @@ impl Empty {
112 check_assist(convert_iter_for_each_to_for, before, after); 125 check_assist(convert_iter_for_each_to_for, before, after);
113 } 126 }
114 127
128 fn check_assist_not_applicable(before: &str) {
129 let before = &format!(
130 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
131 before,
132 EMPTY_ITER_FIXTURE,
133 FamousDefs::FIXTURE,
134 );
135 tests::check_assist_not_applicable(convert_iter_for_each_to_for, before);
136 }
137
115 #[test] 138 #[test]
116 fn test_for_each_in_method_stmt() { 139 fn test_for_each_in_method_stmt() {
117 check_assist_with_fixtures( 140 check_assist_with_fixtures(
@@ -201,13 +224,24 @@ fn main() {
201"#, 224"#,
202 ) 225 )
203 } 226 }
227
204 #[test] 228 #[test]
205 fn test_for_each_not_applicable() { 229 fn test_for_each_not_applicable() {
206 check_assist_not_applicable( 230 check_assist_not_applicable(
207 convert_iter_for_each_to_for,
208 r#" 231 r#"
209fn main() { 232fn main() {
210 value.$0for_each(|x| println!("{}", x)); 233 ().$0for_each(|x| println!("{}", x));
234}"#,
235 )
236 }
237
238 #[test]
239 fn test_for_each_not_applicable_invalid_cursor_pos() {
240 check_assist_not_applicable(
241 r#"
242use empty_iter::*;
243fn main() {
244 Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
211}"#, 245}"#,
212 ) 246 )
213 } 247 }
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index af513ca22..3f77edd8d 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -210,17 +210,24 @@ fn doctest_convert_iter_for_each_to_for() {
210 check_doc_test( 210 check_doc_test(
211 "convert_iter_for_each_to_for", 211 "convert_iter_for_each_to_for",
212 r#####" 212 r#####"
213//- /lib.rs crate:core
214pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
215pub struct SomeIter;
216impl self::iter::traits::iterator::Iterator for SomeIter {}
217//- /lib.rs crate:main deps:core
218use core::SomeIter;
213fn main() { 219fn main() {
214 let vec = vec![(1, 2), (2, 3), (3, 4)]; 220 let iter = SomeIter;
215 x.iter().for_each(|(x, y)| { 221 iter.for_each$0(|(x, y)| {
216 println!("x: {}, y: {}", x, y); 222 println!("x: {}, y: {}", x, y);
217 }); 223 });
218} 224}
219"#####, 225"#####,
220 r#####" 226 r#####"
227use core::SomeIter;
221fn main() { 228fn main() {
222 let vec = vec![(1, 2), (2, 3), (3, 4)]; 229 let iter = SomeIter;
223 for (x, y) in x.iter() { 230 for (x, y) in iter {
224 println!("x: {}, y: {}", x, y); 231 println!("x: {}, y: {}", x, y);
225 } 232 }
226} 233}