about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/redundant_closure_call.rs9
-rw-r--r--tests/ui/redundant_closure_call_fixable.fixed17
-rw-r--r--tests/ui/redundant_closure_call_fixable.rs17
3 files changed, 43 insertions, 0 deletions
diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs
index e3f0ce2a922..f61527cc0a9 100644
--- a/clippy_lints/src/redundant_closure_call.rs
+++ b/clippy_lints/src/redundant_closure_call.rs
@@ -159,6 +159,15 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
             //           ^^  we only want to lint for this call (but we walk up the calls to consider both calls).
             // without this check, we'd end up linting twice.
             && !matches!(recv.kind, hir::ExprKind::Call(..))
+            // Check if `recv` comes from a macro expansion. If it does, make sure that it's an expansion that is
+            // the same as the one the call is in.
+            // For instance, let's assume `x!()` returns a closure:
+            //    B ---v
+            //      x!()()
+            //          ^- A
+            // The call happens in the expansion `A`, while the closure originates from the expansion `B`.
+            // We don't want to suggest replacing `x!()()` with `x!()`.
+            && recv.span.ctxt().outer_expn() == expr.span.ctxt().outer_expn()
             && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
             && 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.
diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed
index ce5c7f2600b..191f7719904 100644
--- a/tests/ui/redundant_closure_call_fixable.fixed
+++ b/tests/ui/redundant_closure_call_fixable.fixed
@@ -111,3 +111,20 @@ fn fp_11274() {
     }
     m!(|x| println!("{x}"));
 }
+
+// Issue #12358: When a macro expands into a closure, immediately calling the expanded closure
+// triggers the lint.
+fn issue_12358() {
+    macro_rules! make_closure {
+        () => {
+            (|| || {})
+        };
+        (x) => {
+            make_closure!()()
+        };
+    }
+
+    // The lint would suggest to alter the line below to `make_closure!(x)`, which is semantically
+    // different.
+    make_closure!(x)();
+}
diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs
index ac09390e6ea..33a3b90f9cf 100644
--- a/tests/ui/redundant_closure_call_fixable.rs
+++ b/tests/ui/redundant_closure_call_fixable.rs
@@ -111,3 +111,20 @@ fn fp_11274() {
     }
     m!(|x| println!("{x}"));
 }
+
+// Issue #12358: When a macro expands into a closure, immediately calling the expanded closure
+// triggers the lint.
+fn issue_12358() {
+    macro_rules! make_closure {
+        () => {
+            (|| || {})
+        };
+        (x) => {
+            make_closure!()()
+        };
+    }
+
+    // The lint would suggest to alter the line below to `make_closure!(x)`, which is semantically
+    // different.
+    make_closure!(x)();
+}