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,46 @@ 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+ if let Some ( gen_param) = node. generic_param_list ( ) {
127+ if let Some ( last_lifetime) = gen_param. lifetime_params ( ) . last ( ) {
128+ editor. insert_all (
129+ Position :: after ( last_lifetime. syntax ( ) ) ,
130+ chain ! ( comma_and_space( ) , lifetime_elements) . collect ( ) ,
131+ ) ;
132+ } else if let Some ( l_angle) = gen_param. l_angle_token ( ) {
126133 lifetime_elements. push ( make:: token ( T ! [ , ] ) . into ( ) ) ;
127134 lifetime_elements. push ( tokens:: single_space ( ) . into ( ) ) ;
135+ editor. insert_all ( Position :: after ( & l_angle) , lifetime_elements) ;
128136 }
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) ;
137+ } else if let Some ( name) = node. name ( ) {
138+ editor. insert_all (
139+ Position :: after ( name. syntax ( ) ) ,
140+ chain ! (
141+ [ make:: token( T ![ <] ) . into( ) ] ,
142+ lifetime_elements,
143+ [ make:: token( T ![ >] ) . into( ) ]
144+ )
145+ . collect ( ) ,
146+ ) ;
137147 }
138148
139149 let snippet = ctx. config . snippet_cap . map ( |cap| builder. make_placeholder_snippet ( cap) ) ;
@@ -276,7 +286,7 @@ struct Foo<'a> {
276286 y: &$0u32
277287}"# ,
278288 r#"
279- struct Foo<${0:'b}, 'a > {
289+ struct Foo<'a, ${0:'b}> {
280290 x: &'a i32,
281291 y: &${0:'b} u32
282292}"# ,
@@ -300,13 +310,22 @@ struct Foo<'a, ${0:'b}> {
300310struct $0Foo<T> {
301311 x: &'a i32,
302312 y: &T
313+ z: &'b u32
303314}"# ,
304315 r#"
305- struct Foo<'a, ${0:'b }, T> {
316+ struct Foo<'a, 'b, ${0:'c }, T> {
306317 x: &'a i32,
307- y: &${0:'b} T
318+ y: &${0:'c} T
319+ z: &'b u32
308320}"# ,
309321 ) ;
322+ check_assist (
323+ add_missing_lifetime,
324+ r#"
325+ struct $0Foo(&fn(&str) -> &str);"# ,
326+ r#"
327+ struct Foo<${0:'a}>(&${0:'a} fn(&str) -> &str);"# ,
328+ ) ;
310329 }
311330
312331 #[ test]
@@ -392,7 +411,7 @@ enum Foo<'a> {
392411 }
393412}"# ,
394413 r#"
395- enum Foo<${0:'b}, 'a > {
414+ enum Foo<'a, ${0:'b}> {
396415 Bar {
397416 x: &'a i32,
398417 y: &${0:'b} u32
@@ -472,7 +491,7 @@ union Foo<'a> {
472491 y: &$0u32
473492}"# ,
474493 r#"
475- union Foo<${0:'b}, 'a > {
494+ union Foo<'a, ${0:'b}> {
476495 x: &'a i32,
477496 y: &${0:'b} u32
478497}"# ,
0 commit comments