Skip to content

Commit 6558956

Browse files
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.
1 parent 0153ca9 commit 6558956

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

clippy_lints/src/redundant_closure_call.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::rustc_lint::LintContext;
22
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
33
use clippy_utils::get_parent_expr;
44
use clippy_utils::sugg::Sugg;
5+
use hir::Param;
56
use rustc_errors::Applicability;
67
use rustc_hir as hir;
78
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
@@ -11,6 +12,7 @@ use rustc_middle::hir::nested_filter;
1112
use rustc_middle::lint::in_external_macro;
1213
use rustc_middle::ty;
1314
use rustc_session::declare_lint_pass;
15+
use rustc_span::{DesugaringKind, ExpnKind};
1416

1517
declare_clippy_lint! {
1618
/// ### What it does
@@ -87,7 +89,12 @@ fn find_innermost_closure<'tcx>(
8789
cx: &LateContext<'tcx>,
8890
mut expr: &'tcx hir::Expr<'tcx>,
8991
mut steps: usize,
90-
) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, ty::Asyncness)> {
92+
) -> Option<(
93+
&'tcx hir::Expr<'tcx>,
94+
&'tcx hir::FnDecl<'tcx>,
95+
ty::Asyncness,
96+
&'tcx [Param<'tcx>],
97+
)> {
9198
let mut data = None;
9299

93100
while let hir::ExprKind::Closure(closure) = expr.kind
@@ -108,6 +115,7 @@ fn find_innermost_closure<'tcx>(
108115
} else {
109116
ty::Asyncness::No
110117
},
118+
body.params,
111119
));
112120
steps -= 1;
113121
}
@@ -136,6 +144,23 @@ fn get_parent_call_exprs<'tcx>(
136144
(expr, depth)
137145
}
138146

147+
/// This has been pulled from `in_external_macro`, and the checks for being outside the
148+
/// current crate have been removed.
149+
fn in_macro(expr: &'_ hir::Expr<'_>) -> bool {
150+
let expn_data = expr.span.ctxt().outer_expn_data();
151+
!matches!(
152+
expn_data.kind,
153+
ExpnKind::Root
154+
| ExpnKind::Desugaring(
155+
DesugaringKind::ForLoop
156+
| DesugaringKind::WhileLoop
157+
| DesugaringKind::OpaqueTy
158+
| DesugaringKind::Async
159+
| DesugaringKind::Await,
160+
)
161+
)
162+
}
163+
139164
impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
140165
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
141166
if in_external_macro(cx.sess(), expr.span) {
@@ -150,7 +175,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
150175
// without this check, we'd end up linting twice.
151176
&& !matches!(recv.kind, hir::ExprKind::Call(..))
152177
&& let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
153-
&& let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth)
178+
&& let Some((body, fn_decl, coroutine_kind, params)) = find_innermost_closure(cx, recv, call_depth)
179+
// outside macros we lint properly. Inside macros, we lint only ||() style closures.
180+
&& (!in_macro(expr) || params.is_empty())
154181
{
155182
span_lint_and_then(
156183
cx,

tests/ui/redundant_closure_call_fixable.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,12 @@ mod issue11707 {
102102
fn avoid_double_parens() {
103103
std::convert::identity(13_i32 + 36_i32).leading_zeros();
104104
}
105+
106+
fn fp_11274() {
107+
macro_rules! m {
108+
($closure:expr) => {
109+
$closure(1)
110+
};
111+
}
112+
m!(|x| println!("{x}"));
113+
}

tests/ui/redundant_closure_call_fixable.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,12 @@ mod issue11707 {
102102
fn avoid_double_parens() {
103103
std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros();
104104
}
105+
106+
fn fp_11274() {
107+
macro_rules! m {
108+
($closure:expr) => {
109+
$closure(1)
110+
};
111+
}
112+
m!(|x| println!("{x}"));
113+
}

0 commit comments

Comments
 (0)