From 77b3ac3d5731b34441cb4ef0badcf9cc261b2013 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 14 Apr 2025 08:50:44 +0200 Subject: [PATCH] Check for lifetime uses in closures as well The `BodyLifetimeChecker` which checks for the use of any non-anonymous non-static lifetime did not recurse into closures, missing lifetime uses. This would lead to a bogus elision suggestion. The `BodyLifetimeChecker` is not refined enough to avoid false positives, as any conforming lifetime, including one coming from the outer context, would be considered a hit. The number of false positives might increase now that we check closures as well, in case those closures define and use lifetimes themselves. --- clippy_lints/src/lifetimes.rs | 19 ++++++++++++++++--- tests/ui/needless_lifetimes.fixed | 7 +++++++ tests/ui/needless_lifetimes.rs | 7 +++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 9b13dfbd0e93..fd6208f6b5ef 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -314,7 +314,7 @@ fn could_use_elision<'tcx>( return None; } - let mut checker = BodyLifetimeChecker; + let mut checker = BodyLifetimeChecker::new(cx); if checker.visit_expr(body.value).is_break() { return None; } @@ -911,10 +911,23 @@ fn elision_suggestions( Some(suggestions) } -struct BodyLifetimeChecker; +struct BodyLifetimeChecker<'tcx> { + tcx: TyCtxt<'tcx>, +} -impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { +impl<'tcx> BodyLifetimeChecker<'tcx> { + fn new(cx: &LateContext<'tcx>) -> Self { + Self { tcx: cx.tcx } + } +} + +impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker<'tcx> { type Result = ControlFlow<()>; + type NestedFilter = middle_nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> { if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime { diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index d59393fb3f3c..e9d811986aa4 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -534,4 +534,11 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +pub fn issue14607<'s>(x: &'s u8) { + #[expect(clippy::redundant_closure_call)] + (|| { + let _: &'s u8 = x; + })(); +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index e24907ab5fcd..0b6eb9755b93 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -534,4 +534,11 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } +pub fn issue14607<'s>(x: &'s u8) { + #[expect(clippy::redundant_closure_call)] + (|| { + let _: &'s u8 = x; + })(); +} + fn main() {}