Skip to content

Commit 4ed8b0b

Browse files
committed
feat: extract_struct_from_function_signature
cleanup and follow stye guide a bit
1 parent 914bdd1 commit 4ed8b0b

File tree

1 file changed

+36
-33
lines changed

1 file changed

+36
-33
lines changed

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

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::ops::Range;
22

3-
use hir::{Function, HasCrate, Module, ModuleDef};
3+
use hir::{HasCrate, Module, ModuleDef};
44
use ide_db::{
55
FxHashSet, RootDatabase,
66
assists::AssistId,
@@ -16,8 +16,7 @@ use syntax::{
1616
AstNode, Edition, SyntaxElement, SyntaxKind, SyntaxNode, T,
1717
algo::find_node_at_range,
1818
ast::{
19-
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasVisibility, MethodCallExpr,
20-
RecordExprField,
19+
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasVisibility,
2120
edit::{AstNodeEdit, IndentLevel},
2221
make,
2322
},
@@ -45,19 +44,19 @@ pub(crate) fn extract_struct_from_function_signature(
4544
ctx: &AssistContext<'_>,
4645
) -> Option<()> {
4746
let find_node_at_offset = ctx.find_node_at_offset::<ast::Fn>()?;
48-
let fn_ast = find_node_at_offset;
49-
let param_list = fn_ast.param_list()?;
47+
let func = find_node_at_offset;
48+
let param_list = func.param_list()?;
5049
let used_param_list = param_list
5150
.params()
5251
// filter to only parameters in selection
5352
.filter(|p| p.syntax().text_range().intersect(ctx.selection_trimmed()).is_some())
5453
.collect_vec();
5554
let target =
5655
used_param_list.iter().map(|p| p.syntax().text_range()).reduce(|t, t2| t.cover(t2))?;
57-
let fn_name = fn_ast.name()?;
56+
let fn_name = func.name()?;
5857
let name = make::name(&format!("{}Struct", stdx::to_camel_case(fn_name.text_non_mutable())));
5958

60-
let fn_hir = ctx.sema.to_def(&fn_ast)?;
59+
let fn_hir = ctx.sema.to_def(&func)?;
6160
if existing_definition(ctx.db(), &name, &fn_hir) {
6261
cov_mark::hit!(test_extract_function_signature_not_applicable_if_struct_exists);
6362
return None;
@@ -76,17 +75,17 @@ pub(crate) fn extract_struct_from_function_signature(
7675
// TODO: (future)special handling for destrutered types (or maybe just don't support code action on
7776
// destructed types yet
7877

79-
let field_list = extract_field_list(&fn_ast, &used_param_list)?;
78+
let field_list = extract_field_list(&func, &used_param_list)?;
8079

81-
let start_index = used_param_list.first()?.syntax().index();
82-
let end_index = used_param_list.last()?.syntax().index();
83-
let used_params_range = start_index..end_index + 1;
80+
let start_idx = used_param_list.first()?.syntax().index();
81+
let end_idx = used_param_list.last()?.syntax().index();
82+
let used_params_range = start_idx..end_idx + 1;
8483
acc.add(
8584
AssistId::refactor_rewrite("extract_struct_from_function_signature"),
8685
"Extract struct from signature of a function",
8786
target,
8887
|builder| {
89-
let new_lifetime_count = field_list.fields().filter_map(|f|f.ty()).map(|t|new_life_time_count(&t)).sum();
88+
let n_new_lifetimes = field_list.fields().filter_map(|f|f.ty()).map(|t|new_life_time_count(&t)).sum();
9089
let edition = fn_hir.krate(ctx.db()).edition(ctx.db());
9190
let enum_module_def = ModuleDef::from(fn_hir);
9291

@@ -121,12 +120,12 @@ pub(crate) fn extract_struct_from_function_signature(
121120

122121
tracing::info!("extract_struct_from_function_signature: starting edit");
123122
builder.edit_file(ctx.vfs_file_id());
124-
let fn_ast_mut = builder.make_mut(fn_ast.clone());
123+
let func_mut = builder.make_mut(func.clone());
125124
builder.make_mut(param_list.clone());
126125
let used_param_list = used_param_list.into_iter().map(|p| builder.make_mut(p)).collect_vec();
127126
tracing::info!("extract_struct_from_function_signature: editing main file");
128127
// this has to be after the edit_file (order matters)
129-
// fn_ast and param_list must be "mut" for the effect to work on used_param_list
128+
// func and param_list must be "mut" for the effect to work on used_param_list
130129
if let Some(references) = def_file_references {
131130
let processed = process_references(
132131
ctx,
@@ -144,7 +143,7 @@ pub(crate) fn extract_struct_from_function_signature(
144143
}
145144

146145

147-
let generic_params = fn_ast
146+
let generic_params = func
148147
.generic_param_list()
149148
.and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
150149
tracing::info!("extract_struct_from_function_signature: collecting generics");
@@ -157,7 +156,7 @@ pub(crate) fn extract_struct_from_function_signature(
157156
// So I do the resolving while its still param list
158157
// and then apply it into record list after
159158
let field_list = if let Some((target_scope, source_scope)) =
160-
ctx.sema.scope(fn_ast.syntax()).zip(ctx.sema.scope(param_list.syntax()))
159+
ctx.sema.scope(func.syntax()).zip(ctx.sema.scope(param_list.syntax()))
161160
{
162161
let field_list = field_list.reset_indent();
163162
let field_list =
@@ -174,11 +173,11 @@ pub(crate) fn extract_struct_from_function_signature(
174173
};
175174
field_list.fields().filter_map(|f|f.ty()).try_for_each(|t|generate_new_lifetimes(&t, &mut generics));
176175
tracing::info!("extract_struct_from_function_signature: collecting fields");
177-
let def = create_struct_def(name.clone(), &fn_ast_mut, &used_param_list, &field_list, generics);
176+
let def = create_struct_def(name.clone(), &func_mut, &used_param_list, &field_list, generics);
178177
tracing::info!("extract_struct_from_function_signature: creating struct");
179178

180179
// if in impl block then put struct before the impl block
181-
let (indent, syntax) = param_list.self_param().and_then(|_|ctx.find_node_at_range::<ast::Impl>() ).map(|impl_|builder.make_mut(impl_)).map(|impl_|( impl_.indent_level(), impl_.syntax().clone())).unwrap_or((fn_ast.indent_level(), fn_ast_mut.syntax().clone()));
180+
let (indent, syntax) = param_list.self_param().and_then(|_|ctx.find_node_at_range::<ast::Impl>() ).map(|imp|builder.make_mut(imp)).map(|imp|( imp.indent_level(), imp.syntax().clone())).unwrap_or((func.indent_level(), func_mut.syntax().clone()));
182181
let def = def.indent(indent);
183182

184183

@@ -190,22 +189,22 @@ pub(crate) fn extract_struct_from_function_signature(
190189
],
191190
);
192191
tracing::info!("extract_struct_from_function_signature: inserting struct {def}");
193-
update_function(name, generic_params.map(|g| g.clone_for_update()), &used_param_list, new_lifetime_count).unwrap();
192+
update_function(name, generic_params.map(|g| g.clone_for_update()), &used_param_list, n_new_lifetimes).unwrap();
194193
tracing::info!("extract_struct_from_function_signature: updating function signature and parameter uses");
195194
},
196195
)
197196
}
198197

199198
fn extract_field_list(
200-
fn_ast: &ast::Fn,
199+
func: &ast::Fn,
201200
used_param_list: &[ast::Param],
202201
) -> Option<ast::RecordFieldList> {
203202
let field_list = make::record_field_list(
204203
used_param_list
205204
.iter()
206205
.map(|param| {
207206
Some(make::record_field(
208-
fn_ast.visibility(),
207+
func.visibility(),
209208
// only works if its an ident pattern
210209
param.pat().and_then(pat_to_name)?,
211210
param.ty().filter(|ty| !contains_impl_trait(ty))?,
@@ -220,14 +219,14 @@ fn update_function(
220219
name: ast::Name,
221220
generics: Option<ast::GenericParamList>,
222221
used_param_list: &[ast::Param],
223-
new_lifetime_count: usize,
222+
n_new_lifetimes: usize,
224223
) -> Option<()> {
225224
let generic_args = generics
226225
.filter(|generics| generics.generic_params().count() > 0)
227-
.or((new_lifetime_count > 0).then_some(make::generic_param_list(std::iter::empty())))
226+
.or((n_new_lifetimes > 0).then_some(make::generic_param_list(std::iter::empty())))
228227
.map(|generics| {
229228
let args = generics.to_generic_args().clone_for_update();
230-
(0..new_lifetime_count).for_each(|_| {
229+
(0..n_new_lifetimes).for_each(|_| {
231230
args.add_generic_arg(
232231
make::lifetime_arg(make::lifetime("'_")).clone_for_update().into(),
233232
)
@@ -258,9 +257,9 @@ fn update_function(
258257

259258
// it is fine to unwrap() to because there is at least one parameter (if there is no parameters
260259
// the code action will not show)
261-
let start_index = used_param_list.first().unwrap().syntax().index();
262-
let end_index = used_param_list.last().unwrap().syntax().index();
263-
let used_params_range = start_index..end_index + 1;
260+
let start_idx = used_param_list.first().unwrap().syntax().index();
261+
let end_idx = used_param_list.last().unwrap().syntax().index();
262+
let used_params_range = start_idx..end_idx + 1;
264263
let new = vec![param.syntax().syntax_element()];
265264
used_param_list.first().unwrap().syntax().parent()?.splice_children(used_params_range, new);
266265
// no need update uses of parameters in function, because we destructure the struct
@@ -274,12 +273,12 @@ fn pat_to_name(pat: ast::Pat) -> Option<ast::Name> {
274273
}
275274
fn create_struct_def(
276275
name: ast::Name,
277-
fn_ast: &ast::Fn,
276+
func: &ast::Fn,
278277
param_ast: &[ast::Param],
279278
field_list: &ast::RecordFieldList,
280279
generics: Option<ast::GenericParamList>,
281280
) -> ast::Struct {
282-
let fn_vis = fn_ast.visibility();
281+
let fn_vis = func.visibility();
283282

284283
let insert_vis = |node: &'_ SyntaxNode, vis: &'_ SyntaxNode| {
285284
let vis = vis.clone_for_update();
@@ -449,7 +448,11 @@ fn tag_generics_in_function_signature(
449448

450449
tagged_one
451450
}
452-
fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Function) -> bool {
451+
fn existing_definition(
452+
db: &RootDatabase,
453+
variant_name: &ast::Name,
454+
variant: &hir::Function,
455+
) -> bool {
453456
variant
454457
.module(db)
455458
.scope(db, None)
@@ -519,7 +522,7 @@ fn reference_to_node(
519522
// return None;
520523
// }
521524

522-
let module = sema.scope(&node.syntax())?.module();
525+
let module = sema.scope(node.syntax())?.module();
523526

524527
Some((node.clone(), node.syntax().clone(), module))
525528
}
@@ -551,7 +554,7 @@ fn apply_references(
551554
// the zip implicitly makes that it will only take the amount of parameters required
552555
.zip(field_list.fields())
553556
.map(|e| {
554-
e.1.name().map(|name| -> RecordExprField {
557+
e.1.name().map(|name| -> ast::RecordExprField {
555558
make::record_expr_field(make::name_ref(name.text_non_mutable()), Some(e.0))
556559
})
557560
})
@@ -591,7 +594,7 @@ impl AstNode for CallExpr {
591594
{
592595
ast::CallExpr::cast(syntax.clone())
593596
.map(CallExpr::Normal)
594-
.or(MethodCallExpr::cast(syntax).map(CallExpr::Method))
597+
.or(ast::MethodCallExpr::cast(syntax).map(CallExpr::Method))
595598
}
596599

597600
fn syntax(&self) -> &SyntaxNode {

0 commit comments

Comments
 (0)