Skip to content

Commit 45756c8

Browse files
committed
Use numbers for lifetimes by default, add setting to prefer using parameter names
1 parent c22fed8 commit 45756c8

File tree

3 files changed

+94
-59
lines changed

3 files changed

+94
-59
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 80 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use either::Either;
22
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+
};
46
use itertools::Itertools;
7+
use rustc_hash::FxHashSet;
58
use stdx::to_lower_snake_case;
69
use syntax::{
710
ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
@@ -19,6 +22,7 @@ pub struct InlayHintsConfig {
1922
pub closure_return_type_hints: bool,
2023
// FIXME: ternary option here, on off non-noisy
2124
pub lifetime_elision_hints: bool,
25+
pub param_names_for_lifetime_elision_hints: bool,
2226
pub hide_named_constructor_hints: bool,
2327
pub max_length: Option<usize>,
2428
}
@@ -136,31 +140,37 @@ fn lifetime_hints(
136140
let ret_type = func.ret_type();
137141
let self_param = param_list.self_param().filter(|it| it.amp_token().is_some());
138142

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();
140150

141151
let mut allocated_lifetimes = vec![];
142152
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()
145158
};
146159

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+
_ => (),
162172
})
163-
.collect();
173+
});
164174

165175
enum LifetimeKind {
166176
Elided,
@@ -184,15 +194,25 @@ fn lifetime_hints(
184194
// allocate names
185195
if let Some(self_param) = &self_param {
186196
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+
});
188202
}
189203
}
190204
potential_lt_refs.iter().for_each(|(name, it)| {
191-
// FIXME: look into the nested types here and check path types
192205
if is_elided(it.lifetime()) {
193206
allocated_lifetimes.push(
194207
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+
),
196216
);
197217
}
198218
});
@@ -221,22 +241,26 @@ fn lifetime_hints(
221241
// apply output if required
222242
match (&output, ret_type) {
223243
(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+
})
233257
}
234258
}
235259
_ => (),
236260
}
237261

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()) => {
240264
if let Some(amp) = self_param.amp_token() {
241265
let lt = allocated_lifetimes[0].clone();
242266
acc.push(InlayHint {
@@ -246,11 +270,8 @@ fn lifetime_hints(
246270
});
247271
}
248272
1
249-
} else {
250-
0
251273
}
252-
} else {
253-
0
274+
_ => 0,
254275
};
255276

256277
for (_, p) in potential_lt_refs.iter() {
@@ -789,6 +810,7 @@ mod tests {
789810
lifetime_elision_hints: false,
790811
hide_named_constructor_hints: false,
791812
closure_return_type_hints: false,
813+
param_names_for_lifetime_elision_hints: false,
792814
max_length: None,
793815
};
794816
const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
@@ -1981,32 +2003,39 @@ fn main() {
19812003
fn empty() {}
19822004
19832005
fn no_gpl(a: &()) {}
1984-
//^^^^^^<'a>
1985-
// ^'a
2006+
//^^^^^^<'0>
2007+
// ^'0
19862008
fn empty_gpl<>(a: &()) {}
1987-
// ^'a ^'a
2009+
// ^'0 ^'0
19882010
fn partial<'b>(a: &(), b: &'b ()) {}
1989-
// ^'a, $ ^'a
2011+
// ^'0, $ ^'0
19902012
fn partial<'a>(a: &'a (), b: &()) {}
1991-
// ^'b, $ ^'b
2013+
// ^'0, $ ^'0
19922014
19932015
fn single_ret(a: &()) -> &() {}
1994-
// ^^^^^^^^^^<'a>
1995-
// ^'a ^'a
2016+
// ^^^^^^^^^^<'0>
2017+
// ^'0 ^'0
19962018
fn full_mul(a: &(), b: &()) {}
1997-
// ^^^^^^^^<'a, 'b>
1998-
// ^'a ^'b
2019+
// ^^^^^^^^<'0, '1>
2020+
// ^'0 ^'1
19992021
20002022
fn foo<'c>(a: &'c ()) -> &() {}
20012023
// ^'c
20022024
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+
20032032
impl () {
20042033
fn foo(&self) -> &() {}
2005-
// ^^^<'self>
2006-
// ^'self ^'self
2034+
// ^^^<'0>
2035+
// ^'0 ^'0
20072036
fn foo(&self, a: &()) -> &() {}
2008-
// ^^^<'self, 'a>
2009-
// ^'self ^'a ^'self$
2037+
// ^^^<'0, '1>
2038+
// ^'0 ^'1 ^'0
20102039
}
20112040
"#,
20122041
);

crates/ide/src/static_index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ impl StaticIndex<'_> {
112112
closure_return_type_hints: true,
113113
lifetime_elision_hints: false,
114114
hide_named_constructor_hints: false,
115+
param_names_for_lifetime_elision_hints: false,
115116
max_length: Some(25),
116117
},
117118
file_id,

crates/rust-analyzer/src/config.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -243,22 +243,24 @@ config_data! {
243243
hoverActions_run: bool = "true",
244244

245245
/// Whether to render trailing colons for parameter hints, and trailing colons for parameter hints.
246-
inlayHints_renderColons: bool = "true",
246+
inlayHints_renderColons: bool = "true",
247247
/// Maximum length for inlay hints. Set to null to have an unlimited length.
248-
inlayHints_maxLength: Option<usize> = "25",
248+
inlayHints_maxLength: Option<usize> = "25",
249249
/// Whether to show function parameter name inlay hints at the call
250250
/// site.
251-
inlayHints_parameterHints: bool = "true",
251+
inlayHints_parameterHints: bool = "true",
252252
/// Whether to show inlay type hints for variables.
253-
inlayHints_typeHints: bool = "true",
253+
inlayHints_typeHints: bool = "true",
254254
/// Whether to show inlay type hints for method chains.
255-
inlayHints_chainingHints: bool = "true",
255+
inlayHints_chainingHints: bool = "true",
256256
/// Whether to show inlay type hints for return types of closures with blocks.
257-
inlayHints_closureReturnTypeHints: bool = "false",
257+
inlayHints_closureReturnTypeHints: bool = "false",
258258
/// Whether to show inlay type hints for elided lifetimes in function signatures.
259-
inlayHints_lifetimeElisionHints: bool = "false",
259+
inlayHints_lifetimeElisionHints: bool = "false",
260+
/// Whether to show prefer using parameter names as the name for elided lifetime hints.
261+
inlayHints_paramNamesForLifetimeElisionHints: bool = "false",
260262
/// Whether to hide inlay hints for constructors.
261-
inlayHints_hideNamedConstructorHints: bool = "false",
263+
inlayHints_hideNamedConstructorHints: bool = "false",
262264

263265
/// Join lines inserts else between consecutive ifs.
264266
joinLines_joinElseIf: bool = "true",
@@ -859,6 +861,9 @@ impl Config {
859861
closure_return_type_hints: self.data.inlayHints_closureReturnTypeHints,
860862
lifetime_elision_hints: self.data.inlayHints_lifetimeElisionHints,
861863
hide_named_constructor_hints: self.data.inlayHints_hideNamedConstructorHints,
864+
param_names_for_lifetime_elision_hints: self
865+
.data
866+
.inlayHints_paramNamesForLifetimeElisionHints,
862867
max_length: self.data.inlayHints_maxLength,
863868
}
864869
}

0 commit comments

Comments
 (0)