@@ -4,11 +4,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
4
4
use clippy_utils:: higher:: ForLoop ;
5
5
use clippy_utils:: macros:: root_macro_call_first_node;
6
6
use clippy_utils:: source:: snippet;
7
+ use clippy_utils:: visitors:: { Descend , for_each_expr_without_closures} ;
7
8
use rustc_errors:: Applicability ;
8
9
use rustc_hir:: { Block , Destination , Expr , ExprKind , HirId , InlineAsmOperand , Pat , Stmt , StmtKind , StructTailExpr } ;
9
10
use rustc_lint:: LateContext ;
10
11
use rustc_span:: { Span , sym} ;
11
12
use std:: iter:: once;
13
+ use std:: ops:: ControlFlow ;
12
14
13
15
pub ( super ) fn check < ' tcx > (
14
16
cx : & LateContext < ' tcx > ,
@@ -24,17 +26,23 @@ pub(super) fn check<'tcx>(
24
26
arg : iterator,
25
27
pat,
26
28
span : for_span,
29
+ label,
27
30
..
28
31
} ) = for_loop
29
32
{
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
+
33
41
diag. span_suggestion_verbose (
34
42
for_span. with_hi ( iterator. span . hi ( ) ) ,
35
43
"if you need the first element of the iterator, try writing" ,
36
44
for_to_if_let_sugg ( cx, iterator, pat) ,
37
- Applicability :: Unspecified ,
45
+ app ,
38
46
) ;
39
47
}
40
48
} ) ;
@@ -43,6 +51,15 @@ pub(super) fn check<'tcx>(
43
51
}
44
52
}
45
53
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
+
46
63
/// The `never_loop` analysis keeps track of three things:
47
64
///
48
65
/// * Has any (reachable) code path hit a `continue` of the main loop?
0 commit comments