@@ -72,7 +72,7 @@ pub(crate) fn extract_struct_from_function_signature(
7272 // clauses
7373 // we also need special handling for method calls
7474
75- // TODO: (future)special handling for destrutered types (or maybe just don't support code action on
75+ // TODO: (future)special handling for destrutered types (right now we don't support code action on
7676 // destructed types yet
7777
7878 let field_list = extract_field_list ( & func, & used_param_list) ?;
@@ -285,7 +285,7 @@ fn create_struct_def(
285285 } ;
286286
287287 // for fields without any existing visibility, use visibility of enum
288- let field_list: ast :: FieldList = {
288+ let field_list = {
289289 if let Some ( vis) = & fn_vis {
290290 field_list
291291 . fields ( )
@@ -294,39 +294,34 @@ fn create_struct_def(
294294 . for_each ( |it| insert_vis ( it. syntax ( ) , vis. syntax ( ) ) ) ;
295295 }
296296
297- field_list. clone ( ) . into ( )
297+ field_list
298298 } ;
299+ // if we do not expleictly copy over comments/attribures they just get lost
300+ // TODO: what about comments/attributes in between parameters
301+ param_ast. iter ( ) . zip ( field_list. fields ( ) ) . for_each ( |( param, field) | {
302+ let elements = take_all_comments ( param. clone ( ) ) ;
303+ ted:: insert_all ( ted:: Position :: first_child_of ( field. syntax ( ) ) , elements) ;
304+ ted:: insert_all (
305+ ted:: Position :: first_child_of ( field. syntax ( ) ) ,
306+ param
307+ . attrs ( )
308+ . flat_map ( |it| [ it. syntax ( ) . clone ( ) . into ( ) , make:: tokens:: single_newline ( ) . into ( ) ] )
309+ . collect ( ) ,
310+ ) ;
311+ } ) ;
299312 let field_list = field_list. indent ( IndentLevel :: single ( ) ) ;
300313
301- let strukt = make:: struct_ ( fn_vis, name, generics, field_list) . clone_for_update ( ) ;
302314
303- // take comments from only inside signature
304- ted:: insert_all (
305- ted:: Position :: first_child_of ( strukt. syntax ( ) ) ,
306- take_all_comments ( param_ast. iter ( ) ) ,
307- ) ;
308315
309- // TODO: this may not be correct as we shouldn't put all the attributes at the top
310- // copy attributes from each parameter
311- ted:: insert_all (
312- ted:: Position :: first_child_of ( strukt. syntax ( ) ) ,
313- param_ast
314- . iter ( )
315- . flat_map ( |p| p. attrs ( ) )
316- . flat_map ( |it| {
317- vec ! [ it. syntax( ) . clone_for_update( ) . into( ) , make:: tokens:: single_newline( ) . into( ) ]
318- } )
319- . collect ( ) ,
320- ) ;
321-
322- strukt
316+ make:: struct_ ( fn_vis, name, generics, field_list. into ( ) ) . clone_for_update ( )
323317}
324318// Note: this also detaches whitespace after comments,
325319// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
326320// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
327- fn take_all_comments < ' a > ( node : impl Iterator < Item = & ' a ast:: Param > ) -> Vec < SyntaxElement > {
321+ fn take_all_comments ( node : impl ast:: AstNode ) -> Vec < SyntaxElement > {
328322 let mut remove_next_ws = false ;
329- node. flat_map ( |p| p. syntax ( ) . children_with_tokens ( ) )
323+ node. syntax ( )
324+ . children_with_tokens ( )
330325 . filter_map ( move |child| match child. kind ( ) {
331326 SyntaxKind :: COMMENT => {
332327 remove_next_ws = true ;
@@ -375,8 +370,13 @@ fn generate_unique_lifetime_param_name(
375370fn new_life_time_count ( ty : & ast:: Type ) -> usize {
376371 ty. syntax ( )
377372 . descendants ( )
378- . filter_map ( ast:: Lifetime :: cast)
379- . filter ( |lifetime| lifetime. text ( ) == "'_" )
373+ . filter ( |t| {
374+ match_ast ! { match t {
375+ ast:: Lifetime ( lt) => lt. text( ) == "'_" ,
376+ ast:: RefType ( r) => r. lifetime( ) . is_none( ) ,
377+ _ => false
378+ } }
379+ } )
380380 . count ( )
381381}
382382fn contains_impl_trait ( ty : & ast:: Type ) -> bool {
@@ -387,6 +387,8 @@ fn generate_new_lifetimes(
387387 existing_type_param_list : & mut Option < ast:: GenericParamList > ,
388388) -> Option < ( ) > {
389389 for token in ty. syntax ( ) . descendants ( ) {
390+ // we do not have to worry about for<'a> because we are only looking at '_ or &Type
391+ // if you have an unbound lifetime thats on you
390392 if let Some ( lt) = ast:: Lifetime :: cast ( token. clone ( ) )
391393 && lt. text ( ) == "'_"
392394 {
@@ -396,7 +398,18 @@ fn generate_new_lifetimes(
396398 . add_generic_param ( make:: lifetime_param ( new_lt. clone ( ) ) . clone_for_update ( ) . into ( ) ) ;
397399
398400 ted:: replace ( lt. syntax ( ) , new_lt. clone_for_update ( ) . syntax ( ) ) ;
401+ } else if let Some ( r) = ast:: RefType :: cast ( token. clone ( ) )
402+ && r. lifetime ( ) . is_none ( )
403+ {
404+ let new_lt = generate_unique_lifetime_param_name ( existing_type_param_list) ?;
405+ existing_type_param_list
406+ . get_or_insert ( make:: generic_param_list ( std:: iter:: empty ( ) ) . clone_for_update ( ) )
407+ . add_generic_param ( make:: lifetime_param ( new_lt. clone ( ) ) . clone_for_update ( ) . into ( ) ) ;
408+ ted:: insert ( ted:: Position :: after ( r. amp_token ( ) ?) , new_lt. clone_for_update ( ) . syntax ( ) ) ;
399409 }
410+ // TODO: nominal types that have only lifetimes
411+ // struct Bar<'a, 'b> { f: &'a &'b i32 }
412+ // fn foo(f: Bar) {}
400413 }
401414 Some ( ( ) )
402415}
@@ -782,6 +795,21 @@ fn foo($0bar: &'_ i32$0, baz: i32) {}
782795 r#"
783796struct FooStruct<'a>{ bar: &'a i32 }
784797
798+ fn foo(FooStruct { bar, .. }: FooStruct<'_>, baz: i32) {}
799+ "# ,
800+ ) ;
801+ }
802+
803+ #[ test]
804+ fn test_extract_function_signature_single_parameter_with_plain_reference_type ( ) {
805+ check_assist (
806+ extract_struct_from_function_signature,
807+ r#"
808+ fn foo($0bar: &i32$0, baz: i32) {}
809+ "# ,
810+ r#"
811+ struct FooStruct<'a>{ bar: &'a i32 }
812+
785813fn foo(FooStruct { bar, .. }: FooStruct<'_>, baz: i32) {}
786814"# ,
787815 ) ;
@@ -889,4 +917,26 @@ fn bar() {
889917"# ,
890918 ) ;
891919 }
920+ #[ test]
921+ fn test_extract_function_signature_in_method_comments_and_attributes ( ) {
922+ check_assist (
923+ extract_struct_from_function_signature,
924+ r#"
925+ fn foo(
926+ #[foo]
927+ // gag
928+ $0f: i32,
929+ ) { }
930+ "# ,
931+ r#"
932+ struct FooStruct{ #[foo]
933+ // gag
934+ f: i32 }
935+
936+ fn foo(
937+ FooStruct { f, .. }: FooStruct,
938+ ) { }
939+ "# ,
940+ )
941+ }
892942}
0 commit comments