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