about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-02 12:36:42 +0000
committerbors <bors@rust-lang.org>2024-05-02 12:36:42 +0000
commita2bd02b57e9e5d433ea0bfa585dbe6f22d58b303 (patch)
treebc9b86be9999062d9432489f144ce689cb121226
parent1325425589efdaf4bba99c37f0d80030ab53aac5 (diff)
parenta3ef100fa6fdb7d07c52b35d2462fa74cbf7ccd3 (diff)
downloadrust-a2bd02b57e9e5d433ea0bfa585dbe6f22d58b303.tar.gz
rust-a2bd02b57e9e5d433ea0bfa585dbe6f22d58b303.zip
Auto merge of #12515 - bend-n:🦀, r=llogiq
fix `for x in y unsafe { }`

fixes #12514

----

changelog: [`needless_for_each`]: unsafe block in for loop body suggestion
-rw-r--r--clippy_lints/src/needless_for_each.rs16
-rw-r--r--tests/ui/needless_for_each_fixable.fixed4
-rw-r--r--tests/ui/needless_for_each_fixable.rs4
3 files changed, 22 insertions, 2 deletions
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs
index 84a07df1bb0..630018238f4 100644
--- a/clippy_lints/src/needless_for_each.rs
+++ b/clippy_lints/src/needless_for_each.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind};
+use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::{sym, Span, Symbol};
@@ -35,6 +35,16 @@ declare_clippy_lint! {
     ///     println!("{}", elem);
     /// }
     /// ```
+    ///
+    /// ### Known Problems
+    /// When doing things such as:
+    /// ```ignore
+    /// let v = vec![0, 1, 2];
+    /// v.iter().for_each(|elem| unsafe {
+    ///     libc::printf(c"%d\n".as_ptr(), elem);
+    /// });
+    /// ```
+    /// This lint will not trigger.
     #[clippy::version = "1.53.0"]
     pub NEEDLESS_FOR_EACH,
     pedantic,
@@ -68,7 +78,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
             && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind
             && let body = cx.tcx.hir().body(body)
-            && let ExprKind::Block(..) = body.value.kind
+            // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
+            // and suggesting `for … in … { unsafe { } }` is a little ugly.
+            && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind
         {
             let mut ret_collector = RetCollector::default();
             ret_collector.visit_expr(body.value);
diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed
index 8c0e7ba7627..2362314290e 100644
--- a/tests/ui/needless_for_each_fixable.fixed
+++ b/tests/ui/needless_for_each_fixable.fixed
@@ -113,6 +113,10 @@ fn should_not_lint() {
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
+    // `for_each` has a closure with an unsafe block.
+    v.iter().for_each(|elem| unsafe {
+        acc += elem;
+    });
 }
 
 fn main() {}
diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs
index cdc903a636c..5b1186daa22 100644
--- a/tests/ui/needless_for_each_fixable.rs
+++ b/tests/ui/needless_for_each_fixable.rs
@@ -113,6 +113,10 @@ fn should_not_lint() {
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
+    // `for_each` has a closure with an unsafe block.
+    v.iter().for_each(|elem| unsafe {
+        acc += elem;
+    });
 }
 
 fn main() {}