@@ -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:: 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 > ,
@@ -27,14 +29,19 @@ pub(super) fn check<'tcx>(
27
29
..
28
30
} ) = for_loop
29
31
{
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`.
32
+ let app = if let Some ( block_expr) = block. expr
33
+ && !is_loop_contains_break_continue ( block_expr)
34
+ {
35
+ Applicability :: MachineApplicable
36
+ } else {
37
+ Applicability :: Unspecified
38
+ } ;
39
+
33
40
diag. span_suggestion_verbose (
34
41
for_span. with_hi ( iterator. span . hi ( ) ) ,
35
42
"if you need the first element of the iterator, try writing" ,
36
43
for_to_if_let_sugg ( cx, iterator, pat) ,
37
- Applicability :: Unspecified ,
44
+ app ,
38
45
) ;
39
46
}
40
47
} ) ;
@@ -43,6 +50,14 @@ pub(super) fn check<'tcx>(
43
50
}
44
51
}
45
52
53
+ fn is_loop_contains_break_continue ( expr : & Expr < ' _ > ) -> bool {
54
+ for_each_expr_without_closures ( expr, |e| match e. kind {
55
+ ExprKind :: Break ( ..) | ExprKind :: Continue ( ..) => ControlFlow :: Break ( ( ) ) ,
56
+ _ => ControlFlow :: Continue ( ( ) ) ,
57
+ } )
58
+ . is_some ( )
59
+ }
60
+
46
61
/// The `never_loop` analysis keeps track of three things:
47
62
///
48
63
/// * Has any (reachable) code path hit a `continue` of the main loop?
0 commit comments