about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-07 11:53:45 +0000
committerbors <bors@rust-lang.org>2023-01-07 11:53:45 +0000
commitcf1d3d03700069d6a31fc142a1808a7f3dcde429 (patch)
tree8f7dc6233b1f205d09ba1da3d38f76cf9a5c0980
parentef5a545f9860fbbea3f6c94bad60ab87f384d458 (diff)
parentce56cf71d956ea78c319ff510651473ca8dce47c (diff)
downloadrust-cf1d3d03700069d6a31fc142a1808a7f3dcde429.tar.gz
rust-cf1d3d03700069d6a31fc142a1808a7f3dcde429.zip
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 -->
-rw-r--r--clippy_lints/src/loops/single_element_loop.rs2
-rw-r--r--clippy_utils/src/visitors.rs11
-rw-r--r--tests/ui/single_element_loop.fixed27
-rw-r--r--tests/ui/single_element_loop.rs26
-rw-r--r--tests/ui/single_element_loop.stderr29
5 files changed, 94 insertions, 1 deletions
diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs
index f4b47808dfa..744fd61bd13 100644
--- a/clippy_lints/src/loops/single_element_loop.rs
+++ b/clippy_lints/src/loops/single_element_loop.rs
@@ -1,6 +1,7 @@
 use super::SINGLE_ELEMENT_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, snippet_with_applicability};
+use clippy_utils::visitors::contains_break_or_continue;
 use if_chain::if_chain;
 use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_ast::Mutability;
@@ -67,6 +68,7 @@ pub(super) fn check<'tcx>(
     if_chain! {
         if let ExprKind::Block(block, _) = body.kind;
         if !block.stmts.is_empty();
+        if !contains_break_or_continue(body);
         then {
             let mut applicability = Applicability::MachineApplicable;
             let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs
index 863fb60fcfc..14c01a60b4c 100644
--- a/clippy_utils/src/visitors.rs
+++ b/clippy_utils/src/visitors.rs
@@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>(
         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()
+}
diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed
index 63d31ff83f9..a0dcc0172e8 100644
--- a/tests/ui/single_element_loop.fixed
+++ b/tests/ui/single_element_loop.fixed
@@ -33,4 +33,31 @@ fn main() {
         let item = 0..5;
         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;
+                }
+            }
+        };
+    }
 }
diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs
index 2cda5a329d2..bc014035c98 100644
--- a/tests/ui/single_element_loop.rs
+++ b/tests/ui/single_element_loop.rs
@@ -27,4 +27,30 @@ fn main() {
     for item in [0..5].into_iter() {
         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;
+                }
+            }
+        };
+    }
 }
diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr
index 0aeb8da1a2e..14437a59745 100644
--- a/tests/ui/single_element_loop.stderr
+++ b/tests/ui/single_element_loop.stderr
@@ -95,5 +95,32 @@ LL +         dbg!(item);
 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