diff options
-rw-r--r-- | crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs | 57 |
1 files changed, 21 insertions, 36 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 5700e6167..7e6cae9e1 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 | |||
@@ -28,38 +28,20 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
28 | /// } | 28 | /// } |
29 | /// ``` | 29 | /// ``` |
30 | pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 30 | pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
31 | let method; | 31 | let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?; |
32 | 32 | let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast); | |
33 | let stmt = if let Some(stmt) = ctx.find_node_at_offset::<ast::ExprStmt>() { | ||
34 | method = ast::MethodCallExpr::cast(stmt.syntax().first_child()?)?; | ||
35 | Some(stmt) | ||
36 | } else { | ||
37 | method = match ctx.find_node_at_offset::<ast::Expr>()? { | ||
38 | ast::Expr::MethodCallExpr(expr) => expr, | ||
39 | ast::Expr::ClosureExpr(expr) => { | ||
40 | ast::MethodCallExpr::cast(expr.syntax().ancestors().nth(2)?)? | ||
41 | } | ||
42 | _ => { | ||
43 | return None; | ||
44 | } | ||
45 | }; | ||
46 | None | ||
47 | }; | ||
48 | 33 | ||
49 | let closure = match method.arg_list()?.args().next()? { | 34 | let closure = match method.arg_list()?.args().next()? { |
50 | ast::Expr::ClosureExpr(expr) => expr, | 35 | ast::Expr::ClosureExpr(expr) => expr, |
51 | _ => { | 36 | _ => return None, |
52 | return None; | ||
53 | } | ||
54 | }; | 37 | }; |
55 | 38 | ||
56 | let (method, parent) = validate_method_call_expr(&ctx.sema, method)?; | 39 | let (method, receiver) = validate_method_call_expr(&ctx.sema, method)?; |
57 | 40 | ||
58 | let param_list = closure.param_list()?; | 41 | let param_list = closure.param_list()?; |
59 | let param = param_list.params().next()?.pat()?; | 42 | let param = param_list.params().next()?.pat()?; |
60 | let body = closure.body()?; | 43 | let body = closure.body()?; |
61 | 44 | ||
62 | let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level()); | ||
63 | let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax()); | 45 | let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax()); |
64 | 46 | ||
65 | acc.add( | 47 | acc.add( |
@@ -67,6 +49,8 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex | |||
67 | "Replace this `Iterator::for_each` with a for loop", | 49 | "Replace this `Iterator::for_each` with a for loop", |
68 | syntax.text_range(), | 50 | syntax.text_range(), |
69 | |builder| { | 51 | |builder| { |
52 | let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level()); | ||
53 | |||
70 | let block = match body { | 54 | let block = match body { |
71 | ast::Expr::BlockExpr(block) => block, | 55 | ast::Expr::BlockExpr(block) => block, |
72 | _ => make::block_expr(Vec::new(), Some(body)), | 56 | _ => make::block_expr(Vec::new(), Some(body)), |
@@ -74,7 +58,7 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex | |||
74 | .reset_indent() | 58 | .reset_indent() |
75 | .indent(indent); | 59 | .indent(indent); |
76 | 60 | ||
77 | let expr_for_loop = make::expr_for_loop(param, parent, block); | 61 | let expr_for_loop = make::expr_for_loop(param, receiver, block); |
78 | builder.replace(syntax.text_range(), expr_for_loop.syntax().text()) | 62 | builder.replace(syntax.text_range(), expr_for_loop.syntax().text()) |
79 | }, | 63 | }, |
80 | ) | 64 | ) |
@@ -88,15 +72,15 @@ fn validate_method_call_expr( | |||
88 | return None; | 72 | return None; |
89 | } | 73 | } |
90 | 74 | ||
75 | let receiver = expr.receiver()?; | ||
91 | let expr = ast::Expr::MethodCallExpr(expr); | 76 | let expr = ast::Expr::MethodCallExpr(expr); |
92 | let parent = ast::Expr::cast(expr.syntax().first_child()?)?; | ||
93 | 77 | ||
94 | let it_type = sema.type_of_expr(&parent)?; | 78 | let it_type = sema.type_of_expr(&receiver)?; |
95 | let module = sema.scope(parent.syntax()).module()?; | 79 | let module = sema.scope(receiver.syntax()).module()?; |
96 | let krate = module.krate(); | 80 | let krate = module.krate(); |
97 | 81 | ||
98 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; | 82 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; |
99 | it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, parent)) | 83 | it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, receiver)) |
100 | } | 84 | } |
101 | 85 | ||
102 | #[cfg(test)] | 86 | #[cfg(test)] |
@@ -175,20 +159,22 @@ fn main() { | |||
175 | } | 159 | } |
176 | 160 | ||
177 | #[test] | 161 | #[test] |
178 | fn test_for_each_without_braces_stmt() { | 162 | fn test_for_each_in_iter_stmt() { |
179 | check_assist_with_fixtures( | 163 | check_assist_with_fixtures( |
180 | r#" | 164 | r#" |
181 | use empty_iter::*; | 165 | use empty_iter::*; |
182 | fn main() { | 166 | fn main() { |
183 | let x = Empty; | 167 | let x = Empty.iter(); |
184 | x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); | 168 | x.$0for_each(|(x, y)| { |
169 | println!("x: {}, y: {}", x, y); | ||
170 | }); | ||
185 | }"#, | 171 | }"#, |
186 | r#" | 172 | r#" |
187 | use empty_iter::*; | 173 | use empty_iter::*; |
188 | fn main() { | 174 | fn main() { |
189 | let x = Empty; | 175 | let x = Empty.iter(); |
190 | for (x, y) in x.iter() { | 176 | for (x, y) in x { |
191 | println!("x: {}, y: {}", x, y) | 177 | println!("x: {}, y: {}", x, y); |
192 | } | 178 | } |
193 | } | 179 | } |
194 | "#, | 180 | "#, |
@@ -196,13 +182,13 @@ fn main() { | |||
196 | } | 182 | } |
197 | 183 | ||
198 | #[test] | 184 | #[test] |
199 | fn test_for_each_in_closure_stmt() { | 185 | fn test_for_each_without_braces_stmt() { |
200 | check_assist_with_fixtures( | 186 | check_assist_with_fixtures( |
201 | r#" | 187 | r#" |
202 | use empty_iter::*; | 188 | use empty_iter::*; |
203 | fn main() { | 189 | fn main() { |
204 | let x = Empty; | 190 | let x = Empty; |
205 | x.iter().for_each($0|(x, y)| println!("x: {}, y: {}", x, y)); | 191 | x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); |
206 | }"#, | 192 | }"#, |
207 | r#" | 193 | r#" |
208 | use empty_iter::*; | 194 | use empty_iter::*; |
@@ -215,7 +201,6 @@ fn main() { | |||
215 | "#, | 201 | "#, |
216 | ) | 202 | ) |
217 | } | 203 | } |
218 | |||
219 | #[test] | 204 | #[test] |
220 | fn test_for_each_not_applicable() { | 205 | fn test_for_each_not_applicable() { |
221 | check_assist_not_applicable( | 206 | check_assist_not_applicable( |