Skip to content

Commit 6fff2c1

Browse files
committed
extract_module: Refactor loops
1 parent 1e71ac2 commit 6fff2c1

File tree

1 file changed

+52
-84
lines changed

1 file changed

+52
-84
lines changed

crates/ide_assists/src/handlers/extract_module.rs

Lines changed: 52 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::{
2+
collections::{HashMap, HashSet},
3+
iter,
4+
};
25

36
use hir::{HasSource, ModuleSource};
47
use ide_db::{
@@ -207,31 +210,25 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<(
207210
#[derive(Debug)]
208211
struct Module {
209212
text_range: TextRange,
210-
name: String,
211-
body_items: Vec<ast::Item>, // All items except use items
212-
use_items: Vec<ast::Item>, // Use items are kept separately as they help when the selection is inside an impl block, we can directly take these items and keep them outside generated impl block inside generated module
213+
name: &'static str,
214+
/// All items except use items.
215+
body_items: Vec<ast::Item>,
216+
/// Use items are kept separately as they help when the selection is inside an impl block,
217+
/// we can directly take these items and keep them outside generated impl block inside
218+
/// generated module.
219+
use_items: Vec<ast::Item>,
213220
}
214221

215222
fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
216-
let mut use_items = vec![];
217-
218-
let mut body_items: Vec<ast::Item> = node
223+
let selected_nodes = node
219224
.children()
220-
.filter(|child| selection_range.contains_range(child.text_range()))
221-
.filter_map(|child| match ast::Item::cast(child) {
222-
Some(it @ ast::Item::Use(_)) => {
223-
use_items.push(it);
224-
None
225-
}
226-
item => item,
227-
})
228-
.collect();
229-
230-
if let Some(node_item) = ast::Item::cast(node.clone()) {
231-
body_items.push(node_item);
232-
}
225+
.filter(|node| selection_range.contains_range(node.text_range()))
226+
.chain(iter::once(node.clone()));
227+
let (use_items, body_items) = selected_nodes
228+
.filter_map(ast::Item::cast)
229+
.partition(|item| matches!(item, ast::Item::Use(..)));
233230

234-
Some(Module { text_range: selection_range, name: "modname".to_string(), body_items, use_items })
231+
Some(Module { text_range: selection_range, name: "modname", body_items, use_items })
235232
}
236233

237234
impl Module {
@@ -245,7 +242,7 @@ impl Module {
245242
//Here impl is not included as each item inside impl will be tied to the parent of
246243
//implementing block(a struct, enum, etc), if the parent is in selected module, it will
247244
//get updated by ADT section given below or if it is not, then we dont need to do any operation
248-
self.body_items.iter().cloned().for_each(|item| {
245+
for item in &self.body_items {
249246
match_ast! {
250247
match (item.syntax()) {
251248
ast::Adt(it) => {
@@ -314,7 +311,7 @@ impl Module {
314311
_ => (),
315312
}
316313
}
317-
});
314+
}
318315

319316
(refs, adt_fields)
320317
}
@@ -323,36 +320,17 @@ impl Module {
323320
&self,
324321
ctx: &AssistContext,
325322
node_def: Definition,
326-
refs: &mut HashMap<FileId, Vec<(TextRange, String)>>,
323+
refs_in_files: &mut HashMap<FileId, Vec<(TextRange, String)>>,
327324
) {
328325
for (file_id, references) in node_def.usages(&ctx.sema).all() {
329-
if let Some(file_refs) = refs.get_mut(&file_id) {
330-
let mut usages = self.expand_ref_to_usages(references, ctx, file_id);
331-
file_refs.append(&mut usages);
332-
} else {
333-
refs.insert(file_id, self.expand_ref_to_usages(references, ctx, file_id));
334-
}
326+
let source_file = ctx.sema.parse(file_id);
327+
let usages_in_file = references
328+
.into_iter()
329+
.filter_map(|usage| self.get_usage_to_be_processed(&source_file, usage));
330+
refs_in_files.entry(file_id).or_default().extend(usages_in_file);
335331
}
336332
}
337333

338-
fn expand_ref_to_usages(
339-
&self,
340-
refs: Vec<FileReference>,
341-
ctx: &AssistContext,
342-
file_id: FileId,
343-
) -> Vec<(TextRange, String)> {
344-
let source_file = ctx.sema.parse(file_id);
345-
346-
let mut usages_to_be_processed_for_file = Vec::new();
347-
for usage in refs {
348-
if let Some(x) = self.get_usage_to_be_processed(&source_file, usage) {
349-
usages_to_be_processed_for_file.push(x);
350-
}
351-
}
352-
353-
usages_to_be_processed_for_file
354-
}
355-
356334
fn get_usage_to_be_processed(
357335
&self,
358336
source_file: &SourceFile,
@@ -380,36 +358,30 @@ impl Module {
380358
let (mut replacements, record_field_parents, impls) =
381359
get_replacements_for_visibilty_change(&mut self.body_items, false);
382360

383-
let mut impl_items = Vec::new();
384-
for impl_ in impls {
385-
let mut this_impl_items = Vec::new();
386-
for node in impl_.syntax().descendants() {
387-
if let Some(item) = ast::Item::cast(node) {
388-
this_impl_items.push(item);
389-
}
390-
}
391-
392-
impl_items.append(&mut this_impl_items);
393-
}
361+
let mut impl_items: Vec<ast::Item> = impls
362+
.into_iter()
363+
.flat_map(|impl_| impl_.syntax().descendants())
364+
.filter_map(ast::Item::cast)
365+
.collect();
394366

395367
let (mut impl_item_replacements, _, _) =
396368
get_replacements_for_visibilty_change(&mut impl_items, true);
397369

398370
replacements.append(&mut impl_item_replacements);
399371

400-
record_field_parents.into_iter().for_each(|x| {
401-
x.1.descendants().filter_map(ast::RecordField::cast).for_each(|desc| {
372+
for (_, field_owner) in record_field_parents {
373+
for desc in field_owner.descendants().filter_map(ast::RecordField::cast) {
402374
let is_record_field_present =
403375
record_fields.clone().into_iter().any(|x| x.to_string() == desc.to_string());
404376
if is_record_field_present {
405377
replacements.push((desc.visibility(), desc.syntax().clone()));
406378
}
407-
});
408-
});
379+
}
380+
}
409381

410-
replacements.into_iter().for_each(|(vis, syntax)| {
382+
for (vis, syntax) in replacements {
411383
add_change_vis(vis, syntax.first_child_or_token());
412-
});
384+
}
413385
}
414386

415387
fn resolve_imports(
@@ -420,8 +392,8 @@ impl Module {
420392
let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
421393
let mut node_set: HashSet<String> = HashSet::new();
422394

423-
self.body_items.clone().into_iter().for_each(|item| {
424-
item.syntax().descendants().for_each(|x| {
395+
for item in self.body_items.clone() {
396+
for x in item.syntax().descendants() {
425397
if let Some(name) = ast::Name::cast(x.clone()) {
426398
if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
427399
//Necessary to avoid two same names going through
@@ -473,8 +445,8 @@ impl Module {
473445
}
474446
}
475447
}
476-
});
477-
});
448+
}
449+
}
478450

479451
import_paths_to_be_removed
480452
}
@@ -495,8 +467,8 @@ impl Module {
495467

496468
let mut exists_inside_sel = false;
497469
let mut exists_outside_sel = false;
498-
usage_res.clone().into_iter().for_each(|x| {
499-
let mut non_use_nodes_itr = (&x.1).iter().filter_map(|x| {
470+
for (_, refs) in usage_res.iter() {
471+
let mut non_use_nodes_itr = refs.iter().filter_map(|x| {
500472
if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
501473
let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
502474
return path_opt;
@@ -514,7 +486,7 @@ impl Module {
514486
if non_use_nodes_itr.any(|x| selection_range.contains_range(x.syntax().text_range())) {
515487
exists_inside_sel = true;
516488
}
517-
});
489+
}
518490

519491
let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
520492
def,
@@ -524,18 +496,14 @@ impl Module {
524496
curr_file_id,
525497
);
526498

527-
let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|x| {
528-
let file_id = x.0;
529-
let mut use_opt: Option<ast::Use> = None;
499+
let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|(file_id, refs)| {
530500
if file_id == curr_file_id {
531-
(&x.1).iter().for_each(|x| {
532-
let node_opt: Option<ast::Use> = find_node_at_range(file.syntax(), x.range);
533-
if let Some(node) = node_opt {
534-
use_opt = Some(node);
535-
}
536-
});
501+
refs.into_iter()
502+
.rev()
503+
.find_map(|fref| find_node_at_range(file.syntax(), fref.range))
504+
} else {
505+
None
537506
}
538-
use_opt
539507
});
540508

541509
let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
@@ -811,7 +779,7 @@ fn get_replacements_for_visibilty_change(
811779
let mut record_field_parents = Vec::new();
812780
let mut impls = Vec::new();
813781

814-
items.into_iter().for_each(|item| {
782+
for item in items {
815783
if !is_clone_for_updated {
816784
*item = item.clone_for_update();
817785
}
@@ -838,7 +806,7 @@ fn get_replacements_for_visibilty_change(
838806
}
839807
_ => (),
840808
}
841-
});
809+
}
842810

843811
(replacements, record_field_parents, impls)
844812
}

0 commit comments

Comments
 (0)