1
1
use syntax:: {
2
2
AstNode , SyntaxKind ,
3
- ast:: { self , HasVisibility , edit_in_place:: Removable , make} ,
4
- ted:: { self , Position } ,
3
+ ast:: {
4
+ self , HasAttrs , HasVisibility ,
5
+ edit:: IndentLevel ,
6
+ edit_in_place:: { AttrsOwnerEdit , Indent } ,
7
+ make,
8
+ syntax_factory:: SyntaxFactory ,
9
+ } ,
10
+ syntax_editor:: { Element , Position , Removable } ,
5
11
} ;
6
12
7
13
use crate :: {
@@ -22,20 +28,17 @@ use crate::{
22
28
// use std::fmt::Display;
23
29
// ```
24
30
pub ( crate ) fn unmerge_use ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
25
- let tree: ast :: UseTree = ctx. find_node_at_offset :: < ast:: UseTree > ( ) ?. clone_for_update ( ) ;
31
+ let tree = ctx. find_node_at_offset :: < ast:: UseTree > ( ) ?;
26
32
27
33
let tree_list = tree. syntax ( ) . parent ( ) . and_then ( ast:: UseTreeList :: cast) ?;
28
34
if tree_list. use_trees ( ) . count ( ) < 2 {
29
35
cov_mark:: hit!( skip_single_use_item) ;
30
36
return None ;
31
37
}
32
38
33
- let use_: ast :: Use = tree_list. syntax ( ) . ancestors ( ) . find_map ( ast:: Use :: cast) ?;
39
+ let use_ = tree_list. syntax ( ) . ancestors ( ) . find_map ( ast:: Use :: cast) ?;
34
40
let path = resolve_full_path ( & tree) ?;
35
41
36
- let old_parent_range = use_. syntax ( ) . parent ( ) ?. text_range ( ) ;
37
- let new_parent = use_. syntax ( ) . parent ( ) ?;
38
-
39
42
// If possible, explain what is going to be done.
40
43
let label = match tree. path ( ) . and_then ( |path| path. first_segment ( ) ) {
41
44
Some ( name) => format ! ( "Unmerge use of `{name}`" ) ,
@@ -44,16 +47,28 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
44
47
45
48
let target = tree. syntax ( ) . text_range ( ) ;
46
49
acc. add ( AssistId :: refactor_rewrite ( "unmerge_use" ) , label, target, |builder| {
47
- let new_use = make:: use_ (
50
+ let make = SyntaxFactory :: new ( ) ;
51
+ let new_use = make. use_ (
48
52
use_. visibility ( ) ,
49
- make:: use_tree ( path, tree. use_tree_list ( ) , tree. rename ( ) , tree. star_token ( ) . is_some ( ) ) ,
50
- )
51
- . clone_for_update ( ) ;
52
-
53
- tree. remove ( ) ;
54
- ted:: insert ( Position :: after ( use_. syntax ( ) ) , new_use. syntax ( ) ) ;
53
+ make. use_tree ( path, tree. use_tree_list ( ) , tree. rename ( ) , tree. star_token ( ) . is_some ( ) ) ,
54
+ ) ;
55
+ // Add any attributes that are present on the use tree
56
+ use_. attrs ( ) . for_each ( |attr| {
57
+ new_use. add_attr ( attr. clone_for_update ( ) ) ;
58
+ } ) ;
59
+ // Indent the new use item
60
+ new_use. indent ( IndentLevel :: from_node ( use_. syntax ( ) ) ) ;
55
61
56
- builder. replace ( old_parent_range, new_parent. to_string ( ) ) ;
62
+ let mut editor = builder. make_editor ( use_. syntax ( ) ) ;
63
+ // Remove the use tree from the current use item
64
+ tree. remove ( & mut editor) ;
65
+ // Insert a leading whitespace and the new use item after the current use item
66
+ editor. insert_all (
67
+ Position :: after ( use_. syntax ( ) ) ,
68
+ vec ! [ make. whitespace( "\n " ) . syntax_element( ) , new_use. syntax( ) . syntax_element( ) ] ,
69
+ ) ;
70
+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
71
+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
57
72
} )
58
73
}
59
74
@@ -230,4 +245,19 @@ pub use std::fmt::Display;
230
245
use std::process;" ,
231
246
) ;
232
247
}
248
+
249
+ #[ test]
250
+ fn unmerge_use_item_with_attributes ( ) {
251
+ check_assist (
252
+ unmerge_use,
253
+ r"
254
+ #[allow(deprecated)]
255
+ use foo::{bar, baz$0};" ,
256
+ r"
257
+ #[allow(deprecated)]
258
+ use foo::{bar};
259
+ #[allow(deprecated)]
260
+ use foo::baz;" ,
261
+ ) ;
262
+ }
233
263
}
0 commit comments