11use ide_db:: { FxIndexSet , syntax_helpers:: suggest_name:: NameGenerator } ;
2+ use itertools:: chain;
23use 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}> {
300312struct $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