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](https://github.com/rust-lang/rust-clippy/pull/10162)
<!-- changelog_checked -->
This commit is contained in:
bors 2023-01-07 11:53:45 +00:00
commit cf1d3d0370
5 changed files with 94 additions and 1 deletions

View file

@ -1,6 +1,7 @@
use super::SINGLE_ELEMENT_LOOP; use super::SINGLE_ELEMENT_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, snippet_with_applicability}; use clippy_utils::source::{indent_of, snippet_with_applicability};
use clippy_utils::visitors::contains_break_or_continue;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::util::parser::PREC_PREFIX;
use rustc_ast::Mutability; use rustc_ast::Mutability;
@ -67,6 +68,7 @@ pub(super) fn check<'tcx>(
if_chain! { if_chain! {
if let ExprKind::Block(block, _) = body.kind; if let ExprKind::Block(block, _) = body.kind;
if !block.stmts.is_empty(); if !block.stmts.is_empty();
if !contains_break_or_continue(body);
then { then {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);

View file

@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>(
ControlFlow::Continue(()) ControlFlow::Continue(())
} }
} }
pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
for_each_expr(expr, |e| {
if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_some()
}

View file

@ -33,4 +33,31 @@ fn main() {
let item = 0..5; let item = 0..5;
dbg!(item); dbg!(item);
} }
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
continue;
}
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
break;
}
}
// should lint (issue #10018)
{
let _ = 42;
let _f = |n: u32| {
for i in 0..n {
if i > 10 {
dbg!(i);
break;
}
}
};
}
} }

View file

@ -27,4 +27,30 @@ fn main() {
for item in [0..5].into_iter() { for item in [0..5].into_iter() {
dbg!(item); dbg!(item);
} }
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
continue;
}
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
break;
}
}
// should lint (issue #10018)
for _ in [42] {
let _f = |n: u32| {
for i in 0..n {
if i > 10 {
dbg!(i);
break;
}
}
};
}
} }

View file

@ -95,5 +95,32 @@ LL + dbg!(item);
LL + } LL + }
| |
error: aborting due to 6 previous errors error: for loop over a single element
--> $DIR/single_element_loop.rs:46:5
|
LL | / for _ in [42] {
LL | | let _f = |n: u32| {
LL | | for i in 0..n {
LL | | if i > 10 {
... |
LL | | };
LL | | }
| |_____^
|
help: try
|
LL ~ {
LL + let _ = 42;
LL + let _f = |n: u32| {
LL + for i in 0..n {
LL + if i > 10 {
LL + dbg!(i);
LL + break;
LL + }
LL + }
LL + };
LL + }
|
error: aborting due to 7 previous errors