@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
44use clippy_utils:: higher:: ForLoop ;
55use clippy_utils:: source:: snippet;
66use 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 } ;
88use rustc_lint:: LateContext ;
99use rustc_span:: Span ;
1010use std:: iter:: { once, Iterator } ;
@@ -16,7 +16,7 @@ pub(super) fn check(
1616 span : Span ,
1717 for_loop : Option < & ForLoop < ' _ > > ,
1818) {
19- match never_loop_block ( block, loop_id) {
19+ match never_loop_block ( block, & mut Vec :: new ( ) , loop_id) {
2020 NeverLoopResult :: AlwaysBreak => {
2121 span_lint_and_then ( cx, NEVER_LOOP , span, "this loop never actually loops" , |diag| {
2222 if let Some ( ForLoop {
@@ -92,35 +92,33 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
9292 }
9393}
9494
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
9797 . stmts
9898 . iter ( )
9999 . filter_map ( stmt_to_expr)
100100 . chain ( block. expr . map ( |expr| ( expr, None ) ) ) ;
101- never_loop_expr_seq ( & mut iter, main_loop_id)
102- }
103101
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+ } )
111108 } )
112109 . fold ( NeverLoopResult :: Otherwise , combine_seq)
113110}
114111
115112fn stmt_to_expr < ' tcx > ( stmt : & Stmt < ' tcx > ) -> Option < ( & ' tcx Expr < ' tcx > , Option < & ' tcx Block < ' tcx > > ) > {
116113 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)
118116 StmtKind :: Local ( local) => local. init . map ( |init| ( init, local. els ) ) ,
119117 StmtKind :: Item ( ..) => None ,
120118 }
121119}
122120
123- fn never_loop_expr ( expr : & Expr < ' _ > , main_loop_id : HirId ) -> NeverLoopResult {
121+ fn never_loop_expr ( expr : & Expr < ' _ > , ignore_ids : & mut Vec < HirId > , main_loop_id : HirId ) -> NeverLoopResult {
124122 match expr. kind {
125123 ExprKind :: Box ( e)
126124 | ExprKind :: Unary ( _, e)
@@ -129,48 +127,56 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
129127 | ExprKind :: Field ( e, _)
130128 | ExprKind :: AddrOf ( _, _, e)
131129 | 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- } ,
130+ | ExprKind :: DropTemps ( e) => never_loop_expr ( e, ignore_ids, main_loop_id) ,
131+ ExprKind :: Let ( let_expr) => never_loop_expr ( let_expr. init , ignore_ids, main_loop_id) ,
132+ ExprKind :: Array ( es) | ExprKind :: Tup ( es) => never_loop_expr_all ( & mut es. iter ( ) , ignore_ids, main_loop_id) ,
133+ ExprKind :: MethodCall ( _, receiver, es, _) => never_loop_expr_all (
134+ & mut std:: iter:: once ( receiver) . chain ( es. iter ( ) ) ,
135+ ignore_ids,
136+ main_loop_id,
137+ ) ,
138138 ExprKind :: Struct ( _, fields, base) => {
139- let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , main_loop_id) ;
139+ let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids , main_loop_id) ;
140140 if let Some ( base) = base {
141- combine_both ( fields, never_loop_expr ( base, main_loop_id) )
141+ combine_both ( fields, never_loop_expr ( base, ignore_ids , main_loop_id) )
142142 } else {
143143 fields
144144 }
145145 } ,
146- ExprKind :: Call ( e, es) => never_loop_expr_all ( & mut once ( e) . chain ( es. iter ( ) ) , main_loop_id) ,
146+ ExprKind :: Call ( e, es) => never_loop_expr_all ( & mut once ( e) . chain ( es. iter ( ) ) , ignore_ids , main_loop_id) ,
147147 ExprKind :: Binary ( _, e1, e2)
148148 | ExprKind :: Assign ( e1, e2, _)
149149 | ExprKind :: AssignOp ( _, e1, e2)
150- | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( & mut [ e1, e2] . iter ( ) . copied ( ) , main_loop_id) ,
150+ | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( & mut [ e1, e2] . iter ( ) . copied ( ) , ignore_ids , main_loop_id) ,
151151 ExprKind :: Loop ( b, _, _, _) => {
152152 // Break can come from the inner loop so remove them.
153- absorb_break ( never_loop_block ( b, main_loop_id) )
153+ absorb_break ( never_loop_block ( b, ignore_ids , main_loop_id) )
154154 } ,
155155 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 ) ) ;
156+ let e1 = never_loop_expr ( e, ignore_ids , main_loop_id) ;
157+ let e2 = never_loop_expr ( e2, ignore_ids , main_loop_id) ;
158+ let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
159+ never_loop_expr ( e , ignore_ids , main_loop_id )
160+ } ) ;
161161 combine_seq ( e1, combine_branches ( e2, e3) )
162162 } ,
163163 ExprKind :: Match ( e, arms, _) => {
164- let e = never_loop_expr ( e, main_loop_id) ;
164+ let e = never_loop_expr ( e, ignore_ids , main_loop_id) ;
165165 if arms. is_empty ( ) {
166166 e
167167 } else {
168- let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| a. body ) , main_loop_id) ;
168+ let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| a. body ) , ignore_ids , main_loop_id) ;
169169 combine_seq ( e, arms)
170170 }
171171 } ,
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) ) ,
172+ ExprKind :: Block ( b, l) => {
173+ if let Some ( _) = l {
174+ ignore_ids. push ( b. hir_id ) ;
175+ }
176+ let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
177+ ignore_ids. pop ( ) ;
178+ ret
179+ } ,
174180 ExprKind :: Continue ( d) => {
175181 let id = d
176182 . target_id
@@ -181,20 +187,31 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
181187 NeverLoopResult :: AlwaysBreak
182188 }
183189 } ,
190+ ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
191+ . map_or ( NeverLoopResult :: Otherwise , |e| {
192+ combine_seq ( never_loop_expr ( e, ignore_ids, main_loop_id) , NeverLoopResult :: Otherwise )
193+ } ) ,
184194 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 )
195+ combine_seq (
196+ never_loop_expr ( e, ignore_ids, main_loop_id) ,
197+ NeverLoopResult :: AlwaysBreak ,
198+ )
186199 } ) ,
187200 ExprKind :: InlineAsm ( asm) => asm
188201 . operands
189202 . iter ( )
190203 . map ( |( o, _) | match o {
191204 InlineAsmOperand :: In { expr, .. } | InlineAsmOperand :: InOut { expr, .. } => {
192- never_loop_expr ( expr, main_loop_id)
205+ never_loop_expr ( expr, ignore_ids , main_loop_id)
193206 } ,
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)
207+ InlineAsmOperand :: Out { expr, .. } => {
208+ never_loop_expr_all ( & mut expr. iter ( ) . copied ( ) , ignore_ids, main_loop_id)
197209 } ,
210+ InlineAsmOperand :: SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all (
211+ & mut once ( * in_expr) . chain ( out_expr. iter ( ) . copied ( ) ) ,
212+ ignore_ids,
213+ main_loop_id,
214+ ) ,
198215 InlineAsmOperand :: Const { .. }
199216 | InlineAsmOperand :: SymFn { .. }
200217 | InlineAsmOperand :: SymStatic { .. } => NeverLoopResult :: Otherwise ,
@@ -209,13 +226,21 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
209226 }
210227}
211228
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) )
229+ fn never_loop_expr_all < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
230+ es : & mut T ,
231+ ignore_ids : & mut Vec < HirId > ,
232+ main_loop_id : HirId ,
233+ ) -> NeverLoopResult {
234+ es. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
214235 . fold ( NeverLoopResult :: Otherwise , combine_both)
215236}
216237
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) )
238+ fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
239+ e : & mut T ,
240+ ignore_ids : & mut Vec < HirId > ,
241+ main_loop_id : HirId ,
242+ ) -> NeverLoopResult {
243+ e. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
219244 . fold ( NeverLoopResult :: AlwaysBreak , combine_branches)
220245}
221246
0 commit comments