Skip to content

Commit 47e45ed

Browse files
committed
needless_lifetimes: ignore lifetimes in explicit self types
1 parent 5cada57 commit 47e45ed

File tree

3 files changed

+138
-9
lines changed

3 files changed

+138
-9
lines changed

clippy_lints/src/lifetimes.rs

+44-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
1515
use rustc_middle::hir::map::Map;
1616
use rustc_session::{declare_lint_pass, declare_tool_lint};
1717
use rustc_span::source_map::Span;
18-
use rustc_span::symbol::{kw, Symbol};
18+
use rustc_span::symbol::{kw, Ident, Symbol};
1919

2020
declare_clippy_lint! {
2121
/// ### What it does
@@ -85,7 +85,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
8585
impl<'tcx> LateLintPass<'tcx> for Lifetimes {
8686
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
8787
if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
88-
check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
88+
check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
8989
}
9090
}
9191

@@ -96,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
9696
cx,
9797
sig.decl,
9898
Some(id),
99+
None,
99100
&item.generics,
100101
item.span,
101102
report_extra_lifetimes,
@@ -105,11 +106,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
105106

106107
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
107108
if let TraitItemKind::Fn(ref sig, ref body) = item.kind {
108-
let body = match *body {
109-
TraitFn::Required(_) => None,
110-
TraitFn::Provided(id) => Some(id),
109+
let (body, trait_sig) = match *body {
110+
TraitFn::Required(sig) => (None, Some(sig)),
111+
TraitFn::Provided(id) => (Some(id), None),
111112
};
112-
check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
113+
check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true);
113114
}
114115
}
115116
}
@@ -126,6 +127,7 @@ fn check_fn_inner<'tcx>(
126127
cx: &LateContext<'tcx>,
127128
decl: &'tcx FnDecl<'_>,
128129
body: Option<BodyId>,
130+
trait_sig: Option<&[Ident]>,
129131
generics: &'tcx Generics<'_>,
130132
span: Span,
131133
report_extra_lifetimes: bool,
@@ -167,7 +169,7 @@ fn check_fn_inner<'tcx>(
167169
}
168170
}
169171
}
170-
if could_use_elision(cx, decl, body, generics.params) {
172+
if could_use_elision(cx, decl, body, trait_sig, generics.params) {
171173
span_lint(
172174
cx,
173175
NEEDLESS_LIFETIMES,
@@ -181,10 +183,31 @@ fn check_fn_inner<'tcx>(
181183
}
182184
}
183185

186+
// elision doesn't work for explicit self types, see rust-lang/rust#69064
187+
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
188+
if_chain! {
189+
if let Some(ident) = ident;
190+
if ident.name == kw::SelfLower;
191+
if !func.implicit_self.has_implicit_self();
192+
193+
if let Some(self_ty) = func.inputs.first();
194+
then {
195+
let mut visitor = RefVisitor::new(cx);
196+
visitor.visit_ty(self_ty);
197+
198+
!visitor.all_lts().is_empty()
199+
}
200+
else {
201+
false
202+
}
203+
}
204+
}
205+
184206
fn could_use_elision<'tcx>(
185207
cx: &LateContext<'tcx>,
186208
func: &'tcx FnDecl<'_>,
187209
body: Option<BodyId>,
210+
trait_sig: Option<&[Ident]>,
188211
named_generics: &'tcx [GenericParam<'_>],
189212
) -> bool {
190213
// There are two scenarios where elision works:
@@ -235,11 +258,24 @@ fn could_use_elision<'tcx>(
235258
let input_lts = input_visitor.lts;
236259
let output_lts = output_visitor.lts;
237260

261+
if let Some(trait_sig) = trait_sig {
262+
if explicit_self_type(cx, func, trait_sig.first().copied()) {
263+
return false;
264+
}
265+
}
266+
238267
if let Some(body_id) = body {
268+
let body = cx.tcx.hir().body(body_id);
269+
270+
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
271+
if explicit_self_type(cx, func, first_ident) {
272+
return false;
273+
}
274+
239275
let mut checker = BodyLifetimeChecker {
240276
lifetimes_used_in_body: false,
241277
};
242-
checker.visit_expr(&cx.tcx.hir().body(body_id).value);
278+
checker.visit_expr(&body.value);
243279
if checker.lifetimes_used_in_body {
244280
return false;
245281
}

tests/ui/needless_lifetimes.rs

+43
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,47 @@ mod issue6159 {
369369
}
370370
}
371371

372+
mod issue7296 {
373+
use std::rc::Rc;
374+
use std::sync::Arc;
375+
376+
struct Foo;
377+
impl Foo {
378+
fn implicit<'a>(&'a self) -> &'a () {
379+
&()
380+
}
381+
fn implicit_mut<'a>(&'a mut self) -> &'a () {
382+
&()
383+
}
384+
385+
fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
386+
&()
387+
}
388+
fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
389+
&()
390+
}
391+
392+
fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
393+
&()
394+
}
395+
}
396+
397+
trait Bar {
398+
fn implicit<'a>(&'a self) -> &'a ();
399+
fn implicit_provided<'a>(&'a self) -> &'a () {
400+
&()
401+
}
402+
403+
fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
404+
fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
405+
&()
406+
}
407+
408+
fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
409+
fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
410+
&()
411+
}
412+
}
413+
}
414+
372415
fn main() {}

tests/ui/needless_lifetimes.stderr

+51-1
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,55 @@ error: explicit lifetimes given in parameter types where they could be elided (o
150150
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
151151
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
152152

153-
error: aborting due to 25 previous errors
153+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
154+
--> $DIR/needless_lifetimes.rs:378:9
155+
|
156+
LL | fn implicit<'a>(&'a self) -> &'a () {
157+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
158+
159+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
160+
--> $DIR/needless_lifetimes.rs:381:9
161+
|
162+
LL | fn implicit_mut<'a>(&'a mut self) -> &'a () {
163+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
164+
165+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
166+
--> $DIR/needless_lifetimes.rs:392:9
167+
|
168+
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
169+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
170+
171+
error: local variable doesn't need to be boxed here
172+
--> $DIR/needless_lifetimes.rs:392:35
173+
|
174+
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
175+
| ^^^^
176+
|
177+
= note: `-D clippy::boxed-local` implied by `-D warnings`
178+
179+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
180+
--> $DIR/needless_lifetimes.rs:398:9
181+
|
182+
LL | fn implicit<'a>(&'a self) -> &'a ();
183+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
184+
185+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
186+
--> $DIR/needless_lifetimes.rs:399:9
187+
|
188+
LL | fn implicit_provided<'a>(&'a self) -> &'a () {
189+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
190+
191+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
192+
--> $DIR/needless_lifetimes.rs:408:9
193+
|
194+
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
195+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
196+
197+
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
198+
--> $DIR/needless_lifetimes.rs:409:9
199+
|
200+
LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
201+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
202+
203+
error: aborting due to 33 previous errors
154204

0 commit comments

Comments
 (0)