@@ -89,6 +89,7 @@ pub(crate) fn extract_struct_from_function_signature(
89
89
"Extract struct from signature of a function" ,
90
90
target,
91
91
|builder| {
92
+ let new_lifetime_count = field_list. fields ( ) . filter_map ( |f|f. ty ( ) ) . map ( |t|new_life_time_count ( & t) ) . sum ( ) ;
92
93
let edition = fn_hir. krate ( ctx. db ( ) ) . edition ( ctx. db ( ) ) ;
93
94
let enum_module_def = ModuleDef :: from ( fn_hir) ;
94
95
@@ -115,7 +116,10 @@ pub(crate) fn extract_struct_from_function_signature(
115
116
name. clone ( )
116
117
) ;
117
118
processed. into_iter ( ) . for_each ( |( path, node, import) | {
118
- apply_references ( ctx. config . insert_use , path, node, import, edition, used_params_range. clone ( ) , & field_list) ;
119
+ apply_references ( ctx. config . insert_use , path, node, import, edition, used_params_range. clone ( ) , & field_list,
120
+ name. clone ( ) ,
121
+ new_lifetime_count
122
+ ) ;
119
123
} ) ;
120
124
}
121
125
@@ -138,7 +142,10 @@ pub(crate) fn extract_struct_from_function_signature(
138
142
name. clone ( )
139
143
) ;
140
144
processed. into_iter ( ) . for_each ( |( path, node, import) | {
141
- apply_references ( ctx. config . insert_use , path, node, import, edition, used_params_range. clone ( ) , & field_list) ;
145
+ apply_references ( ctx. config . insert_use , path, node, import, edition, used_params_range. clone ( ) , & field_list,
146
+ name. clone ( ) ,
147
+ new_lifetime_count
148
+ ) ;
142
149
} ) ;
143
150
}
144
151
@@ -147,7 +154,7 @@ pub(crate) fn extract_struct_from_function_signature(
147
154
. generic_param_list ( )
148
155
. and_then ( |known_generics| extract_generic_params ( & known_generics, & field_list) ) ;
149
156
tracing:: info!( "extract_struct_from_function_signature: collecting generics" ) ;
150
- let generics = generic_params. as_ref ( ) . map ( |generics| generics. clone_for_update ( ) ) ;
157
+ let mut generics = generic_params. as_ref ( ) . map ( |generics| generics. clone_for_update ( ) ) ;
151
158
152
159
// resolve GenericArg in field_list to actual type
153
160
// we would get a query error from salsa, if we would use the field_list
@@ -171,6 +178,7 @@ pub(crate) fn extract_struct_from_function_signature(
171
178
} else {
172
179
field_list. clone_for_update ( )
173
180
} ;
181
+ field_list. fields ( ) . filter_map ( |f|f. ty ( ) ) . try_for_each ( |t|generate_new_lifetimes ( & t, & mut generics) ) ;
174
182
tracing:: info!( "extract_struct_from_function_signature: collecting fields" ) ;
175
183
let def = create_struct_def ( name. clone ( ) , & fn_ast_mut, & used_param_list, & field_list, generics) ;
176
184
tracing:: info!( "extract_struct_from_function_signature: creating struct" ) ;
@@ -187,7 +195,7 @@ pub(crate) fn extract_struct_from_function_signature(
187
195
] ,
188
196
) ;
189
197
tracing:: info!( "extract_struct_from_function_signature: inserting struct {def}" ) ;
190
- update_function ( name, generic_params. map ( |g| g. clone_for_update ( ) ) , & used_param_list) . unwrap ( ) ;
198
+ update_function ( name, generic_params. map ( |g| g. clone_for_update ( ) ) , & used_param_list, new_lifetime_count ) . unwrap ( ) ;
191
199
tracing:: info!( "extract_struct_from_function_signature: updating function signature and parameter uses" ) ;
192
200
} ,
193
201
)
@@ -197,10 +205,19 @@ fn update_function(
197
205
name : ast:: Name ,
198
206
generics : Option < ast:: GenericParamList > ,
199
207
used_param_list : & [ ast:: Param ] ,
208
+ new_lifetime_count : usize ,
200
209
) -> Option < ( ) > {
201
- let generic_args = generics
202
- . filter ( |generics| generics. generic_params ( ) . count ( ) > 0 )
203
- . map ( |generics| generics. to_generic_args ( ) ) ;
210
+ // TODO: add new generics if needed
211
+ let generic_args =
212
+ generics. filter ( |generics| generics. generic_params ( ) . count ( ) > 0 ) . map ( |generics| {
213
+ let args = generics. to_generic_args ( ) . clone_for_update ( ) ;
214
+ ( 0 ..new_lifetime_count) . for_each ( |_| {
215
+ args. add_generic_arg (
216
+ make:: lifetime_arg ( make:: lifetime ( "'_" ) ) . clone_for_update ( ) . into ( ) ,
217
+ )
218
+ } ) ;
219
+ args
220
+ } ) ;
204
221
// FIXME: replace with a `ast::make` constructor
205
222
let ty = match generic_args {
206
223
Some ( generic_args) => make:: ty ( & format ! ( "{name}{generic_args}" ) ) ,
@@ -212,6 +229,7 @@ fn update_function(
212
229
// makes it easier in that we would not have to update all the uses of the variables in
213
230
// the function
214
231
ast:: Pat :: RecordPat ( make:: record_pat (
232
+ // TODO: need to have no turbofish kept lifetimes/generics if
215
233
make:: path_from_text ( name. text_non_mutable ( ) ) ,
216
234
used_param_list
217
235
. iter ( )
@@ -328,6 +346,44 @@ fn extract_generic_params(
328
346
let generics = generics. into_iter ( ) . filter_map ( |( param, tag) | tag. then_some ( param) ) ;
329
347
tagged_one. then ( || make:: generic_param_list ( generics) )
330
348
}
349
+ fn generate_unique_lifetime_param_name (
350
+ existing_type_param_list : & Option < ast:: GenericParamList > ,
351
+ ) -> Option < ast:: Lifetime > {
352
+ match existing_type_param_list {
353
+ Some ( type_params) => {
354
+ let used_lifetime_params: FxHashSet < _ > =
355
+ type_params. lifetime_params ( ) . map ( |p| p. syntax ( ) . text ( ) . to_string ( ) ) . collect ( ) ;
356
+ ( 'a' ..='z' ) . map ( |it| format ! ( "'{it}" ) ) . find ( |it| !used_lifetime_params. contains ( it) )
357
+ }
358
+ None => Some ( "'a" . to_owned ( ) ) ,
359
+ }
360
+ . map ( |it| make:: lifetime ( & it) )
361
+ }
362
+ fn new_life_time_count ( ty : & ast:: Type ) -> usize {
363
+ ty. syntax ( )
364
+ . descendants ( )
365
+ . filter_map ( ast:: Lifetime :: cast)
366
+ . filter ( |lifetime| lifetime. text ( ) == "'_" )
367
+ . count ( )
368
+ }
369
+ fn generate_new_lifetimes (
370
+ ty : & ast:: Type ,
371
+ existing_type_param_list : & mut Option < ast:: GenericParamList > ,
372
+ ) -> Option < ( ) > {
373
+ for token in ty. syntax ( ) . descendants ( ) {
374
+ if let Some ( lt) = ast:: Lifetime :: cast ( token. clone ( ) )
375
+ && lt. text ( ) == "'_"
376
+ {
377
+ let new_lt = generate_unique_lifetime_param_name ( existing_type_param_list) ?;
378
+ existing_type_param_list
379
+ . get_or_insert ( make:: generic_param_list ( std:: iter:: empty ( ) ) . clone_for_update ( ) )
380
+ . add_generic_param ( make:: lifetime_param ( new_lt. clone ( ) ) . clone_for_update ( ) . into ( ) ) ;
381
+
382
+ ted:: replace ( lt. syntax ( ) , new_lt. clone_for_update ( ) . syntax ( ) ) ;
383
+ }
384
+ }
385
+ Some ( ( ) )
386
+ }
331
387
fn tag_generics_in_function_signature (
332
388
ty : & ast:: Type ,
333
389
generics : & mut [ ( ast:: GenericParam , bool ) ] ,
@@ -409,8 +465,7 @@ fn process_references(
409
465
let name = make:: name_ref ( name. text_non_mutable ( ) ) ;
410
466
refs. into_iter ( )
411
467
. flat_map ( |reference| {
412
- let ( segment, scope_node, module) =
413
- reference_to_node ( & ctx. sema , reference, name. clone ( ) ) ?;
468
+ let ( segment, scope_node, module) = reference_to_node ( & ctx. sema , reference) ?;
414
469
let scope_node = builder. make_syntax_mut ( scope_node) ;
415
470
if !visited_modules. contains ( & module) {
416
471
let mod_path = module. find_use_path (
@@ -434,7 +489,6 @@ fn process_references(
434
489
fn reference_to_node (
435
490
sema : & hir:: Semantics < ' _ , RootDatabase > ,
436
491
reference : FileReference ,
437
- name : ast:: NameRef ,
438
492
) -> Option < ( ast:: PathSegment , SyntaxNode , hir:: Module ) > {
439
493
// filter out the reference in macro
440
494
let segment =
@@ -456,8 +510,8 @@ fn reference_to_node(
456
510
}
457
511
} ;
458
512
let module = sema. scope ( & expr_or_pat) ?. module ( ) ;
459
- let segment = make :: path_segment ( name ) ;
460
- Some ( ( segment, expr_or_pat, module) )
513
+
514
+ Some ( ( segment. clone_for_update ( ) , expr_or_pat, module) )
461
515
}
462
516
463
517
fn apply_references (
@@ -468,12 +522,28 @@ fn apply_references(
468
522
edition : Edition ,
469
523
used_params_range : Range < usize > ,
470
524
field_list : & ast:: RecordFieldList ,
525
+ name : ast:: Name ,
526
+ new_lifetime_count : usize ,
471
527
) -> Option < ( ) > {
472
528
if let Some ( ( scope, path) ) = import {
473
529
insert_use ( & scope, mod_path_to_ast ( & path, edition) , & insert_use_cfg) ;
474
530
}
531
+ // TODO: figure out lifetimes in referecnecs
532
+ // becauuse we have to convert from segment being non turbofish, also only need
533
+ // generics/lifetimes that are used in struct possibly not all the no ones for the original call
534
+ // if no specified lifetimes/generics we just give empty one
535
+ // if new_lifetime_count > 0 {
536
+ // (0..new_lifetime_count).for_each(|_| {
537
+ // segment
538
+ // .get_or_create_generic_arg_list()
539
+ // .add_generic_arg(make::lifetime_arg(make::lifetime("'_")).clone_for_update().into())
540
+ // });
541
+ // }
542
+
543
+ ted:: replace ( segment. name_ref ( ) ?. syntax ( ) , name. clone_for_update ( ) . syntax ( ) ) ;
475
544
// deep clone to prevent cycle
476
545
let path = make:: path_from_segments ( std:: iter:: once ( segment. clone_subtree ( ) ) , false ) ;
546
+ // TODO: do I need to to method call to
477
547
let call = CallExpr :: cast ( node) ?;
478
548
let fields = make:: record_expr_field_list (
479
549
call. arg_list ( ) ?
@@ -489,6 +559,7 @@ fn apply_references(
489
559
. collect :: < Option < Vec < _ > > > ( ) ?,
490
560
) ;
491
561
let record_expr = make:: record_expr ( path, fields) . clone_for_update ( ) ;
562
+
492
563
call. arg_list ( ) ?
493
564
. syntax ( )
494
565
. splice_children ( used_params_range, vec ! [ record_expr. syntax( ) . syntax_element( ) ] ) ;
@@ -561,7 +632,7 @@ fn main() {
561
632
) ;
562
633
}
563
634
#[ test]
564
- fn test_extract_function_signature_single_parameter_with_reference_seperate_and_inself ( ) {
635
+ fn test_extract_function_signature_single_parameter_with_reference_separate_and_in_self ( ) {
565
636
check_assist (
566
637
extract_struct_from_function_signature,
567
638
r#"
@@ -620,4 +691,86 @@ mod b {
620
691
"# ,
621
692
) ;
622
693
}
694
+
695
+ #[ test]
696
+ fn test_extract_function_signature_single_parameter_generic ( ) {
697
+ check_assist (
698
+ extract_struct_from_function_signature,
699
+ r#"
700
+ fn foo<'a, A>($0bar: &'a A$0, baz: i32) {}
701
+ "# ,
702
+ r#"
703
+ struct FooStruct<'a, A>{ bar: &'a A }
704
+
705
+ fn foo<'a, A>(FooStruct { bar, .. }: FooStruct<'a, A>, baz: i32) {}
706
+ "# ,
707
+ ) ;
708
+ }
709
+ #[ test]
710
+ fn test_extract_function_signature_single_parameter_generic_with_reference_in_self ( ) {
711
+ check_assist (
712
+ extract_struct_from_function_signature,
713
+ r#"
714
+ fn foo<'a, A>($0bar: &'a A$0, baz: i32) {
715
+ foo(1, 2)
716
+ }
717
+ "# ,
718
+ r#"
719
+ struct FooStruct<'a, A>{ bar: &'a A }
720
+
721
+ fn foo<'a, A>(FooStruct { bar, .. }: FooStruct<'a, A>, baz: i32) {
722
+ foo(FooStruct { bar: 1 }, 2)
723
+ }
724
+ "# ,
725
+ ) ;
726
+ }
727
+
728
+ #[ test]
729
+ fn test_extract_function_signature_single_parameter_anonymous_lifetime ( ) {
730
+ check_assist (
731
+ extract_struct_from_function_signature,
732
+ r#"
733
+ fn foo($0bar: &'_ i32$0, baz: i32) {}
734
+ "# ,
735
+ r#"
736
+ struct FooStruct<'a>{ bar: &'a i32 }
737
+
738
+ fn foo(FooStruct { bar, .. }: FooStruct, baz: i32) {}
739
+ "# ,
740
+ ) ;
741
+ }
742
+ #[ test]
743
+ fn test_extract_function_signature_single_parameter_anonymous_and_normal_lifetime ( ) {
744
+ check_assist (
745
+ extract_struct_from_function_signature,
746
+ r#"
747
+ fn foo<'a>($0bar: &'_ &'a i32$0, baz: i32) {}
748
+ "# ,
749
+ r#"
750
+ struct FooStruct<'a, 'b>{ bar: &'b &'a i32 }
751
+
752
+ fn foo<'a>(FooStruct { bar, .. }: FooStruct<'a, '_>, baz: i32) {}
753
+ "# ,
754
+ ) ;
755
+ }
756
+
757
+ #[ test]
758
+ fn test_extract_function_signature_single_parameter_anonymous_and_normal_lifetime_with_reference_in_self ( )
759
+ {
760
+ check_assist (
761
+ extract_struct_from_function_signature,
762
+ r#"
763
+ fn foo<'a>($0bar: &'_ &'a i32$0, baz: i32) {
764
+ foo(bar, baz)
765
+ }
766
+ "# ,
767
+ r#"
768
+ struct FooStruct<'a, 'b>{ bar: &'b &'a i32 }
769
+
770
+ fn foo<'a>(FooStruct { bar, .. }: FooStruct<'a, '_>, baz: i32) {
771
+ foo(FooStruct { bar: bar }, baz)
772
+ }
773
+ "# ,
774
+ ) ;
775
+ }
623
776
}
0 commit comments