about summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuinn Sinclair <me@partiallytyped.dev>2024-01-03 13:36:44 +0200
committerQuinn Sinclair <me@partiallytyped.dev>2024-01-13 17:45:30 +0100
commite0228eeb94501cd864b0fb6edb019f401111d586 (patch)
treeae8d9e469964882387ae3d531ce417418b14f384
parenta71211d0b52c01f1b37fe544e0e13fd1bdc31979 (diff)
downloadrust-e0228eeb94501cd864b0fb6edb019f401111d586.tar.gz
rust-e0228eeb94501cd864b0fb6edb019f401111d586.zip
Fixes FP in `redundant_closure_call` when closures are passed to macros
There are cases where the closure call is needed in some macros, this in
particular occurs when the closure has parameters. To handle this case,
we allow the lint when there are no parameters in the closure, or the
closure is outside a macro invocation.

fixes: #11274, #1553
changelog: FP: [`redundant_closure_call`] when closures with parameters
are passed in macros.
-rw-r--r--clippy_lints/src/redundant_closure_call.rs14
-rw-r--r--tests/ui/redundant_closure_call_fixable.fixed9
-rw-r--r--tests/ui/redundant_closure_call_fixable.rs9
3 files changed, 30 insertions, 2 deletions
diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs
index cde08dfcc74..bd893893435 100644
--- a/clippy_lints/src/redundant_closure_call.rs
+++ b/clippy_lints/src/redundant_closure_call.rs
@@ -2,6 +2,7 @@ use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::get_parent_expr;
 use clippy_utils::sugg::Sugg;
+use hir::Param;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
@@ -11,6 +12,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
+use rustc_span::ExpnKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -87,7 +89,12 @@ fn find_innermost_closure<'tcx>(
     cx: &LateContext<'tcx>,
     mut expr: &'tcx hir::Expr<'tcx>,
     mut steps: usize,
-) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> {
+) -> Option<(
+    &'tcx hir::Expr<'tcx>,
+    &'tcx hir::FnDecl<'tcx>,
+    ty::Asyncness,
+    &'tcx [Param<'tcx>],
+)> {
     let mut data = None;
 
     while let hir::ExprKind::Closure(closure) = expr.kind
@@ -108,6 +115,7 @@ fn find_innermost_closure<'tcx>(
             } else {
                 ty::Asyncness::No
             },
+            body.params,
         ));
         steps -= 1;
     }
@@ -150,7 +158,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
             // without this check, we'd end up linting twice.
             && !matches!(recv.kind, hir::ExprKind::Call(..))
             && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
-            && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth)
+            && let Some((body, fn_decl, coroutine_kind, params)) = find_innermost_closure(cx, recv, call_depth)
+            // outside macros we lint properly. Inside macros, we lint only ||() style closures.
+            && (!matches!(expr.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(_, _)) || params.is_empty())
         {
             span_lint_and_then(
                 cx,
diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed
index f272d8359a3..ce5c7f2600b 100644
--- a/tests/ui/redundant_closure_call_fixable.fixed
+++ b/tests/ui/redundant_closure_call_fixable.fixed
@@ -102,3 +102,12 @@ mod issue11707 {
 fn avoid_double_parens() {
     std::convert::identity(13_i32 + 36_i32).leading_zeros();
 }
+
+fn fp_11274() {
+    macro_rules! m {
+        ($closure:expr) => {
+            $closure(1)
+        };
+    }
+    m!(|x| println!("{x}"));
+}
diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs
index f45db8c9cff..ac09390e6ea 100644
--- a/tests/ui/redundant_closure_call_fixable.rs
+++ b/tests/ui/redundant_closure_call_fixable.rs
@@ -102,3 +102,12 @@ mod issue11707 {
 fn avoid_double_parens() {
     std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
 }
+
+fn fp_11274() {
+    macro_rules! m {
+        ($closure:expr) => {
+            $closure(1)
+        };
+    }
+    m!(|x| println!("{x}"));
+}