@@ -49,31 +49,28 @@ impl LateLintPass<'_> for NeedlessForEach {
49
49
fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
50
50
let expr = match stmt. kind {
51
51
StmtKind :: Expr ( expr) | StmtKind :: Semi ( expr) => expr,
52
- StmtKind :: Local ( local) if local. init . is_some ( ) => local. init . unwrap ( ) ,
53
52
_ => return ,
54
53
} ;
55
54
56
55
if_chain ! {
57
56
// 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;
59
58
if method_name. ident. name == Symbol :: intern( "for_each" ) ;
60
59
// Check `for_each` is an associated function of `Iterator`.
61
60
if is_trait_method( cx, expr, sym:: Iterator ) ;
62
61
// 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;
65
63
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
66
64
// `v.foo().iter().for_each()` must be skipped.
67
- if let Some ( iter_receiver) = iter_args. get( 0 ) ;
68
65
if matches!(
69
- iter_receiver . kind,
66
+ iter_recv . kind,
70
67
ExprKind :: Array ( ..) | ExprKind :: Call ( ..) | ExprKind :: Path ( ..)
71
68
) ;
72
69
// 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( ) ;
74
71
// Skip the lint if the body is not block because this is simpler than `for` loop.
75
72
// 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;
77
74
let body = cx. tcx. hir( ) . body( body_id) ;
78
75
if let ExprKind :: Block ( ..) = body. value. kind;
79
76
then {
@@ -85,38 +82,37 @@ impl LateLintPass<'_> for NeedlessForEach {
85
82
return ;
86
83
}
87
84
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 )
93
87
} 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
+ )
95
98
} ;
96
99
97
- let mut suggs = vec![ ] ;
98
- suggs. push( ( stmt. span, format!(
100
+ let sugg = format!(
99
101
"for {} in {} {}" ,
100
102
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) ,
102
104
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
+ ) ;
108
106
109
107
span_lint_and_then(
110
108
cx,
111
109
NEEDLESS_FOR_EACH ,
112
110
stmt. span,
113
111
"needless use of `for_each`" ,
114
112
|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) ;
120
116
}
121
117
}
122
118
)
0 commit comments