11use  std:: iter; 
22
3+ use  either:: Either ; 
34use  hir:: { HasSource ,  HirFileIdExt ,  ModuleSource } ; 
45use  ide_db:: { 
56 assists:: { AssistId ,  AssistKind } , 
@@ -10,15 +11,14 @@ use ide_db::{
1011} ; 
1112use  itertools:: Itertools ; 
1213use  smallvec:: SmallVec ; 
13- use  stdx:: format_to; 
1414use  syntax:: { 
1515 algo:: find_node_at_range, 
1616 ast:: { 
1717 self , 
1818 edit:: { AstNodeEdit ,  IndentLevel } , 
1919 make,  HasVisibility , 
2020 } , 
21-  match_ast,  ted,  AstNode ,   SourceFile , 
21+  match_ast,  ted,  AstNode , 
2222 SyntaxKind :: { self ,  WHITESPACE } , 
2323 SyntaxNode ,  TextRange , 
2424} ; 
@@ -114,63 +114,23 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
114114 let  import_paths_to_be_removed = module. resolve_imports ( curr_parent_module,  ctx) ; 
115115 module. change_visibility ( record_fields) ; 
116116
117-  let  mut  body_items:  Vec < String >  = Vec :: new ( ) ; 
118-  let  mut  items_to_be_processed:  Vec < ast:: Item >  = module. body_items . clone ( ) ; 
117+  let  module_def = generate_module_def ( & impl_parent,  & mut  module,  old_item_indent) ; 
119118
120-  let  new_item_indent = if  impl_parent. is_some ( )  { 
121-  old_item_indent + 2 
122-  }  else  { 
123-  items_to_be_processed = [ module. use_items . clone ( ) ,  items_to_be_processed] . concat ( ) ; 
124-  old_item_indent + 1 
125-  } ; 
126- 
127-  for  item in  items_to_be_processed { 
128-  let  item = item. indent ( IndentLevel ( 1 ) ) ; 
129-  let  mut  indented_item = String :: new ( ) ; 
130-  format_to ! ( indented_item,  "{new_item_indent}{item}" ) ; 
131-  body_items. push ( indented_item) ; 
132-  } 
133- 
134-  let  mut  body = body_items. join ( "\n \n " ) ; 
135- 
136-  if  let  Some ( impl_)  = & impl_parent { 
137-  if  let  Some ( self_ty)  = impl_. self_ty ( )  { 
138-  let  impl_indent = old_item_indent + 1 ; 
139-  let  mut  impl_body_def = String :: new ( ) ; 
140-  format_to ! ( 
141-  impl_body_def, 
142-  "{impl_indent}impl {self_ty} {{\n {body}\n {impl_indent}}}" , 
143-  ) ; 
144-  body = impl_body_def; 
145- 
146-  // Add the import for enum/struct corresponding to given impl block 
147-  module. make_use_stmt_of_node_with_super ( self_ty. syntax ( ) ) ; 
148-  for  item in  module. use_items  { 
149-  let  item_indent = old_item_indent + 1 ; 
150-  body = format ! ( "{item_indent}{item}\n \n {body}" ) ; 
151-  } 
152-  } 
153-  } 
154- 
155-  let  mut  module_def = String :: new ( ) ; 
156-  let  module_name = module. name ; 
157-  format_to ! ( module_def,  "mod {module_name} {{\n {body}\n {old_item_indent}}}" ) ; 
158- 
159-  let  mut  usages_to_be_updated_for_curr_file = vec ! [ ] ; 
160-  for  usages_to_be_updated_for_file in  usages_to_be_processed { 
161-  if  usages_to_be_updated_for_file. 0  == ctx. file_id ( )  { 
162-  usages_to_be_updated_for_curr_file = usages_to_be_updated_for_file. 1 ; 
119+  let  mut  usages_to_be_processed_for_cur_file = vec ! [ ] ; 
120+  for  ( file_id,  usages)  in  usages_to_be_processed { 
121+  if  file_id == ctx. file_id ( )  { 
122+  usages_to_be_processed_for_cur_file = usages; 
163123 continue ; 
164124 } 
165-  builder. edit_file ( usages_to_be_updated_for_file . 0 ) ; 
166-  for  usage_to_be_processed  in  usages_to_be_updated_for_file . 1  { 
167-  builder. replace ( usage_to_be_processed . 0 ,  usage_to_be_processed . 1 ) 
125+  builder. edit_file ( file_id ) ; 
126+  for  ( text_range ,  usage )   in  usages  { 
127+  builder. replace ( text_range ,  usage ) 
168128 } 
169129 } 
170130
171131 builder. edit_file ( ctx. file_id ( ) ) ; 
172-  for  usage_to_be_processed  in  usages_to_be_updated_for_curr_file  { 
173-  builder. replace ( usage_to_be_processed . 0 ,  usage_to_be_processed . 1 ) 
132+  for  ( text_range ,  usage )   in  usages_to_be_processed_for_cur_file  { 
133+  builder. replace ( text_range ,  usage ) ; 
174134 } 
175135
176136 if  let  Some ( impl_)  = impl_parent { 
@@ -205,6 +165,37 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
205165 ) 
206166} 
207167
168+ fn  generate_module_def ( 
169+  parent_impl :  & Option < ast:: Impl > , 
170+  module :  & mut  Module , 
171+  old_indent :  IndentLevel , 
172+ )  -> String  { 
173+  let  ( items_to_be_processed,  new_item_indent)  = if  parent_impl. is_some ( )  { 
174+  ( Either :: Left ( module. body_items . iter ( ) ) ,  old_indent + 2 ) 
175+  }  else  { 
176+  ( Either :: Right ( module. use_items . iter ( ) . chain ( module. body_items . iter ( ) ) ) ,  old_indent + 1 ) 
177+  } ; 
178+ 
179+  let  mut  body = items_to_be_processed
180+  . map ( |item| item. indent ( IndentLevel ( 1 ) ) ) 
181+  . map ( |item| format ! ( "{new_item_indent}{item}" ) ) 
182+  . join ( "\n \n " ) ; 
183+ 
184+  if  let  Some ( self_ty)  = parent_impl. as_ref ( ) . and_then ( |imp| imp. self_ty ( ) )  { 
185+  let  impl_indent = old_indent + 1 ; 
186+  body = format ! ( "{impl_indent}impl {self_ty} {{\n {body}\n {impl_indent}}}" ) ; 
187+ 
188+  // Add the import for enum/struct corresponding to given impl block 
189+  module. make_use_stmt_of_node_with_super ( self_ty. syntax ( ) ) ; 
190+  for  item in  module. use_items . iter ( )  { 
191+  body = format ! ( "{impl_indent}{item}\n \n {body}" ) ; 
192+  } 
193+  } 
194+ 
195+  let  module_name = module. name ; 
196+  format ! ( "mod {module_name} {{\n {body}\n {old_indent}}}" ) 
197+ } 
198+ 
208199#[ derive( Debug ) ]  
209200struct  Module  { 
210201 text_range :  TextRange , 
@@ -240,6 +231,7 @@ impl Module {
240231 //Here impl is not included as each item inside impl will be tied to the parent of 
241232 //implementing block(a struct, enum, etc), if the parent is in selected module, it will 
242233 //get updated by ADT section given below or if it is not, then we dont need to do any operation 
234+ 
243235 for  item in  & self . body_items  { 
244236 match_ast !  { 
245237 match  ( item. syntax( ) )  { 
@@ -320,48 +312,38 @@ impl Module {
320312 node_def :  Definition , 
321313 refs_in_files :  & mut  FxHashMap < FileId ,  Vec < ( TextRange ,  String ) > > , 
322314 )  { 
323-  for  ( file_id,  references)  in  node_def. usages ( & ctx. sema ) . all ( )  { 
315+  let  mod_name = self . name ; 
316+  let  out_of_sel = |node :  & SyntaxNode | !self . text_range . contains_range ( node. text_range ( ) ) ; 
317+  for  ( file_id,  refs)  in  node_def. usages ( & ctx. sema ) . all ( )  { 
324318 let  source_file = ctx. sema . parse ( file_id) ; 
325-  let  usages_in_file = references
326-  . into_iter ( ) 
327-  . filter_map ( |usage| self . get_usage_to_be_processed ( & source_file,  usage) ) ; 
328-  refs_in_files. entry ( file_id) . or_default ( ) . extend ( usages_in_file) ; 
329-  } 
330-  } 
331- 
332-  fn  get_usage_to_be_processed ( 
333-  & self , 
334-  source_file :  & SourceFile , 
335-  FileReference  {  range,  name,  .. } :  FileReference , 
336-  )  -> Option < ( TextRange ,  String ) >  { 
337-  let  path:  ast:: Path  = find_node_at_range ( source_file. syntax ( ) ,  range) ?; 
338- 
339-  for  desc in  path. syntax ( ) . descendants ( )  { 
340-  if  desc. to_string ( )  == name. syntax ( ) . to_string ( ) 
341-  && !self . text_range . contains_range ( desc. text_range ( ) ) 
342-  { 
343-  if  let  Some ( name_ref)  = ast:: NameRef :: cast ( desc)  { 
344-  let  mod_name = self . name ; 
345-  return  Some ( ( 
346-  name_ref. syntax ( ) . text_range ( ) , 
347-  format ! ( "{mod_name}::{name_ref}" ) , 
348-  ) ) ; 
319+  let  usages = refs. into_iter ( ) . filter_map ( |FileReference  {  range,  name,  .. } | { 
320+  let  path:  ast:: Path  = find_node_at_range ( source_file. syntax ( ) ,  range) ?; 
321+  let  name = name. syntax ( ) . to_string ( ) ; 
322+ 
323+  for  desc in  path. syntax ( ) . descendants ( )  { 
324+  if  desc. to_string ( )  == name && out_of_sel ( & desc)  { 
325+  if  let  Some ( name_ref)  = ast:: NameRef :: cast ( desc)  { 
326+  let  new_ref = format ! ( "{mod_name}::{name_ref}" ) ; 
327+  return  Some ( ( name_ref. syntax ( ) . text_range ( ) ,  new_ref) ) ; 
328+  } 
329+  } 
349330 } 
350-  } 
351-  } 
352331
353-  None 
332+  None 
333+  } ) ; 
334+  refs_in_files. entry ( file_id) . or_default ( ) . extend ( usages) ; 
335+  } 
354336 } 
355337
356338 fn  change_visibility ( & mut  self ,  record_fields :  Vec < SyntaxNode > )  { 
357339 let  ( mut  replacements,  record_field_parents,  impls)  =
358340 get_replacements_for_visibility_change ( & mut  self . body_items ,  false ) ; 
359341
360-  let  mut  impl_items:   Vec < ast :: Item >  = impls
342+  let  mut  impl_items = impls
361343 . into_iter ( ) 
362344 . flat_map ( |impl_| impl_. syntax ( ) . descendants ( ) ) 
363345 . filter_map ( ast:: Item :: cast) 
364-  . collect ( ) ; 
346+  . collect_vec ( ) ; 
365347
366348 let  ( mut  impl_item_replacements,  _,  _)  =
367349 get_replacements_for_visibility_change ( & mut  impl_items,  true ) ; 
@@ -444,19 +426,19 @@ impl Module {
444426 let  file = ctx. sema . parse ( file_id) ; 
445427
446428 // track uses which does not exists in `Use` 
447-  let  mut  exists_inside_sel  = false ; 
448-  let  mut  exists_outside_sel  = false ; 
429+  let  mut  uses_exist_in_sel  = false ; 
430+  let  mut  uses_exist_out_sel  = false ; 
449431 ' outside:  for  ( _,  refs)  in  usage_res. iter ( )  { 
450432 for  x in  refs
451433 . iter ( ) 
452434 . filter ( |x| find_node_at_range :: < ast:: Use > ( file. syntax ( ) ,  x. range ) . is_none ( ) ) 
453435 . filter_map ( |x| find_node_at_range :: < ast:: Path > ( file. syntax ( ) ,  x. range ) ) 
454436 { 
455437 let  in_selectin = selection_range. contains_range ( x. syntax ( ) . text_range ( ) ) ; 
456-  exists_inside_sel  |= in_selectin; 
457-  exists_outside_sel  |= !in_selectin; 
438+  uses_exist_in_sel  |= in_selectin; 
439+  uses_exist_out_sel  |= !in_selectin; 
458440
459-  if  exists_inside_sel  && exists_outside_sel  { 
441+  if  uses_exist_in_sel  && uses_exist_out_sel  { 
460442 break  ' outside; 
461443 } 
462444 } 
@@ -475,7 +457,7 @@ impl Module {
475457 !selection_range. contains_range ( use_stmt. syntax ( ) . text_range ( ) ) 
476458 } ) ; 
477459
478-  let  mut  use_tree_str_opt :  Option < Vec < ast:: Path > >  = None ; 
460+  let  mut  use_tree_paths :  Option < Vec < ast:: Path > >  = None ; 
479461 //Exists inside and outside selection 
480462 // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new 
481463 // module 
@@ -489,13 +471,13 @@ impl Module {
489471 //get the use_tree_str, reconstruct the use stmt in new module 
490472
491473 let  mut  import_path_to_be_removed:  Option < TextRange >  = None ; 
492-  if  exists_inside_sel  && exists_outside_sel  { 
474+  if  uses_exist_in_sel  && uses_exist_out_sel  { 
493475 //Changes to be made only inside new module 
494476
495477 //If use_stmt exists, find the use_tree_str, reconstruct it inside new module 
496478 //If not, insert a use stmt with super and the given nameref 
497479 match  self . process_use_stmt_for_import_resolve ( use_stmt,  use_node)  { 
498-  Some ( ( use_tree_str,  _) )  => use_tree_str_opt  = Some ( use_tree_str) , 
480+  Some ( ( use_tree_str,  _) )  => use_tree_paths  = Some ( use_tree_str) , 
499481 None  if  def_in_mod && def_out_sel => { 
500482 //Considered only after use_stmt is not present 
501483 //def_in_mod && def_out_sel | exists_outside_sel(exists_inside_sel = 
@@ -509,7 +491,7 @@ impl Module {
509491 } 
510492 None  => { } 
511493 } 
512-  }  else  if  exists_inside_sel  && !exists_outside_sel  { 
494+  }  else  if  uses_exist_in_sel  && !uses_exist_out_sel  { 
513495 //Changes to be made inside new module, and remove import from outside 
514496
515497 if  let  Some ( ( mut  use_tree_str,  text_range_opt) )  =
@@ -531,43 +513,42 @@ impl Module {
531513 } 
532514 } 
533515
534-  use_tree_str_opt  = Some ( use_tree_str) ; 
516+  use_tree_paths  = Some ( use_tree_str) ; 
535517 }  else  if  def_in_mod && def_out_sel { 
536518 self . make_use_stmt_of_node_with_super ( use_node) ; 
537519 } 
538520 } 
539521
540-  if  let  Some ( use_tree_str)  = use_tree_str_opt { 
541-  let  mut  use_tree_str = use_tree_str; 
542-  use_tree_str. reverse ( ) ; 
522+  if  let  Some ( mut  use_tree_paths)  = use_tree_paths { 
523+  use_tree_paths. reverse ( ) ; 
543524
544-  if  exists_outside_sel  || !exists_inside_sel  || !def_in_mod || !def_out_sel { 
545-  if  let  Some ( first_path_in_use_tree)  = use_tree_str . first ( )  { 
525+  if  uses_exist_out_sel  || !uses_exist_in_sel  || !def_in_mod || !def_out_sel { 
526+  if  let  Some ( first_path_in_use_tree)  = use_tree_paths . first ( )  { 
546527 if  first_path_in_use_tree. to_string ( ) . contains ( "super" )  { 
547-  use_tree_str . insert ( 0 ,  make:: ext:: ident_path ( "super" ) ) ; 
528+  use_tree_paths . insert ( 0 ,  make:: ext:: ident_path ( "super" ) ) ; 
548529 } 
549530 } 
550531 } 
551532
552-  let  use_ =
553-  make:: use_ ( None ,  make:: use_tree ( make:: join_paths ( use_tree_str) ,  None ,  None ,  false ) ) ; 
554-  let  item = ast:: Item :: from ( use_) ; 
555- 
556-  let  is_item = match  def { 
557-  Definition :: Macro ( _)  => true , 
558-  Definition :: Module ( _)  => true , 
559-  Definition :: Function ( _)  => true , 
560-  Definition :: Adt ( _)  => true , 
561-  Definition :: Const ( _)  => true , 
562-  Definition :: Static ( _)  => true , 
563-  Definition :: Trait ( _)  => true , 
564-  Definition :: TraitAlias ( _)  => true , 
565-  Definition :: TypeAlias ( _)  => true , 
566-  _ => false , 
567-  } ; 
533+  let  is_item = matches ! ( 
534+  def, 
535+  Definition :: Macro ( _) 
536+  | Definition :: Module ( _) 
537+  | Definition :: Function ( _) 
538+  | Definition :: Adt ( _) 
539+  | Definition :: Const ( _) 
540+  | Definition :: Static ( _) 
541+  | Definition :: Trait ( _) 
542+  | Definition :: TraitAlias ( _) 
543+  | Definition :: TypeAlias ( _) 
544+  ) ; 
568545
569546 if  ( def_out_sel || !is_item)  && use_stmt_not_in_sel { 
570-  self . use_items . insert ( 0 ,  item. clone ( ) ) ; 
547+  let  use_ = make:: use_ ( 
548+  None , 
549+  make:: use_tree ( make:: join_paths ( use_tree_paths) ,  None ,  None ,  false ) , 
550+  ) ; 
551+  self . use_items . insert ( 0 ,  ast:: Item :: from ( use_) ) ; 
571552 } 
572553 } 
573554
0 commit comments