11use super :: utils:: make_iterator_snippet;
22use super :: NEVER_LOOP ;
3- use clippy_utils:: diagnostics :: span_lint_and_then ;
3+ use clippy_utils:: consts :: constant ;
44use clippy_utils:: higher:: ForLoop ;
55use clippy_utils:: source:: snippet;
6+ use clippy_utils:: { consts:: Constant , diagnostics:: span_lint_and_then} ;
67use rustc_errors:: Applicability ;
78use rustc_hir:: { Block , Destination , Expr , ExprKind , HirId , InlineAsmOperand , Pat , Stmt , StmtKind } ;
89use rustc_lint:: LateContext ;
910use rustc_span:: Span ;
1011use std:: iter:: { once, Iterator } ;
1112
12- pub ( super ) fn check (
13- cx : & LateContext < ' _ > ,
14- block : & Block < ' _ > ,
13+ pub ( super ) fn check < ' tcx > (
14+ cx : & LateContext < ' tcx > ,
15+ block : & Block < ' tcx > ,
1516 loop_id : HirId ,
1617 span : Span ,
1718 for_loop : Option < & ForLoop < ' _ > > ,
1819) {
19- match never_loop_block ( block, & mut Vec :: new ( ) , loop_id) {
20+ match never_loop_block ( cx , block, & mut Vec :: new ( ) , loop_id) {
2021 NeverLoopResult :: AlwaysBreak => {
2122 span_lint_and_then ( cx, NEVER_LOOP , span, "this loop never actually loops" , |diag| {
2223 if let Some ( ForLoop {
@@ -95,18 +96,23 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirI
9596 }
9697}
9798
98- fn never_loop_block ( block : & Block < ' _ > , ignore_ids : & mut Vec < HirId > , main_loop_id : HirId ) -> NeverLoopResult {
99+ fn never_loop_block < ' tcx > (
100+ cx : & LateContext < ' tcx > ,
101+ block : & Block < ' tcx > ,
102+ ignore_ids : & mut Vec < HirId > ,
103+ main_loop_id : HirId ,
104+ ) -> NeverLoopResult {
99105 let iter = block
100106 . stmts
101107 . iter ( )
102108 . filter_map ( stmt_to_expr)
103109 . chain ( block. expr . map ( |expr| ( expr, None ) ) ) ;
104110
105111 iter. map ( |( e, els) | {
106- let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
112+ let e = never_loop_expr ( cx , e, ignore_ids, main_loop_id) ;
107113 // els is an else block in a let...else binding
108114 els. map_or ( e, |els| {
109- combine_branches ( e, never_loop_block ( els, ignore_ids, main_loop_id) , ignore_ids)
115+ combine_branches ( e, never_loop_block ( cx , els, ignore_ids, main_loop_id) , ignore_ids)
110116 } )
111117 } )
112118 . fold ( NeverLoopResult :: Otherwise , combine_seq)
@@ -122,61 +128,72 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
122128}
123129
124130#[ allow( clippy:: too_many_lines) ]
125- fn never_loop_expr ( expr : & Expr < ' _ > , ignore_ids : & mut Vec < HirId > , main_loop_id : HirId ) -> NeverLoopResult {
131+ fn never_loop_expr < ' tcx > (
132+ cx : & LateContext < ' tcx > ,
133+ expr : & Expr < ' tcx > ,
134+ ignore_ids : & mut Vec < HirId > ,
135+ main_loop_id : HirId ,
136+ ) -> NeverLoopResult {
126137 match expr. kind {
127138 ExprKind :: Unary ( _, e)
128139 | ExprKind :: Cast ( e, _)
129140 | ExprKind :: Type ( e, _)
130141 | ExprKind :: Field ( e, _)
131142 | ExprKind :: AddrOf ( _, _, e)
132143 | ExprKind :: Repeat ( e, _)
133- | ExprKind :: DropTemps ( e) => never_loop_expr ( e, ignore_ids, main_loop_id) ,
134- ExprKind :: Let ( let_expr) => never_loop_expr ( let_expr. init , ignore_ids, main_loop_id) ,
135- ExprKind :: Array ( es) | ExprKind :: Tup ( es) => never_loop_expr_all ( & mut es. iter ( ) , ignore_ids, main_loop_id) ,
144+ | ExprKind :: DropTemps ( e) => never_loop_expr ( cx , e, ignore_ids, main_loop_id) ,
145+ ExprKind :: Let ( let_expr) => never_loop_expr ( cx , let_expr. init , ignore_ids, main_loop_id) ,
146+ ExprKind :: Array ( es) | ExprKind :: Tup ( es) => never_loop_expr_all ( cx , & mut es. iter ( ) , ignore_ids, main_loop_id) ,
136147 ExprKind :: MethodCall ( _, receiver, es, _) => never_loop_expr_all (
148+ cx,
137149 & mut std:: iter:: once ( receiver) . chain ( es. iter ( ) ) ,
138150 ignore_ids,
139151 main_loop_id,
140152 ) ,
141153 ExprKind :: Struct ( _, fields, base) => {
142- let fields = never_loop_expr_all ( & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids, main_loop_id) ;
154+ let fields = never_loop_expr_all ( cx , & mut fields. iter ( ) . map ( |f| f. expr ) , ignore_ids, main_loop_id) ;
143155 if let Some ( base) = base {
144- combine_seq ( fields, never_loop_expr ( base, ignore_ids, main_loop_id) )
156+ combine_seq ( fields, never_loop_expr ( cx , base, ignore_ids, main_loop_id) )
145157 } else {
146158 fields
147159 }
148160 } ,
149- ExprKind :: Call ( e, es) => never_loop_expr_all ( & mut once ( e) . chain ( es. iter ( ) ) , ignore_ids, main_loop_id) ,
161+ ExprKind :: Call ( e, es) => never_loop_expr_all ( cx , & mut once ( e) . chain ( es. iter ( ) ) , ignore_ids, main_loop_id) ,
150162 ExprKind :: Binary ( _, e1, e2)
151163 | ExprKind :: Assign ( e1, e2, _)
152164 | ExprKind :: AssignOp ( _, e1, e2)
153- | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( & mut [ e1, e2] . iter ( ) . copied ( ) , ignore_ids, main_loop_id) ,
165+ | ExprKind :: Index ( e1, e2) => never_loop_expr_all ( cx , & mut [ e1, e2] . iter ( ) . copied ( ) , ignore_ids, main_loop_id) ,
154166 ExprKind :: Loop ( b, _, _, _) => {
155167 // Break can come from the inner loop so remove them.
156- absorb_break ( never_loop_block ( b, ignore_ids, main_loop_id) )
168+ absorb_break ( never_loop_block ( cx , b, ignore_ids, main_loop_id) )
157169 } ,
158170 ExprKind :: If ( e, e2, e3) => {
159- let e1 = never_loop_expr ( e, ignore_ids, main_loop_id) ;
160- let e2 = never_loop_expr ( e2, ignore_ids, main_loop_id) ;
171+ let e1 = never_loop_expr ( cx, e, ignore_ids, main_loop_id) ;
172+ let e2 = never_loop_expr ( cx, e2, ignore_ids, main_loop_id) ;
173+ // If we know the `if` condition evaluates to `true`, don't check everything past it; it
174+ // should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable
175+ if let Some ( Constant :: Bool ( true ) ) = constant ( cx, cx. typeck_results ( ) , e) {
176+ return combine_seq ( e1, e2) ;
177+ }
161178 let e3 = e3. as_ref ( ) . map_or ( NeverLoopResult :: Otherwise , |e| {
162- never_loop_expr ( e, ignore_ids, main_loop_id)
179+ never_loop_expr ( cx , e, ignore_ids, main_loop_id)
163180 } ) ;
164181 combine_seq ( e1, combine_branches ( e2, e3, ignore_ids) )
165182 } ,
166183 ExprKind :: Match ( e, arms, _) => {
167- let e = never_loop_expr ( e, ignore_ids, main_loop_id) ;
184+ let e = never_loop_expr ( cx , e, ignore_ids, main_loop_id) ;
168185 if arms. is_empty ( ) {
169186 e
170187 } else {
171- let arms = never_loop_expr_branch ( & mut arms. iter ( ) . map ( |a| a. body ) , ignore_ids, main_loop_id) ;
188+ let arms = never_loop_expr_branch ( cx , & mut arms. iter ( ) . map ( |a| a. body ) , ignore_ids, main_loop_id) ;
172189 combine_seq ( e, arms)
173190 }
174191 } ,
175192 ExprKind :: Block ( b, l) => {
176193 if l. is_some ( ) {
177194 ignore_ids. push ( b. hir_id ) ;
178195 }
179- let ret = never_loop_block ( b, ignore_ids, main_loop_id) ;
196+ let ret = never_loop_block ( cx , b, ignore_ids, main_loop_id) ;
180197 if l. is_some ( ) {
181198 ignore_ids. pop ( ) ;
182199 }
@@ -198,11 +215,11 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
198215 // checks if break targets a block instead of a loop
199216 ExprKind :: Break ( Destination { target_id : Ok ( t) , .. } , e) if ignore_ids. contains ( & t) => e
200217 . map_or ( NeverLoopResult :: IgnoreUntilEnd ( t) , |e| {
201- never_loop_expr ( e, ignore_ids, main_loop_id)
218+ never_loop_expr ( cx , e, ignore_ids, main_loop_id)
202219 } ) ,
203220 ExprKind :: Break ( _, e) | ExprKind :: Ret ( e) => e. as_ref ( ) . map_or ( NeverLoopResult :: AlwaysBreak , |e| {
204221 combine_seq (
205- never_loop_expr ( e, ignore_ids, main_loop_id) ,
222+ never_loop_expr ( cx , e, ignore_ids, main_loop_id) ,
206223 NeverLoopResult :: AlwaysBreak ,
207224 )
208225 } ) ,
@@ -211,12 +228,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
211228 . iter ( )
212229 . map ( |( o, _) | match o {
213230 InlineAsmOperand :: In { expr, .. } | InlineAsmOperand :: InOut { expr, .. } => {
214- never_loop_expr ( expr, ignore_ids, main_loop_id)
231+ never_loop_expr ( cx , expr, ignore_ids, main_loop_id)
215232 } ,
216233 InlineAsmOperand :: Out { expr, .. } => {
217- never_loop_expr_all ( & mut expr. iter ( ) . copied ( ) , ignore_ids, main_loop_id)
234+ never_loop_expr_all ( cx , & mut expr. iter ( ) . copied ( ) , ignore_ids, main_loop_id)
218235 } ,
219236 InlineAsmOperand :: SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all (
237+ cx,
220238 & mut once ( * in_expr) . chain ( out_expr. iter ( ) . copied ( ) ) ,
221239 ignore_ids,
222240 main_loop_id,
@@ -236,22 +254,24 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
236254 }
237255}
238256
239- fn never_loop_expr_all < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
257+ fn never_loop_expr_all < ' tcx , T : Iterator < Item = & ' tcx Expr < ' tcx > > > (
258+ cx : & LateContext < ' tcx > ,
240259 es : & mut T ,
241260 ignore_ids : & mut Vec < HirId > ,
242261 main_loop_id : HirId ,
243262) -> NeverLoopResult {
244- es. map ( |e| never_loop_expr ( e, ignore_ids, main_loop_id) )
263+ es. map ( |e| never_loop_expr ( cx , e, ignore_ids, main_loop_id) )
245264 . fold ( NeverLoopResult :: Otherwise , combine_seq)
246265}
247266
248- fn never_loop_expr_branch < ' a , T : Iterator < Item = & ' a Expr < ' a > > > (
267+ fn never_loop_expr_branch < ' tcx , T : Iterator < Item = & ' tcx Expr < ' tcx > > > (
268+ cx : & LateContext < ' tcx > ,
249269 e : & mut T ,
250270 ignore_ids : & mut Vec < HirId > ,
251271 main_loop_id : HirId ,
252272) -> NeverLoopResult {
253273 e. fold ( NeverLoopResult :: AlwaysBreak , |a, b| {
254- combine_branches ( a, never_loop_expr ( b, ignore_ids, main_loop_id) , ignore_ids)
274+ combine_branches ( a, never_loop_expr ( cx , b, ignore_ids, main_loop_id) , ignore_ids)
255275 } )
256276}
257277
0 commit comments