@@ -20,7 +20,7 @@ use syntax::{
20
20
} ,
21
21
match_ast, ted, AstNode ,
22
22
SyntaxKind :: { self , WHITESPACE } ,
23
- SyntaxNode , TextRange ,
23
+ SyntaxNode , TextRange , TextSize ,
24
24
} ;
25
25
26
26
use crate :: { AssistContext , Assists } ;
@@ -109,7 +109,14 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
109
109
110
110
//We are getting item usages and record_fields together, record_fields
111
111
//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
+ } ) ;
113
120
114
121
let import_paths_to_be_removed = module. resolve_imports ( curr_parent_module, ctx) ;
115
122
module. change_visibility ( record_fields) ;
@@ -224,9 +231,12 @@ impl Module {
224
231
fn get_usages_and_record_fields (
225
232
& self ,
226
233
ctx : & AssistContext < ' _ > ,
227
- ) -> ( FxHashMap < FileId , Vec < ( TextRange , String ) > > , Vec < SyntaxNode > ) {
234
+ ) -> ( FxHashMap < FileId , Vec < ( TextRange , String ) > > , Vec < SyntaxNode > , FxHashMap < TextSize , ast:: Use > )
235
+ {
228
236
let mut adt_fields = Vec :: new ( ) ;
229
237
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 ( ) ;
230
240
231
241
//Here impl is not included as each item inside impl will be tied to the parent of
232
242
//implementing block(a struct, enum, etc), if the parent is in selected module, it will
@@ -238,7 +248,7 @@ impl Module {
238
248
ast:: Adt ( it) => {
239
249
if let Some ( nod ) = ctx. sema. to_def( & it) {
240
250
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 ) ;
242
252
243
253
//Enum Fields are not allowed to explicitly specify pub, it is implied
244
254
match it {
@@ -272,59 +282,84 @@ impl Module {
272
282
ast:: TypeAlias ( it) => {
273
283
if let Some ( nod ) = ctx. sema. to_def( & it) {
274
284
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 ) ;
276
286
}
277
287
} ,
278
288
ast:: Const ( it) => {
279
289
if let Some ( nod ) = ctx. sema. to_def( & it) {
280
290
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 ) ;
282
292
}
283
293
} ,
284
294
ast:: Static ( it) => {
285
295
if let Some ( nod ) = ctx. sema. to_def( & it) {
286
296
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 ) ;
288
298
}
289
299
} ,
290
300
ast:: Fn ( it) => {
291
301
if let Some ( nod ) = ctx. sema. to_def( & it) {
292
302
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 ) ;
294
304
}
295
305
} ,
296
306
ast:: Macro ( it) => {
297
307
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 ) ;
299
309
}
300
310
} ,
301
311
_ => ( ) ,
302
312
}
303
313
}
304
314
}
305
315
306
- ( refs, adt_fields)
316
+ ( refs, adt_fields, use_stmts_to_be_inserted )
307
317
}
308
318
309
319
fn expand_and_group_usages_file_wise (
310
320
& self ,
311
321
ctx : & AssistContext < ' _ > ,
312
322
node_def : Definition ,
313
323
refs_in_files : & mut FxHashMap < FileId , Vec < ( TextRange , String ) > > ,
324
+ use_stmts_to_be_inserted : & mut FxHashMap < TextSize , ast:: Use > ,
314
325
) {
315
326
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
+ } ;
316
331
let out_of_sel = |node : & SyntaxNode | !self . text_range . contains_range ( node. text_range ( ) ) ;
332
+ let mut use_stmts_set = FxHashSet :: default ( ) ;
317
333
318
334
for ( file_id, refs) in node_def. usages ( & ctx. sema ) . all ( ) {
319
335
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, .. } | {
321
337
// handle normal usages
322
338
let name_ref = find_node_at_range :: < ast:: NameRef > ( source_file. syntax ( ) , range) ?;
323
- let name = name. syntax ( ) . to_string ( ) ;
324
339
325
340
if out_of_sel ( name_ref. syntax ( ) ) {
326
341
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
+ }
328
363
}
329
364
330
365
None
0 commit comments