aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs57
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/// ```
30pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 30pub(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#"
181use empty_iter::*; 165use empty_iter::*;
182fn main() { 166fn 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#"
187use empty_iter::*; 173use empty_iter::*;
188fn main() { 174fn 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#"
202use empty_iter::*; 188use empty_iter::*;
203fn main() { 189fn 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#"
208use empty_iter::*; 194use 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(