diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs | 56 | ||||
-rw-r--r-- | crates/ide_assists/src/tests/generated.rs | 15 |
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 | |||
30 | pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 38 | pub(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 | ||
67 | fn validate_method_call_expr( | 75 | fn 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)] |
87 | mod tests { | 100 | mod 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#" |
209 | fn main() { | 232 | fn 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#" | ||
242 | use empty_iter::*; | ||
243 | fn 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 | ||
214 | pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } } | ||
215 | pub struct SomeIter; | ||
216 | impl self::iter::traits::iterator::Iterator for SomeIter {} | ||
217 | //- /lib.rs crate:main deps:core | ||
218 | use core::SomeIter; | ||
213 | fn main() { | 219 | fn 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#####" |
227 | use core::SomeIter; | ||
221 | fn main() { | 228 | fn 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 | } |