@@ -72,7 +72,7 @@ pub(crate) fn extract_struct_from_function_signature(
72
72
// clauses
73
73
// we also need special handling for method calls
74
74
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
76
76
// destructed types yet
77
77
78
78
let field_list = extract_field_list ( & func, & used_param_list) ?;
@@ -285,7 +285,7 @@ fn create_struct_def(
285
285
} ;
286
286
287
287
// for fields without any existing visibility, use visibility of enum
288
- let field_list: ast :: FieldList = {
288
+ let field_list = {
289
289
if let Some ( vis) = & fn_vis {
290
290
field_list
291
291
. fields ( )
@@ -294,39 +294,34 @@ fn create_struct_def(
294
294
. for_each ( |it| insert_vis ( it. syntax ( ) , vis. syntax ( ) ) ) ;
295
295
}
296
296
297
- field_list. clone ( ) . into ( )
297
+ field_list
298
298
} ;
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
+ } ) ;
299
312
let field_list = field_list. indent ( IndentLevel :: single ( ) ) ;
300
313
301
- let strukt = make:: struct_ ( fn_vis, name, generics, field_list) . clone_for_update ( ) ;
302
314
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
- ) ;
308
315
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 ( )
323
317
}
324
318
// Note: this also detaches whitespace after comments,
325
319
// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
326
320
// 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 > {
328
322
let mut remove_next_ws = false ;
329
- node. flat_map ( |p| p. syntax ( ) . children_with_tokens ( ) )
323
+ node. syntax ( )
324
+ . children_with_tokens ( )
330
325
. filter_map ( move |child| match child. kind ( ) {
331
326
SyntaxKind :: COMMENT => {
332
327
remove_next_ws = true ;
@@ -375,8 +370,13 @@ fn generate_unique_lifetime_param_name(
375
370
fn new_life_time_count ( ty : & ast:: Type ) -> usize {
376
371
ty. syntax ( )
377
372
. 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
+ } )
380
380
. count ( )
381
381
}
382
382
fn contains_impl_trait ( ty : & ast:: Type ) -> bool {
@@ -387,6 +387,8 @@ fn generate_new_lifetimes(
387
387
existing_type_param_list : & mut Option < ast:: GenericParamList > ,
388
388
) -> Option < ( ) > {
389
389
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
390
392
if let Some ( lt) = ast:: Lifetime :: cast ( token. clone ( ) )
391
393
&& lt. text ( ) == "'_"
392
394
{
@@ -396,7 +398,18 @@ fn generate_new_lifetimes(
396
398
. add_generic_param ( make:: lifetime_param ( new_lt. clone ( ) ) . clone_for_update ( ) . into ( ) ) ;
397
399
398
400
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 ( ) ) ;
399
409
}
410
+ // TODO: nominal types that have only lifetimes
411
+ // struct Bar<'a, 'b> { f: &'a &'b i32 }
412
+ // fn foo(f: Bar) {}
400
413
}
401
414
Some ( ( ) )
402
415
}
@@ -782,6 +795,21 @@ fn foo($0bar: &'_ i32$0, baz: i32) {}
782
795
r#"
783
796
struct FooStruct<'a>{ bar: &'a i32 }
784
797
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
+
785
813
fn foo(FooStruct { bar, .. }: FooStruct<'_>, baz: i32) {}
786
814
"# ,
787
815
) ;
@@ -889,4 +917,26 @@ fn bar() {
889
917
"# ,
890
918
) ;
891
919
}
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
+ }
892
942
}
0 commit comments