@@ -43,14 +43,14 @@ pub(crate) fn extract_struct_from_function_signature(
43
43
acc : & mut Assists ,
44
44
ctx : & AssistContext < ' _ > ,
45
45
) -> Option < ( ) > {
46
- let fn_ast = ctx. find_node_at_offset :: < ast:: Fn > ( ) ?;
46
+ let find_node_at_offset = ctx. find_node_at_offset :: < ast:: Fn > ( ) ?;
47
+ let fn_ast = find_node_at_offset;
47
48
let param_list = fn_ast. param_list ( ) ?;
48
49
let used_param_list = param_list
49
50
. params ( )
50
51
// filter to only parameters in selection
51
52
. filter ( |p| p. syntax ( ) . text_range ( ) . intersect ( ctx. selection_trimmed ( ) ) . is_some ( ) )
52
53
. collect_vec ( ) ;
53
- // TODO: make sure at least one thing there
54
54
let target =
55
55
used_param_list. iter ( ) . map ( |p| p. syntax ( ) . text_range ( ) ) . reduce ( |t, t2| t. cover ( t2) ) ?;
56
56
let fn_name = fn_ast. name ( ) ?;
@@ -62,25 +62,20 @@ pub(crate) fn extract_struct_from_function_signature(
62
62
return None ;
63
63
}
64
64
65
- // TODO: special handling for self?
66
- // TODO: special handling for destrutered types (or maybe just don't support code action on
65
+ // TODO: (future)special handling for self
66
+ // since it puts struct above function it invalid needs to go outside the the impl block
67
+ // if uses self parameter and that is selected:
68
+ // do we still keep in it in the impl block/does it matter what type of impl block it is (if its
69
+ // a trait then probably not)
70
+ // what should the name for self parameter be in the struct
71
+ // also you would need to grab out any generics from that impl block itself and any where
72
+ // clauses
73
+ // we also need special handling for method calls
74
+
75
+ // TODO: (future)special handling for destrutered types (or maybe just don't support code action on
67
76
// destructed types yet
68
77
69
- // TODO: don't allow if there is impl traits
70
- let field_list = make:: record_field_list (
71
- used_param_list
72
- . iter ( )
73
- . map ( |param| {
74
- Some ( make:: record_field (
75
- fn_ast. visibility ( ) ,
76
- // only works if its an ident pattern
77
- param. pat ( ) . and_then ( pat_to_name) ?,
78
- // TODO: how are we going to handle references without explicit lifetimes
79
- param. ty ( ) ?,
80
- ) )
81
- } )
82
- . collect :: < Option < Vec < _ > > > ( ) ?,
83
- ) ;
78
+ let field_list = extract_field_list ( & fn_ast, & used_param_list) ?;
84
79
85
80
let start_index = used_param_list. first ( ) ?. syntax ( ) . index ( ) ;
86
81
let end_index = used_param_list. last ( ) ?. syntax ( ) . index ( ) ;
@@ -201,6 +196,26 @@ pub(crate) fn extract_struct_from_function_signature(
201
196
)
202
197
}
203
198
199
+ fn extract_field_list (
200
+ fn_ast : & ast:: Fn ,
201
+ used_param_list : & [ ast:: Param ] ,
202
+ ) -> Option < ast:: RecordFieldList > {
203
+ let field_list = make:: record_field_list (
204
+ used_param_list
205
+ . iter ( )
206
+ . map ( |param| {
207
+ Some ( make:: record_field (
208
+ fn_ast. visibility ( ) ,
209
+ // only works if its an ident pattern
210
+ param. pat ( ) . and_then ( pat_to_name) ?,
211
+ param. ty ( ) . filter ( |ty| !contains_impl_trait ( ty) ) ?,
212
+ ) )
213
+ } )
214
+ . collect :: < Option < Vec < _ > > > ( ) ?,
215
+ ) ;
216
+ Some ( field_list)
217
+ }
218
+
204
219
fn update_function (
205
220
name : ast:: Name ,
206
221
generics : Option < ast:: GenericParamList > ,
@@ -226,11 +241,10 @@ fn update_function(
226
241
} ;
227
242
228
243
let param = make:: param (
229
- // do we want to destructure the struct
244
+ // we destructure the struct
230
245
// makes it easier in that we would not have to update all the uses of the variables in
231
246
// the function
232
247
ast:: Pat :: RecordPat ( make:: record_pat (
233
- // TODO: need to have no turbofish kept lifetimes/generics if
234
248
make:: path_from_text ( name. text_non_mutable ( ) ) ,
235
249
used_param_list
236
250
. iter ( )
@@ -241,17 +255,17 @@ fn update_function(
241
255
ty,
242
256
)
243
257
. clone_for_update ( ) ;
244
- // TODO: will eventually need to handle self too
245
258
259
+ // it is fine to unwrap() to because there is at least one parameter (if there is no parameters
260
+ // the code action will not show)
246
261
let start_index = used_param_list. first ( ) . unwrap ( ) . syntax ( ) . index ( ) ;
247
262
let end_index = used_param_list. last ( ) . unwrap ( ) . syntax ( ) . index ( ) ;
248
263
let used_params_range = start_index..end_index + 1 ;
249
264
let new = vec ! [ param. syntax( ) . syntax_element( ) ] ;
250
- used_param_list. first ( ) ? . syntax ( ) . parent ( ) ?. splice_children ( used_params_range, new) ;
265
+ used_param_list. first ( ) . unwrap ( ) . syntax ( ) . parent ( ) ?. splice_children ( used_params_range, new) ;
251
266
// no need update uses of parameters in function, because we destructure the struct
252
267
Some ( ( ) )
253
268
}
254
-
255
269
fn pat_to_name ( pat : ast:: Pat ) -> Option < ast:: Name > {
256
270
match pat {
257
271
ast:: Pat :: IdentPat ( ident_pat) => ident_pat. name ( ) ,
@@ -367,6 +381,9 @@ fn new_life_time_count(ty: &ast::Type) -> usize {
367
381
. filter ( |lifetime| lifetime. text ( ) == "'_" )
368
382
. count ( )
369
383
}
384
+ fn contains_impl_trait ( ty : & ast:: Type ) -> bool {
385
+ ty. syntax ( ) . descendants ( ) . any ( |ty| ty. kind ( ) == ast:: ImplTraitType :: kind ( ) )
386
+ }
370
387
fn generate_new_lifetimes (
371
388
ty : & ast:: Type ,
372
389
existing_type_param_list : & mut Option < ast:: GenericParamList > ,
@@ -778,4 +795,11 @@ fn foo<'a>(FooStruct { bar, .. }: FooStruct<'a, '_>, baz: i32) {
778
795
"# ,
779
796
) ;
780
797
}
798
+ #[ test]
799
+ fn test_extract_function_signature_not_applicable_with_impl_trait ( ) {
800
+ check_assist_not_applicable (
801
+ extract_struct_from_function_signature,
802
+ r"fn foo($0i: impl ToString) { }" ,
803
+ ) ;
804
+ }
781
805
}
0 commit comments