@@ -4,11 +4,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
44use clippy_utils:: higher:: ForLoop ;
55use clippy_utils:: macros:: root_macro_call_first_node;
66use clippy_utils:: source:: snippet;
7+ use clippy_utils:: visitors:: { Descend , for_each_expr_without_closures} ;
78use rustc_errors:: Applicability ;
89use rustc_hir:: { Block , Destination , Expr , ExprKind , HirId , InlineAsmOperand , Pat , Stmt , StmtKind , StructTailExpr } ;
910use rustc_lint:: LateContext ;
1011use rustc_span:: { Span , sym} ;
1112use std:: iter:: once;
13+ use std:: ops:: ControlFlow ;
1214
1315pub ( super ) fn check < ' tcx > (
1416 cx : & LateContext < ' tcx > ,
@@ -24,17 +26,23 @@ pub(super) fn check<'tcx>(
2426 arg : iterator,
2527 pat,
2628 span : for_span,
29+ label,
2730 ..
2831 } ) = for_loop
2932 {
30- // Suggests using an `if let` instead. This is `Unspecified` because the
31- // loop may (probably) contain `break` statements which would be invalid
32- // in an `if let`.
33+ // If the block contains a break or continue, or if the loop has a label, `MachineApplicable` is not
34+ // appropriate.
35+ let app = if !contains_any_break_or_continue ( block) && label. is_none ( ) {
36+ Applicability :: MachineApplicable
37+ } else {
38+ Applicability :: Unspecified
39+ } ;
40+
3341 diag. span_suggestion_verbose (
3442 for_span. with_hi ( iterator. span . hi ( ) ) ,
3543 "if you need the first element of the iterator, try writing" ,
3644 for_to_if_let_sugg ( cx, iterator, pat) ,
37- Applicability :: Unspecified ,
45+ app ,
3846 ) ;
3947 }
4048 } ) ;
@@ -43,6 +51,15 @@ pub(super) fn check<'tcx>(
4351 }
4452}
4553
54+ fn contains_any_break_or_continue ( block : & Block < ' _ > ) -> bool {
55+ for_each_expr_without_closures ( block, |e| match e. kind {
56+ ExprKind :: Break ( ..) | ExprKind :: Continue ( ..) => ControlFlow :: Break ( ( ) ) ,
57+ ExprKind :: Loop ( ..) => ControlFlow :: Continue ( Descend :: No ) ,
58+ _ => ControlFlow :: Continue ( Descend :: Yes ) ,
59+ } )
60+ . is_some ( )
61+ }
62+
4663/// The `never_loop` analysis keeps track of three things:
4764///
4865/// * Has any (reachable) code path hit a `continue` of the main loop?
0 commit comments