diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 0e2b78609..618cf4b8b 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, Ident, Symbol}; declare_clippy_lint! { /// ### What it does @@ -85,7 +85,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, ref generics, id) = item.kind { - check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true); + check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true); } } @@ -96,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { cx, sig.decl, Some(id), + None, &item.generics, item.span, report_extra_lifetimes, @@ -105,11 +106,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(ref sig, ref body) = item.kind { - let body = match *body { - TraitFn::Required(_) => None, - TraitFn::Provided(id) => Some(id), + let (body, trait_sig) = match *body { + TraitFn::Required(sig) => (None, Some(sig)), + TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true); + check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true); } } } @@ -126,6 +127,7 @@ fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: Option, + trait_sig: Option<&[Ident]>, generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, @@ -167,7 +169,7 @@ fn check_fn_inner<'tcx>( } } } - if could_use_elision(cx, decl, body, generics.params) { + if could_use_elision(cx, decl, body, trait_sig, generics.params) { span_lint( cx, NEEDLESS_LIFETIMES, @@ -181,10 +183,31 @@ fn check_fn_inner<'tcx>( } } +// elision doesn't work for explicit self types, see rust-lang/rust#69064 +fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option) -> bool { + if_chain! { + if let Some(ident) = ident; + if ident.name == kw::SelfLower; + if !func.implicit_self.has_implicit_self(); + + if let Some(self_ty) = func.inputs.first(); + then { + let mut visitor = RefVisitor::new(cx); + visitor.visit_ty(self_ty); + + !visitor.all_lts().is_empty() + } + else { + false + } + } +} + fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option, + trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], ) -> bool { // There are two scenarios where elision works: @@ -235,11 +258,24 @@ fn could_use_elision<'tcx>( let input_lts = input_visitor.lts; let output_lts = output_visitor.lts; + if let Some(trait_sig) = trait_sig { + if explicit_self_type(cx, func, trait_sig.first().copied()) { + return false; + } + } + if let Some(body_id) = body { + let body = cx.tcx.hir().body(body_id); + + let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); + if explicit_self_type(cx, func, first_ident) { + return false; + } + let mut checker = BodyLifetimeChecker { lifetimes_used_in_body: false, }; - checker.visit_expr(&cx.tcx.hir().body(body_id).value); + checker.visit_expr(&body.value); if checker.lifetimes_used_in_body { return false; } diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index b07c4a238..f3eafe8e9 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,11 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)] +#![allow( + dead_code, + clippy::boxed_local, + clippy::needless_pass_by_value, + clippy::unnecessary_wraps, + dyn_drop +)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -369,4 +375,47 @@ mod issue6159 { } } +mod issue7296 { + use std::rc::Rc; + use std::sync::Arc; + + struct Foo; + impl Foo { + fn implicit<'a>(&'a self) -> &'a () { + &() + } + fn implicit_mut<'a>(&'a mut self) -> &'a () { + &() + } + + fn explicit<'a>(self: &'a Arc) -> &'a () { + &() + } + fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { + &() + } + + fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { + &() + } + } + + trait Bar { + fn implicit<'a>(&'a self) -> &'a (); + fn implicit_provided<'a>(&'a self) -> &'a () { + &() + } + + fn explicit<'a>(self: &'a Arc) -> &'a (); + fn explicit_provided<'a>(self: &'a Arc) -> &'a () { + &() + } + + fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); + fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { + &() + } + } +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 4114e6f18..ffa152427 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:4:1 + --> $DIR/needless_lifetimes.rs:10:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,148 +7,190 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:6:1 + --> $DIR/needless_lifetimes.rs:12:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:16:1 + --> $DIR/needless_lifetimes.rs:22:1 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:56:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:55:1 + --> $DIR/needless_lifetimes.rs:61:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:67:1 + --> $DIR/needless_lifetimes.rs:73:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:91:1 + --> $DIR/needless_lifetimes.rs:97:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:121:5 + --> $DIR/needless_lifetimes.rs:127:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:130:5 + --> $DIR/needless_lifetimes.rs:136:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:149:1 + --> $DIR/needless_lifetimes.rs:155:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:179:1 + --> $DIR/needless_lifetimes.rs:185:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:185:1 + --> $DIR/needless_lifetimes.rs:191:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:204:1 + --> $DIR/needless_lifetimes.rs:210:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:212:1 + --> $DIR/needless_lifetimes.rs:218:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:248:1 + --> $DIR/needless_lifetimes.rs:254:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:255:9 + --> $DIR/needless_lifetimes.rs:261:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:259:9 + --> $DIR/needless_lifetimes.rs:265:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:272:9 + --> $DIR/needless_lifetimes.rs:278:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:301:5 + --> $DIR/needless_lifetimes.rs:307:5 | LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:304:5 + --> $DIR/needless_lifetimes.rs:310:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:313:5 + --> $DIR/needless_lifetimes.rs:319:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:325:5 + --> $DIR/needless_lifetimes.rs:331:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:340:5 + --> $DIR/needless_lifetimes.rs:346:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:353:5 + --> $DIR/needless_lifetimes.rs:359:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:356:5 + --> $DIR/needless_lifetimes.rs:362:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 25 previous errors +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:384:9 + | +LL | fn implicit<'a>(&'a self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:387:9 + | +LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:398:9 + | +LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:404:9 + | +LL | fn implicit<'a>(&'a self) -> &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:405:9 + | +LL | fn implicit_provided<'a>(&'a self) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:414:9 + | +LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) + --> $DIR/needless_lifetimes.rs:415:9 + | +LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 32 previous errors