@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
15
15
use rustc_middle:: hir:: map:: Map ;
16
16
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
17
17
use rustc_span:: source_map:: Span ;
18
- use rustc_span:: symbol:: { kw, Symbol } ;
18
+ use rustc_span:: symbol:: { kw, Ident , Symbol } ;
19
19
20
20
declare_clippy_lint ! {
21
21
/// ### What it does
@@ -85,7 +85,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
85
85
impl < ' tcx > LateLintPass < ' tcx > for Lifetimes {
86
86
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
87
87
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 ) ;
89
89
}
90
90
}
91
91
@@ -96,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
96
96
cx,
97
97
sig. decl ,
98
98
Some ( id) ,
99
+ None ,
99
100
& item. generics ,
100
101
item. span ,
101
102
report_extra_lifetimes,
@@ -105,11 +106,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
105
106
106
107
fn check_trait_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx TraitItem < ' _ > ) {
107
108
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 ) ,
111
112
} ;
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 ) ;
113
114
}
114
115
}
115
116
}
@@ -126,6 +127,7 @@ fn check_fn_inner<'tcx>(
126
127
cx : & LateContext < ' tcx > ,
127
128
decl : & ' tcx FnDecl < ' _ > ,
128
129
body : Option < BodyId > ,
130
+ trait_sig : Option < & [ Ident ] > ,
129
131
generics : & ' tcx Generics < ' _ > ,
130
132
span : Span ,
131
133
report_extra_lifetimes : bool ,
@@ -167,7 +169,7 @@ fn check_fn_inner<'tcx>(
167
169
}
168
170
}
169
171
}
170
- if could_use_elision ( cx, decl, body, generics. params ) {
172
+ if could_use_elision ( cx, decl, body, trait_sig , generics. params ) {
171
173
span_lint (
172
174
cx,
173
175
NEEDLESS_LIFETIMES ,
@@ -181,10 +183,31 @@ fn check_fn_inner<'tcx>(
181
183
}
182
184
}
183
185
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
+
184
206
fn could_use_elision < ' tcx > (
185
207
cx : & LateContext < ' tcx > ,
186
208
func : & ' tcx FnDecl < ' _ > ,
187
209
body : Option < BodyId > ,
210
+ trait_sig : Option < & [ Ident ] > ,
188
211
named_generics : & ' tcx [ GenericParam < ' _ > ] ,
189
212
) -> bool {
190
213
// There are two scenarios where elision works:
@@ -235,11 +258,24 @@ fn could_use_elision<'tcx>(
235
258
let input_lts = input_visitor. lts ;
236
259
let output_lts = output_visitor. lts ;
237
260
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
+
238
267
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
+
239
275
let mut checker = BodyLifetimeChecker {
240
276
lifetimes_used_in_body : false ,
241
277
} ;
242
- checker. visit_expr ( & cx . tcx . hir ( ) . body ( body_id ) . value ) ;
278
+ checker. visit_expr ( & body. value ) ;
243
279
if checker. lifetimes_used_in_body {
244
280
return false ;
245
281
}
0 commit comments