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