@@ -11,37 +11,45 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
1111// Converts an Iterator::for_each function into a for loop.
1212//
1313// ```
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;
1420// fn main() {
15- // let vec = vec![(1, 2), (2, 3), (3, 4)] ;
16- // x. iter() .for_each(|(x, y)| {
21+ // let iter = SomeIter ;
22+ // iter.for_each$0 (|(x, y)| {
1723// println!("x: {}, y: {}", x, y);
1824// });
1925// }
2026// ```
2127// ->
2228// ```
29+ // # use core::SomeIter;
2330// fn main() {
24- // let vec = vec![(1, 2), (2, 3), (3, 4)] ;
25- // for (x, y) in x. iter() {
31+ // let iter = SomeIter ;
32+ // for (x, y) in iter {
2633// println!("x: {}, y: {}", x, y);
2734// }
2835// }
2936// ```
37+
3038pub ( crate ) fn convert_iter_for_each_to_for ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
3139 let method = ctx. find_node_at_offset :: < ast:: MethodCallExpr > ( ) ?;
32- let stmt = method. syntax ( ) . parent ( ) . and_then ( ast:: ExprStmt :: cast) ;
3340
3441 let closure = match method. arg_list ( ) ?. args ( ) . next ( ) ? {
3542 ast:: Expr :: ClosureExpr ( expr) => expr,
3643 _ => return None ,
3744 } ;
3845
39- let ( method, receiver) = validate_method_call_expr ( & ctx. sema , method) ?;
46+ let ( method, receiver) = validate_method_call_expr ( ctx, method) ?;
4047
4148 let param_list = closure. param_list ( ) ?;
4249 let param = param_list. params ( ) . next ( ) ?. pat ( ) ?;
4350 let body = closure. body ( ) ?;
4451
52+ let stmt = method. syntax ( ) . parent ( ) . and_then ( ast:: ExprStmt :: cast) ;
4553 let syntax = stmt. as_ref ( ) . map_or ( method. syntax ( ) , |stmt| stmt. syntax ( ) ) ;
4654
4755 acc. add (
@@ -65,13 +73,18 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex
6573}
6674
6775fn validate_method_call_expr (
68- sema : & hir :: Semantics < ide_db :: RootDatabase > ,
76+ ctx : & AssistContext ,
6977 expr : ast:: MethodCallExpr ,
7078) -> 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+ {
7283 return None ;
7384 }
7485
86+ let sema = & ctx. sema ;
87+
7588 let receiver = expr. receiver ( ) ?;
7689 let expr = ast:: Expr :: MethodCallExpr ( expr) ;
7790
@@ -85,7 +98,7 @@ fn validate_method_call_expr(
8598
8699#[ cfg( test) ]
87100mod tests {
88- use crate :: tests:: { check_assist , check_assist_not_applicable } ;
101+ use crate :: tests:: { self , check_assist } ;
89102
90103 use super :: * ;
91104
@@ -112,6 +125,16 @@ impl Empty {
112125 check_assist ( convert_iter_for_each_to_for, before, after) ;
113126 }
114127
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+
115138 #[ test]
116139 fn test_for_each_in_method_stmt ( ) {
117140 check_assist_with_fixtures (
@@ -201,13 +224,24 @@ fn main() {
201224"# ,
202225 )
203226 }
227+
204228 #[ test]
205229 fn test_for_each_not_applicable ( ) {
206230 check_assist_not_applicable (
207- convert_iter_for_each_to_for,
208231 r#"
209232fn 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));
211245}"# ,
212246 )
213247 }
0 commit comments