diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index e3f0ce2a9..f61527cc0 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 ce5c7f260..191f77199 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 ac09390e6..33a3b90f9 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)(); +}