]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/extract_module.rs
Merge #11445
[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.iter().cloned().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                     ast::Macro(it) => {
244                         if let Some(nod) = ctx.sema.to_def(&it) {
245                             self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs);
246                         }
247                     },
248                     _ => (),
249                 }
250             }
251         });
252
253         return (refs, adt_fields);
254     }
255
256     fn expand_and_group_usages_file_wise(
257         &self,
258         ctx: &AssistContext,
259         node_def: Definition,
260         refs: &mut HashMap<FileId, Vec<(TextRange, String)>>,
261     ) {
262         for (file_id, references) in node_def.usages(&ctx.sema).all() {
263             if let Some(file_refs) = refs.get_mut(&file_id) {
264                 let mut usages = self.expand_ref_to_usages(references, ctx, file_id);
265                 file_refs.append(&mut usages);
266             } else {
267                 refs.insert(file_id, self.expand_ref_to_usages(references, ctx, file_id));
268             }
269         }
270     }
271
272     fn expand_ref_to_usages(
273         &self,
274         refs: Vec<FileReference>,
275         ctx: &AssistContext,
276         file_id: FileId,
277     ) -> Vec<(TextRange, String)> {
278         let source_file = ctx.sema.parse(file_id);
279
280         let mut usages_to_be_processed_for_file = Vec::new();
281         for usage in refs {
282             if let Some(x) = self.get_usage_to_be_processed(&source_file, usage) {
283                 usages_to_be_processed_for_file.push(x);
284             }
285         }
286
287         usages_to_be_processed_for_file
288     }
289
290     fn get_usage_to_be_processed(
291         &self,
292         source_file: &SourceFile,
293         FileReference { range, name, .. }: FileReference,
294     ) -> Option<(TextRange, String)> {
295         let path: Option<ast::Path> = find_node_at_range(source_file.syntax(), range);
296
297         let path = path?;
298
299         for desc in path.syntax().descendants() {
300             if desc.to_string() == name.syntax().to_string()
301                 && !self.text_range.contains_range(desc.text_range())
302             {
303                 if let Some(name_ref) = ast::NameRef::cast(desc) {
304                     return Some((
305                         name_ref.syntax().text_range(),
306                         format!("{}::{}", self.name, name_ref),
307                     ));
308                 }
309             }
310         }
311
312         None
313     }
314
315     fn change_visibility(&self, record_fields: Vec<SyntaxNode>) -> Option<Vec<ast::Item>> {
316         let (body_items, mut replacements, record_field_parents, impls) =
317             get_replacements_for_visibilty_change(self.body_items.clone(), false);
318
319         let mut impl_items = Vec::new();
320         for impl_ in impls {
321             let mut this_impl_items = Vec::new();
322             for node in impl_.syntax().descendants() {
323                 if let Some(item) = ast::Item::cast(node) {
324                     this_impl_items.push(item);
325                 }
326             }
327
328             impl_items.append(&mut this_impl_items);
329         }
330
331         let (_, mut impl_item_replacements, _, _) =
332             get_replacements_for_visibilty_change(impl_items, true);
333
334         replacements.append(&mut impl_item_replacements);
335
336         record_field_parents.into_iter().for_each(|x| {
337             x.1.descendants().filter_map(|x| ast::RecordField::cast(x)).for_each(|desc| {
338                 let is_record_field_present = record_fields
339                     .clone()
340                     .into_iter()
341                     .find(|x| x.to_string() == desc.to_string())
342                     .is_some();
343                 if is_record_field_present {
344                     replacements.push((desc.visibility(), desc.syntax().clone()));
345                 }
346             });
347         });
348
349         replacements.into_iter().for_each(|(vis, syntax)| {
350             add_change_vis(vis, syntax.first_child_or_token());
351         });
352
353         Some(body_items)
354     }
355
356     fn resolve_imports(
357         &mut self,
358         curr_parent_module: Option<ast::Module>,
359         ctx: &AssistContext,
360     ) -> Vec<TextRange> {
361         let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
362         let mut node_set: HashSet<String> = HashSet::new();
363
364         self.body_items.clone().into_iter().for_each(|item| {
365             item.syntax().descendants().for_each(|x| {
366                 if let Some(name) = ast::Name::cast(x.clone()) {
367                     if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
368                         //Necessary to avoid two same names going through
369                         if !node_set.contains(&name.syntax().to_string()) {
370                             node_set.insert(name.syntax().to_string());
371                             let def_opt: Option<Definition> = match name_classify {
372                                 NameClass::Definition(def) => Some(def),
373                                 _ => None,
374                             };
375
376                             if let Some(def) = def_opt {
377                                 if let Some(import_path) = self
378                                     .process_names_and_namerefs_for_import_resolve(
379                                         def,
380                                         name.syntax(),
381                                         &curr_parent_module,
382                                         ctx,
383                                     )
384                                 {
385                                     import_paths_to_be_removed.push(import_path);
386                                 }
387                             }
388                         }
389                     }
390                 }
391
392                 if let Some(name_ref) = ast::NameRef::cast(x) {
393                     if let Some(name_classify) = NameRefClass::classify(&ctx.sema, &name_ref) {
394                         //Necessary to avoid two same names going through
395                         if !node_set.contains(&name_ref.syntax().to_string()) {
396                             node_set.insert(name_ref.syntax().to_string());
397                             let def_opt: Option<Definition> = match name_classify {
398                                 NameRefClass::Definition(def) => Some(def),
399                                 _ => None,
400                             };
401
402                             if let Some(def) = def_opt {
403                                 if let Some(import_path) = self
404                                     .process_names_and_namerefs_for_import_resolve(
405                                         def,
406                                         name_ref.syntax(),
407                                         &curr_parent_module,
408                                         ctx,
409                                     )
410                                 {
411                                     import_paths_to_be_removed.push(import_path);
412                                 }
413                             }
414                         }
415                     }
416                 }
417             });
418         });
419
420         import_paths_to_be_removed
421     }
422
423     fn process_names_and_namerefs_for_import_resolve(
424         &mut self,
425         def: Definition,
426         node_syntax: &SyntaxNode,
427         curr_parent_module: &Option<ast::Module>,
428         ctx: &AssistContext,
429     ) -> Option<TextRange> {
430         //We only need to find in the current file
431         let selection_range = ctx.selection_trimmed();
432         let curr_file_id = ctx.file_id();
433         let search_scope = SearchScope::single_file(curr_file_id);
434         let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all();
435         let file = ctx.sema.parse(curr_file_id);
436
437         let mut exists_inside_sel = false;
438         let mut exists_outside_sel = false;
439         usage_res.clone().into_iter().for_each(|x| {
440             let mut non_use_nodes_itr = (&x.1).into_iter().filter_map(|x| {
441                 if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
442                     let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
443                     return path_opt;
444                 }
445
446                 None
447             });
448
449             if non_use_nodes_itr
450                 .clone()
451                 .find(|x| !selection_range.contains_range(x.syntax().text_range()))
452                 .is_some()
453             {
454                 exists_outside_sel = true;
455             }
456             if non_use_nodes_itr
457                 .find(|x| selection_range.contains_range(x.syntax().text_range()))
458                 .is_some()
459             {
460                 exists_inside_sel = true;
461             }
462         });
463
464         let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
465             def,
466             ctx,
467             curr_parent_module,
468             selection_range,
469             curr_file_id,
470         );
471
472         let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|x| {
473             let file_id = x.0;
474             let mut use_opt: Option<ast::Use> = None;
475             if file_id == curr_file_id {
476                 (&x.1).into_iter().for_each(|x| {
477                     let node_opt: Option<ast::Use> = find_node_at_range(file.syntax(), x.range);
478                     if let Some(node) = node_opt {
479                         use_opt = Some(node);
480                     }
481                 });
482             }
483             return use_opt;
484         });
485
486         let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
487         //Exists inside and outside selection
488         // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new
489         // module
490         // - Use stmt for item is not present ->
491         //If it is not found, the definition is either ported inside new module or it stays
492         //outside:
493         //- Def is inside: Nothing to import
494         //- Def is outside: Import it inside with super
495
496         //Exists inside selection but not outside -> Check for the import of it in original module,
497         //get the use_tree_str, reconstruct the use stmt in new module
498
499         let mut import_path_to_be_removed: Option<TextRange> = None;
500         if exists_inside_sel && exists_outside_sel {
501             //Changes to be made only inside new module
502
503             //If use_stmt exists, find the use_tree_str, reconstruct it inside new module
504             //If not, insert a use stmt with super and the given nameref
505             if let Some((use_tree_str, _)) =
506                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
507             {
508                 use_tree_str_opt = Some(use_tree_str);
509             } else if source_exists_outside_sel_in_same_mod {
510                 //Considered only after use_stmt is not present
511                 //source_exists_outside_sel_in_same_mod | exists_outside_sel(exists_inside_sel =
512                 //true for all cases)
513                 // false | false -> Do nothing
514                 // false | true -> If source is in selection -> nothing to do, If source is outside
515                 // mod -> ust_stmt transversal
516                 // true  | false -> super import insertion
517                 // true  | true -> super import insertion
518                 self.make_use_stmt_of_node_with_super(node_syntax);
519             }
520         } else if exists_inside_sel && !exists_outside_sel {
521             //Changes to be made inside new module, and remove import from outside
522
523             if let Some((use_tree_str, text_range_opt)) =
524                 self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
525             {
526                 if let Some(text_range) = text_range_opt {
527                     import_path_to_be_removed = Some(text_range);
528                 }
529                 use_tree_str_opt = Some(use_tree_str);
530             } else if source_exists_outside_sel_in_same_mod {
531                 self.make_use_stmt_of_node_with_super(node_syntax);
532             }
533         }
534
535         if let Some(use_tree_str) = use_tree_str_opt {
536             let mut use_tree_str = use_tree_str;
537             use_tree_str.reverse();
538             if use_tree_str[0].to_string().contains("super") {
539                 let super_path = make::ext::ident_path("super");
540                 use_tree_str.insert(0, super_path)
541             }
542
543             let use_ =
544                 make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
545             if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
546                 self.body_items.insert(0, item);
547             }
548         }
549
550         import_path_to_be_removed
551     }
552
553     fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) {
554         let super_path = make::ext::ident_path("super");
555         let node_path = make::ext::ident_path(&node_syntax.to_string());
556         let use_ = make::use_(
557             None,
558             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false),
559         );
560         if let Some(item) = ast::Item::cast(use_.syntax().clone()) {
561             self.body_items.insert(0, item);
562         }
563     }
564
565     fn process_use_stmt_for_import_resolve(
566         &self,
567         use_stmt_opt: Option<ast::Use>,
568         node_syntax: &SyntaxNode,
569     ) -> Option<(Vec<ast::Path>, Option<TextRange>)> {
570         if let Some(use_stmt) = use_stmt_opt {
571             for desc in use_stmt.syntax().descendants() {
572                 if let Some(path_seg) = ast::PathSegment::cast(desc) {
573                     if path_seg.syntax().to_string() == node_syntax.to_string() {
574                         let mut use_tree_str = vec![path_seg.parent_path()];
575                         get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
576                         for ancs in path_seg.syntax().ancestors() {
577                             //Here we are looking for use_tree with same string value as node
578                             //passed above as the range_to_remove function looks for a comma and
579                             //then includes it in the text range to remove it. But the comma only
580                             //appears at the use_tree level
581                             if let Some(use_tree) = ast::UseTree::cast(ancs) {
582                                 if use_tree.syntax().to_string() == node_syntax.to_string() {
583                                     return Some((
584                                         use_tree_str,
585                                         Some(range_to_remove(use_tree.syntax())),
586                                     ));
587                                 }
588                             }
589                         }
590
591                         return Some((use_tree_str, None));
592                     }
593                 }
594             }
595         }
596
597         None
598     }
599 }
600
601 fn does_source_exists_outside_sel_in_same_mod(
602     def: Definition,
603     ctx: &AssistContext,
604     curr_parent_module: &Option<ast::Module>,
605     selection_range: TextRange,
606     curr_file_id: FileId,
607 ) -> bool {
608     let mut source_exists_outside_sel_in_same_mod = false;
609     match def {
610         Definition::Module(x) => {
611             let source = x.definition_source(ctx.db());
612             let have_same_parent;
613             if let Some(ast_module) = &curr_parent_module {
614                 if let Some(hir_module) = x.parent(ctx.db()) {
615                     have_same_parent =
616                         compare_hir_and_ast_module(&ast_module, hir_module, ctx).is_some();
617                 } else {
618                     let source_file_id = source.file_id.original_file(ctx.db());
619                     have_same_parent = source_file_id == curr_file_id;
620                 }
621             } else {
622                 let source_file_id = source.file_id.original_file(ctx.db());
623                 have_same_parent = source_file_id == curr_file_id;
624             }
625
626             if have_same_parent {
627                 match source.value {
628                     ModuleSource::Module(module_) => {
629                         source_exists_outside_sel_in_same_mod =
630                             !selection_range.contains_range(module_.syntax().text_range());
631                     }
632                     _ => {}
633                 }
634             }
635         }
636         Definition::Function(x) => {
637             if let Some(source) = x.source(ctx.db()) {
638                 let have_same_parent;
639                 if let Some(ast_module) = &curr_parent_module {
640                     have_same_parent =
641                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
642                 } else {
643                     let source_file_id = source.file_id.original_file(ctx.db());
644                     have_same_parent = source_file_id == curr_file_id;
645                 }
646
647                 if have_same_parent {
648                     source_exists_outside_sel_in_same_mod =
649                         !selection_range.contains_range(source.value.syntax().text_range());
650                 }
651             }
652         }
653         Definition::Adt(x) => {
654             if let Some(source) = x.source(ctx.db()) {
655                 let have_same_parent;
656                 if let Some(ast_module) = &curr_parent_module {
657                     have_same_parent =
658                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
659                 } else {
660                     let source_file_id = source.file_id.original_file(ctx.db());
661                     have_same_parent = source_file_id == curr_file_id;
662                 }
663
664                 if have_same_parent {
665                     source_exists_outside_sel_in_same_mod =
666                         !selection_range.contains_range(source.value.syntax().text_range());
667                 }
668             }
669         }
670         Definition::Variant(x) => {
671             if let Some(source) = x.source(ctx.db()) {
672                 let have_same_parent;
673                 if let Some(ast_module) = &curr_parent_module {
674                     have_same_parent =
675                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
676                 } else {
677                     let source_file_id = source.file_id.original_file(ctx.db());
678                     have_same_parent = source_file_id == curr_file_id;
679                 }
680
681                 if have_same_parent {
682                     source_exists_outside_sel_in_same_mod =
683                         !selection_range.contains_range(source.value.syntax().text_range());
684                 }
685             }
686         }
687         Definition::Const(x) => {
688             if let Some(source) = x.source(ctx.db()) {
689                 let have_same_parent;
690                 if let Some(ast_module) = &curr_parent_module {
691                     have_same_parent =
692                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
693                 } else {
694                     let source_file_id = source.file_id.original_file(ctx.db());
695                     have_same_parent = source_file_id == curr_file_id;
696                 }
697
698                 if have_same_parent {
699                     source_exists_outside_sel_in_same_mod =
700                         !selection_range.contains_range(source.value.syntax().text_range());
701                 }
702             }
703         }
704         Definition::Static(x) => {
705             if let Some(source) = x.source(ctx.db()) {
706                 let have_same_parent;
707                 if let Some(ast_module) = &curr_parent_module {
708                     have_same_parent =
709                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
710                 } else {
711                     let source_file_id = source.file_id.original_file(ctx.db());
712                     have_same_parent = source_file_id == curr_file_id;
713                 }
714
715                 if have_same_parent {
716                     source_exists_outside_sel_in_same_mod =
717                         !selection_range.contains_range(source.value.syntax().text_range());
718                 }
719             }
720         }
721         Definition::Trait(x) => {
722             if let Some(source) = x.source(ctx.db()) {
723                 let have_same_parent;
724                 if let Some(ast_module) = &curr_parent_module {
725                     have_same_parent =
726                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
727                 } else {
728                     let source_file_id = source.file_id.original_file(ctx.db());
729                     have_same_parent = source_file_id == curr_file_id;
730                 }
731
732                 if have_same_parent {
733                     source_exists_outside_sel_in_same_mod =
734                         !selection_range.contains_range(source.value.syntax().text_range());
735                 }
736             }
737         }
738         Definition::TypeAlias(x) => {
739             if let Some(source) = x.source(ctx.db()) {
740                 let have_same_parent;
741                 if let Some(ast_module) = &curr_parent_module {
742                     have_same_parent =
743                         compare_hir_and_ast_module(&ast_module, x.module(ctx.db()), ctx).is_some();
744                 } else {
745                     let source_file_id = source.file_id.original_file(ctx.db());
746                     have_same_parent = source_file_id == curr_file_id;
747                 }
748
749                 if have_same_parent {
750                     source_exists_outside_sel_in_same_mod =
751                         !selection_range.contains_range(source.value.syntax().text_range());
752                 }
753             }
754         }
755         _ => {}
756     }
757
758     return source_exists_outside_sel_in_same_mod;
759 }
760
761 fn get_replacements_for_visibilty_change(
762     items: Vec<ast::Item>,
763     is_clone_for_updated: bool,
764 ) -> (
765     Vec<ast::Item>,
766     Vec<(Option<ast::Visibility>, SyntaxNode)>,
767     Vec<(Option<ast::Visibility>, SyntaxNode)>,
768     Vec<ast::Impl>,
769 ) {
770     let mut replacements = Vec::new();
771     let mut record_field_parents = Vec::new();
772     let mut impls = Vec::new();
773     let mut body_items = Vec::new();
774
775     items.into_iter().for_each(|item| {
776         let mut item = item;
777         if !is_clone_for_updated {
778             item = item.clone_for_update();
779         }
780         body_items.push(item.clone());
781         //Use stmts are ignored
782         match item {
783             ast::Item::Const(it) => replacements.push((it.visibility(), it.syntax().clone())),
784             ast::Item::Enum(it) => replacements.push((it.visibility(), it.syntax().clone())),
785             ast::Item::ExternCrate(it) => replacements.push((it.visibility(), it.syntax().clone())),
786             ast::Item::Fn(it) => replacements.push((it.visibility(), it.syntax().clone())),
787             //Associated item's visibility should not be changed
788             ast::Item::Impl(it) if it.for_token().is_none() => impls.push(it),
789             ast::Item::MacroDef(it) => replacements.push((it.visibility(), it.syntax().clone())),
790             ast::Item::Module(it) => replacements.push((it.visibility(), it.syntax().clone())),
791             ast::Item::Static(it) => replacements.push((it.visibility(), it.syntax().clone())),
792             ast::Item::Struct(it) => {
793                 replacements.push((it.visibility(), it.syntax().clone()));
794                 record_field_parents.push((it.visibility(), it.syntax().clone()));
795             }
796             ast::Item::Trait(it) => replacements.push((it.visibility(), it.syntax().clone())),
797             ast::Item::TypeAlias(it) => replacements.push((it.visibility(), it.syntax().clone())),
798             ast::Item::Union(it) => {
799                 replacements.push((it.visibility(), it.syntax().clone()));
800                 record_field_parents.push((it.visibility(), it.syntax().clone()));
801             }
802             _ => (),
803         }
804     });
805
806     return (body_items, replacements, record_field_parents, impls);
807 }
808
809 fn get_use_tree_paths_from_path(
810     path: ast::Path,
811     use_tree_str: &mut Vec<ast::Path>,
812 ) -> Option<&mut Vec<ast::Path>> {
813     path.syntax().ancestors().filter(|x| x.to_string() != path.to_string()).find_map(|x| {
814         if let Some(use_tree) = ast::UseTree::cast(x) {
815             if let Some(upper_tree_path) = use_tree.path() {
816                 if upper_tree_path.to_string() != path.to_string() {
817                     use_tree_str.push(upper_tree_path.clone());
818                     get_use_tree_paths_from_path(upper_tree_path, use_tree_str);
819                     return Some(use_tree);
820                 }
821             }
822         }
823         None
824     })?;
825
826     Some(use_tree_str)
827 }
828
829 fn add_change_vis(
830     vis: Option<ast::Visibility>,
831     node_or_token_opt: Option<syntax::SyntaxElement>,
832 ) -> Option<()> {
833     if let None = vis {
834         if let Some(node_or_token) = node_or_token_opt {
835             let pub_crate_vis = make::visibility_pub_crate().clone_for_update();
836             if let Some(node) = node_or_token.as_node() {
837                 ted::insert(ted::Position::before(node), pub_crate_vis.syntax());
838             }
839             if let Some(token) = node_or_token.as_token() {
840                 ted::insert(ted::Position::before(token), pub_crate_vis.syntax());
841             }
842         }
843     }
844
845     Some(())
846 }
847
848 fn compare_hir_and_ast_module(
849     ast_module: &ast::Module,
850     hir_module: hir::Module,
851     ctx: &AssistContext,
852 ) -> Option<()> {
853     let hir_mod_name = hir_module.name(ctx.db())?;
854     let ast_mod_name = ast_module.name()?;
855     if hir_mod_name.to_string() != ast_mod_name.to_string() {
856         return None;
857     }
858
859     return Some(());
860 }
861
862 #[cfg(test)]
863 mod tests {
864     use crate::tests::{check_assist, check_assist_not_applicable};
865
866     use super::*;
867
868     #[test]
869     fn test_not_applicable_without_selection() {
870         check_assist_not_applicable(
871             extract_module,
872             r"
873 $0pub struct PublicStruct {
874     field: i32,
875 }
876             ",
877         )
878     }
879
880     #[test]
881     fn test_extract_module() {
882         check_assist(
883             extract_module,
884             r"
885             mod thirdpartycrate {
886                 pub mod nest {
887                     pub struct SomeType;
888                     pub struct SomeType2;
889                 }
890                 pub struct SomeType1;
891             }
892
893             mod bar {
894                 use crate::thirdpartycrate::{nest::{SomeType, SomeType2}, SomeType1};
895
896                 pub struct PublicStruct {
897                     field: PrivateStruct,
898                     field1: SomeType1,
899                 }
900
901                 impl PublicStruct {
902                     pub fn new() -> Self {
903                         Self { field: PrivateStruct::new(), field1: SomeType1 }
904                     }
905                 }
906
907                 fn foo() {
908                     let _s = PrivateStruct::new();
909                     let _a = bar();
910                 }
911
912 $0struct PrivateStruct {
913     inner: SomeType,
914 }
915
916 pub struct PrivateStruct1 {
917     pub inner: i32,
918 }
919
920 impl PrivateStruct {
921     fn new() -> Self {
922          PrivateStruct { inner: SomeType }
923     }
924 }
925
926 fn bar() -> i32 {
927     2
928 }$0
929             }
930             ",
931             r"
932             mod thirdpartycrate {
933                 pub mod nest {
934                     pub struct SomeType;
935                     pub struct SomeType2;
936                 }
937                 pub struct SomeType1;
938             }
939
940             mod bar {
941                 use crate::thirdpartycrate::{nest::{SomeType2}, SomeType1};
942
943                 pub struct PublicStruct {
944                     field: modname::PrivateStruct,
945                     field1: SomeType1,
946                 }
947
948                 impl PublicStruct {
949                     pub fn new() -> Self {
950                         Self { field: modname::PrivateStruct::new(), field1: SomeType1 }
951                     }
952                 }
953
954                 fn foo() {
955                     let _s = modname::PrivateStruct::new();
956                     let _a = modname::bar();
957                 }
958
959 mod modname {
960     use crate::thirdpartycrate::nest::SomeType;
961
962     pub(crate) struct PrivateStruct {
963         pub(crate) inner: SomeType,
964     }
965
966     pub struct PrivateStruct1 {
967         pub inner: i32,
968     }
969
970     impl PrivateStruct {
971         pub(crate) fn new() -> Self {
972              PrivateStruct { inner: SomeType }
973         }
974     }
975
976     pub(crate) fn bar() -> i32 {
977         2
978     }
979 }
980             }
981             ",
982         );
983     }
984
985     #[test]
986     fn test_extract_module_for_function_only() {
987         check_assist(
988             extract_module,
989             r"
990 $0fn foo(name: i32) -> i32 {
991     name + 1
992 }$0
993
994                 fn bar(name: i32) -> i32 {
995                     name + 2
996                 }
997             ",
998             r"
999 mod modname {
1000     pub(crate) fn foo(name: i32) -> i32 {
1001         name + 1
1002     }
1003 }
1004
1005                 fn bar(name: i32) -> i32 {
1006                     name + 2
1007                 }
1008             ",
1009         )
1010     }
1011
1012     #[test]
1013     fn test_extract_module_for_impl_having_corresponding_adt_in_selection() {
1014         check_assist(
1015             extract_module,
1016             r"
1017             mod impl_play {
1018 $0struct A {}
1019
1020 impl A {
1021     pub fn new_a() -> i32 {
1022         2
1023     }
1024 }$0
1025
1026                 fn a() {
1027                     let _a = A::new_a();
1028                 }
1029             }
1030             ",
1031             r"
1032             mod impl_play {
1033 mod modname {
1034     pub(crate) struct A {}
1035
1036     impl A {
1037         pub fn new_a() -> i32 {
1038             2
1039         }
1040     }
1041 }
1042
1043                 fn a() {
1044                     let _a = modname::A::new_a();
1045                 }
1046             }
1047             ",
1048         )
1049     }
1050
1051     #[test]
1052     fn test_import_resolve_when_its_only_inside_selection() {
1053         check_assist(
1054             extract_module,
1055             r"
1056             mod foo {
1057                 pub struct PrivateStruct;
1058                 pub struct PrivateStruct1;
1059             }
1060
1061             mod bar {
1062                 use super::foo::{PrivateStruct, PrivateStruct1};
1063
1064 $0struct Strukt {
1065     field: PrivateStruct,
1066 }$0
1067
1068                 struct Strukt1 {
1069                     field: PrivateStruct1,
1070                 }
1071             }
1072             ",
1073             r"
1074             mod foo {
1075                 pub struct PrivateStruct;
1076                 pub struct PrivateStruct1;
1077             }
1078
1079             mod bar {
1080                 use super::foo::{PrivateStruct1};
1081
1082 mod modname {
1083     use super::super::foo::PrivateStruct;
1084
1085     pub(crate) struct Strukt {
1086         pub(crate) field: PrivateStruct,
1087     }
1088 }
1089
1090                 struct Strukt1 {
1091                     field: PrivateStruct1,
1092                 }
1093             }
1094             ",
1095         )
1096     }
1097
1098     #[test]
1099     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_not_in_same_mod() {
1100         check_assist(
1101             extract_module,
1102             r"
1103             mod foo {
1104                 pub struct PrivateStruct;
1105             }
1106
1107             mod bar {
1108                 use super::foo::PrivateStruct;
1109
1110 $0struct Strukt {
1111     field: PrivateStruct,
1112 }$0
1113
1114                 struct Strukt1 {
1115                     field: PrivateStruct,
1116                 }
1117             }
1118             ",
1119             r"
1120             mod foo {
1121                 pub struct PrivateStruct;
1122             }
1123
1124             mod bar {
1125                 use super::foo::PrivateStruct;
1126
1127 mod modname {
1128     use super::super::foo::PrivateStruct;
1129
1130     pub(crate) struct Strukt {
1131         pub(crate) field: PrivateStruct,
1132     }
1133 }
1134
1135                 struct Strukt1 {
1136                     field: PrivateStruct,
1137                 }
1138             }
1139             ",
1140         )
1141     }
1142
1143     #[test]
1144     fn test_import_resolve_when_its_inside_and_outside_selection_and_source_is_in_same_mod() {
1145         check_assist(
1146             extract_module,
1147             r"
1148             mod bar {
1149                 pub struct PrivateStruct;
1150
1151 $0struct Strukt {
1152    field: PrivateStruct,
1153 }$0
1154
1155                 struct Strukt1 {
1156                     field: PrivateStruct,
1157                 }
1158             }
1159             ",
1160             r"
1161             mod bar {
1162                 pub struct PrivateStruct;
1163
1164 mod modname {
1165     use super::PrivateStruct;
1166
1167     pub(crate) struct Strukt {
1168        pub(crate) field: PrivateStruct,
1169     }
1170 }
1171
1172                 struct Strukt1 {
1173                     field: PrivateStruct,
1174                 }
1175             }
1176             ",
1177         )
1178     }
1179
1180     #[test]
1181     fn test_extract_module_for_correspoding_adt_of_impl_present_in_same_mod_but_not_in_selection() {
1182         check_assist(
1183             extract_module,
1184             r"
1185             mod impl_play {
1186                 struct A {}
1187
1188 $0impl A {
1189     pub fn new_a() -> i32 {
1190         2
1191     }
1192 }$0
1193
1194                 fn a() {
1195                     let _a = A::new_a();
1196                 }
1197             }
1198             ",
1199             r"
1200             mod impl_play {
1201                 struct A {}
1202
1203 mod modname {
1204     use super::A;
1205
1206     impl A {
1207         pub fn new_a() -> i32 {
1208             2
1209         }
1210     }
1211 }
1212
1213                 fn a() {
1214                     let _a = A::new_a();
1215                 }
1216             }
1217             ",
1218         )
1219     }
1220
1221     #[test]
1222     fn test_extract_module_for_impl_not_having_corresponding_adt_in_selection_and_not_in_same_mod_but_with_super(
1223     ) {
1224         check_assist(
1225             extract_module,
1226             r"
1227             mod foo {
1228                 pub struct A {}
1229             }
1230             mod impl_play {
1231                 use super::foo::A;
1232
1233 $0impl A {
1234     pub fn new_a() -> i32 {
1235         2
1236     }
1237 }$0
1238
1239                 fn a() {
1240                     let _a = A::new_a();
1241                 }
1242             }
1243             ",
1244             r"
1245             mod foo {
1246                 pub struct A {}
1247             }
1248             mod impl_play {
1249                 use super::foo::A;
1250
1251 mod modname {
1252     use super::super::foo::A;
1253
1254     impl A {
1255         pub fn new_a() -> i32 {
1256             2
1257         }
1258     }
1259 }
1260
1261                 fn a() {
1262                     let _a = A::new_a();
1263                 }
1264             }
1265             ",
1266         )
1267     }
1268
1269     #[test]
1270     fn test_import_resolve_for_trait_bounds_on_function() {
1271         check_assist(
1272             extract_module,
1273             r"
1274             mod impl_play2 {
1275                 trait JustATrait {}
1276
1277 $0struct A {}
1278
1279 fn foo<T: JustATrait>(arg: T) -> T {
1280     arg
1281 }
1282
1283 impl JustATrait for A {}
1284
1285 fn bar() {
1286     let a = A {};
1287     foo(a);
1288 }$0
1289             }
1290             ",
1291             r"
1292             mod impl_play2 {
1293                 trait JustATrait {}
1294
1295 mod modname {
1296     use super::JustATrait;
1297
1298     pub(crate) struct A {}
1299
1300     pub(crate) fn foo<T: JustATrait>(arg: T) -> T {
1301         arg
1302     }
1303
1304     impl JustATrait for A {}
1305
1306     pub(crate) fn bar() {
1307         let a = A {};
1308         foo(a);
1309     }
1310 }
1311             }
1312             ",
1313         )
1314     }
1315
1316     #[test]
1317     fn test_extract_module_for_module() {
1318         check_assist(
1319             extract_module,
1320             r"
1321             mod impl_play2 {
1322 $0mod impl_play {
1323     pub struct A {}
1324 }$0
1325             }
1326             ",
1327             r"
1328             mod impl_play2 {
1329 mod modname {
1330     pub(crate) mod impl_play {
1331         pub struct A {}
1332     }
1333 }
1334             }
1335             ",
1336         )
1337     }
1338
1339     #[test]
1340     fn test_extract_module_with_multiple_files() {
1341         check_assist(
1342             extract_module,
1343             r"
1344             //- /main.rs
1345             mod foo;
1346
1347             use foo::PrivateStruct;
1348
1349             pub struct Strukt {
1350                 field: PrivateStruct,
1351             }
1352
1353             fn main() {
1354                 $0struct Strukt1 {
1355                     field: Strukt,
1356                 }$0
1357             }
1358             //- /foo.rs
1359             pub struct PrivateStruct;
1360             ",
1361             r"
1362             mod foo;
1363
1364             use foo::PrivateStruct;
1365
1366             pub struct Strukt {
1367                 field: PrivateStruct,
1368             }
1369
1370             fn main() {
1371                 mod modname {
1372                     use super::Strukt;
1373
1374                     pub(crate) struct Strukt1 {
1375                         pub(crate) field: Strukt,
1376                     }
1377                 }
1378             }
1379             ",
1380         )
1381     }
1382
1383     #[test]
1384     fn test_extract_module_macro_rules() {
1385         check_assist(
1386             extract_module,
1387             r"
1388 $0macro_rules! m {
1389     () => {};
1390 }$0
1391 m! {}
1392             ",
1393             r"
1394 mod modname {
1395     macro_rules! m {
1396         () => {};
1397     }
1398 }
1399 modname::m! {}
1400             ",
1401         );
1402     }
1403
1404     #[test]
1405     fn test_do_not_apply_visibility_modifier_to_trait_impl_items() {
1406         check_assist(
1407             extract_module,
1408             r"
1409             trait ATrait {
1410                 fn function();
1411             }
1412
1413             struct A {}
1414
1415 $0impl ATrait for A {
1416     fn function() {}
1417 }$0
1418             ",
1419             r"
1420             trait ATrait {
1421                 fn function();
1422             }
1423
1424             struct A {}
1425
1426 mod modname {
1427     use super::A;
1428
1429     use super::ATrait;
1430
1431     impl ATrait for A {
1432         fn function() {}
1433     }
1434 }
1435             ",
1436         )
1437     }
1438 }