• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::{
2     collections::{HashMap, HashSet},
3     iter,
4 };
5 
6 use hir::{HasSource, ModuleSource};
7 use ide_db::{
8     assists::{AssistId, AssistKind},
9     base_db::FileId,
10     defs::{Definition, NameClass, NameRefClass},
11     search::{FileReference, SearchScope},
12 };
13 use itertools::Itertools;
14 use smallvec::SmallVec;
15 use stdx::format_to;
16 use syntax::{
17     algo::find_node_at_range,
18     ast::{
19         self,
20         edit::{AstNodeEdit, IndentLevel},
21         make, HasName, HasVisibility,
22     },
23     match_ast, ted, AstNode, SourceFile,
24     SyntaxKind::{self, WHITESPACE},
25     SyntaxNode, TextRange,
26 };
27 
28 use crate::{AssistContext, Assists};
29 
30 use super::remove_unused_param::range_to_remove;
31 
32 // Assist: extract_module
33 //
34 // Extracts a selected region as separate module. All the references, visibility and imports are
35 // resolved.
36 //
37 // ```
38 // $0fn foo(name: i32) -> i32 {
39 //     name + 1
40 // }$0
41 //
42 // fn bar(name: i32) -> i32 {
43 //     name + 2
44 // }
45 // ```
46 // ->
47 // ```
48 // mod modname {
49 //     pub(crate) fn foo(name: i32) -> i32 {
50 //         name + 1
51 //     }
52 // }
53 //
54 // fn bar(name: i32) -> i32 {
55 //     name + 2
56 // }
57 // ```
extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>58 pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
59     if ctx.has_empty_selection() {
60         return None;
61     }
62 
63     let node = ctx.covering_element();
64     let node = match node {
65         syntax::NodeOrToken::Node(n) => n,
66         syntax::NodeOrToken::Token(t) => t.parent()?,
67     };
68 
69     //If the selection is inside impl block, we need to place new module outside impl block,
70     //as impl blocks cannot contain modules
71 
72     let mut impl_parent: Option<ast::Impl> = None;
73     let mut impl_child_count: usize = 0;
74     if let Some(parent_assoc_list) = node.parent() {
75         if let Some(parent_impl) = parent_assoc_list.parent() {
76             if let Some(impl_) = ast::Impl::cast(parent_impl) {
77                 impl_child_count = parent_assoc_list.children().count();
78                 impl_parent = Some(impl_);
79             }
80         }
81     }
82 
83     let mut curr_parent_module: Option<ast::Module> = None;
84     if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
85         curr_parent_module = ast::Module::cast(mod_syn_opt);
86     }
87 
88     let mut module = extract_target(&node, ctx.selection_trimmed())?;
89     if module.body_items.is_empty() {
90         return None;
91     }
92 
93     let old_item_indent = module.body_items[0].indent_level();
94 
95     acc.add(
96         AssistId("extract_module", AssistKind::RefactorExtract),
97         "Extract Module",
98         module.text_range,
99         |builder| {
100             //This takes place in three steps:
101             //
102             //- Firstly, we will update the references(usages) e.g. converting a
103             //  function call bar() to modname::bar(), and similarly for other items
104             //
105             //- Secondly, changing the visibility of each item inside the newly selected module
106             //  i.e. making a fn a() {} to pub(crate) fn a() {}
107             //
108             //- Thirdly, resolving all the imports this includes removing paths from imports
109             //  outside the module, shifting/cloning them inside new module, or shifting the imports, or making
110             //  new import statements
111 
112             //We are getting item usages and record_fields together, record_fields
113             //for change_visibility and usages for first point mentioned above in the process
114             let (usages_to_be_processed, record_fields) = module.get_usages_and_record_fields(ctx);
115 
116             let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx);
117             module.change_visibility(record_fields);
118 
119             let mut body_items: Vec<String> = Vec::new();
120             let mut items_to_be_processed: Vec<ast::Item> = module.body_items.clone();
121 
122             let new_item_indent = if impl_parent.is_some() {
123                 old_item_indent + 2
124             } else {
125                 items_to_be_processed = [module.use_items.clone(), items_to_be_processed].concat();
126                 old_item_indent + 1
127             };
128 
129             for item in items_to_be_processed {
130                 let item = item.indent(IndentLevel(1));
131                 let mut indented_item = String::new();
132                 format_to!(indented_item, "{new_item_indent}{item}");
133                 body_items.push(indented_item);
134             }
135 
136             let mut body = body_items.join("\n\n");
137 
138             if let Some(impl_) = &impl_parent {
139                 let mut impl_body_def = String::new();
140 
141                 if let Some(self_ty) = impl_.self_ty() {
142                     {
143                         let impl_indent = old_item_indent + 1;
144                         format_to!(
145                             impl_body_def,
146                             "{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}",
147                         );
148                     }
149                     body = impl_body_def;
150 
151                     // Add the import for enum/struct corresponding to given impl block
152                     module.make_use_stmt_of_node_with_super(self_ty.syntax());
153                     for item in module.use_items {
154                         let item_indent = old_item_indent + 1;
155                         body = format!("{item_indent}{item}\n\n{body}");
156                     }
157                 }
158             }
159 
160             let mut module_def = String::new();
161 
162             let module_name = module.name;
163             format_to!(module_def, "mod {module_name} {{\n{body}\n{old_item_indent}}}");
164 
165             let mut usages_to_be_updated_for_curr_file = vec![];
166             for usages_to_be_updated_for_file in usages_to_be_processed {
167                 if usages_to_be_updated_for_file.0 == ctx.file_id() {
168                     usages_to_be_updated_for_curr_file = usages_to_be_updated_for_file.1;
169                     continue;
170                 }
171                 builder.edit_file(usages_to_be_updated_for_file.0);
172                 for usage_to_be_processed in usages_to_be_updated_for_file.1 {
173                     builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
174                 }
175             }
176 
177             builder.edit_file(ctx.file_id());
178             for usage_to_be_processed in usages_to_be_updated_for_curr_file {
179                 builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
180             }
181 
182             for import_path_text_range in import_paths_to_be_removed {
183                 builder.delete(import_path_text_range);
184             }
185 
186             if let Some(impl_) = impl_parent {
187                 // Remove complete impl block if it has only one child (as such it will be empty
188                 // after deleting that child)
189                 let node_to_be_removed = if impl_child_count == 1 {
190                     impl_.syntax()
191                 } else {
192                     //Remove selected node
193                     &node
194                 };
195 
196                 builder.delete(node_to_be_removed.text_range());
197                 // Remove preceding indentation from node
198                 if let Some(range) = indent_range_before_given_node(node_to_be_removed) {
199                     builder.delete(range);
200                 }
201 
202                 builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
203             } else {
204                 builder.replace(module.text_range, module_def)
205             }
206         },
207     )
208 }
209 
210 #[derive(Debug)]
211 struct Module {
212     text_range: TextRange,
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>,
220 }
221 
extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module>222 fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
223     let selected_nodes = node
224         .children()
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(..)));
230 
231     Some(Module { text_range: selection_range, name: "modname", body_items, use_items })
232 }
233 
234 impl Module {
get_usages_and_record_fields( &self, ctx: &AssistContext<'_>, ) -> (HashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>)235     fn get_usages_and_record_fields(
236         &self,
237         ctx: &AssistContext<'_>,
238     ) -> (HashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
239         let mut adt_fields = Vec::new();
240         let mut refs: HashMap<FileId, Vec<(TextRange, String)>> = HashMap::new();
241 
242         //Here impl is not included as each item inside impl will be tied to the parent of
243         //implementing block(a struct, enum, etc), if the parent is in selected module, it will
244         //get updated by ADT section given below or if it is not, then we dont need to do any operation
245         for item in &self.body_items {
246             match_ast! {
247                 match (item.syntax()) {
248                     ast::Adt(it) => {
249                         if let Some( nod ) = ctx.sema.to_def(&it) {
250                             let node_def = Definition::Adt(nod);
251                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
252 
253                             //Enum Fields are not allowed to explicitly specify pub, it is implied
254                             match it {
255                                 ast::Adt::Struct(x) => {
256                                     if let Some(field_list) = x.field_list() {
257                                         match field_list {
258                                             ast::FieldList::RecordFieldList(record_field_list) => {
259                                                 record_field_list.fields().for_each(|record_field| {
260                                                     adt_fields.push(record_field.syntax().clone());
261                                                 });
262                                             },
263                                             ast::FieldList::TupleFieldList(tuple_field_list) => {
264                                                 tuple_field_list.fields().for_each(|tuple_field| {
265                                                     adt_fields.push(tuple_field.syntax().clone());
266                                                 });
267                                             },
268                                         }
269                                     }
270                                 },
271                                 ast::Adt::Union(x) => {
272                                         if let Some(record_field_list) = x.record_field_list() {
273                                             record_field_list.fields().for_each(|record_field| {
274                                                     adt_fields.push(record_field.syntax().clone());
275                                             });
276                                         }
277                                 },
278                                 ast::Adt::Enum(_) => {},
279                             }
280                         }
281                     },
282                     ast::TypeAlias(it) => {
283                         if let Some( nod ) = ctx.sema.to_def(&it) {
284                             let node_def = Definition::TypeAlias(nod);
285                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
286                         }
287                     },
288                     ast::Const(it) => {
289                         if let Some( nod ) = ctx.sema.to_def(&it) {
290                             let node_def = Definition::Const(nod);
291                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
292                         }
293                     },
294                     ast::Static(it) => {
295                         if let Some( nod ) = ctx.sema.to_def(&it) {
296                             let node_def = Definition::Static(nod);
297                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
298                         }
299                     },
300                     ast::Fn(it) => {
301                         if let Some( nod ) = ctx.sema.to_def(&it) {
302                             let node_def = Definition::Function(nod);
303                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
304                         }
305                     },
306                     ast::Macro(it) => {
307                         if let Some(nod) = ctx.sema.to_def(&it) {
308                             self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs);
309                         }
310                     },
311                     _ => (),
312                 }
313             }
314         }
315 
316         (refs, adt_fields)
317     }
318 
expand_and_group_usages_file_wise( &self, ctx: &AssistContext<'_>, node_def: Definition, refs_in_files: &mut HashMap<FileId, Vec<(TextRange, String)>>, )319     fn expand_and_group_usages_file_wise(
320         &self,
321         ctx: &AssistContext<'_>,
322         node_def: Definition,
323         refs_in_files: &mut HashMap<FileId, Vec<(TextRange, String)>>,
324     ) {
325         for (file_id, references) in node_def.usages(&ctx.sema).all() {
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);
331         }
332     }
333 
334     fn get_usage_to_be_processed(
335         &self,
336         source_file: &SourceFile,
337         FileReference { range, name, .. }: FileReference,
338     ) -> Option<(TextRange, String)> {
339         let path: ast::Path = find_node_at_range(source_file.syntax(), range)?;
340 
341         for desc in path.syntax().descendants() {
342             if desc.to_string() == name.syntax().to_string()
343                 && !self.text_range.contains_range(desc.text_range())
344             {
345                 if let Some(name_ref) = ast::NameRef::cast(desc) {
346                     let mod_name = self.name;
347                     return Some((
348                         name_ref.syntax().text_range(),
349                         format!("{mod_name}::{name_ref}"),
350                     ));
351                 }
352             }
353         }
354 
355         None
356     }
357 
change_visibility(&mut self, record_fields: Vec<SyntaxNode>)358     fn change_visibility(&mut self, record_fields: Vec<SyntaxNode>) {
359         let (mut replacements, record_field_parents, impls) =
360             get_replacements_for_visibility_change(&mut self.body_items, false);
361 
362         let mut impl_items: Vec<ast::Item> = impls
363             .into_iter()
364             .flat_map(|impl_| impl_.syntax().descendants())
365             .filter_map(ast::Item::cast)
366             .collect();
367 
368         let (mut impl_item_replacements, _, _) =
369             get_replacements_for_visibility_change(&mut impl_items, true);
370 
371         replacements.append(&mut impl_item_replacements);
372 
373         for (_, field_owner) in record_field_parents {
374             for desc in field_owner.descendants().filter_map(ast::RecordField::cast) {
375                 let is_record_field_present =
376                     record_fields.clone().into_iter().any(|x| x.to_string() == desc.to_string());
377                 if is_record_field_present {
378                     replacements.push((desc.visibility(), desc.syntax().clone()));
379                 }
380             }
381         }
382 
383         for (vis, syntax) in replacements {
384             let item = syntax.children_with_tokens().find(|node_or_token| {
385                 match node_or_token.kind() {
386                     // We're skipping comments, doc comments, and attribute macros that may precede the keyword
387                     // that the visibility should be placed before.
388                     SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE => false,
389                     _ => true,
390                 }
391             });
392 
393             add_change_vis(vis, item);
394         }
395     }
396 
resolve_imports( &mut self, curr_parent_module: Option<ast::Module>, ctx: &AssistContext<'_>, ) -> Vec<TextRange>397     fn resolve_imports(
398         &mut self,
399         curr_parent_module: Option<ast::Module>,
400         ctx: &AssistContext<'_>,
401     ) -> Vec<TextRange> {
402         let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
403         let mut node_set: HashSet<String> = HashSet::new();
404 
405         for item in self.body_items.clone() {
406             for x in item.syntax().descendants() {
407                 if let Some(name) = ast::Name::cast(x.clone()) {
408                     if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
409                         //Necessary to avoid two same names going through
410                         if !node_set.contains(&name.syntax().to_string()) {
411                             node_set.insert(name.syntax().to_string());
412                             let def_opt: Option<Definition> = match name_classify {
413                                 NameClass::Definition(def) => Some(def),
414                                 _ => None,
415                             };
416 
417                             if let Some(def) = def_opt {
418                                 if let Some(import_path) = self
419                                     .process_names_and_namerefs_for_import_resolve(
420                                         def,
421                                         name.syntax(),
422                                         &curr_parent_module,
423                                         ctx,
424                                     )
425                                 {
426                                     check_intersection_and_push(
427                                         &mut import_paths_to_be_removed,
428                                         import_path,
429                                     );
430                                 }
431                             }
432                         }
433                     }
434                 }
435 
436                 if let Some(name_ref) = ast::NameRef::cast(x) {
437                     if let Some(name_classify) = NameRefClass::classify(&ctx.sema, &name_ref) {
438                         //Necessary to avoid two same names going through
439                         if !node_set.contains(&name_ref.syntax().to_string()) {
440                             node_set.insert(name_ref.syntax().to_string());
441                             let def_opt: Option<Definition> = match name_classify {
442                                 NameRefClass::Definition(def) => Some(def),
443                                 _ => None,
444                             };
445 
446                             if let Some(def) = def_opt {
447                                 if let Some(import_path) = self
448                                     .process_names_and_namerefs_for_import_resolve(
449                                         def,
450                                         name_ref.syntax(),
451                                         &curr_parent_module,
452                                         ctx,
453                                     )
454                                 {
455                                     check_intersection_and_push(
456                                         &mut import_paths_to_be_removed,
457                                         import_path,
458                                     );
459                                 }
460                             }
461                         }
462                     }
463                 }
464             }
465         }
466 
467         import_paths_to_be_removed
468     }
469 
process_names_and_namerefs_for_import_resolve( &mut self, def: Definition, node_syntax: &SyntaxNode, curr_parent_module: &Option<ast::Module>, ctx: &AssistContext<'_>, ) -> Option<TextRange>470     fn process_names_and_namerefs_for_import_resolve(
471         &mut self,
472         def: Definition,
473         node_syntax: &SyntaxNode,
474         curr_parent_module: &Option<ast::Module>,
475         ctx: &AssistContext<'_>,
476     ) -> Option<TextRange> {
477         //We only need to find in the current file
478         let selection_range = ctx.selection_trimmed();
479         let curr_file_id = ctx.file_id();
480         let search_scope = SearchScope::single_file(curr_file_id);
481         let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all();
482         let file = ctx.sema.parse(curr_file_id);
483 
484         let mut exists_inside_sel = false;
485         let mut exists_outside_sel = false;
486         for (_, refs) in usage_res.iter() {
487             let mut non_use_nodes_itr = refs.iter().filter_map(|x| {
488                 if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
489                     let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
490                     return path_opt;
491                 }
492 
493                 None
494             });
495 
496             if non_use_nodes_itr
497                 .clone()
498                 .any(|x| !selection_range.contains_range(x.syntax().text_range()))
499             {
500                 exists_outside_sel = true;
501             }
502             if non_use_nodes_itr.any(|x| selection_range.contains_range(x.syntax().text_range())) {
503                 exists_inside_sel = true;
504             }
505         }
506 
507         let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
508             def,
509             ctx,
510             curr_parent_module,
511             selection_range,
512             curr_file_id,
513         );
514 
515         let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|(file_id, refs)| {
516             if file_id == curr_file_id {
517                 refs.into_iter()
518                     .rev()
519                     .find_map(|fref| find_node_at_range(file.syntax(), fref.range))
520             } else {
521                 None
522             }
523         });
524 
525         let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
526         //Exists inside and outside selection
527         // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new
528         // module
529         // - Use stmt for item is not present ->
530         //If it is not found, the definition is either ported inside new module or it stays
531         //outside:
532         //- Def is inside: Nothing to import
533         //- Def is outside: Import it inside with super
534 
535         //Exists inside selection but not outside -> Check for the import of it in original module,
536         //get the use_tree_str, reconstruct the use stmt in new module
537 
538         let mut import_path_to_be_removed: Option<TextRange> = None;
539         if exists_inside_sel && exists_outside_sel {
540             //Changes to be made only inside new module
541 
542             //If use_stmt exists, find the use_tree_str, reconstruct it inside new module
543             //If not, insert a use stmt with super and the given nameref
544             if let Some((use_tree_str, _)) =
545                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
546             {
547                 use_tree_str_opt = Some(use_tree_str);
548             } else if source_exists_outside_sel_in_same_mod {
549                 //Considered only after use_stmt is not present
550                 //source_exists_outside_sel_in_same_mod | exists_outside_sel(exists_inside_sel =
551                 //true for all cases)
552                 // false | false -> Do nothing
553                 // false | true -> If source is in selection -> nothing to do, If source is outside
554                 // mod -> ust_stmt transversal
555                 // true  | false -> super import insertion
556                 // true  | true -> super import insertion
557                 self.make_use_stmt_of_node_with_super(node_syntax);
558             }
559         } else if exists_inside_sel && !exists_outside_sel {
560             //Changes to be made inside new module, and remove import from outside
561 
562             if let Some((mut use_tree_str, text_range_opt)) =
563                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
564             {
565                 if let Some(text_range) = text_range_opt {
566                     import_path_to_be_removed = Some(text_range);
567                 }
568 
569                 if source_exists_outside_sel_in_same_mod {
570                     if let Some(first_path_in_use_tree) = use_tree_str.last() {
571                         let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
572                         if !first_path_in_use_tree_str.contains("super")
573                             && !first_path_in_use_tree_str.contains("crate")
574                         {
575                             let super_path = make::ext::ident_path("super");
576                             use_tree_str.push(super_path);
577                         }
578                     }
579                 }
580 
581                 use_tree_str_opt = Some(use_tree_str);
582             } else if source_exists_outside_sel_in_same_mod {
583                 self.make_use_stmt_of_node_with_super(node_syntax);
584             }
585         }
586 
587         if let Some(use_tree_str) = use_tree_str_opt {
588             let mut use_tree_str = use_tree_str;
589             use_tree_str.reverse();
590 
591             if !(!exists_outside_sel && exists_inside_sel && source_exists_outside_sel_in_same_mod)
592             {
593                 if let Some(first_path_in_use_tree) = use_tree_str.first() {
594                     let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
595                     if first_path_in_use_tree_str.contains("super") {
596                         let super_path = make::ext::ident_path("super");
597                         use_tree_str.insert(0, super_path)
598                     }
599                 }
600             }
601 
602             let use_ =
603                 make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
604             let item = ast::Item::from(use_);
605             self.use_items.insert(0, item);
606         }
607 
608         import_path_to_be_removed
609     }
610 
make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item611     fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item {
612         let super_path = make::ext::ident_path("super");
613         let node_path = make::ext::ident_path(&node_syntax.to_string());
614         let use_ = make::use_(
615             None,
616             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
617         );
618 
619         let item = ast::Item::from(use_);
620         self.use_items.insert(0, item.clone());
621         item
622     }
623 
process_use_stmt_for_import_resolve( &self, use_stmt_opt: Option<ast::Use>, node_syntax: &SyntaxNode, ) -> Option<(Vec<ast::Path>, Option<TextRange>)>624     fn process_use_stmt_for_import_resolve(
625         &self,
626         use_stmt_opt: Option<ast::Use>,
627         node_syntax: &SyntaxNode,
628     ) -> Option<(Vec<ast::Path>, Option<TextRange>)> {
629         if let Some(use_stmt) = use_stmt_opt {
630             for desc in use_stmt.syntax().descendants() {
631                 if let Some(path_seg) = ast::PathSegment::cast(desc) {
632                     if path_seg.syntax().to_string() == node_syntax.to_string() {
633                         let mut use_tree_str = vec![path_seg.parent_path()];
634                         get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
635                         for ancs in path_seg.syntax().ancestors() {
636                             //Here we are looking for use_tree with same string value as node
637                             //passed above as the range_to_remove function looks for a comma and
638                             //then includes it in the text range to remove it. But the comma only
639                             //appears at the use_tree level
640                             if let Some(use_tree) = ast::UseTree::cast(ancs) {
641                                 if use_tree.syntax().to_string() == node_syntax.to_string() {
642                                     return Some((
643                                         use_tree_str,
644                                         Some(range_to_remove(use_tree.syntax())),
645                                     ));
646                                 }
647                             }
648                         }
649 
650                         return Some((use_tree_str, None));
651                     }
652                 }
653             }
654         }
655 
656         None
657     }
658 }
659 
check_intersection_and_push( import_paths_to_be_removed: &mut Vec<TextRange>, mut import_path: TextRange, )660 fn check_intersection_and_push(
661     import_paths_to_be_removed: &mut Vec<TextRange>,
662     mut import_path: TextRange,
663 ) {
664     // Text ranges received here for imports are extended to the
665     // next/previous comma which can cause intersections among them
666     // and later deletion of these can cause panics similar
667     // to reported in #11766. So to mitigate it, we
668     // check for intersection between all current members
669     // and combine all such ranges into one.
670     let s: SmallVec<[_; 2]> = import_paths_to_be_removed
671         .into_iter()
672         .positions(|it| it.intersect(import_path).is_some())
673         .collect();
674     for pos in s.into_iter().rev() {
675         let intersecting_path = import_paths_to_be_removed.swap_remove(pos);
676         import_path = import_path.cover(intersecting_path);
677     }
678     import_paths_to_be_removed.push(import_path);
679 }
680 
does_source_exists_outside_sel_in_same_mod( def: Definition, ctx: &AssistContext<'_>, curr_parent_module: &Option<ast::Module>, selection_range: TextRange, curr_file_id: FileId, ) -> bool681 fn does_source_exists_outside_sel_in_same_mod(
682     def: Definition,
683     ctx: &AssistContext<'_>,
684     curr_parent_module: &Option<ast::Module>,
685     selection_range: TextRange,
686     curr_file_id: FileId,
687 ) -> bool {
688     let mut source_exists_outside_sel_in_same_mod = false;
689     match def {
690         Definition::Module(x) => {
691             let source = x.definition_source(ctx.db());
692             let have_same_parent;
693             if let Some(ast_module) = &curr_parent_module {
694                 if let Some(hir_module) = x.parent(ctx.db()) {
695                     have_same_parent =
696                         compare_hir_and_ast_module(ast_module, hir_module, ctx).is_some();
697                 } else {
698                     let source_file_id = source.file_id.original_file(ctx.db());
699                     have_same_parent = source_file_id == curr_file_id;
700                 }
701             } else {
702                 let source_file_id = source.file_id.original_file(ctx.db());
703                 have_same_parent = source_file_id == curr_file_id;
704             }
705 
706             if have_same_parent {
707                 match source.value {
708                     ModuleSource::Module(module_) => {
709                         source_exists_outside_sel_in_same_mod =
710                             !selection_range.contains_range(module_.syntax().text_range());
711                     }
712                     _ => {}
713                 }
714             }
715         }
716         Definition::Function(x) => {
717             if let Some(source) = x.source(ctx.db()) {
718                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
719                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
720                 } else {
721                     let source_file_id = source.file_id.original_file(ctx.db());
722                     source_file_id == curr_file_id
723                 };
724 
725                 if have_same_parent {
726                     source_exists_outside_sel_in_same_mod =
727                         !selection_range.contains_range(source.value.syntax().text_range());
728                 }
729             }
730         }
731         Definition::Adt(x) => {
732             if let Some(source) = x.source(ctx.db()) {
733                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
734                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
735                 } else {
736                     let source_file_id = source.file_id.original_file(ctx.db());
737                     source_file_id == curr_file_id
738                 };
739 
740                 if have_same_parent {
741                     source_exists_outside_sel_in_same_mod =
742                         !selection_range.contains_range(source.value.syntax().text_range());
743                 }
744             }
745         }
746         Definition::Variant(x) => {
747             if let Some(source) = x.source(ctx.db()) {
748                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
749                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
750                 } else {
751                     let source_file_id = source.file_id.original_file(ctx.db());
752                     source_file_id == curr_file_id
753                 };
754 
755                 if have_same_parent {
756                     source_exists_outside_sel_in_same_mod =
757                         !selection_range.contains_range(source.value.syntax().text_range());
758                 }
759             }
760         }
761         Definition::Const(x) => {
762             if let Some(source) = x.source(ctx.db()) {
763                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
764                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
765                 } else {
766                     let source_file_id = source.file_id.original_file(ctx.db());
767                     source_file_id == curr_file_id
768                 };
769 
770                 if have_same_parent {
771                     source_exists_outside_sel_in_same_mod =
772                         !selection_range.contains_range(source.value.syntax().text_range());
773                 }
774             }
775         }
776         Definition::Static(x) => {
777             if let Some(source) = x.source(ctx.db()) {
778                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
779                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
780                 } else {
781                     let source_file_id = source.file_id.original_file(ctx.db());
782                     source_file_id == curr_file_id
783                 };
784 
785                 if have_same_parent {
786                     source_exists_outside_sel_in_same_mod =
787                         !selection_range.contains_range(source.value.syntax().text_range());
788                 }
789             }
790         }
791         Definition::Trait(x) => {
792             if let Some(source) = x.source(ctx.db()) {
793                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
794                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
795                 } else {
796                     let source_file_id = source.file_id.original_file(ctx.db());
797                     source_file_id == curr_file_id
798                 };
799 
800                 if have_same_parent {
801                     source_exists_outside_sel_in_same_mod =
802                         !selection_range.contains_range(source.value.syntax().text_range());
803                 }
804             }
805         }
806         Definition::TypeAlias(x) => {
807             if let Some(source) = x.source(ctx.db()) {
808                 let have_same_parent = if let Some(ast_module) = &curr_parent_module {
809                     compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
810                 } else {
811                     let source_file_id = source.file_id.original_file(ctx.db());
812                     source_file_id == curr_file_id
813                 };
814 
815                 if have_same_parent {
816                     source_exists_outside_sel_in_same_mod =
817                         !selection_range.contains_range(source.value.syntax().text_range());
818                 }
819             }
820         }
821         _ => {}
822     }
823 
824     source_exists_outside_sel_in_same_mod
825 }
826 
get_replacements_for_visibility_change( items: &mut [ast::Item], is_clone_for_updated: bool, ) -> ( Vec<(Option<ast::Visibility>, SyntaxNode)>, Vec<(Option<ast::Visibility>, SyntaxNode)>, Vec<ast::Impl>, )827 fn get_replacements_for_visibility_change(
828     items: &mut [ast::Item],
829     is_clone_for_updated: bool,
830 ) -> (
831     Vec<(Option<ast::Visibility>, SyntaxNode)>,
832     Vec<(Option<ast::Visibility>, SyntaxNode)>,
833     Vec<ast::Impl>,
834 ) {
835     let mut replacements = Vec::new();
836     let mut record_field_parents = Vec::new();
837     let mut impls = Vec::new();
838 
839     for item in items {
840         if !is_clone_for_updated {
841             *item = item.clone_for_update();
842         }
843         //Use stmts are ignored
844         match item {
845             ast::Item::Const(it) => replacements.push((it.visibility(), it.syntax().clone())),
846             ast::Item::Enum(it) => replacements.push((it.visibility(), it.syntax().clone())),
847             ast::Item::ExternCrate(it) => replacements.push((it.visibility(), it.syntax().clone())),
848             ast::Item::Fn(it) => replacements.push((it.visibility(), it.syntax().clone())),
849             //Associated item's visibility should not be changed
850             ast::Item::Impl(it) if it.for_token().is_none() => impls.push(it.clone()),
851             ast::Item::MacroDef(it) => replacements.push((it.visibility(), it.syntax().clone())),
852             ast::Item::Module(it) => replacements.push((it.visibility(), it.syntax().clone())),
853             ast::Item::Static(it) => replacements.push((it.visibility(), it.syntax().clone())),
854             ast::Item::Struct(it) => {
855                 replacements.push((it.visibility(), it.syntax().clone()));
856                 record_field_parents.push((it.visibility(), it.syntax().clone()));
857             }
858             ast::Item::Trait(it) => replacements.push((it.visibility(), it.syntax().clone())),
859             ast::Item::TypeAlias(it) => replacements.push((it.visibility(), it.syntax().clone())),
860             ast::Item::Union(it) => {
861                 replacements.push((it.visibility(), it.syntax().clone()));
862                 record_field_parents.push((it.visibility(), it.syntax().clone()));
863             }
864             _ => (),
865         }
866     }
867 
868     (replacements, record_field_parents, impls)
869 }
870 
get_use_tree_paths_from_path( path: ast::Path, use_tree_str: &mut Vec<ast::Path>, ) -> Option<&mut Vec<ast::Path>>871 fn get_use_tree_paths_from_path(
872     path: ast::Path,
873     use_tree_str: &mut Vec<ast::Path>,
874 ) -> Option<&mut Vec<ast::Path>> {
875     path.syntax().ancestors().filter(|x| x.to_string() != path.to_string()).find_map(|x| {
876         if let Some(use_tree) = ast::UseTree::cast(x) {
877             if let Some(upper_tree_path) = use_tree.path() {
878                 if upper_tree_path.to_string() != path.to_string() {
879                     use_tree_str.push(upper_tree_path.clone());
880                     get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
881                     return Some(use_tree);
882                 }
883             }
884         }
885         None
886     })?;
887 
888     Some(use_tree_str)
889 }
890 
add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax::SyntaxElement>)891 fn add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax::SyntaxElement>) {
892     if vis.is_none() {
893         if let Some(node_or_token) = node_or_token_opt {
894             let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
895             ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax());
896         }
897     }
898 }
899 
compare_hir_and_ast_module( ast_module: &ast::Module, hir_module: hir::Module, ctx: &AssistContext<'_>, ) -> Option<()>900 fn compare_hir_and_ast_module(
901     ast_module: &ast::Module,
902     hir_module: hir::Module,
903     ctx: &AssistContext<'_>,
904 ) -> Option<()> {
905     let hir_mod_name = hir_module.name(ctx.db())?;
906     let ast_mod_name = ast_module.name()?;
907     if hir_mod_name.display(ctx.db()).to_string() != ast_mod_name.to_string() {
908         return None;
909     }
910 
911     Some(())
912 }
913 
indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange>914 fn indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange> {
915     node.siblings_with_tokens(syntax::Direction::Prev)
916         .find(|x| x.kind() == WHITESPACE)
917         .map(|x| x.text_range())
918 }
919 
920 #[cfg(test)]
921 mod tests {
922     use crate::tests::{check_assist, check_assist_not_applicable};
923 
924     use super::*;
925 
926     #[test]
test_not_applicable_without_selection()927     fn test_not_applicable_without_selection() {
928         check_assist_not_applicable(
929             extract_module,
930             r"
931 $0pub struct PublicStruct {
932     field: i32,
933 }
934             ",
935         )
936     }
937 
938     #[test]
test_extract_module()939     fn test_extract_module() {
940         check_assist(
941             extract_module,
942             r"
943             mod thirdpartycrate {
944                 pub mod nest {
945                     pub struct SomeType;
946                     pub struct SomeType2;
947                 }
948                 pub struct SomeType1;
949             }
950 
951             mod bar {
952                 use crate::thirdpartycrate::{nest::{SomeType, SomeType2}, SomeType1};
953 
954                 pub struct PublicStruct {
955                     field: PrivateStruct,
956                     field1: SomeType1,
957                 }
958 
959                 impl PublicStruct {
960                     pub fn new() -> Self {
961                         Self { field: PrivateStruct::new(), field1: SomeType1 }
962                     }
963                 }
964 
965                 fn foo() {
966                     let _s = PrivateStruct::new();
967                     let _a = bar();
968                 }
969 
970 $0struct PrivateStruct {
971     inner: SomeType,
972 }
973 
974 pub struct PrivateStruct1 {
975     pub inner: i32,
976 }
977 
978 impl PrivateStruct {
979     fn new() -> Self {
980          PrivateStruct { inner: SomeType }
981     }
982 }
983 
984 fn bar() -> i32 {
985     2
986 }$0
987             }
988             ",
989             r"
990             mod thirdpartycrate {
991                 pub mod nest {
992                     pub struct SomeType;
993                     pub struct SomeType2;
994                 }
995                 pub struct SomeType1;
996             }
997 
998             mod bar {
999                 use crate::thirdpartycrate::{nest::{SomeType2}, SomeType1};
1000 
1001                 pub struct PublicStruct {
1002                     field: modname::PrivateStruct,
1003                     field1: SomeType1,
1004                 }
1005 
1006                 impl PublicStruct {
1007                     pub fn new() -> Self {
1008                         Self { field: modname::PrivateStruct::new(), field1: SomeType1 }
1009                     }
1010                 }
1011 
1012                 fn foo() {
1013                     let _s = modname::PrivateStruct::new();
1014                     let _a = modname::bar();
1015                 }
1016 
1017 mod modname {
1018     use crate::thirdpartycrate::nest::SomeType;
1019 
1020     pub(crate) struct PrivateStruct {
1021         pub(crate) inner: SomeType,
1022     }
1023 
1024     pub struct PrivateStruct1 {
1025         pub inner: i32,
1026     }
1027 
1028     impl PrivateStruct {
1029         pub(crate) fn new() -> Self {
1030              PrivateStruct { inner: SomeType }
1031         }
1032     }
1033 
1034     pub(crate) fn bar() -> i32 {
1035         2
1036     }
1037 }
1038             }
1039             ",
1040         );
1041     }
1042 
1043     #[test]
test_extract_module_for_function_only()1044     fn test_extract_module_for_function_only() {
1045         check_assist(
1046             extract_module,
1047             r"
1048 $0fn foo(name: i32) -> i32 {
1049     name + 1
1050 }$0
1051 
1052                 fn bar(name: i32) -> i32 {
1053                     name + 2
1054                 }
1055             ",
1056             r"
1057 mod modname {
1058     pub(crate) fn foo(name: i32) -> i32 {
1059         name + 1
1060     }
1061 }
1062 
1063                 fn bar(name: i32) -> i32 {
1064                     name + 2
1065                 }
1066             ",
1067         )
1068     }
1069 
1070     #[test]
test_extract_module_for_impl_having_corresponding_adt_in_selection()1071     fn test_extract_module_for_impl_having_corresponding_adt_in_selection() {
1072         check_assist(
1073             extract_module,
1074             r"
1075             mod impl_play {
1076 $0struct A {}
1077 
1078 impl A {
1079     pub fn new_a() -> i32 {
1080         2
1081     }
1082 }$0
1083 
1084                 fn a() {
1085                     let _a = A::new_a();
1086                 }
1087             }
1088             ",
1089             r"
1090             mod impl_play {
1091 mod modname {
1092     pub(crate) struct A {}
1093 
1094     impl A {
1095         pub fn new_a() -> i32 {
1096             2
1097         }
1098     }
1099 }
1100 
1101                 fn a() {
1102                     let _a = modname::A::new_a();
1103                 }
1104             }
1105             ",
1106         )
1107     }
1108 
1109     #[test]
test_import_resolve_when_its_only_inside_selection()1110     fn test_import_resolve_when_its_only_inside_selection() {
1111         check_assist(
1112             extract_module,
1113             r"
1114             mod foo {
1115                 pub struct PrivateStruct;
1116                 pub struct PrivateStruct1;
1117             }
1118 
1119             mod bar {
1120                 use super::foo::{PrivateStruct, PrivateStruct1};
1121 
1122 $0struct Strukt {
1123     field: PrivateStruct,
1124 }$0
1125 
1126                 struct Strukt1 {
1127                     field: PrivateStruct1,
1128                 }
1129             }
1130             ",
1131             r"
1132             mod foo {
1133                 pub struct PrivateStruct;
1134                 pub struct PrivateStruct1;
1135             }
1136 
1137             mod bar {
1138                 use super::foo::{PrivateStruct1};
1139 
1140 mod modname {
1141     use super::super::foo::PrivateStruct;
1142 
1143     pub(crate) struct Strukt {
1144         pub(crate) field: PrivateStruct,
1145     }
1146 }
1147 
1148                 struct Strukt1 {
1149                     field: PrivateStruct1,
1150                 }
1151             }
1152             ",
1153         )
1154     }
1155 
1156     #[test]
test_import_resolve_when_its_inside_and_outside_selection_and_source_not_in_same_mod()1157     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_not_in_same_mod() {
1158         check_assist(
1159             extract_module,
1160             r"
1161             mod foo {
1162                 pub struct PrivateStruct;
1163             }
1164 
1165             mod bar {
1166                 use super::foo::PrivateStruct;
1167 
1168 $0struct Strukt {
1169     field: PrivateStruct,
1170 }$0
1171 
1172                 struct Strukt1 {
1173                     field: PrivateStruct,
1174                 }
1175             }
1176             ",
1177             r"
1178             mod foo {
1179                 pub struct PrivateStruct;
1180             }
1181 
1182             mod bar {
1183                 use super::foo::PrivateStruct;
1184 
1185 mod modname {
1186     use super::super::foo::PrivateStruct;
1187 
1188     pub(crate) struct Strukt {
1189         pub(crate) field: PrivateStruct,
1190     }
1191 }
1192 
1193                 struct Strukt1 {
1194                     field: PrivateStruct,
1195                 }
1196             }
1197             ",
1198         )
1199     }
1200 
1201     #[test]
test_import_resolve_when_its_inside_and_outside_selection_and_source_is_in_same_mod()1202     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_is_in_same_mod() {
1203         check_assist(
1204             extract_module,
1205             r"
1206             mod bar {
1207                 pub struct PrivateStruct;
1208 
1209 $0struct Strukt {
1210    field: PrivateStruct,
1211 }$0
1212 
1213                 struct Strukt1 {
1214                     field: PrivateStruct,
1215                 }
1216             }
1217             ",
1218             r"
1219             mod bar {
1220                 pub struct PrivateStruct;
1221 
1222 mod modname {
1223     use super::PrivateStruct;
1224 
1225     pub(crate) struct Strukt {
1226        pub(crate) field: PrivateStruct,
1227     }
1228 }
1229 
1230                 struct Strukt1 {
1231                     field: PrivateStruct,
1232                 }
1233             }
1234             ",
1235         )
1236     }
1237 
1238     #[test]
test_extract_module_for_corresponding_adt_of_impl_present_in_same_mod_but_not_in_selection()1239     fn test_extract_module_for_corresponding_adt_of_impl_present_in_same_mod_but_not_in_selection()
1240     {
1241         check_assist(
1242             extract_module,
1243             r"
1244             mod impl_play {
1245                 struct A {}
1246 
1247 $0impl A {
1248     pub fn new_a() -> i32 {
1249         2
1250     }
1251 }$0
1252 
1253                 fn a() {
1254                     let _a = A::new_a();
1255                 }
1256             }
1257             ",
1258             r"
1259             mod impl_play {
1260                 struct A {}
1261 
1262 mod modname {
1263     use super::A;
1264 
1265     impl A {
1266         pub fn new_a() -> i32 {
1267             2
1268         }
1269     }
1270 }
1271 
1272                 fn a() {
1273                     let _a = A::new_a();
1274                 }
1275             }
1276             ",
1277         )
1278     }
1279 
1280     #[test]
test_extract_module_for_impl_not_having_corresponding_adt_in_selection_and_not_in_same_mod_but_with_super( )1281     fn test_extract_module_for_impl_not_having_corresponding_adt_in_selection_and_not_in_same_mod_but_with_super(
1282     ) {
1283         check_assist(
1284             extract_module,
1285             r"
1286             mod foo {
1287                 pub struct A {}
1288             }
1289             mod impl_play {
1290                 use super::foo::A;
1291 
1292 $0impl A {
1293     pub fn new_a() -> i32 {
1294         2
1295     }
1296 }$0
1297 
1298                 fn a() {
1299                     let _a = A::new_a();
1300                 }
1301             }
1302             ",
1303             r"
1304             mod foo {
1305                 pub struct A {}
1306             }
1307             mod impl_play {
1308                 use super::foo::A;
1309 
1310 mod modname {
1311     use super::super::foo::A;
1312 
1313     impl A {
1314         pub fn new_a() -> i32 {
1315             2
1316         }
1317     }
1318 }
1319 
1320                 fn a() {
1321                     let _a = A::new_a();
1322                 }
1323             }
1324             ",
1325         )
1326     }
1327 
1328     #[test]
test_import_resolve_for_trait_bounds_on_function()1329     fn test_import_resolve_for_trait_bounds_on_function() {
1330         check_assist(
1331             extract_module,
1332             r"
1333             mod impl_play2 {
1334                 trait JustATrait {}
1335 
1336 $0struct A {}
1337 
1338 fn foo<T: JustATrait>(arg: T) -> T {
1339     arg
1340 }
1341 
1342 impl JustATrait for A {}
1343 
1344 fn bar() {
1345     let a = A {};
1346     foo(a);
1347 }$0
1348             }
1349             ",
1350             r"
1351             mod impl_play2 {
1352                 trait JustATrait {}
1353 
1354 mod modname {
1355     use super::JustATrait;
1356 
1357     pub(crate) struct A {}
1358 
1359     pub(crate) fn foo<T: JustATrait>(arg: T) -> T {
1360         arg
1361     }
1362 
1363     impl JustATrait for A {}
1364 
1365     pub(crate) fn bar() {
1366         let a = A {};
1367         foo(a);
1368     }
1369 }
1370             }
1371             ",
1372         )
1373     }
1374 
1375     #[test]
test_extract_module_for_module()1376     fn test_extract_module_for_module() {
1377         check_assist(
1378             extract_module,
1379             r"
1380             mod impl_play2 {
1381 $0mod impl_play {
1382     pub struct A {}
1383 }$0
1384             }
1385             ",
1386             r"
1387             mod impl_play2 {
1388 mod modname {
1389     pub(crate) mod impl_play {
1390         pub struct A {}
1391     }
1392 }
1393             }
1394             ",
1395         )
1396     }
1397 
1398     #[test]
test_extract_module_with_multiple_files()1399     fn test_extract_module_with_multiple_files() {
1400         check_assist(
1401             extract_module,
1402             r"
1403             //- /main.rs
1404             mod foo;
1405 
1406             use foo::PrivateStruct;
1407 
1408             pub struct Strukt {
1409                 field: PrivateStruct,
1410             }
1411 
1412             fn main() {
1413                 $0struct Strukt1 {
1414                     field: Strukt,
1415                 }$0
1416             }
1417             //- /foo.rs
1418             pub struct PrivateStruct;
1419             ",
1420             r"
1421             mod foo;
1422 
1423             use foo::PrivateStruct;
1424 
1425             pub struct Strukt {
1426                 field: PrivateStruct,
1427             }
1428 
1429             fn main() {
1430                 mod modname {
1431                     use super::Strukt;
1432 
1433                     pub(crate) struct Strukt1 {
1434                         pub(crate) field: Strukt,
1435                     }
1436                 }
1437             }
1438             ",
1439         )
1440     }
1441 
1442     #[test]
test_extract_module_macro_rules()1443     fn test_extract_module_macro_rules() {
1444         check_assist(
1445             extract_module,
1446             r"
1447 $0macro_rules! m {
1448     () => {};
1449 }$0
1450 m! {}
1451             ",
1452             r"
1453 mod modname {
1454     macro_rules! m {
1455         () => {};
1456     }
1457 }
1458 modname::m! {}
1459             ",
1460         );
1461     }
1462 
1463     #[test]
test_do_not_apply_visibility_modifier_to_trait_impl_items()1464     fn test_do_not_apply_visibility_modifier_to_trait_impl_items() {
1465         check_assist(
1466             extract_module,
1467             r"
1468             trait ATrait {
1469                 fn function();
1470             }
1471 
1472             struct A {}
1473 
1474 $0impl ATrait for A {
1475     fn function() {}
1476 }$0
1477             ",
1478             r"
1479             trait ATrait {
1480                 fn function();
1481             }
1482 
1483             struct A {}
1484 
1485 mod modname {
1486     use super::A;
1487 
1488     use super::ATrait;
1489 
1490     impl ATrait for A {
1491         fn function() {}
1492     }
1493 }
1494             ",
1495         )
1496     }
1497 
1498     #[test]
test_if_inside_impl_block_generate_module_outside()1499     fn test_if_inside_impl_block_generate_module_outside() {
1500         check_assist(
1501             extract_module,
1502             r"
1503             struct A {}
1504 
1505             impl A {
1506 $0fn foo() {}$0
1507                 fn bar() {}
1508             }
1509         ",
1510             r"
1511             struct A {}
1512 
1513             impl A {
1514                 fn bar() {}
1515             }
1516 
1517 mod modname {
1518     use super::A;
1519 
1520     impl A {
1521         pub(crate) fn foo() {}
1522     }
1523 }
1524         ",
1525         )
1526     }
1527 
1528     #[test]
test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child()1529     fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() {
1530         check_assist(
1531             extract_module,
1532             r"
1533             struct A {}
1534             struct B {}
1535 
1536             impl A {
1537 $0fn foo(x: B) {}$0
1538             }
1539         ",
1540             r"
1541             struct A {}
1542             struct B {}
1543 
1544 mod modname {
1545     use super::B;
1546 
1547     use super::A;
1548 
1549     impl A {
1550         pub(crate) fn foo(x: B) {}
1551     }
1552 }
1553         ",
1554         )
1555     }
1556 
1557     #[test]
test_issue_11766()1558     fn test_issue_11766() {
1559         //https://github.com/rust-lang/rust-analyzer/issues/11766
1560         check_assist(
1561             extract_module,
1562             r"
1563             mod x {
1564                 pub struct Foo;
1565                 pub struct Bar;
1566             }
1567 
1568             use x::{Bar, Foo};
1569 
1570             $0type A = (Foo, Bar);$0
1571         ",
1572             r"
1573             mod x {
1574                 pub struct Foo;
1575                 pub struct Bar;
1576             }
1577 
1578             use x::{};
1579 
1580             mod modname {
1581                 use super::x::Bar;
1582 
1583                 use super::x::Foo;
1584 
1585                 pub(crate) type A = (Foo, Bar);
1586             }
1587         ",
1588         )
1589     }
1590 
1591     #[test]
test_issue_12790()1592     fn test_issue_12790() {
1593         check_assist(
1594             extract_module,
1595             r"
1596             $0/// A documented function
1597             fn documented_fn() {}
1598 
1599             // A commented function with a #[] attribute macro
1600             #[cfg(test)]
1601             fn attribute_fn() {}
1602 
1603             // A normally commented function
1604             fn normal_fn() {}
1605 
1606             /// A documented Struct
1607             struct DocumentedStruct {
1608                 // Normal field
1609                 x: i32,
1610 
1611                 /// Documented field
1612                 y: i32,
1613 
1614                 // Macroed field
1615                 #[cfg(test)]
1616                 z: i32,
1617             }
1618 
1619             // A macroed Struct
1620             #[cfg(test)]
1621             struct MacroedStruct {
1622                 // Normal field
1623                 x: i32,
1624 
1625                 /// Documented field
1626                 y: i32,
1627 
1628                 // Macroed field
1629                 #[cfg(test)]
1630                 z: i32,
1631             }
1632 
1633             // A normal Struct
1634             struct NormalStruct {
1635                 // Normal field
1636                 x: i32,
1637 
1638                 /// Documented field
1639                 y: i32,
1640 
1641                 // Macroed field
1642                 #[cfg(test)]
1643                 z: i32,
1644             }
1645 
1646             /// A documented type
1647             type DocumentedType = i32;
1648 
1649             // A macroed type
1650             #[cfg(test)]
1651             type MacroedType = i32;
1652 
1653             /// A module to move
1654             mod module {}
1655 
1656             /// An impl to move
1657             impl NormalStruct {
1658                 /// A method
1659                 fn new() {}
1660             }
1661 
1662             /// A documented trait
1663             trait DocTrait {
1664                 /// Inner function
1665                 fn doc() {}
1666             }
1667 
1668             /// An enum
1669             enum DocumentedEnum {
1670                 /// A variant
1671                 A,
1672                 /// Another variant
1673                 B { x: i32, y: i32 }
1674             }
1675 
1676             /// Documented const
1677             const MY_CONST: i32 = 0;$0
1678         ",
1679             r"
1680             mod modname {
1681                 /// A documented function
1682                 pub(crate) fn documented_fn() {}
1683 
1684                 // A commented function with a #[] attribute macro
1685                 #[cfg(test)]
1686                 pub(crate) fn attribute_fn() {}
1687 
1688                 // A normally commented function
1689                 pub(crate) fn normal_fn() {}
1690 
1691                 /// A documented Struct
1692                 pub(crate) struct DocumentedStruct {
1693                     // Normal field
1694                     pub(crate) x: i32,
1695 
1696                     /// Documented field
1697                     pub(crate) y: i32,
1698 
1699                     // Macroed field
1700                     #[cfg(test)]
1701                     pub(crate) z: i32,
1702                 }
1703 
1704                 // A macroed Struct
1705                 #[cfg(test)]
1706                 pub(crate) struct MacroedStruct {
1707                     // Normal field
1708                     pub(crate) x: i32,
1709 
1710                     /// Documented field
1711                     pub(crate) y: i32,
1712 
1713                     // Macroed field
1714                     #[cfg(test)]
1715                     pub(crate) z: i32,
1716                 }
1717 
1718                 // A normal Struct
1719                 pub(crate) struct NormalStruct {
1720                     // Normal field
1721                     pub(crate) x: i32,
1722 
1723                     /// Documented field
1724                     pub(crate) y: i32,
1725 
1726                     // Macroed field
1727                     #[cfg(test)]
1728                     pub(crate) z: i32,
1729                 }
1730 
1731                 /// A documented type
1732                 pub(crate) type DocumentedType = i32;
1733 
1734                 // A macroed type
1735                 #[cfg(test)]
1736                 pub(crate) type MacroedType = i32;
1737 
1738                 /// A module to move
1739                 pub(crate) mod module {}
1740 
1741                 /// An impl to move
1742                 impl NormalStruct {
1743                     /// A method
1744                     pub(crate) fn new() {}
1745                 }
1746 
1747                 /// A documented trait
1748                 pub(crate) trait DocTrait {
1749                     /// Inner function
1750                     fn doc() {}
1751                 }
1752 
1753                 /// An enum
1754                 pub(crate) enum DocumentedEnum {
1755                     /// A variant
1756                     A,
1757                     /// Another variant
1758                     B { x: i32, y: i32 }
1759                 }
1760 
1761                 /// Documented const
1762                 pub(crate) const MY_CONST: i32 = 0;
1763             }
1764         ",
1765         )
1766     }
1767 
1768     #[test]
test_merge_multiple_intersections()1769     fn test_merge_multiple_intersections() {
1770         check_assist(
1771             extract_module,
1772             r#"
1773 mod dep {
1774     pub struct A;
1775     pub struct B;
1776     pub struct C;
1777 }
1778 
1779 use dep::{A, B, C};
1780 
1781 $0struct S {
1782     inner: A,
1783     state: C,
1784     condvar: B,
1785 }$0
1786 "#,
1787             r#"
1788 mod dep {
1789     pub struct A;
1790     pub struct B;
1791     pub struct C;
1792 }
1793 
1794 use dep::{};
1795 
1796 mod modname {
1797     use super::dep::B;
1798 
1799     use super::dep::C;
1800 
1801     use super::dep::A;
1802 
1803     pub(crate) struct S {
1804         pub(crate) inner: A,
1805         pub(crate) state: C,
1806         pub(crate) condvar: B,
1807     }
1808 }
1809 "#,
1810         );
1811     }
1812 }
1813