@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
4
4
use clippy_utils:: higher:: ForLoop ;
5
5
use clippy_utils:: source:: snippet;
6
6
use rustc_errors:: Applicability ;
7
- use rustc_hir:: { Block , Expr , ExprKind , HirId , InlineAsmOperand , Pat , Stmt , StmtKind } ;
7
+ use rustc_hir:: { Block , Destination , Expr , ExprKind , HirId , InlineAsmOperand , Pat , Stmt , StmtKind } ;
8
8
use rustc_lint:: LateContext ;
9
9
use rustc_span:: Span ;
10
10
use std:: iter:: { once, Iterator } ;
@@ -16,7 +16,7 @@ pub(super) fn check(
16
16
span : Span ,
17
17
for_loop : Option < & ForLoop < ' _ > > ,
18
18
) {
19
- match never_loop_block ( block, loop_id) {
19
+ match never_loop_block ( block, & mut Vec :: new ( ) , loop_id) {
20
20
NeverLoopResult :: AlwaysBreak => {
21
21
span_lint_and_then ( cx, NEVER_LOOP , span, "this loop never actually loops" , |diag| {
22
22
if let Some ( ForLoop {
@@ -92,35 +92,34 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
92
92
}
93
93
}
94
94
95
- fn never_loop_block ( block : & Block < ' _ > , main_loop_id : HirId ) -> NeverLoopResult {
96
- let mut iter = block
95
+ fn never_loop_block ( block : & Block < ' _ > , ignore_ids : & mut Vec < HirId > , main_loop_id : HirId ) -> NeverLoopResult {
96
+ let iter = block
97
97
. stmts
98
98
. iter ( )
99
99
. filter_map ( stmt_to_expr)
100
100
. chain ( block. expr . map ( |expr| ( expr, None ) ) ) ;
101
- never_loop_expr_seq ( & mut iter, main_loop_id)
102
- }
103
101
104
- fn never_loop_expr_seq < ' a , T : Iterator < Item = ( & ' a Expr < ' a > , Option < & ' a Block < ' a > > ) > > (
105
- es : & mut T ,
106
- main_loop_id : HirId ,
107
- ) -> NeverLoopResult {
108
- es. map ( |( e, els) | {
109
- let e = never_loop_expr ( e, main_loop_id) ;
110
- els. map_or ( e, |els| combine_branches ( e, never_loop_block ( els, main_loop_id) ) )
102
+ iter. map ( |( e, els) | {
103
+ let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
104
+ // els is an else block in a let...else binding
105
+ els. map_or ( e, |els| {
106
+ combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) )
107
+ } )
111
108
} )
112
109
. fold ( NeverLoopResult :: Otherwise , combine_seq)
113
110
}
114
111
115
112
fn stmt_to_expr < ' tcx > ( stmt : & Stmt < ' tcx > ) -> Option < ( & ' tcx Expr < ' tcx > , Option < & ' tcx Block < ' tcx > > ) > {
116
113
match stmt. kind {
117
- StmtKind :: Semi ( e, ..) | StmtKind :: Expr ( e, ..) => Some ( ( e, None ) ) ,
114
+ StmtKind :: Semi ( e) | StmtKind :: Expr ( e) => Some ( ( e, None ) ) ,
115
+ // add the let...else expression (if present)
118
116
StmtKind :: Local ( local) => local. init . map ( |init| ( init, local. els ) ) ,
119
117
StmtKind :: Item ( ..) => None ,
120
118
}
121
119
}
122
120
123
- fn never_loop_expr ( expr : & Expr < ' _ > , main_loop_id : HirId ) -> NeverLoopResult {
121
+ #[ allow( clippy:: too_many_lines) ]
122
+ fn never_loop_expr ( expr : & Expr < ' _ > , ignore_ids : & mut Vec < HirId > , main_loop_id : HirId ) -> NeverLoopResult {
124
123
match expr. kind {
125
124
ExprKind :: Box ( e)
126
125
| ExprKind :: Unary ( _, e)
@@ -129,48 +128,56 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
129
128
| ExprKind :: Field ( e, _)
130
129
| ExprKind :: AddrOf ( _, _, e)
131
130
| ExprKind :: Repeat ( e, _)
132
- | ExprKind :: DropTemps ( e) => never_loop_expr ( e, main_loop_id) ,
133
- ExprKind :: Let ( let_expr) => never_loop_expr ( let_expr. init , main_loop_id) ,
134
- ExprKind :: Array ( es) | ExprKind :: Tup ( es) => never_loop_expr_all ( & mut es. iter ( ) , main_loop_id) ,
135
- ExprKind :: MethodCall ( _, receiver, es, _) => {
136
- never_loop_expr_all ( & mut std:: iter:: once ( receiver) . chain ( es. iter ( ) ) , main_loop_id)
137
- } ,
131
+ | ExprKind :: DropTemps ( e) => never_loop_expr ( e, ignore_ids, main_loop_id) ,
132
+ ExprKind :: Let ( let_expr) => never_loop_expr ( let_expr. init , ignore_ids, main_loop_id) ,
133
+ ExprKind :: Array ( es) | ExprKind :: Tup ( es) => never_loop_expr_all ( & mut es. iter ( ) , ignore_ids, main_loop_id) ,
134
+ ExprKind :: MethodCall ( _, receiver, es, _) => never_loop_expr_all (
135
+ & mut std:: iter:: once ( receiver) . chain ( es. iter ( ) ) ,
136
+ ignore_ids,
137
+ main_loop_id,
138
+ ) ,
138
139
ExprKind :: Struct ( _, fields, base) => {
139
- let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , main_loop_id) ;
140
+ let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids , main_loop_id) ;
140
141
if let Some ( base) = base {
141
- combine_both ( fields, never_loop_expr ( base, main_loop_id) )
142
+ combine_both ( fields, never_loop_expr ( base, ignore_ids , main_loop_id) )
142
143
} else {
143
144
fields
144
145
}
145
146
} ,
146
- ExprKind :: Call ( e, es) => never_loop_expr_all ( & mut once ( e) . chain ( es. iter ( ) ) , main_loop_id) ,
147
+ ExprKind :: Call ( e, es) => never_loop_expr_all ( & mut once ( e) . chain ( es. iter ( ) ) , ignore_ids , main_loop_id) ,
147
148
ExprKind :: Binary ( _, e1, e2)
148
149
| ExprKind :: Assign ( e1, e2, _)
149
150
| ExprKind :: AssignOp ( _, e1, e2)
150
- | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( & mut [ e1, e2] . iter ( ) . copied ( ) , main_loop_id) ,
151
+ | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( & mut [ e1, e2] . iter ( ) . copied ( ) , ignore_ids , main_loop_id) ,
151
152
ExprKind :: Loop ( b, _, _, _) => {
152
153
// Break can come from the inner loop so remove them.
153
- absorb_break ( never_loop_block ( b, main_loop_id) )
154
+ absorb_break ( never_loop_block ( b, ignore_ids , main_loop_id) )
154
155
} ,
155
156
ExprKind :: If ( e, e2, e3) => {
156
- let e1 = never_loop_expr ( e, main_loop_id) ;
157
- let e2 = never_loop_expr ( e2, main_loop_id) ;
158
- let e3 = e3
159
- . as_ref ( )
160
- . map_or ( NeverLoopResult :: Otherwise , |e| never_loop_expr ( e , main_loop_id ) ) ;
157
+ let e1 = never_loop_expr ( e, ignore_ids , main_loop_id) ;
158
+ let e2 = never_loop_expr ( e2, ignore_ids , main_loop_id) ;
159
+ let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
160
+ never_loop_expr ( e , ignore_ids , main_loop_id )
161
+ } ) ;
161
162
combine_seq ( e1, combine_branches ( e2, e3) )
162
163
} ,
163
164
ExprKind :: Match ( e, arms, _) => {
164
- let e = never_loop_expr ( e, main_loop_id) ;
165
+ let e = never_loop_expr ( e, ignore_ids , main_loop_id) ;
165
166
if arms. is_empty ( ) {
166
167
e
167
168
} else {
168
- let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| a. body ) , main_loop_id) ;
169
+ let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| a. body ) , ignore_ids , main_loop_id) ;
169
170
combine_seq ( e, arms)
170
171
}
171
172
} ,
172
- ExprKind :: Block ( b, None ) => never_loop_block ( b, main_loop_id) ,
173
- ExprKind :: Block ( b, Some ( _label) ) => absorb_break ( never_loop_block ( b, main_loop_id) ) ,
173
+ ExprKind :: Block ( b, l) => {
174
+ if l. is_some ( ) {
175
+ ignore_ids. push ( b. hir_id ) ;
176
+ }
177
+ let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
178
+ ignore_ids. pop ( ) ;
179
+ ret
180
+ } ,
174
181
ExprKind :: Continue ( d) => {
175
182
let id = d
176
183
. target_id
@@ -181,20 +188,32 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
181
188
NeverLoopResult :: AlwaysBreak
182
189
}
183
190
} ,
191
+ // checks if break targets a block instead of a loop
192
+ ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
193
+ . map_or ( NeverLoopResult :: Otherwise , |e| {
194
+ combine_seq ( never_loop_expr ( e, ignore_ids, main_loop_id) , NeverLoopResult :: Otherwise )
195
+ } ) ,
184
196
ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
185
- combine_seq ( never_loop_expr ( e, main_loop_id) , NeverLoopResult :: AlwaysBreak )
197
+ combine_seq (
198
+ never_loop_expr ( e, ignore_ids, main_loop_id) ,
199
+ NeverLoopResult :: AlwaysBreak ,
200
+ )
186
201
} ) ,
187
202
ExprKind :: InlineAsm ( asm) => asm
188
203
. operands
189
204
. iter ( )
190
205
. map ( |( o, _) | match o {
191
206
InlineAsmOperand :: In { expr, .. } | InlineAsmOperand :: InOut { expr, .. } => {
192
- never_loop_expr ( expr, main_loop_id)
207
+ never_loop_expr ( expr, ignore_ids , main_loop_id)
193
208
} ,
194
- InlineAsmOperand :: Out { expr, .. } => never_loop_expr_all ( & mut expr. iter ( ) . copied ( ) , main_loop_id) ,
195
- InlineAsmOperand :: SplitInOut { in_expr, out_expr, .. } => {
196
- never_loop_expr_all ( & mut once ( * in_expr) . chain ( out_expr. iter ( ) . copied ( ) ) , main_loop_id)
209
+ InlineAsmOperand :: Out { expr, .. } => {
210
+ never_loop_expr_all ( & mut expr. iter ( ) . copied ( ) , ignore_ids, main_loop_id)
197
211
} ,
212
+ InlineAsmOperand :: SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all (
213
+ & mut once ( * in_expr) . chain ( out_expr. iter ( ) . copied ( ) ) ,
214
+ ignore_ids,
215
+ main_loop_id,
216
+ ) ,
198
217
InlineAsmOperand :: Const { .. }
199
218
| InlineAsmOperand :: SymFn { .. }
200
219
| InlineAsmOperand :: SymStatic { .. } => NeverLoopResult :: Otherwise ,
@@ -209,13 +228,21 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
209
228
}
210
229
}
211
230
212
- fn never_loop_expr_all < ' a , T : Iterator < Item = & ' a Expr < ' a > > > ( es : & mut T , main_loop_id : HirId ) -> NeverLoopResult {
213
- es. map ( |e| never_loop_expr ( e, main_loop_id) )
231
+ fn never_loop_expr_all < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
232
+ es : & mut T ,
233
+ ignore_ids : & mut Vec < HirId > ,
234
+ main_loop_id : HirId ,
235
+ ) -> NeverLoopResult {
236
+ es. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
214
237
. fold ( NeverLoopResult :: Otherwise , combine_both)
215
238
}
216
239
217
- fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > ( e : & mut T , main_loop_id : HirId ) -> NeverLoopResult {
218
- e. map ( |e| never_loop_expr ( e, main_loop_id) )
240
+ fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
241
+ e : & mut T ,
242
+ ignore_ids : & mut Vec < HirId > ,
243
+ main_loop_id : HirId ,
244
+ ) -> NeverLoopResult {
245
+ e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
219
246
. fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
220
247
}
221
248
0 commit comments