1
+ use clippy_config:: Conf ;
1
2
use clippy_utils:: diagnostics:: { span_lint, span_lint_and_then} ;
3
+ use clippy_utils:: msrvs:: { self , Msrv } ;
2
4
use clippy_utils:: trait_ref_of_method;
3
5
use itertools:: Itertools ;
4
6
use rustc_ast:: visit:: { try_visit, walk_list} ;
@@ -20,7 +22,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
20
22
use rustc_middle:: hir:: map:: Map ;
21
23
use rustc_middle:: hir:: nested_filter as middle_nested_filter;
22
24
use rustc_middle:: lint:: in_external_macro;
23
- use rustc_session:: declare_lint_pass ;
25
+ use rustc_session:: impl_lint_pass ;
24
26
use rustc_span:: Span ;
25
27
use rustc_span:: def_id:: LocalDefId ;
26
28
use rustc_span:: symbol:: { Ident , kw} ;
@@ -91,7 +93,19 @@ declare_clippy_lint! {
91
93
"unused lifetimes in function definitions"
92
94
}
93
95
94
- declare_lint_pass ! ( Lifetimes => [ NEEDLESS_LIFETIMES , EXTRA_UNUSED_LIFETIMES ] ) ;
96
+ pub struct Lifetimes {
97
+ msrv : Msrv ,
98
+ }
99
+
100
+ impl Lifetimes {
101
+ pub fn new ( conf : & ' static Conf ) -> Self {
102
+ Self {
103
+ msrv : conf. msrv . clone ( ) ,
104
+ }
105
+ }
106
+ }
107
+
108
+ impl_lint_pass ! ( Lifetimes => [ NEEDLESS_LIFETIMES , EXTRA_UNUSED_LIFETIMES ] ) ;
95
109
96
110
impl < ' tcx > LateLintPass < ' tcx > for Lifetimes {
97
111
fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
@@ -102,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
102
116
..
103
117
} = item. kind
104
118
{
105
- check_fn_inner ( cx, sig, Some ( id) , None , generics, item. span , true ) ;
119
+ check_fn_inner ( cx, sig, Some ( id) , None , generics, item. span , true , & self . msrv ) ;
106
120
} else if let ItemKind :: Impl ( impl_) = item. kind {
107
121
if !item. span . from_expansion ( ) {
108
122
report_extra_impl_lifetimes ( cx, impl_) ;
@@ -121,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
121
135
item. generics ,
122
136
item. span ,
123
137
report_extra_lifetimes,
138
+ & self . msrv ,
124
139
) ;
125
140
}
126
141
}
@@ -131,11 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
131
146
TraitFn :: Required ( sig) => ( None , Some ( sig) ) ,
132
147
TraitFn :: Provided ( id) => ( Some ( id) , None ) ,
133
148
} ;
134
- check_fn_inner ( cx, sig, body, trait_sig, item. generics , item. span , true ) ;
149
+ check_fn_inner ( cx, sig, body, trait_sig, item. generics , item. span , true , & self . msrv ) ;
135
150
}
136
151
}
152
+
153
+ extract_msrv_attr ! ( LateContext ) ;
137
154
}
138
155
156
+ #[ allow( clippy:: too_many_arguments) ]
139
157
fn check_fn_inner < ' tcx > (
140
158
cx : & LateContext < ' tcx > ,
141
159
sig : & ' tcx FnSig < ' _ > ,
@@ -144,6 +162,7 @@ fn check_fn_inner<'tcx>(
144
162
generics : & ' tcx Generics < ' _ > ,
145
163
span : Span ,
146
164
report_extra_lifetimes : bool ,
165
+ msrv : & Msrv ,
147
166
) {
148
167
if in_external_macro ( cx. sess ( ) , span) || has_where_lifetimes ( cx, generics) {
149
168
return ;
@@ -195,7 +214,7 @@ fn check_fn_inner<'tcx>(
195
214
}
196
215
}
197
216
198
- if let Some ( ( elidable_lts, usages) ) = could_use_elision ( cx, sig. decl , body, trait_sig, generics. params ) {
217
+ if let Some ( ( elidable_lts, usages) ) = could_use_elision ( cx, sig. decl , body, trait_sig, generics. params , msrv ) {
199
218
if usages. iter ( ) . any ( |usage| !usage. ident . span . eq_ctxt ( span) ) {
200
219
return ;
201
220
}
@@ -216,6 +235,7 @@ fn could_use_elision<'tcx>(
216
235
body : Option < BodyId > ,
217
236
trait_sig : Option < & [ Ident ] > ,
218
237
named_generics : & ' tcx [ GenericParam < ' _ > ] ,
238
+ msrv : & Msrv ,
219
239
) -> Option < ( Vec < LocalDefId > , Vec < Lifetime > ) > {
220
240
// There are two scenarios where elision works:
221
241
// * no output references, all input references have different LT
@@ -249,17 +269,17 @@ fn could_use_elision<'tcx>(
249
269
let input_lts = input_visitor. lts ;
250
270
let output_lts = output_visitor. lts ;
251
271
252
- if let Some ( trait_sig) = trait_sig {
253
- if explicit_self_type ( cx, func, trait_sig. first ( ) . copied ( ) ) {
254
- return None ;
255
- }
272
+ if let Some ( trait_sig) = trait_sig
273
+ && non_elidable_self_type ( cx, func, trait_sig. first ( ) . copied ( ) , msrv )
274
+ {
275
+ return None ;
256
276
}
257
277
258
278
if let Some ( body_id) = body {
259
279
let body = cx. tcx . hir ( ) . body ( body_id) ;
260
280
261
281
let first_ident = body. params . first ( ) . and_then ( |param| param. pat . simple_ident ( ) ) ;
262
- if explicit_self_type ( cx, func, first_ident) {
282
+ if non_elidable_self_type ( cx, func, first_ident, msrv ) {
263
283
return None ;
264
284
}
265
285
@@ -332,9 +352,15 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefI
332
352
. collect ( )
333
353
}
334
354
335
- // elision doesn't work for explicit self types, see rust-lang/rust#69064
336
- fn explicit_self_type < ' tcx > ( cx : & LateContext < ' tcx > , func : & FnDecl < ' tcx > , ident : Option < Ident > ) -> bool {
337
- if let Some ( ident) = ident
355
+ // elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
356
+ fn non_elidable_self_type < ' tcx > (
357
+ cx : & LateContext < ' tcx > ,
358
+ func : & FnDecl < ' tcx > ,
359
+ ident : Option < Ident > ,
360
+ msrv : & Msrv ,
361
+ ) -> bool {
362
+ if !msrv. meets ( msrvs:: EXPLICIT_SELF_TYPE_ELISION )
363
+ && let Some ( ident) = ident
338
364
&& ident. name == kw:: SelfLower
339
365
&& !func. implicit_self . has_implicit_self ( )
340
366
&& let Some ( self_ty) = func. inputs . first ( )
0 commit comments