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