Skip to content

Commit

Permalink
Auto merge of #8278 - Alexendoo:needless-lifetime-explicit-self-ty, r…
Browse files Browse the repository at this point in the history
…=xFrednet

`needless_lifetimes`: ignore lifetimes in explicit self types

changelog: false positive fix: [`needless_lifetimes`] no longer lints lifetimes in explicit self types

They're not currently elidable (rust-lang/rust#69064)

Fixes #7296
  • Loading branch information
bors committed Jan 22, 2022
2 parents acfc161 + 9ef6e21 commit 1e546c5
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 35 deletions.
52 changes: 44 additions & 8 deletions clippy_lints/src/lifetimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -96,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
cx,
sig.decl,
Some(id),
None,
&item.generics,
item.span,
report_extra_lifetimes,
Expand All @@ -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);
}
}
}
Expand All @@ -126,6 +127,7 @@ fn check_fn_inner<'tcx>(
cx: &LateContext<'tcx>,
decl: &'tcx FnDecl<'_>,
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
generics: &'tcx Generics<'_>,
span: Span,
report_extra_lifetimes: bool,
Expand Down Expand Up @@ -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,
Expand All @@ -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<Ident>) -> 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<BodyId>,
trait_sig: Option<&[Ident]>,
named_generics: &'tcx [GenericParam<'_>],
) -> bool {
// There are two scenarios where elision works:
Expand Down Expand Up @@ -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;
}
Expand Down
51 changes: 50 additions & 1 deletion tests/ui/needless_lifetimes.rs
Original file line number Diff line number Diff line change
@@ -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) {}

Expand Down Expand Up @@ -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<Self>) -> &'a () {
&()
}
fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
&()
}

fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
&()
}
}

trait Bar {
fn implicit<'a>(&'a self) -> &'a ();
fn implicit_provided<'a>(&'a self) -> &'a () {
&()
}

fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
&()
}

fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
&()
}
}
}

fn main() {}
Loading

0 comments on commit 1e546c5

Please sign in to comment.