@@ -20,7 +20,7 @@ use syntax::{
2020 } ,
2121 match_ast, ted, AstNode ,
2222 SyntaxKind :: { self , WHITESPACE } ,
23- SyntaxNode , TextRange ,
23+ SyntaxNode , TextRange , TextSize ,
2424} ;
2525
2626use crate :: { AssistContext , Assists } ;
@@ -109,7 +109,14 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
109109
110110 //We are getting item usages and record_fields together, record_fields
111111 //for change_visibility and usages for first point mentioned above in the process
112- let ( usages_to_be_processed, record_fields) = module. get_usages_and_record_fields ( ctx) ;
112+
113+ let ( usages_to_be_processed, record_fields, use_stmts_to_be_inserted) =
114+ module. get_usages_and_record_fields ( ctx) ;
115+
116+ builder. edit_file ( ctx. file_id ( ) ) ;
117+ use_stmts_to_be_inserted. into_iter ( ) . for_each ( |( _, use_stmt) | {
118+ builder. insert ( ctx. selection_trimmed ( ) . end ( ) , format ! ( "\n {use_stmt}" ) ) ;
119+ } ) ;
113120
114121 let import_paths_to_be_removed = module. resolve_imports ( curr_parent_module, ctx) ;
115122 module. change_visibility ( record_fields) ;
@@ -224,9 +231,12 @@ impl Module {
224231 fn get_usages_and_record_fields (
225232 & self ,
226233 ctx : & AssistContext < ' _ > ,
227- ) -> ( FxHashMap < FileId , Vec < ( TextRange , String ) > > , Vec < SyntaxNode > ) {
234+ ) -> ( FxHashMap < FileId , Vec < ( TextRange , String ) > > , Vec < SyntaxNode > , FxHashMap < TextSize , ast:: Use > )
235+ {
228236 let mut adt_fields = Vec :: new ( ) ;
229237 let mut refs: FxHashMap < FileId , Vec < ( TextRange , String ) > > = FxHashMap :: default ( ) ;
238+ // use `TextSize` as key to avoid repeated use stmts
239+ let mut use_stmts_to_be_inserted = FxHashMap :: default ( ) ;
230240
231241 //Here impl is not included as each item inside impl will be tied to the parent of
232242 //implementing block(a struct, enum, etc), if the parent is in selected module, it will
@@ -238,7 +248,7 @@ impl Module {
238248 ast:: Adt ( it) => {
239249 if let Some ( nod ) = ctx. sema. to_def( & it) {
240250 let node_def = Definition :: Adt ( nod) ;
241- self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs) ;
251+ self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs, & mut use_stmts_to_be_inserted ) ;
242252
243253 //Enum Fields are not allowed to explicitly specify pub, it is implied
244254 match it {
@@ -272,59 +282,84 @@ impl Module {
272282 ast:: TypeAlias ( it) => {
273283 if let Some ( nod ) = ctx. sema. to_def( & it) {
274284 let node_def = Definition :: TypeAlias ( nod) ;
275- self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs) ;
285+ self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs, & mut use_stmts_to_be_inserted ) ;
276286 }
277287 } ,
278288 ast:: Const ( it) => {
279289 if let Some ( nod ) = ctx. sema. to_def( & it) {
280290 let node_def = Definition :: Const ( nod) ;
281- self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs) ;
291+ self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs, & mut use_stmts_to_be_inserted ) ;
282292 }
283293 } ,
284294 ast:: Static ( it) => {
285295 if let Some ( nod ) = ctx. sema. to_def( & it) {
286296 let node_def = Definition :: Static ( nod) ;
287- self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs) ;
297+ self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs, & mut use_stmts_to_be_inserted ) ;
288298 }
289299 } ,
290300 ast:: Fn ( it) => {
291301 if let Some ( nod ) = ctx. sema. to_def( & it) {
292302 let node_def = Definition :: Function ( nod) ;
293- self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs) ;
303+ self . expand_and_group_usages_file_wise( ctx, node_def, & mut refs, & mut use_stmts_to_be_inserted ) ;
294304 }
295305 } ,
296306 ast:: Macro ( it) => {
297307 if let Some ( nod) = ctx. sema. to_def( & it) {
298- self . expand_and_group_usages_file_wise( ctx, Definition :: Macro ( nod) , & mut refs) ;
308+ self . expand_and_group_usages_file_wise( ctx, Definition :: Macro ( nod) , & mut refs, & mut use_stmts_to_be_inserted ) ;
299309 }
300310 } ,
301311 _ => ( ) ,
302312 }
303313 }
304314 }
305315
306- ( refs, adt_fields)
316+ ( refs, adt_fields, use_stmts_to_be_inserted )
307317 }
308318
309319 fn expand_and_group_usages_file_wise (
310320 & self ,
311321 ctx : & AssistContext < ' _ > ,
312322 node_def : Definition ,
313323 refs_in_files : & mut FxHashMap < FileId , Vec < ( TextRange , String ) > > ,
324+ use_stmts_to_be_inserted : & mut FxHashMap < TextSize , ast:: Use > ,
314325 ) {
315326 let mod_name = self . name ;
327+ let covering_node = match ctx. covering_element ( ) {
328+ syntax:: NodeOrToken :: Node ( node) => node,
329+ syntax:: NodeOrToken :: Token ( tok) => tok. parent ( ) . unwrap ( ) , // won't panic
330+ } ;
316331 let out_of_sel = |node : & SyntaxNode | !self . text_range . contains_range ( node. text_range ( ) ) ;
332+ let mut use_stmts_set = FxHashSet :: default ( ) ;
317333
318334 for ( file_id, refs) in node_def. usages ( & ctx. sema ) . all ( ) {
319335 let source_file = ctx. sema . parse ( file_id) ;
320- let usages = refs. into_iter ( ) . filter_map ( |FileReference { range, name , .. } | {
336+ let usages = refs. into_iter ( ) . filter_map ( |FileReference { range, .. } | {
321337 // handle normal usages
322338 let name_ref = find_node_at_range :: < ast:: NameRef > ( source_file. syntax ( ) , range) ?;
323- let name = name. syntax ( ) . to_string ( ) ;
324339
325340 if out_of_sel ( name_ref. syntax ( ) ) {
326341 let new_ref = format ! ( "{mod_name}::{name_ref}" ) ;
327- return Some ( ( name_ref. syntax ( ) . text_range ( ) , new_ref) ) ;
342+ return Some ( ( range, new_ref) ) ;
343+ } else if let Some ( use_) = name_ref. syntax ( ) . ancestors ( ) . find_map ( ast:: Use :: cast) {
344+ // handle usages in use_stmts which is in_sel
345+ // check if `use` is top stmt in selection
346+ if use_. syntax ( ) . parent ( ) . is_some_and ( |parent| parent == covering_node)
347+ && use_stmts_set. insert ( use_. syntax ( ) . text_range ( ) . start ( ) )
348+ {
349+ let use_ = use_stmts_to_be_inserted
350+ . entry ( use_. syntax ( ) . text_range ( ) . start ( ) )
351+ . or_insert_with ( || use_. clone_subtree ( ) . clone_for_update ( ) ) ;
352+ for seg in use_
353+ . syntax ( )
354+ . descendants ( )
355+ . filter_map ( ast:: NameRef :: cast)
356+ . filter ( |seg| seg. syntax ( ) . to_string ( ) == name_ref. to_string ( ) )
357+ {
358+ let new_ref = make:: path_from_text ( & format ! ( "{mod_name}::{seg}" ) )
359+ . clone_for_update ( ) ;
360+ ted:: replace ( seg. syntax ( ) . parent ( ) ?, new_ref. syntax ( ) ) ;
361+ }
362+ }
328363 }
329364
330365 None
0 commit comments