]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/extract_module.rs
chore: reposition comment
[rust.git] / crates / ide_assists / src / handlers / extract_module.rs
1 use std::collections::{HashMap, HashSet};
2
3 use hir::{HasSource, ModuleSource};
4 use ide_db::{
5     assists::{AssistId, AssistKind},
6     base_db::FileId,
7     defs::{Definition, NameClass, NameRefClass},
8     search::{FileReference, SearchScope},
9 };
10 use stdx::format_to;
11 use syntax::{
12     algo::find_node_at_range,
13     ast::{
14         self,
15         edit::{AstNodeEdit, IndentLevel},
16         make, HasName, HasVisibility,
17     },
18     match_ast, ted, AstNode, SourceFile, SyntaxNode, TextRange,
19 };
20
21 use crate::{AssistContext, Assists};
22
23 use super::remove_unused_param::range_to_remove;
24
25 // Assist: extract_module
26 //
27 // Extracts a selected region as seperate module. All the references, visibility and imports are
28 // resolved.
29 //
30 // ```
31 // $0fn foo(name: i32) -> i32 {
32 //     name + 1
33 // }$0
34 //
35 // fn bar(name: i32) -> i32 {
36 //     name + 2
37 // }
38 // ```
39 // ->
40 // ```
41 // mod modname {
42 //     pub(crate) fn foo(name: i32) -> i32 {
43 //         name + 1
44 //     }
45 // }
46 //
47 // fn bar(name: i32) -> i32 {
48 //     name + 2
49 // }
50 // ```
51 pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
52     if ctx.has_empty_selection() {
53         return None;
54     }
55
56     let node = ctx.covering_element();
57     let node = match node {
58         syntax::NodeOrToken::Node(n) => n,
59         syntax::NodeOrToken::Token(t) => t.parent()?,
60     };
61
62     let mut curr_parent_module: Option<ast::Module> = None;
63     if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) {
64         curr_parent_module = ast::Module::cast(mod_syn_opt);
65     }
66
67     let mut module = extract_target(&node, ctx.selection_trimmed())?;
68     if module.body_items.len() == 0 {
69         return None;
70     }
71
72     let old_item_indent = module.body_items[0].indent_level();
73
74     //This takes place in three steps:
75     //
76     //- Firstly, we will update the references(usages) e.g. converting a
77     //  function call bar() to modname::bar(), and similarly for other items
78     //
79     //- Secondly, changing the visibility of each item inside the newly selected module
80     //  i.e. making a fn a() {} to pub(crate) fn a() {}
81     //
82     //- Thirdly, resolving all the imports this includes removing paths from imports
83     //  outside the module, shifting/cloning them inside new module, or shifting the imports, or making
84     //  new import statemnts
85
86     //We are getting item usages and record_fields together, record_fields
87     //for change_visibility and usages for first point mentioned above in the process
88     let (usages_to_be_processed, record_fields) = module.get_usages_and_record_fields(ctx);
89
90     let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, &ctx);
91     module.body_items = module.change_visibility(record_fields)?;
92     if module.body_items.len() == 0 {
93         return None;
94     }
95
96     acc.add(
97         AssistId("extract_module", AssistKind::RefactorExtract),
98         "Extract Module",
99         module.text_range,
100         |builder| {
101             let _ = &module;
102
103             let mut body_items = Vec::new();
104             let new_item_indent = old_item_indent + 1;
105             for item in module.body_items {
106                 let item = item.indent(IndentLevel(1));
107                 let mut indented_item = String::new();
108                 format_to!(indented_item, "{}{}", new_item_indent, item.to_string());
109                 body_items.push(indented_item);
110             }
111
112             let body = body_items.join("\n\n");
113
114             let mut module_def = String::new();
115
116             format_to!(module_def, "mod {} {{\n{}\n{}}}", module.name, body, old_item_indent);
117
118             let mut usages_to_be_updated_for_curr_file = vec![];
119             for usages_to_be_updated_for_file in usages_to_be_processed {
120                 if usages_to_be_updated_for_file.0 == ctx.file_id() {
121                     usages_to_be_updated_for_curr_file = usages_to_be_updated_for_file.1;
122                     continue;
123                 }
124                 builder.edit_file(usages_to_be_updated_for_file.0);
125                 for usage_to_be_processed in usages_to_be_updated_for_file.1 {
126                     builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
127                 }
128             }
129
130             builder.edit_file(ctx.file_id());
131             for usage_to_be_processed in usages_to_be_updated_for_curr_file {
132                 builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
133             }
134
135             for import_path_text_range in import_paths_to_be_removed {
136                 builder.delete(import_path_text_range);
137             }
138             builder.replace(module.text_range, module_def)
139         },
140     )
141 }
142
143 #[derive(Debug)]
144 struct Module {
145     text_range: TextRange,
146     name: String,
147     body_items: Vec<ast::Item>,
148 }
149
150 fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> {
151     let mut body_items: Vec<ast::Item> = node
152         .children()
153         .filter_map(|child| {
154             if let Some(item) = ast::Item::cast(child) {
155                 if selection_range.contains_range(item.syntax().text_range()) {
156                     return Some(item);
157                 }
158                 return None;
159             }
160             None
161         })
162         .collect();
163
164     if let Some(node_item) = ast::Item::cast(node.clone()) {
165         body_items.push(node_item);
166     }
167
168     Some(Module { text_range: selection_range, name: "modname".to_string(), body_items })
169 }
170
171 impl Module {
172     fn get_usages_and_record_fields(
173         &self,
174         ctx: &AssistContext,
175     ) -> (HashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
176         let mut adt_fields = Vec::new();
177         let mut refs: HashMap<FileId, Vec<(TextRange, String)>> = HashMap::new();
178
179         //Here impl is not included as each item inside impl will be tied to the parent of
180         //implementing block(a struct, enum, etc), if the parent is in selected module, it will
181         //get updated by ADT section given below or if it is not, then we dont need to do any operation
182         self.body_items.clone().into_iter().for_each(|item| {
183             match_ast! {
184                 match (item.syntax()) {
185                     ast::Adt(it) => {
186                         if let Some( nod ) = ctx.sema.to_def(&it) {
187                             let node_def = Definition::Adt(nod.into());
188                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
189
190                             //Enum Fields are not allowed to explicitly specify pub, it is implied
191                             match it {
192                                 ast::Adt::Struct(x) => {
193                                     if let Some(field_list) = x.field_list() {
194                                         match field_list {
195                                             ast::FieldList::RecordFieldList(record_field_list) => {
196                                                 record_field_list.fields().for_each(|record_field| {
197                                                     adt_fields.push(record_field.syntax().clone());
198                                                 });
199                                             },
200                                             ast::FieldList::TupleFieldList(tuple_field_list) => {
201                                                 tuple_field_list.fields().for_each(|tuple_field| {
202                                                     adt_fields.push(tuple_field.syntax().clone());
203                                                 });
204                                             },
205                                         }
206                                     }
207                                 },
208                                 ast::Adt::Union(x) => {
209                                         if let Some(record_field_list) = x.record_field_list() {
210                                             record_field_list.fields().for_each(|record_field| {
211                                                     adt_fields.push(record_field.syntax().clone());
212                                             });
213                                         }
214                                 },
215                                 ast::Adt::Enum(_) => {},
216                             }
217                         }
218                     },
219                     ast::TypeAlias(it) => {
220                         if let Some( nod ) = ctx.sema.to_def(&it) {
221                             let node_def = Definition::TypeAlias(nod.into());
222                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
223                         }
224                     },
225                     ast::Const(it) => {
226                         if let Some( nod ) = ctx.sema.to_def(&it) {
227                             let node_def = Definition::Const(nod.into());
228                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
229                         }
230                     },
231                     ast::Static(it) => {
232                         if let Some( nod ) = ctx.sema.to_def(&it) {
233                             let node_def = Definition::Static(nod.into());
234                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
235                         }
236                     },
237                     ast::Fn(it) => {
238                         if let Some( nod ) = ctx.sema.to_def(&it) {
239                             let node_def = Definition::Function(nod.into());
240                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
241                         }
242                     },
243                     _ => (),
244                 }
245             }
246         });
247
248         return (refs, adt_fields);
249     }
250
251     fn expand_and_group_usages_file_wise(
252         &self,
253         ctx: &AssistContext,
254         node_def: Definition,
255         refs: &mut HashMap<FileId, Vec<(TextRange, String)>>,
256     ) {
257         for (file_id, references) in node_def.usages(&ctx.sema).all() {
258             if let Some(file_refs) = refs.get_mut(&file_id) {
259                 let mut usages = self.expand_ref_to_usages(references, ctx, file_id);
260                 file_refs.append(&mut usages);
261             } else {
262                 refs.insert(file_id, self.expand_ref_to_usages(references, ctx, file_id));
263             }
264         }
265     }
266
267     fn expand_ref_to_usages(
268         &self,
269         refs: Vec<FileReference>,
270         ctx: &AssistContext,
271         file_id: FileId,
272     ) -> Vec<(TextRange, String)> {
273         let source_file = ctx.sema.parse(file_id);
274
275         let mut usages_to_be_processed_for_file = Vec::new();
276         for usage in refs {
277             if let Some(x) = self.get_usage_to_be_processed(&source_file, usage) {
278                 usages_to_be_processed_for_file.push(x);
279             }
280         }
281
282         usages_to_be_processed_for_file
283     }
284
285     fn get_usage_to_be_processed(
286         &self,
287         source_file: &SourceFile,
288         FileReference { range, name, .. }: FileReference,
289     ) -> Option<(TextRange, String)> {
290         let path: Option<ast::Path> = find_node_at_range(source_file.syntax(), range);
291
292         let path = path?;
293
294         for desc in path.syntax().descendants() {
295             if desc.to_string() == name.syntax().to_string()
296                 && !self.text_range.contains_range(desc.text_range())
297             {
298                 if let Some(name_ref) = ast::NameRef::cast(desc) {
299                     return Some((
300                         name_ref.syntax().text_range(),
301                         format!("{}::{}", self.name, name_ref),
302                     ));
303                 }
304             }
305         }
306
307         None
308     }
309
310     fn change_visibility(&self, record_fields: Vec<SyntaxNode>) -> Option<Vec<ast::Item>> {
311         let (body_items, mut replacements, record_field_parents, impls) =
312             get_replacements_for_visibilty_change(self.body_items.clone(), false);
313
314         let mut impl_items = Vec::new();
315         for impl_ in impls {
316             let mut this_impl_items = Vec::new();
317             for node in impl_.syntax().descendants() {
318                 if let Some(item) = ast::Item::cast(node) {
319                     this_impl_items.push(item);
320                 }
321             }
322
323             impl_items.append(&mut this_impl_items);
324         }
325
326         let (_, mut impl_item_replacements, _, _) =
327             get_replacements_for_visibilty_change(impl_items, true);
328
329         replacements.append(&mut impl_item_replacements);
330
331         record_field_parents.into_iter().for_each(|x| {
332             x.1.descendants().filter_map(|x| ast::RecordField::cast(x)).for_each(|desc| {
333                 let is_record_field_present = record_fields
334                     .clone()
335                     .into_iter()
336                     .find(|x| x.to_string() == desc.to_string())
337                     .is_some();
338                 if is_record_field_present {
339                     replacements.push((desc.visibility(), desc.syntax().clone()));
340                 }
341             });
342         });
343
344         replacements.into_iter().for_each(|(vis, syntax)| {
345             add_change_vis(vis, syntax.first_child_or_token());
346         });
347
348         Some(body_items)
349     }
350
351     fn resolve_imports(
352         &mut self,
353         curr_parent_module: Option<ast::Module>,
354         ctx: &AssistContext,
355     ) -> Vec<TextRange> {
356         let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
357         let mut node_set: HashSet<String> = HashSet::new();
358
359         self.body_items.clone().into_iter().for_each(|item| {
360             item.syntax().descendants().for_each(|x| {
361                 if let Some(name) = ast::Name::cast(x.clone()) {
362                     if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
363                         //Necessary to avoid two same names going through
364                         if !node_set.contains(&name.syntax().to_string()) {
365                             node_set.insert(name.syntax().to_string());
366                             let def_opt: Option<Definition> = match name_classify {
367                                 NameClass::Definition(def) => Some(def),
368                                 _ => None,
369                             };
370
371                             if let Some(def) = def_opt {
372                                 if let Some(import_path) = self
373                                     .process_names_and_namerefs_for_import_resolve(
374                                         def,
375                                         name.syntax(),
376                                         &curr_parent_module,
377                                         ctx,
378                                     )
379                                 {
380                                     import_paths_to_be_removed.push(import_path);
381                                 }
382                             }
383                         }
384                     }
385                 }
386
387                 if let Some(name_ref) = ast::NameRef::cast(x) {
388                     if let Some(name_classify) = NameRefClass::classify(&ctx.sema, &name_ref) {
389                         //Necessary to avoid two same names going through
390                         if !node_set.contains(&name_ref.syntax().to_string()) {
391                             node_set.insert(name_ref.syntax().to_string());
392                             let def_opt: Option<Definition> = match name_classify {
393                                 NameRefClass::Definition(def) => Some(def),
394                                 _ => None,
395                             };
396
397                             if let Some(def) = def_opt {
398                                 if let Some(import_path) = self
399                                     .process_names_and_namerefs_for_import_resolve(
400                                         def,
401                                         name_ref.syntax(),
402                                         &curr_parent_module,
403                                         ctx,
404                                     )
405                                 {
406                                     import_paths_to_be_removed.push(import_path);
407                                 }
408                             }
409                         }
410                     }
411                 }
412             });
413         });
414
415         import_paths_to_be_removed
416     }
417
418     fn process_names_and_namerefs_for_import_resolve(
419         &mut self,
420         def: Definition,
421         node_syntax: &SyntaxNode,
422         curr_parent_module: &Option<ast::Module>,
423         ctx: &AssistContext,
424     ) -> Option<TextRange> {
425         //We only need to find in the current file
426         let selection_range = ctx.selection_trimmed();
427         let curr_file_id = ctx.file_id();
428         let search_scope = SearchScope::single_file(curr_file_id);
429         let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all();
430         let file = ctx.sema.parse(curr_file_id);
431
432         let mut exists_inside_sel = false;
433         let mut exists_outside_sel = false;
434         usage_res.clone().into_iter().for_each(|x| {
435             let mut non_use_nodes_itr = (&x.1).into_iter().filter_map(|x| {
436                 if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
437                     let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
438                     return path_opt;
439                 }
440
441                 None
442             });
443
444             if non_use_nodes_itr
445                 .clone()
446                 .find(|x| !selection_range.contains_range(x.syntax().text_range()))
447                 .is_some()
448             {
449                 exists_outside_sel = true;
450             }
451             if non_use_nodes_itr
452                 .find(|x| selection_range.contains_range(x.syntax().text_range()))
453                 .is_some()
454             {
455                 exists_inside_sel = true;
456             }
457         });
458
459         let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
460             def,
461             ctx,
462             curr_parent_module,
463             selection_range,
464             curr_file_id,
465         );
466
467         let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|x| {
468             let file_id = x.0;
469             let mut use_opt: Option<ast::Use> = None;
470             if file_id == curr_file_id {
471                 (&x.1).into_iter().for_each(|x| {
472                     let node_opt: Option<ast::Use> = find_node_at_range(file.syntax(), x.range);
473                     if let Some(node) = node_opt {
474                         use_opt = Some(node);
475                     }
476                 });
477             }
478             return use_opt;
479         });
480
481         let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
482         //Exists inside and outside selection
483         // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new
484         // module
485         // - Use stmt for item is not present ->
486         //If it is not found, the definition is either ported inside new module or it stays
487         //outside:
488         //- Def is inside: Nothing to import
489         //- Def is outside: Import it inside with super
490
491         //Exists inside selection but not outside -> Check for the import of it in original module,
492         //get the use_tree_str, reconstruct the use stmt in new module
493
494         let mut import_path_to_be_removed: Option<TextRange> = None;
495         if exists_inside_sel && exists_outside_sel {
496             //Changes to be made only inside new module
497
498             //If use_stmt exists, find the use_tree_str, reconstruct it inside new module
499             //If not, insert a use stmt with super and the given nameref
500             if let Some((use_tree_str, _)) =
501                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
502             {
503                 use_tree_str_opt = Some(use_tree_str);
504             } else if source_exists_outside_sel_in_same_mod {
505                 //Considered only after use_stmt is not present
506                 //source_exists_outside_sel_in_same_mod | exists_outside_sel(exists_inside_sel =
507                 //true for all cases)
508                 // false | false -> Do nothing
509                 // false | true -> If source is in selection -> nothing to do, If source is outside
510                 // mod -> ust_stmt transversal
511                 // true  | false -> super import insertion
512                 // true  | true -> super import insertion
513                 self.make_use_stmt_of_node_with_super(node_syntax);
514             }
515         } else if exists_inside_sel && !exists_outside_sel {
516             //Changes to be made inside new module, and remove import from outside
517
518             if let Some((use_tree_str, text_range_opt)) =
519                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
520             {
521                 if let Some(text_range) = text_range_opt {
522                     import_path_to_be_removed = Some(text_range);
523                 }
524                 use_tree_str_opt = Some(use_tree_str);
525             } else if source_exists_outside_sel_in_same_mod {
526                 self.make_use_stmt_of_node_with_super(node_syntax);
527             }
528         }
529
530         if let Some(use_tree_str) = use_tree_str_opt {
531             let mut use_tree_str = use_tree_str;
532             use_tree_str.reverse();
533             if use_tree_str[0].to_string().contains("super") {
534                 let super_path = make::ext::ident_path("super");
535                 use_tree_str.insert(0, super_path)
536             }
537
538             let use_ =
539                 make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
540             if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
541                 self.body_items.insert(0, item);
542             }
543         }
544
545         import_path_to_be_removed
546     }
547
548     fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) {
549         let super_path = make::ext::ident_path("super");
550         let node_path = make::ext::ident_path(&node_syntax.to_string());
551         let use_ = make::use_(
552             None,
553             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
554         );
555         if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
556             self.body_items.insert(0, item);
557         }
558     }
559
560     fn process_use_stmt_for_import_resolve(
561         &self,
562         use_stmt_opt: Option<ast::Use>,
563         node_syntax: &SyntaxNode,
564     ) -> Option<(Vec<ast::Path>, Option<TextRange>)> {
565         if let Some(use_stmt) = use_stmt_opt {
566             for desc in use_stmt.syntax().descendants() {
567                 if let Some(path_seg) = ast::PathSegment::cast(desc) {
568                     if path_seg.syntax().to_string() == node_syntax.to_string() {
569                         let mut use_tree_str = vec![path_seg.parent_path()];
570                         get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
571                         for ancs in path_seg.syntax().ancestors() {
572                             //Here we are looking for use_tree with same string value as node
573                             //passed above as the range_to_remove function looks for a comma and
574                             //then includes it in the text range to remove it. But the comma only
575                             //appears at the use_tree level
576                             if let Some(use_tree) = ast::UseTree::cast(ancs) {
577                                 if use_tree.syntax().to_string() == node_syntax.to_string() {
578                                     return Some((
579                                         use_tree_str,
580                                         Some(range_to_remove(use_tree.syntax())),
581                                     ));
582                                 }
583                             }
584                         }
585
586                         return Some((use_tree_str, None));
587                     }
588                 }
589             }
590         }
591
592         None
593     }
594 }
595
596 fn does_source_exists_outside_sel_in_same_mod(
597     def: Definition,
598     ctx: &AssistContext,
599     curr_parent_module: &Option<ast::Module>,
600     selection_range: TextRange,
601     curr_file_id: FileId,
602 ) -> bool {
603     let mut source_exists_outside_sel_in_same_mod = false;
604     match def {
605         Definition::Module(x) => {
606             let source = x.definition_source(ctx.db());
607             let have_same_parent;
608             if let Some(ast_module) = &curr_parent_module {
609                 if let Some(hir_module) = x.parent(ctx.db()) {
610                     have_same_parent =
611                         compare_hir_and_ast_module(&ast_module, hir_module, ctx).is_some();
612                 } else {
613                     let source_file_id = source.file_id.original_file(ctx.db());
614                     have_same_parent = source_file_id == curr_file_id;
615                 }
616             } else {
617                 let source_file_id = source.file_id.original_file(ctx.db());
618                 have_same_parent = source_file_id == curr_file_id;
619             }
620
621             if have_same_parent {
622                 match source.value {
623                     ModuleSource::Module(module_) => {
624                         source_exists_outside_sel_in_same_mod =
625                             !selection_range.contains_range(module_.syntax().text_range());
626                     }
627                     _ => {}
628                 }
629             }
630         }
631         Definition::Function(x) => {
632             if let Some(source) = x.source(ctx.db()) {
633                 let have_same_parent;
634                 if let Some(ast_module) = &curr_parent_module {
635                     have_same_parent =
636                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
637                 } else {
638                     let source_file_id = source.file_id.original_file(ctx.db());
639                     have_same_parent = source_file_id == curr_file_id;
640                 }
641
642                 if have_same_parent {
643                     source_exists_outside_sel_in_same_mod =
644                         !selection_range.contains_range(source.value.syntax().text_range());
645                 }
646             }
647         }
648         Definition::Adt(x) => {
649             if let Some(source) = x.source(ctx.db()) {
650                 let have_same_parent;
651                 if let Some(ast_module) = &curr_parent_module {
652                     have_same_parent =
653                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
654                 } else {
655                     let source_file_id = source.file_id.original_file(ctx.db());
656                     have_same_parent = source_file_id == curr_file_id;
657                 }
658
659                 if have_same_parent {
660                     source_exists_outside_sel_in_same_mod =
661                         !selection_range.contains_range(source.value.syntax().text_range());
662                 }
663             }
664         }
665         Definition::Variant(x) => {
666             if let Some(source) = x.source(ctx.db()) {
667                 let have_same_parent;
668                 if let Some(ast_module) = &curr_parent_module {
669                     have_same_parent =
670                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
671                 } else {
672                     let source_file_id = source.file_id.original_file(ctx.db());
673                     have_same_parent = source_file_id == curr_file_id;
674                 }
675
676                 if have_same_parent {
677                     source_exists_outside_sel_in_same_mod =
678                         !selection_range.contains_range(source.value.syntax().text_range());
679                 }
680             }
681         }
682         Definition::Const(x) => {
683             if let Some(source) = x.source(ctx.db()) {
684                 let have_same_parent;
685                 if let Some(ast_module) = &curr_parent_module {
686                     have_same_parent =
687                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
688                 } else {
689                     let source_file_id = source.file_id.original_file(ctx.db());
690                     have_same_parent = source_file_id == curr_file_id;
691                 }
692
693                 if have_same_parent {
694                     source_exists_outside_sel_in_same_mod =
695                         !selection_range.contains_range(source.value.syntax().text_range());
696                 }
697             }
698         }
699         Definition::Static(x) => {
700             if let Some(source) = x.source(ctx.db()) {
701                 let have_same_parent;
702                 if let Some(ast_module) = &curr_parent_module {
703                     have_same_parent =
704                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
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                     source_exists_outside_sel_in_same_mod =
712                         !selection_range.contains_range(source.value.syntax().text_range());
713                 }
714             }
715         }
716         Definition::Trait(x) => {
717             if let Some(source) = x.source(ctx.db()) {
718                 let have_same_parent;
719                 if let Some(ast_module) = &curr_parent_module {
720                     have_same_parent =
721                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
722                 } else {
723                     let source_file_id = source.file_id.original_file(ctx.db());
724                     have_same_parent = source_file_id == curr_file_id;
725                 }
726
727                 if have_same_parent {
728                     source_exists_outside_sel_in_same_mod =
729                         !selection_range.contains_range(source.value.syntax().text_range());
730                 }
731             }
732         }
733         Definition::TypeAlias(x) => {
734             if let Some(source) = x.source(ctx.db()) {
735                 let have_same_parent;
736                 if let Some(ast_module) = &curr_parent_module {
737                     have_same_parent =
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                     have_same_parent = 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         _ => {}
751     }
752
753     return source_exists_outside_sel_in_same_mod;
754 }
755
756 fn get_replacements_for_visibilty_change(
757     items: Vec<ast::Item>,
758     is_clone_for_updated: bool,
759 ) -> (
760     Vec<ast::Item>,
761     Vec<(Option<ast::Visibility>, SyntaxNode)>,
762     Vec<(Option<ast::Visibility>, SyntaxNode)>,
763     Vec<ast::Impl>,
764 ) {
765     let mut replacements = Vec::new();
766     let mut record_field_parents = Vec::new();
767     let mut impls = Vec::new();
768     let mut body_items = Vec::new();
769
770     items.into_iter().for_each(|item| {
771         let mut item = item;
772         if !is_clone_for_updated {
773             item = item.clone_for_update();
774         }
775         body_items.push(item.clone());
776         //Use stmts are ignored
777         match item {
778             ast::Item::Const(it) => replacements.push((it.visibility(), it.syntax().clone())),
779             ast::Item::Enum(it) => replacements.push((it.visibility(), it.syntax().clone())),
780             ast::Item::ExternCrate(it) => replacements.push((it.visibility(), it.syntax().clone())),
781             ast::Item::Fn(it) => replacements.push((it.visibility(), it.syntax().clone())),
782             //Associated item's visibility should not be changed
783             ast::Item::Impl(it) if it.for_token().is_none() => impls.push(it),
784             ast::Item::MacroRules(it) => replacements.push((it.visibility(), it.syntax().clone())),
785             ast::Item::MacroDef(it) => replacements.push((it.visibility(), it.syntax().clone())),
786             ast::Item::Module(it) => replacements.push((it.visibility(), it.syntax().clone())),
787             ast::Item::Static(it) => replacements.push((it.visibility(), it.syntax().clone())),
788             ast::Item::Struct(it) => {
789                 replacements.push((it.visibility(), it.syntax().clone()));
790                 record_field_parents.push((it.visibility(), it.syntax().clone()));
791             }
792             ast::Item::Trait(it) => replacements.push((it.visibility(), it.syntax().clone())),
793             ast::Item::TypeAlias(it) => replacements.push((it.visibility(), it.syntax().clone())),
794             ast::Item::Union(it) => {
795                 replacements.push((it.visibility(), it.syntax().clone()));
796                 record_field_parents.push((it.visibility(), it.syntax().clone()));
797             }
798             _ => (),
799         }
800     });
801
802     return (body_items, replacements, record_field_parents, impls);
803 }
804
805 fn get_use_tree_paths_from_path(
806     path: ast::Path,
807     use_tree_str: &mut Vec<ast::Path>,
808 ) -> Option<&mut Vec<ast::Path>> {
809     path.syntax().ancestors().filter(|x| x.to_string() != path.to_string()).find_map(|x| {
810         if let Some(use_tree) = ast::UseTree::cast(x) {
811             if let Some(upper_tree_path) = use_tree.path() {
812                 if upper_tree_path.to_string() != path.to_string() {
813                     use_tree_str.push(upper_tree_path.clone());
814                     get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
815                     return Some(use_tree);
816                 }
817             }
818         }
819         None
820     })?;
821
822     Some(use_tree_str)
823 }
824
825 fn add_change_vis(
826     vis: Option<ast::Visibility>,
827     node_or_token_opt: Option<syntax::SyntaxElement>,
828 ) -> Option<()> {
829     if let None = vis {
830         if let Some(node_or_token) = node_or_token_opt {
831             let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
832             if let Some(node) = node_or_token.as_node() {
833                 ted::insert(ted::Position::before(node), pub_crate_vis.syntax());
834             }
835             if let Some(token) = node_or_token.as_token() {
836                 ted::insert(ted::Position::before(token), pub_crate_vis.syntax());
837             }
838         }
839     }
840
841     Some(())
842 }
843
844 fn compare_hir_and_ast_module(
845     ast_module: &ast::Module,
846     hir_module: hir::Module,
847     ctx: &AssistContext,
848 ) -> Option<()> {
849     let hir_mod_name = hir_module.name(ctx.db())?;
850     let ast_mod_name = ast_module.name()?;
851     if hir_mod_name.to_string() != ast_mod_name.to_string() {
852         return None;
853     }
854
855     return Some(());
856 }
857
858 #[cfg(test)]
859 mod tests {
860     use crate::tests::{check_assist, check_assist_not_applicable};
861
862     use super::*;
863
864     #[test]
865     fn test_not_applicable_without_selection() {
866         check_assist_not_applicable(
867             extract_module,
868             r"
869 $0pub struct PublicStruct {
870     field: i32,
871 }
872             ",
873         )
874     }
875
876     #[test]
877     fn test_extract_module() {
878         check_assist(
879             extract_module,
880             r"
881             mod thirdpartycrate {
882                 pub mod nest {
883                     pub struct SomeType;
884                     pub struct SomeType2;
885                 }
886                 pub struct SomeType1;
887             }
888
889             mod bar {
890                 use crate::thirdpartycrate::{nest::{SomeType, SomeType2}, SomeType1};
891
892                 pub struct PublicStruct {
893                     field: PrivateStruct,
894                     field1: SomeType1,
895                 }
896
897                 impl PublicStruct {
898                     pub fn new() -> Self {
899                         Self { field: PrivateStruct::new(), field1: SomeType1 }
900                     }
901                 }
902
903                 fn foo() {
904                     let _s = PrivateStruct::new();
905                     let _a = bar();
906                 }
907
908 $0struct PrivateStruct {
909     inner: SomeType,
910 }
911
912 pub struct PrivateStruct1 {
913     pub inner: i32,
914 }
915
916 impl PrivateStruct {
917     fn new() -> Self {
918          PrivateStruct { inner: SomeType }
919     }
920 }
921
922 fn bar() -> i32 {
923     2
924 }$0
925             }
926             ",
927             r"
928             mod thirdpartycrate {
929                 pub mod nest {
930                     pub struct SomeType;
931                     pub struct SomeType2;
932                 }
933                 pub struct SomeType1;
934             }
935
936             mod bar {
937                 use crate::thirdpartycrate::{nest::{SomeType2}, SomeType1};
938
939                 pub struct PublicStruct {
940                     field: modname::PrivateStruct,
941                     field1: SomeType1,
942                 }
943
944                 impl PublicStruct {
945                     pub fn new() -> Self {
946                         Self { field: modname::PrivateStruct::new(), field1: SomeType1 }
947                     }
948                 }
949
950                 fn foo() {
951                     let _s = modname::PrivateStruct::new();
952                     let _a = modname::bar();
953                 }
954
955 mod modname {
956     use crate::thirdpartycrate::nest::SomeType;
957
958     pub(crate) struct PrivateStruct {
959         pub(crate) inner: SomeType,
960     }
961
962     pub struct PrivateStruct1 {
963         pub inner: i32,
964     }
965
966     impl PrivateStruct {
967         pub(crate) fn new() -> Self {
968              PrivateStruct { inner: SomeType }
969         }
970     }
971
972     pub(crate) fn bar() -> i32 {
973         2
974     }
975 }
976             }
977             ",
978         );
979     }
980
981     #[test]
982     fn test_extract_module_for_function_only() {
983         check_assist(
984             extract_module,
985             r"
986 $0fn foo(name: i32) -> i32 {
987     name + 1
988 }$0
989
990                 fn bar(name: i32) -> i32 {
991                     name + 2
992                 }
993             ",
994             r"
995 mod modname {
996     pub(crate) fn foo(name: i32) -> i32 {
997         name + 1
998     }
999 }
1000
1001                 fn bar(name: i32) -> i32 {
1002                     name + 2
1003                 }
1004             ",
1005         )
1006     }
1007
1008     #[test]
1009     fn test_extract_module_for_impl_having_corresponding_adt_in_selection() {
1010         check_assist(
1011             extract_module,
1012             r"
1013             mod impl_play {
1014 $0struct A {}
1015
1016 impl A {
1017     pub fn new_a() -> i32 {
1018         2
1019     }
1020 }$0
1021
1022                 fn a() {
1023                     let _a = A::new_a();
1024                 }
1025             }
1026             ",
1027             r"
1028             mod impl_play {
1029 mod modname {
1030     pub(crate) struct A {}
1031
1032     impl A {
1033         pub fn new_a() -> i32 {
1034             2
1035         }
1036     }
1037 }
1038
1039                 fn a() {
1040                     let _a = modname::A::new_a();
1041                 }
1042             }
1043             ",
1044         )
1045     }
1046
1047     #[test]
1048     fn test_import_resolve_when_its_only_inside_selection() {
1049         check_assist(
1050             extract_module,
1051             r"
1052             mod foo {
1053                 pub struct PrivateStruct;
1054                 pub struct PrivateStruct1;
1055             }
1056
1057             mod bar {
1058                 use super::foo::{PrivateStruct, PrivateStruct1};
1059
1060 $0struct Strukt {
1061     field: PrivateStruct,
1062 }$0
1063
1064                 struct Strukt1 {
1065                     field: PrivateStruct1,
1066                 }
1067             }
1068             ",
1069             r"
1070             mod foo {
1071                 pub struct PrivateStruct;
1072                 pub struct PrivateStruct1;
1073             }
1074
1075             mod bar {
1076                 use super::foo::{PrivateStruct1};
1077
1078 mod modname {
1079     use super::super::foo::PrivateStruct;
1080
1081     pub(crate) struct Strukt {
1082         pub(crate) field: PrivateStruct,
1083     }
1084 }
1085
1086                 struct Strukt1 {
1087                     field: PrivateStruct1,
1088                 }
1089             }
1090             ",
1091         )
1092     }
1093
1094     #[test]
1095     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_not_in_same_mod() {
1096         check_assist(
1097             extract_module,
1098             r"
1099             mod foo {
1100                 pub struct PrivateStruct;
1101             }
1102
1103             mod bar {
1104                 use super::foo::PrivateStruct;
1105
1106 $0struct Strukt {
1107     field: PrivateStruct,
1108 }$0
1109
1110                 struct Strukt1 {
1111                     field: PrivateStruct,
1112                 }
1113             }
1114             ",
1115             r"
1116             mod foo {
1117                 pub struct PrivateStruct;
1118             }
1119
1120             mod bar {
1121                 use super::foo::PrivateStruct;
1122
1123 mod modname {
1124     use super::super::foo::PrivateStruct;
1125
1126     pub(crate) struct Strukt {
1127         pub(crate) field: PrivateStruct,
1128     }
1129 }
1130
1131                 struct Strukt1 {
1132                     field: PrivateStruct,
1133                 }
1134             }
1135             ",
1136         )
1137     }
1138
1139     #[test]
1140     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_is_in_same_mod() {
1141         check_assist(
1142             extract_module,
1143             r"
1144             mod bar {
1145                 pub struct PrivateStruct;
1146
1147 $0struct Strukt {
1148    field: PrivateStruct,
1149 }$0
1150
1151                 struct Strukt1 {
1152                     field: PrivateStruct,
1153                 }
1154             }
1155             ",
1156             r"
1157             mod bar {
1158                 pub struct PrivateStruct;
1159
1160 mod modname {
1161     use super::PrivateStruct;
1162
1163     pub(crate) struct Strukt {
1164        pub(crate) field: PrivateStruct,
1165     }
1166 }
1167
1168                 struct Strukt1 {
1169                     field: PrivateStruct,
1170                 }
1171             }
1172             ",
1173         )
1174     }
1175
1176     #[test]
1177     fn test_extract_module_for_correspoding_adt_of_impl_present_in_same_mod_but_not_in_selection() {
1178         check_assist(
1179             extract_module,
1180             r"
1181             mod impl_play {
1182                 struct A {}
1183
1184 $0impl A {
1185     pub fn new_a() -> i32 {
1186         2
1187     }
1188 }$0
1189
1190                 fn a() {
1191                     let _a = A::new_a();
1192                 }
1193             }
1194             ",
1195             r"
1196             mod impl_play {
1197                 struct A {}
1198
1199 mod modname {
1200     use super::A;
1201
1202     impl A {
1203         pub fn new_a() -> i32 {
1204             2
1205         }
1206     }
1207 }
1208
1209                 fn a() {
1210                     let _a = A::new_a();
1211                 }
1212             }
1213             ",
1214         )
1215     }
1216
1217     #[test]
1218     fn test_extract_module_for_impl_not_having_corresponding_adt_in_selection_and_not_in_same_mod_but_with_super(
1219     ) {
1220         check_assist(
1221             extract_module,
1222             r"
1223             mod foo {
1224                 pub struct A {}
1225             }
1226             mod impl_play {
1227                 use super::foo::A;
1228
1229 $0impl A {
1230     pub fn new_a() -> i32 {
1231         2
1232     }
1233 }$0
1234
1235                 fn a() {
1236                     let _a = A::new_a();
1237                 }
1238             }
1239             ",
1240             r"
1241             mod foo {
1242                 pub struct A {}
1243             }
1244             mod impl_play {
1245                 use super::foo::A;
1246
1247 mod modname {
1248     use super::super::foo::A;
1249
1250     impl A {
1251         pub fn new_a() -> i32 {
1252             2
1253         }
1254     }
1255 }
1256
1257                 fn a() {
1258                     let _a = A::new_a();
1259                 }
1260             }
1261             ",
1262         )
1263     }
1264
1265     #[test]
1266     fn test_import_resolve_for_trait_bounds_on_function() {
1267         check_assist(
1268             extract_module,
1269             r"
1270             mod impl_play2 {
1271                 trait JustATrait {}
1272
1273 $0struct A {}
1274
1275 fn foo<T: JustATrait>(arg: T) -> T {
1276     arg
1277 }
1278
1279 impl JustATrait for A {}
1280
1281 fn bar() {
1282     let a = A {};
1283     foo(a);
1284 }$0
1285             }
1286             ",
1287             r"
1288             mod impl_play2 {
1289                 trait JustATrait {}
1290
1291 mod modname {
1292     use super::JustATrait;
1293
1294     pub(crate) struct A {}
1295
1296     pub(crate) fn foo<T: JustATrait>(arg: T) -> T {
1297         arg
1298     }
1299
1300     impl JustATrait for A {}
1301
1302     pub(crate) fn bar() {
1303         let a = A {};
1304         foo(a);
1305     }
1306 }
1307             }
1308             ",
1309         )
1310     }
1311
1312     #[test]
1313     fn test_extract_module_for_module() {
1314         check_assist(
1315             extract_module,
1316             r"
1317             mod impl_play2 {
1318 $0mod impl_play {
1319     pub struct A {}
1320 }$0
1321             }
1322             ",
1323             r"
1324             mod impl_play2 {
1325 mod modname {
1326     pub(crate) mod impl_play {
1327         pub struct A {}
1328     }
1329 }
1330             }
1331             ",
1332         )
1333     }
1334
1335     #[test]
1336     fn test_extract_module_with_multiple_files() {
1337         check_assist(
1338             extract_module,
1339             r"
1340             //- /main.rs
1341             mod foo;
1342
1343             use foo::PrivateStruct;
1344
1345             pub struct Strukt {
1346                 field: PrivateStruct,
1347             }
1348
1349             fn main() {
1350                 $0struct Strukt1 {
1351                     field: Strukt,
1352                 }$0
1353             }
1354             //- /foo.rs
1355             pub struct PrivateStruct;
1356             ",
1357             r"
1358             mod foo;
1359
1360             use foo::PrivateStruct;
1361
1362             pub struct Strukt {
1363                 field: PrivateStruct,
1364             }
1365
1366             fn main() {
1367                 mod modname {
1368                     use super::Strukt;
1369
1370                     pub(crate) struct Strukt1 {
1371                         pub(crate) field: Strukt,
1372                     }
1373                 }
1374             }
1375             ",
1376         )
1377     }
1378
1379     #[test]
1380     fn test_do_not_apply_visibility_modifier_to_trait_impl_items() {
1381         check_assist(
1382             extract_module,
1383             r"
1384             trait ATrait {
1385                 fn function();
1386             }
1387
1388             struct A {}
1389
1390 $0impl ATrait for A {
1391     fn function() {}
1392 }$0
1393             ",
1394             r"
1395             trait ATrait {
1396                 fn function();
1397             }
1398
1399             struct A {}
1400
1401 mod modname {
1402     use super::A;
1403
1404     use super::ATrait;
1405
1406     impl ATrait for A {
1407         fn function() {}
1408     }
1409 }
1410             ",
1411         )
1412     }
1413 }