Skip to content

Commit ee51e11

Browse files
make the generated lifetime more orderly
1 parent 6aa7edf commit ee51e11

File tree

1 file changed

+50
-29
lines changed

1 file changed

+50
-29
lines changed

crates/ide-assists/src/handlers/add_missing_lifetime.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use ide_db::{FxIndexSet, syntax_helpers::suggest_name::NameGenerator};
2+
use itertools::chain;
23
use syntax::{
34
NodeOrToken, SmolStr, T,
45
ast::{
@@ -53,7 +54,10 @@ pub(crate) fn add_missing_lifetime(acc: &mut Assists, ctx: &AssistContext<'_>) -
5354
.filter(|lt_text| !adt_declared_lifetimes.contains(lt_text))
5455
.collect();
5556

56-
if refs_without_lifetime.is_empty() && adt_undeclared_lifetimes.is_empty() {
57+
let has_refs_without_lifetime = !refs_without_lifetime.is_empty();
58+
let has_undeclared_lifetimes = !adt_undeclared_lifetimes.is_empty();
59+
60+
if !has_refs_without_lifetime && !has_undeclared_lifetimes {
5761
return None;
5862
}
5963

@@ -67,6 +71,8 @@ pub(crate) fn add_missing_lifetime(acc: &mut Assists, ctx: &AssistContext<'_>) -
6771
adt_undeclared_lifetimes,
6872
refs_without_lifetime,
6973
all_existing_lifetimes,
74+
has_refs_without_lifetime,
75+
has_undeclared_lifetimes,
7076
)
7177
}
7278

@@ -77,10 +83,9 @@ fn add_and_declare_lifetimes(
7783
adt_undeclared_lifetimes: FxIndexSet<SmolStr>,
7884
refs_without_lifetime: Vec<ast::RefType>,
7985
all_existing_lifetimes: Vec<SmolStr>,
86+
has_refs_without_lifetime: bool,
87+
has_undeclared_lifetimes: bool,
8088
) -> Option<()> {
81-
let has_refs_without_lifetime = !refs_without_lifetime.is_empty();
82-
let has_undeclared_lifetimes = !adt_undeclared_lifetimes.is_empty();
83-
8489
let message = match (has_refs_without_lifetime, has_undeclared_lifetimes) {
8590
(false, true) => "Declare used lifetimes in generic parameters",
8691
(true, false) | (true, true) => "Add missing lifetimes",
@@ -99,41 +104,48 @@ fn add_and_declare_lifetimes(
99104
|builder| {
100105
let make = SyntaxFactory::with_mappings();
101106
let mut editor = builder.make_editor(node.syntax());
102-
let comma_and_space = [make::token(T![,]).into(), tokens::single_space().into()];
107+
let comma_and_space = || [make::token(T![,]).into(), tokens::single_space().into()];
103108

104109
let mut lifetime_elements = vec![];
105110
let mut new_lifetime_to_annotate = None;
106111

107112
if has_undeclared_lifetimes {
108113
for (i, lifetime_text) in adt_undeclared_lifetimes.iter().enumerate() {
109-
(i > 0).then(|| lifetime_elements.extend(comma_and_space.clone()));
110-
let new_lifetime = make.lifetime(lifetime_text);
111-
lifetime_elements.push(new_lifetime.syntax().clone().into());
114+
(i > 0).then(|| lifetime_elements.extend(comma_and_space()));
115+
lifetime_elements.push(make.lifetime(lifetime_text).syntax().clone().into());
112116
}
113117
}
114118

115119
if has_refs_without_lifetime {
116-
has_undeclared_lifetimes.then(|| lifetime_elements.extend(comma_and_space.clone()));
120+
has_undeclared_lifetimes.then(|| lifetime_elements.extend(comma_and_space()));
117121
let lifetime = make.lifetime(&new_lifetime_name);
118-
new_lifetime_to_annotate = Some(lifetime.clone());
119122
lifetime_elements.push(lifetime.syntax().clone().into());
123+
new_lifetime_to_annotate = Some(lifetime);
120124
}
121125

122-
if let Some(gen_param) = node.generic_param_list()
123-
&& let Some(left_angle) = gen_param.l_angle_token()
124-
{
125-
if !lifetime_elements.is_empty() {
126-
lifetime_elements.push(make::token(T![,]).into());
127-
lifetime_elements.push(tokens::single_space().into());
126+
if !lifetime_elements.is_empty() {
127+
if let Some(gen_param) = node.generic_param_list() {
128+
if let Some(last_lifetime) = gen_param.lifetime_params().last() {
129+
editor.insert_all(
130+
Position::after(last_lifetime.syntax()),
131+
chain!(comma_and_space(), lifetime_elements).collect(),
132+
);
133+
} else if let Some(l_angle) = gen_param.l_angle_token() {
134+
lifetime_elements.push(make::token(T![,]).into());
135+
lifetime_elements.push(tokens::single_space().into());
136+
editor.insert_all(Position::after(&l_angle), lifetime_elements);
137+
}
138+
} else if let Some(name) = node.name() {
139+
editor.insert_all(
140+
Position::after(name.syntax()),
141+
chain!(
142+
[make::token(T![<]).into()],
143+
lifetime_elements,
144+
[make::token(T![>]).into()]
145+
)
146+
.collect(),
147+
);
128148
}
129-
editor.insert_all(Position::after(&left_angle), lifetime_elements);
130-
} else if let Some(name) = node.name()
131-
&& !lifetime_elements.is_empty()
132-
{
133-
let mut final_elements = vec![make::token(T![<]).into()];
134-
final_elements.append(&mut lifetime_elements);
135-
final_elements.push(make::token(T![>]).into());
136-
editor.insert_all(Position::after(name.syntax()), final_elements);
137149
}
138150

139151
let snippet = ctx.config.snippet_cap.map(|cap| builder.make_placeholder_snippet(cap));
@@ -276,7 +288,7 @@ struct Foo<'a> {
276288
y: &$0u32
277289
}"#,
278290
r#"
279-
struct Foo<${0:'b}, 'a> {
291+
struct Foo<'a, ${0:'b}> {
280292
x: &'a i32,
281293
y: &${0:'b} u32
282294
}"#,
@@ -300,13 +312,22 @@ struct Foo<'a, ${0:'b}> {
300312
struct $0Foo<T> {
301313
x: &'a i32,
302314
y: &T
315+
z: &'b u32
303316
}"#,
304317
r#"
305-
struct Foo<'a, ${0:'b}, T> {
318+
struct Foo<'a, 'b, ${0:'c}, T> {
306319
x: &'a i32,
307-
y: &${0:'b} T
320+
y: &${0:'c} T
321+
z: &'b u32
308322
}"#,
309323
);
324+
check_assist(
325+
add_missing_lifetime,
326+
r#"
327+
struct $0Foo(&fn(&str) -> &str);"#,
328+
r#"
329+
struct Foo<${0:'a}>(&${0:'a} fn(&str) -> &str);"#,
330+
);
310331
}
311332

312333
#[test]
@@ -392,7 +413,7 @@ enum Foo<'a> {
392413
}
393414
}"#,
394415
r#"
395-
enum Foo<${0:'b}, 'a> {
416+
enum Foo<'a, ${0:'b}> {
396417
Bar {
397418
x: &'a i32,
398419
y: &${0:'b} u32
@@ -472,7 +493,7 @@ union Foo<'a> {
472493
y: &$0u32
473494
}"#,
474495
r#"
475-
union Foo<${0:'b}, 'a> {
496+
union Foo<'a, ${0:'b}> {
476497
x: &'a i32,
477498
y: &${0:'b} u32
478499
}"#,

0 commit comments

Comments
 (0)