Skip to content

Commit 94f0994

Browse files
authored
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 #14607
2 parents 26f43ff + 77b3ac3 commit 94f0994

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

clippy_lints/src/lifetimes.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ fn could_use_elision<'tcx>(
314314
return None;
315315
}
316316

317-
let mut checker = BodyLifetimeChecker;
317+
let mut checker = BodyLifetimeChecker::new(cx);
318318
if checker.visit_expr(body.value).is_break() {
319319
return None;
320320
}
@@ -911,10 +911,23 @@ fn elision_suggestions(
911911
Some(suggestions)
912912
}
913913

914-
struct BodyLifetimeChecker;
914+
struct BodyLifetimeChecker<'tcx> {
915+
tcx: TyCtxt<'tcx>,
916+
}
917+
918+
impl<'tcx> BodyLifetimeChecker<'tcx> {
919+
fn new(cx: &LateContext<'tcx>) -> Self {
920+
Self { tcx: cx.tcx }
921+
}
922+
}
915923

916-
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
924+
impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker<'tcx> {
917925
type Result = ControlFlow<()>;
926+
type NestedFilter = middle_nested_filter::OnlyBodies;
927+
928+
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
929+
self.tcx
930+
}
918931
// for lifetimes as parameters of generics
919932
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> {
920933
if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {

tests/ui/needless_lifetimes.fixed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,4 +534,11 @@ mod issue13749bis {
534534
impl<'a, T: 'a> Generic<T> {}
535535
}
536536

537+
pub fn issue14607<'s>(x: &'s u8) {
538+
#[expect(clippy::redundant_closure_call)]
539+
(|| {
540+
let _: &'s u8 = x;
541+
})();
542+
}
543+
537544
fn main() {}

tests/ui/needless_lifetimes.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,4 +534,11 @@ mod issue13749bis {
534534
impl<'a, T: 'a> Generic<T> {}
535535
}
536536

537+
pub fn issue14607<'s>(x: &'s u8) {
538+
#[expect(clippy::redundant_closure_call)]
539+
(|| {
540+
let _: &'s u8 = x;
541+
})();
542+
}
543+
537544
fn main() {}

0 commit comments

Comments
 (0)