1
1
use either:: Either ;
2
2
use hir:: { known, Callable , HasVisibility , HirDisplay , Semantics , TypeInfo } ;
3
- use ide_db:: { base_db:: FileRange , famous_defs:: FamousDefs , RootDatabase } ;
3
+ use ide_db:: {
4
+ base_db:: FileRange , famous_defs:: FamousDefs , syntax_helpers:: node_ext:: walk_ty, RootDatabase ,
5
+ } ;
4
6
use itertools:: Itertools ;
7
+ use rustc_hash:: FxHashSet ;
5
8
use stdx:: to_lower_snake_case;
6
9
use syntax:: {
7
10
ast:: { self , AstNode , HasArgList , HasGenericParams , HasName , UnaryOp } ,
@@ -19,6 +22,7 @@ pub struct InlayHintsConfig {
19
22
pub closure_return_type_hints : bool ,
20
23
// FIXME: ternary option here, on off non-noisy
21
24
pub lifetime_elision_hints : bool ,
25
+ pub param_names_for_lifetime_elision_hints : bool ,
22
26
pub hide_named_constructor_hints : bool ,
23
27
pub max_length : Option < usize > ,
24
28
}
@@ -136,31 +140,37 @@ fn lifetime_hints(
136
140
let ret_type = func. ret_type ( ) ;
137
141
let self_param = param_list. self_param ( ) . filter ( |it| it. amp_token ( ) . is_some ( ) ) ;
138
142
139
- // FIXME: don't use already used lifetimenames
143
+ let used_names: FxHashSet < SmolStr > = generic_param_list
144
+ . iter ( )
145
+ . filter ( |_| !config. param_names_for_lifetime_elision_hints )
146
+ . flat_map ( |gpl| gpl. lifetime_params ( ) )
147
+ . filter_map ( |param| param. lifetime ( ) )
148
+ . map ( |lt| SmolStr :: from ( lt. text ( ) . as_str ( ) ) )
149
+ . collect ( ) ;
140
150
141
151
let mut allocated_lifetimes = vec ! [ ] ;
142
152
let mut gen_name = {
143
- let mut gen = ( 'a' ..) . map ( |it| SmolStr :: from_iter ( [ '\'' , it] ) ) ;
144
- move || gen. next ( ) . unwrap_or_else ( SmolStr :: default)
153
+ let mut gen = ( 0u8 ..) . map ( |idx| match idx {
154
+ idx if idx < 10 => SmolStr :: from_iter ( [ '\'' , ( idx + 48 ) as char ] ) ,
155
+ idx => format ! ( "'{idx}" ) . into ( ) ,
156
+ } ) ;
157
+ move || gen. next ( ) . unwrap_or_default ( )
145
158
} ;
146
159
147
- let potential_lt_refs: Vec < _ > = param_list
148
- . params ( )
149
- . filter_map ( |it| {
150
- let ty = it. ty ( ) ?;
151
- // FIXME: look into the nested types here and check path types
152
- match ty {
153
- ast:: Type :: RefType ( r) => Some ( (
154
- it. pat ( ) . and_then ( |it| match it {
155
- ast:: Pat :: IdentPat ( p) => p. name ( ) ,
156
- _ => None ,
157
- } ) ,
158
- r,
159
- ) ) ,
160
- _ => None ,
161
- }
160
+ let mut potential_lt_refs: Vec < _ > = vec ! [ ] ;
161
+ param_list. params ( ) . filter_map ( |it| Some ( ( it. pat ( ) , it. ty ( ) ?) ) ) . for_each ( |( pat, ty) | {
162
+ // FIXME: check path types
163
+ walk_ty ( & ty, & mut |ty| match ty {
164
+ ast:: Type :: RefType ( r) => potential_lt_refs. push ( (
165
+ pat. as_ref ( ) . and_then ( |it| match it {
166
+ ast:: Pat :: IdentPat ( p) => p. name ( ) ,
167
+ _ => None ,
168
+ } ) ,
169
+ r,
170
+ ) ) ,
171
+ _ => ( ) ,
162
172
} )
163
- . collect ( ) ;
173
+ } ) ;
164
174
165
175
enum LifetimeKind {
166
176
Elided ,
@@ -184,15 +194,25 @@ fn lifetime_hints(
184
194
// allocate names
185
195
if let Some ( self_param) = & self_param {
186
196
if is_elided ( self_param. lifetime ( ) ) {
187
- allocated_lifetimes. push ( SmolStr :: new_inline ( "'self" ) ) ;
197
+ allocated_lifetimes. push ( if config. param_names_for_lifetime_elision_hints {
198
+ "'self" . into ( )
199
+ } else {
200
+ gen_name ( )
201
+ } ) ;
188
202
}
189
203
}
190
204
potential_lt_refs. iter ( ) . for_each ( |( name, it) | {
191
- // FIXME: look into the nested types here and check path types
192
205
if is_elided ( it. lifetime ( ) ) {
193
206
allocated_lifetimes. push (
194
207
name. as_ref ( )
195
- . map_or_else ( || gen_name ( ) , |it| SmolStr :: from_iter ( [ "'" , it. text ( ) . as_str ( ) ] ) ) ,
208
+ . filter ( |it| {
209
+ config. param_names_for_lifetime_elision_hints
210
+ && !used_names. contains ( it. text ( ) . as_str ( ) )
211
+ } )
212
+ . map_or_else (
213
+ || gen_name ( ) ,
214
+ |it| SmolStr :: from_iter ( [ "\' " , it. text ( ) . as_str ( ) ] ) ,
215
+ ) ,
196
216
) ;
197
217
}
198
218
} ) ;
@@ -221,22 +241,26 @@ fn lifetime_hints(
221
241
// apply output if required
222
242
match ( & output, ret_type) {
223
243
( Some ( output_lt) , Some ( r) ) => {
224
- if let Some ( ast:: Type :: RefType ( t) ) = r. ty ( ) {
225
- if t. lifetime ( ) . is_none ( ) {
226
- let amp = t. amp_token ( ) ?;
227
- acc. push ( InlayHint {
228
- range : amp. text_range ( ) ,
229
- kind : InlayKind :: LifetimeHint ,
230
- label : output_lt. clone ( ) ,
231
- } ) ;
232
- }
244
+ if let Some ( ty) = r. ty ( ) {
245
+ walk_ty ( & ty, & mut |ty| match ty {
246
+ ast:: Type :: RefType ( ty) if ty. lifetime ( ) . is_none ( ) => {
247
+ if let Some ( amp) = ty. amp_token ( ) {
248
+ acc. push ( InlayHint {
249
+ range : amp. text_range ( ) ,
250
+ kind : InlayKind :: LifetimeHint ,
251
+ label : output_lt. clone ( ) ,
252
+ } ) ;
253
+ }
254
+ }
255
+ _ => ( ) ,
256
+ } )
233
257
}
234
258
}
235
259
_ => ( ) ,
236
260
}
237
261
238
- let mut idx = if let Some ( self_param ) = & self_param {
239
- if is_elided ( self_param. lifetime ( ) ) {
262
+ let mut idx = match & self_param {
263
+ Some ( self_param ) if is_elided ( self_param. lifetime ( ) ) => {
240
264
if let Some ( amp) = self_param. amp_token ( ) {
241
265
let lt = allocated_lifetimes[ 0 ] . clone ( ) ;
242
266
acc. push ( InlayHint {
@@ -246,11 +270,8 @@ fn lifetime_hints(
246
270
} ) ;
247
271
}
248
272
1
249
- } else {
250
- 0
251
273
}
252
- } else {
253
- 0
274
+ _ => 0 ,
254
275
} ;
255
276
256
277
for ( _, p) in potential_lt_refs. iter ( ) {
@@ -789,6 +810,7 @@ mod tests {
789
810
lifetime_elision_hints : false ,
790
811
hide_named_constructor_hints : false ,
791
812
closure_return_type_hints : false ,
813
+ param_names_for_lifetime_elision_hints : false ,
792
814
max_length : None ,
793
815
} ;
794
816
const TEST_CONFIG : InlayHintsConfig = InlayHintsConfig {
@@ -1981,32 +2003,39 @@ fn main() {
1981
2003
fn empty() {}
1982
2004
1983
2005
fn no_gpl(a: &()) {}
1984
- //^^^^^^<'a >
1985
- // ^'a
2006
+ //^^^^^^<'0 >
2007
+ // ^'0
1986
2008
fn empty_gpl<>(a: &()) {}
1987
- // ^'a ^'a
2009
+ // ^'0 ^'0
1988
2010
fn partial<'b>(a: &(), b: &'b ()) {}
1989
- // ^'a , $ ^'a
2011
+ // ^'0 , $ ^'0
1990
2012
fn partial<'a>(a: &'a (), b: &()) {}
1991
- // ^'b , $ ^'b
2013
+ // ^'0 , $ ^'0
1992
2014
1993
2015
fn single_ret(a: &()) -> &() {}
1994
- // ^^^^^^^^^^<'a >
1995
- // ^'a ^'a
2016
+ // ^^^^^^^^^^<'0 >
2017
+ // ^'0 ^'0
1996
2018
fn full_mul(a: &(), b: &()) {}
1997
- // ^^^^^^^^<'a , 'b >
1998
- // ^'a ^'b
2019
+ // ^^^^^^^^<'0 , '1 >
2020
+ // ^'0 ^'1
1999
2021
2000
2022
fn foo<'c>(a: &'c ()) -> &() {}
2001
2023
// ^'c
2002
2024
2025
+ fn nested_in(a: & &X< &()>) {}
2026
+ // ^^^^^^^^^<'0, '1, '2>
2027
+ //^'0 ^'1 ^'2
2028
+ fn nested_out(a: &()) -> & &X< &()>{}
2029
+ // ^^^^^^^^^^<'0>
2030
+ //^'0 ^'0 ^'0 ^'0
2031
+
2003
2032
impl () {
2004
2033
fn foo(&self) -> &() {}
2005
- // ^^^<'self >
2006
- // ^'self ^'self
2034
+ // ^^^<'0 >
2035
+ // ^'0 ^'0
2007
2036
fn foo(&self, a: &()) -> &() {}
2008
- // ^^^<'self , 'a >
2009
- // ^'self ^'a ^'self$
2037
+ // ^^^<'0 , '1 >
2038
+ // ^'0 ^'1 ^'0
2010
2039
}
2011
2040
"# ,
2012
2041
) ;
0 commit comments