Skip to content

Commit 9c11270

Browse files
committed
feat: extract_struct_from_function_signature
do not support if there is impl trait also ideas for when handling self parameter cleaned up comments
1 parent 40c7666 commit 9c11270

File tree

1 file changed

+48
-24
lines changed

1 file changed

+48
-24
lines changed

crates/ide-assists/src/handlers/extract_struct_from_function_signature.rs

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ pub(crate) fn extract_struct_from_function_signature(
4343
acc: &mut Assists,
4444
ctx: &AssistContext<'_>,
4545
) -> 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;
4748
let param_list = fn_ast.param_list()?;
4849
let used_param_list = param_list
4950
.params()
5051
// filter to only parameters in selection
5152
.filter(|p| p.syntax().text_range().intersect(ctx.selection_trimmed()).is_some())
5253
.collect_vec();
53-
// TODO: make sure at least one thing there
5454
let target =
5555
used_param_list.iter().map(|p| p.syntax().text_range()).reduce(|t, t2| t.cover(t2))?;
5656
let fn_name = fn_ast.name()?;
@@ -62,25 +62,20 @@ pub(crate) fn extract_struct_from_function_signature(
6262
return None;
6363
}
6464

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
6776
// destructed types yet
6877

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)?;
8479

8580
let start_index = used_param_list.first()?.syntax().index();
8681
let end_index = used_param_list.last()?.syntax().index();
@@ -201,6 +196,26 @@ pub(crate) fn extract_struct_from_function_signature(
201196
)
202197
}
203198

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+
204219
fn update_function(
205220
name: ast::Name,
206221
generics: Option<ast::GenericParamList>,
@@ -226,11 +241,10 @@ fn update_function(
226241
};
227242

228243
let param = make::param(
229-
// do we want to destructure the struct
244+
// we destructure the struct
230245
// makes it easier in that we would not have to update all the uses of the variables in
231246
// the function
232247
ast::Pat::RecordPat(make::record_pat(
233-
// TODO: need to have no turbofish kept lifetimes/generics if
234248
make::path_from_text(name.text_non_mutable()),
235249
used_param_list
236250
.iter()
@@ -241,17 +255,17 @@ fn update_function(
241255
ty,
242256
)
243257
.clone_for_update();
244-
// TODO: will eventually need to handle self too
245258

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)
246261
let start_index = used_param_list.first().unwrap().syntax().index();
247262
let end_index = used_param_list.last().unwrap().syntax().index();
248263
let used_params_range = start_index..end_index + 1;
249264
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);
251266
// no need update uses of parameters in function, because we destructure the struct
252267
Some(())
253268
}
254-
255269
fn pat_to_name(pat: ast::Pat) -> Option<ast::Name> {
256270
match pat {
257271
ast::Pat::IdentPat(ident_pat) => ident_pat.name(),
@@ -367,6 +381,9 @@ fn new_life_time_count(ty: &ast::Type) -> usize {
367381
.filter(|lifetime| lifetime.text() == "'_")
368382
.count()
369383
}
384+
fn contains_impl_trait(ty: &ast::Type) -> bool {
385+
ty.syntax().descendants().any(|ty| ty.kind() == ast::ImplTraitType::kind())
386+
}
370387
fn generate_new_lifetimes(
371388
ty: &ast::Type,
372389
existing_type_param_list: &mut Option<ast::GenericParamList>,
@@ -778,4 +795,11 @@ fn foo<'a>(FooStruct { bar, .. }: FooStruct<'a, '_>, baz: i32) {
778795
"#,
779796
);
780797
}
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+
}
781805
}

0 commit comments

Comments
 (0)