@@ -49,31 +49,28 @@ impl LateLintPass<'_> for NeedlessForEach {
4949 fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
5050 let expr = match stmt. kind {
5151 StmtKind :: Expr ( expr) | StmtKind :: Semi ( expr) => expr,
52- StmtKind :: Local ( local) if local. init . is_some ( ) => local. init . unwrap ( ) ,
5352 _ => return ,
5453 } ;
5554
5655 if_chain ! {
5756 // Check the method name is `for_each`.
58- if let ExprKind :: MethodCall ( method_name, _, for_each_args , _) = expr. kind;
57+ if let ExprKind :: MethodCall ( method_name, _, [ for_each_recv , for_each_arg ] , _) = expr. kind;
5958 if method_name. ident. name == Symbol :: intern( "for_each" ) ;
6059 // Check `for_each` is an associated function of `Iterator`.
6160 if is_trait_method( cx, expr, sym:: Iterator ) ;
6261 // Checks the receiver of `for_each` is also a method call.
63- if let Some ( for_each_receiver) = for_each_args. get( 0 ) ;
64- if let ExprKind :: MethodCall ( _, _, iter_args, _) = for_each_receiver. kind;
62+ if let ExprKind :: MethodCall ( _, _, [ iter_recv] , _) = for_each_recv. kind;
6563 // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
6664 // `v.foo().iter().for_each()` must be skipped.
67- if let Some ( iter_receiver) = iter_args. get( 0 ) ;
6865 if matches!(
69- iter_receiver . kind,
66+ iter_recv . kind,
7067 ExprKind :: Array ( ..) | ExprKind :: Call ( ..) | ExprKind :: Path ( ..)
7168 ) ;
7269 // Checks the type of the `iter` method receiver is NOT a user defined type.
73- if has_iter_method( cx, cx. typeck_results( ) . expr_ty( & iter_receiver ) ) . is_some( ) ;
70+ if has_iter_method( cx, cx. typeck_results( ) . expr_ty( & iter_recv ) ) . is_some( ) ;
7471 // Skip the lint if the body is not block because this is simpler than `for` loop.
7572 // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
76- if let ExprKind :: Closure ( _, _, body_id, ..) = for_each_args [ 1 ] . kind;
73+ if let ExprKind :: Closure ( _, _, body_id, ..) = for_each_arg . kind;
7774 let body = cx. tcx. hir( ) . body( body_id) ;
7875 if let ExprKind :: Block ( ..) = body. value. kind;
7976 then {
@@ -85,38 +82,37 @@ impl LateLintPass<'_> for NeedlessForEach {
8582 return ;
8683 }
8784
88- // We can't use `Applicability::MachineApplicable` when the closure contains `return`
89- // because `Diagnostic::multipart_suggestion` doesn't work with multiple overlapped
90- // spans.
91- let mut applicability = if ret_collector. spans. is_empty( ) {
92- Applicability :: MachineApplicable
85+ let ( mut applicability, ret_suggs) = if ret_collector. spans. is_empty( ) {
86+ ( Applicability :: MachineApplicable , None )
9387 } else {
94- Applicability :: MaybeIncorrect
88+ (
89+ Applicability :: MaybeIncorrect ,
90+ Some (
91+ ret_collector
92+ . spans
93+ . into_iter( )
94+ . map( |span| ( span, "continue" . to_string( ) ) )
95+ . collect( ) ,
96+ ) ,
97+ )
9598 } ;
9699
97- let mut suggs = vec![ ] ;
98- suggs. push( ( stmt. span, format!(
100+ let sugg = format!(
99101 "for {} in {} {}" ,
100102 snippet_with_applicability( cx, body. params[ 0 ] . pat. span, ".." , & mut applicability) ,
101- snippet_with_applicability( cx, for_each_args [ 0 ] . span, ".." , & mut applicability) ,
103+ snippet_with_applicability( cx, for_each_recv . span, ".." , & mut applicability) ,
102104 snippet_with_applicability( cx, body. value. span, ".." , & mut applicability) ,
103- ) ) ) ;
104-
105- for span in & ret_collector. spans {
106- suggs. push( ( * span, "continue" . to_string( ) ) ) ;
107- }
105+ ) ;
108106
109107 span_lint_and_then(
110108 cx,
111109 NEEDLESS_FOR_EACH ,
112110 stmt. span,
113111 "needless use of `for_each`" ,
114112 |diag| {
115- diag. multipart_suggestion( "try" , suggs, applicability) ;
116- // `Diagnostic::multipart_suggestion` ignores the second and subsequent overlapped spans,
117- // so `span_note` is needed here even though `suggs` includes the replacements.
118- for span in ret_collector. spans {
119- diag. span_note( span, "replace `return` with `continue`" ) ;
113+ diag. span_suggestion( stmt. span, "try" , sugg, applicability) ;
114+ if let Some ( ret_suggs) = ret_suggs {
115+ diag. multipart_suggestion( "try replacing `return` with `continue`" , ret_suggs, applicability) ;
120116 }
121117 }
122118 )
0 commit comments