Skip to content

Commit cf1d3d0

Browse files
committed
Auto merge of #10162 - tamaroning:fix10018, r=xFrednet
Fix FP of single-element-loop closes #10018 --- changelog: [`single_element_loop`]: No longer lints, if the loop contains a `break` or `continue` [#10162](rust-lang/rust-clippy#10162) <!-- changelog_checked -->
2 parents ef5a545 + ce56cf7 commit cf1d3d0

File tree

5 files changed

+94
-1
lines changed

5 files changed

+94
-1
lines changed

clippy_lints/src/loops/single_element_loop.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::SINGLE_ELEMENT_LOOP;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::source::{indent_of, snippet_with_applicability};
4+
use clippy_utils::visitors::contains_break_or_continue;
45
use if_chain::if_chain;
56
use rustc_ast::util::parser::PREC_PREFIX;
67
use rustc_ast::Mutability;
@@ -67,6 +68,7 @@ pub(super) fn check<'tcx>(
6768
if_chain! {
6869
if let ExprKind::Block(block, _) = body.kind;
6970
if !block.stmts.is_empty();
71+
if !contains_break_or_continue(body);
7072
then {
7173
let mut applicability = Applicability::MachineApplicable;
7274
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);

clippy_utils/src/visitors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>(
724724
ControlFlow::Continue(())
725725
}
726726
}
727+
728+
pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
729+
for_each_expr(expr, |e| {
730+
if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
731+
ControlFlow::Break(())
732+
} else {
733+
ControlFlow::Continue(())
734+
}
735+
})
736+
.is_some()
737+
}

tests/ui/single_element_loop.fixed

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,31 @@ fn main() {
3333
let item = 0..5;
3434
dbg!(item);
3535
}
36+
37+
// should not lint (issue #10018)
38+
for e in [42] {
39+
if e > 0 {
40+
continue;
41+
}
42+
}
43+
44+
// should not lint (issue #10018)
45+
for e in [42] {
46+
if e > 0 {
47+
break;
48+
}
49+
}
50+
51+
// should lint (issue #10018)
52+
{
53+
let _ = 42;
54+
let _f = |n: u32| {
55+
for i in 0..n {
56+
if i > 10 {
57+
dbg!(i);
58+
break;
59+
}
60+
}
61+
};
62+
}
3663
}

tests/ui/single_element_loop.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,30 @@ fn main() {
2727
for item in [0..5].into_iter() {
2828
dbg!(item);
2929
}
30+
31+
// should not lint (issue #10018)
32+
for e in [42] {
33+
if e > 0 {
34+
continue;
35+
}
36+
}
37+
38+
// should not lint (issue #10018)
39+
for e in [42] {
40+
if e > 0 {
41+
break;
42+
}
43+
}
44+
45+
// should lint (issue #10018)
46+
for _ in [42] {
47+
let _f = |n: u32| {
48+
for i in 0..n {
49+
if i > 10 {
50+
dbg!(i);
51+
break;
52+
}
53+
}
54+
};
55+
}
3056
}

tests/ui/single_element_loop.stderr

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,32 @@ LL + dbg!(item);
9595
LL + }
9696
|
9797

98-
error: aborting due to 6 previous errors
98+
error: for loop over a single element
99+
--> $DIR/single_element_loop.rs:46:5
100+
|
101+
LL | / for _ in [42] {
102+
LL | | let _f = |n: u32| {
103+
LL | | for i in 0..n {
104+
LL | | if i > 10 {
105+
... |
106+
LL | | };
107+
LL | | }
108+
| |_____^
109+
|
110+
help: try
111+
|
112+
LL ~ {
113+
LL + let _ = 42;
114+
LL + let _f = |n: u32| {
115+
LL + for i in 0..n {
116+
LL + if i > 10 {
117+
LL + dbg!(i);
118+
LL + break;
119+
LL + }
120+
LL + }
121+
LL + };
122+
LL + }
123+
|
124+
125+
error: aborting due to 7 previous errors
99126

0 commit comments

Comments
 (0)