Check for lifetime uses in closures as well (#14608)

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.

changelog: [`needless_lifetimes`]: do not suggest removing a lifetime
which is later used in a closure

Fixes rust-lang/rust-clippy#14607
This commit is contained in:
dswij 2025-04-17 16:14:31 +00:00 committed by GitHub
commit 94f0994b1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 30 additions and 3 deletions

View file

@ -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 {

View file

@ -534,4 +534,11 @@ mod issue13749bis {
impl<'a, T: 'a> Generic<T> {}
}
pub fn issue14607<'s>(x: &'s u8) {
#[expect(clippy::redundant_closure_call)]
(|| {
let _: &'s u8 = x;
})();
}
fn main() {}

View file

@ -534,4 +534,11 @@ mod issue13749bis {
impl<'a, T: 'a> Generic<T> {}
}
pub fn issue14607<'s>(x: &'s u8) {
#[expect(clippy::redundant_closure_call)]
(|| {
let _: &'s u8 = x;
})();
}
fn main() {}