@@ -19,8 +19,8 @@ use syntax::{
1919 AstNode , Edition , NodeOrToken , SyntaxElement , SyntaxKind , SyntaxNode ,
2020 algo:: find_node_at_range,
2121 ast:: {
22- self , HasArgList , HasAttrs , HasGenericParams , HasName , HasVisibility , RecordField , make ,
23- syntax_factory:: SyntaxFactory ,
22+ self , GenericParam , HasArgList , HasAttrs , HasGenericParams , HasName , HasVisibility ,
23+ RecordField , make , syntax_factory:: SyntaxFactory ,
2424 } ,
2525 match_ast,
2626 syntax_editor:: { Element , Position , SyntaxEditor } ,
@@ -175,23 +175,12 @@ pub(crate) fn extract_struct_from_function_signature(
175175 // and then apply it into record list after
176176 let field_list = make. record_field_list ( field_list) . clone_subtree ( ) ;
177177 let mut field_editor = SyntaxEditor :: new ( field_list. syntax ( ) . clone ( ) ) ;
178- let mut generic_editor = generics. map ( |generics| {
179- let syntax_editor = SyntaxEditor :: new ( generics. clone_subtree ( ) . syntax ( ) . clone ( ) ) ;
180- ( generics, syntax_editor)
181- } ) ;
178+ let mut generic_editor = generics;
182179 field_list
183180 . fields ( )
184181 . flat_map ( |f| f. ty ( ) )
185182 . try_for_each ( |ty| generate_new_lifetimes ( & mut field_editor, & ty, & mut generic_editor) ) ;
186- let generics = generic_editor. map ( |( _, editor) | { let binding = editor. finish ( ) ;
187- let generics = binding. new_root ( ) ;
188- match_ast ! { match generics {
189-
190- ast:: GenericParamList ( generics) => generics,
191- _ => unreachable!( ) ,
192-
193- } }
194- } ) ;
183+ let generics = generic_editor. map ( make:: generic_param_list) ;
195184
196185
197186 move_comments_and_attributes ( & mut field_editor, & used_param_list, & field_list) ;
@@ -223,7 +212,7 @@ pub(crate) fn extract_struct_from_function_signature(
223212 ] ,
224213 ) ;
225214 tracing:: info!( "extract_struct_from_function_signature: inserting struct {def}" ) ;
226- update_function ( & mut editor, name, generic_params, & used_param_list, n_new_lifetimes)
215+ update_function ( & mut editor, name, generic_params. map ( make :: generic_param_list ) , & used_param_list, n_new_lifetimes)
227216 . unwrap ( ) ;
228217 tracing:: info!(
229218 "extract_struct_from_function_signature: updating function signature and parameter uses"
@@ -259,15 +248,11 @@ fn update_function(
259248 . filter ( |generics| generics. generic_params ( ) . count ( ) > 0 )
260249 . or ( ( n_new_lifetimes > 0 ) . then_some ( make:: generic_param_list ( std:: iter:: empty ( ) ) ) )
261250 . map ( move |generics| {
262- let args = generics. to_generic_args ( ) . clone_subtree ( ) ;
263- let mut editor = SyntaxEditor :: new ( args. syntax ( ) . clone ( ) ) ;
251+ let mut args = generics. to_generic_args ( ) . clone_subtree ( ) . generic_args ( ) . collect_vec ( ) ;
264252 ( 0 ..n_new_lifetimes) . for_each ( |_| {
265- editor. add_generic_arg (
266- & args,
267- make:: lifetime_arg ( make:: lifetime ( "'_" ) ) . clone_for_update ( ) . into ( ) ,
268- ) ;
253+ args. push ( make:: lifetime_arg ( make:: lifetime ( "'_" ) ) . clone_for_update ( ) . into ( ) )
269254 } ) ;
270- editor . finish ( ) . new_root ( ) . clone ( )
255+ make :: generic_arg_list ( args )
271256 } ) ;
272257 // FIXME: replace with a `ast::make` constructor
273258 let ty = match generic_args {
@@ -363,28 +348,36 @@ fn take_all_comments(node: impl ast::AstNode) -> Vec<SyntaxElement> {
363348fn extract_generic_params < ' a > (
364349 known_generics : & ast:: GenericParamList ,
365350 field_list : impl Iterator < Item = & ' a RecordField > ,
366- ) -> Option < ast :: GenericParamList > {
351+ ) -> Option < Vec < GenericParam > > {
367352 let mut generics = known_generics. generic_params ( ) . map ( |param| ( param, false ) ) . collect_vec ( ) ;
368353
369354 let tagged_one = field_list
370355 . filter_map ( |f| f. ty ( ) )
371356 . fold ( false , |tagged, ty| tag_generics_in_function_signature ( & ty, & mut generics) || tagged) ;
372357
373358 let generics = generics. into_iter ( ) . filter_map ( |( param, tag) | tag. then_some ( param) ) ;
374- tagged_one. then ( || make :: generic_param_list ( generics) )
359+ tagged_one. then ( || generics. collect_vec ( ) )
375360}
376361fn generate_unique_lifetime_param_name (
377- existing_type_param_list : & Option < ( ast :: GenericParamList , SyntaxEditor ) > ,
362+ existing_type_param_list : & Option < Vec < GenericParam > > ,
378363) -> Option < ast:: Lifetime > {
379- match existing_type_param_list {
380- Some ( ( type_params, _) ) => {
381- let used_lifetime_params: FxHashSet < _ > =
382- type_params. lifetime_params ( ) . map ( |p| p. syntax ( ) . text ( ) . to_string ( ) ) . collect ( ) ;
383- ( 'a' ..='z' ) . map ( |it| format ! ( "'{it}" ) ) . find ( |it| !used_lifetime_params. contains ( it) )
384- }
385- None => Some ( "'a" . to_owned ( ) ) ,
386- }
387- . map ( |it| make:: lifetime ( & it) )
364+ existing_type_param_list. as_ref ( ) . map_or_else (
365+ || Some ( make:: lifetime ( "'a" ) ) ,
366+ |existing_type_param_list| {
367+ let used_lifetime_params: FxHashSet < _ > = existing_type_param_list
368+ . iter ( )
369+ . filter_map ( |l| match l {
370+ ast:: GenericParam :: LifetimeParam ( l) => Some ( l) ,
371+ _ => None ,
372+ } )
373+ . map ( |p| p. syntax ( ) . text ( ) . to_string ( ) )
374+ . collect ( ) ;
375+ ( 'a' ..='z' )
376+ . map ( |it| format ! ( "'{it}" ) )
377+ . find ( |it| !used_lifetime_params. contains ( it) )
378+ . map ( |it| make:: lifetime ( & it) )
379+ } ,
380+ )
388381}
389382fn new_life_time_count ( ty : & ast:: Type ) -> usize {
390383 ty. syntax ( )
@@ -404,7 +397,7 @@ fn contains_impl_trait(ty: &ast::Type) -> bool {
404397fn generate_new_lifetimes (
405398 fields_editor : & mut SyntaxEditor ,
406399 ty : & ast:: Type ,
407- existing_type_param_list : & mut Option < ( ast :: GenericParamList , SyntaxEditor ) > ,
400+ existing_type_param_list : & mut Option < Vec < GenericParam > > ,
408401) -> Option < ( ) > {
409402 for token in ty. syntax ( ) . descendants ( ) {
410403 // we do not have to worry about for<'a> because we are only looking at '_ or &Type
@@ -414,16 +407,8 @@ fn generate_new_lifetimes(
414407 {
415408 let new_lt = generate_unique_lifetime_param_name ( existing_type_param_list) ?;
416409 fields_editor. replace ( lt. syntax ( ) , new_lt. syntax ( ) . clone_for_update ( ) ) ;
417- let ( generics, editor) = existing_type_param_list. get_or_insert_with ( || {
418- let generics = make:: generic_param_list ( std:: iter:: empty ( ) ) ;
419- let syntax_editor = SyntaxEditor :: new ( generics. syntax ( ) . clone_subtree ( ) ) ;
420-
421- ( generics, syntax_editor)
422- } ) ;
423- editor. add_generic_param (
424- generics,
425- make:: lifetime_param ( new_lt) . clone_for_update ( ) . into ( ) ,
426- ) ;
410+ let existing_type_param_list = existing_type_param_list. get_or_insert_default ( ) ;
411+ existing_type_param_list. push ( make:: lifetime_param ( new_lt) . clone_for_update ( ) . into ( ) ) ;
427412 } else if let Some ( r) = ast:: RefType :: cast ( token. clone ( ) )
428413 && r. lifetime ( ) . is_none ( )
429414 {
@@ -435,17 +420,8 @@ fn generate_new_lifetimes(
435420 make:: tokens:: whitespace( " " ) . into( ) ,
436421 ] ,
437422 ) ;
438- let ( generics, editor) = existing_type_param_list. get_or_insert_with ( || {
439- let generics = make:: generic_param_list ( std:: iter:: empty ( ) ) ;
440- let syntax_editor = SyntaxEditor :: new ( generics. syntax ( ) . clone_subtree ( ) ) ;
441-
442- ( generics, syntax_editor)
443- } ) ;
444-
445- editor. add_generic_param (
446- generics,
447- make:: lifetime_param ( new_lt) . clone_for_update ( ) . into ( ) ,
448- ) ;
423+ let existing_type_param_list = existing_type_param_list. get_or_insert_default ( ) ;
424+ existing_type_param_list. push ( make:: lifetime_param ( new_lt) . clone_for_update ( ) . into ( ) ) ;
449425 }
450426 // TODO: nominal types that have only lifetimes
451427 // struct Bar<'a, 'b> { f: &'a &'b i32 }
@@ -526,7 +502,7 @@ fn existing_definition(
526502}
527503
528504fn process_references (
529- ctx : & AssistContext < ' _ > ,
505+ ctx : & ' _ AssistContext < ' _ > ,
530506 visited_modules : & mut FxHashSet < Module > ,
531507 function_module_def : & ModuleDef ,
532508 refs : Vec < FileReference > ,
@@ -984,6 +960,28 @@ f: i32 }
984960fn foo(
985961 FooStruct { f, .. }: FooStruct,
986962) { }
963+ "# ,
964+ )
965+ }
966+ #[ test]
967+ fn test_extract_function_signature_with_annoynmous_and_hidden_lifetime ( ) {
968+ check_assist (
969+ extract_struct_from_function_signature,
970+ r#"
971+ struct Foo<'a>(&'a i32);
972+
973+ fn foo(
974+ $0ctx: &Foo<'_>$0,
975+ ) { }
976+ "# ,
977+ r#"
978+ struct Foo<'a>(&'a i32);
979+
980+ struct FooStruct<'a, 'b> { ctx: &'a Foo<'b> }
981+
982+ fn foo(
983+ FooStruct { ctx, .. }: FooStruct<'_, '_>,
984+ ) { }
987985"# ,
988986 )
989987 }
0 commit comments