diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-01-15 19:43:59 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-01-15 19:43:59 +0000 |
commit | d93d3d6d7334bc94bdbfe9f3ab50cafd0113211e (patch) | |
tree | 5bd9f3c17f87851325565c3fb0aa698d5583f62c /crates/assists/src/handlers | |
parent | 8a869e870ac6328967fb120a0ebe44a9c900eaf0 (diff) | |
parent | c303014f3923e46ae63fbcdc6cf6f166bb040b1e (diff) |
Merge #7289
7289: Add Unmerge Use assist r=matklad a=unexge
Closes https://github.com/rust-analyzer/rust-analyzer/issues/7185
Co-authored-by: unexge <[email protected]>
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r-- | crates/assists/src/handlers/unmerge_use.rs | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/unmerge_use.rs b/crates/assists/src/handlers/unmerge_use.rs new file mode 100644 index 000000000..6da1795da --- /dev/null +++ b/crates/assists/src/handlers/unmerge_use.rs | |||
@@ -0,0 +1,228 @@ | |||
1 | use syntax::{ | ||
2 | algo::SyntaxRewriter, | ||
3 | ast::{self, edit::AstNodeEdit, VisibilityOwner}, | ||
4 | AstNode, SyntaxKind, | ||
5 | }; | ||
6 | |||
7 | use crate::{ | ||
8 | assist_context::{AssistContext, Assists}, | ||
9 | AssistId, AssistKind, | ||
10 | }; | ||
11 | |||
12 | // Assist: unmerge_use | ||
13 | // | ||
14 | // Extracts single use item from use list. | ||
15 | // | ||
16 | // ``` | ||
17 | // use std::fmt::{Debug, Display$0}; | ||
18 | // ``` | ||
19 | // -> | ||
20 | // ``` | ||
21 | // use std::fmt::{Debug}; | ||
22 | // use std::fmt::Display; | ||
23 | // ``` | ||
24 | pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
25 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | ||
26 | |||
27 | let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; | ||
28 | if tree_list.use_trees().count() < 2 { | ||
29 | return None; | ||
30 | } | ||
31 | |||
32 | let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; | ||
33 | let path = resolve_full_path(&tree)?; | ||
34 | |||
35 | let target = tree.syntax().text_range(); | ||
36 | acc.add( | ||
37 | AssistId("unmerge_use", AssistKind::RefactorRewrite), | ||
38 | "Unmerge use", | ||
39 | target, | ||
40 | |builder| { | ||
41 | let new_use = ast::make::use_( | ||
42 | use_.visibility(), | ||
43 | ast::make::use_tree( | ||
44 | path, | ||
45 | tree.use_tree_list(), | ||
46 | tree.rename(), | ||
47 | tree.star_token().is_some(), | ||
48 | ), | ||
49 | ); | ||
50 | |||
51 | let mut rewriter = SyntaxRewriter::default(); | ||
52 | rewriter += tree.remove(); | ||
53 | rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline()); | ||
54 | if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize { | ||
55 | rewriter.insert_after( | ||
56 | use_.syntax(), | ||
57 | &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)), | ||
58 | ); | ||
59 | } | ||
60 | rewriter.insert_after(use_.syntax(), new_use.syntax()); | ||
61 | |||
62 | builder.rewrite(rewriter); | ||
63 | }, | ||
64 | ) | ||
65 | } | ||
66 | |||
67 | fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> { | ||
68 | let mut paths = tree | ||
69 | .syntax() | ||
70 | .ancestors() | ||
71 | .take_while(|n| n.kind() != SyntaxKind::USE_KW) | ||
72 | .filter_map(ast::UseTree::cast) | ||
73 | .filter_map(|t| t.path()); | ||
74 | |||
75 | let mut final_path = paths.next()?; | ||
76 | for path in paths { | ||
77 | final_path = ast::make::path_concat(path, final_path) | ||
78 | } | ||
79 | Some(final_path) | ||
80 | } | ||
81 | |||
82 | #[cfg(test)] | ||
83 | mod tests { | ||
84 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
85 | |||
86 | use super::*; | ||
87 | |||
88 | #[test] | ||
89 | fn skip_single_use_item() { | ||
90 | check_assist_not_applicable( | ||
91 | unmerge_use, | ||
92 | r" | ||
93 | use std::fmt::Debug$0; | ||
94 | ", | ||
95 | ); | ||
96 | check_assist_not_applicable( | ||
97 | unmerge_use, | ||
98 | r" | ||
99 | use std::fmt::{Debug$0}; | ||
100 | ", | ||
101 | ); | ||
102 | check_assist_not_applicable( | ||
103 | unmerge_use, | ||
104 | r" | ||
105 | use std::fmt::Debug as Dbg$0; | ||
106 | ", | ||
107 | ); | ||
108 | } | ||
109 | |||
110 | #[test] | ||
111 | fn skip_single_glob_import() { | ||
112 | check_assist_not_applicable( | ||
113 | unmerge_use, | ||
114 | r" | ||
115 | use std::fmt::*$0; | ||
116 | ", | ||
117 | ); | ||
118 | } | ||
119 | |||
120 | #[test] | ||
121 | fn unmerge_use_item() { | ||
122 | check_assist( | ||
123 | unmerge_use, | ||
124 | r" | ||
125 | use std::fmt::{Debug, Display$0}; | ||
126 | ", | ||
127 | r" | ||
128 | use std::fmt::{Debug}; | ||
129 | use std::fmt::Display; | ||
130 | ", | ||
131 | ); | ||
132 | |||
133 | check_assist( | ||
134 | unmerge_use, | ||
135 | r" | ||
136 | use std::fmt::{Debug, format$0, Display}; | ||
137 | ", | ||
138 | r" | ||
139 | use std::fmt::{Debug, Display}; | ||
140 | use std::fmt::format; | ||
141 | ", | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn unmerge_glob_import() { | ||
147 | check_assist( | ||
148 | unmerge_use, | ||
149 | r" | ||
150 | use std::fmt::{*$0, Display}; | ||
151 | ", | ||
152 | r" | ||
153 | use std::fmt::{Display}; | ||
154 | use std::fmt::*; | ||
155 | ", | ||
156 | ); | ||
157 | } | ||
158 | |||
159 | #[test] | ||
160 | fn unmerge_renamed_use_item() { | ||
161 | check_assist( | ||
162 | unmerge_use, | ||
163 | r" | ||
164 | use std::fmt::{Debug, Display as Disp$0}; | ||
165 | ", | ||
166 | r" | ||
167 | use std::fmt::{Debug}; | ||
168 | use std::fmt::Display as Disp; | ||
169 | ", | ||
170 | ); | ||
171 | } | ||
172 | |||
173 | #[test] | ||
174 | fn unmerge_indented_use_item() { | ||
175 | check_assist( | ||
176 | unmerge_use, | ||
177 | r" | ||
178 | mod format { | ||
179 | use std::fmt::{Debug, Display$0 as Disp, format}; | ||
180 | } | ||
181 | ", | ||
182 | r" | ||
183 | mod format { | ||
184 | use std::fmt::{Debug, format}; | ||
185 | use std::fmt::Display as Disp; | ||
186 | } | ||
187 | ", | ||
188 | ); | ||
189 | } | ||
190 | |||
191 | #[test] | ||
192 | fn unmerge_nested_use_item() { | ||
193 | check_assist( | ||
194 | unmerge_use, | ||
195 | r" | ||
196 | use foo::bar::{baz::{qux$0, foobar}, barbaz}; | ||
197 | ", | ||
198 | r" | ||
199 | use foo::bar::{baz::{foobar}, barbaz}; | ||
200 | use foo::bar::baz::qux; | ||
201 | ", | ||
202 | ); | ||
203 | check_assist( | ||
204 | unmerge_use, | ||
205 | r" | ||
206 | use foo::bar::{baz$0::{qux, foobar}, barbaz}; | ||
207 | ", | ||
208 | r" | ||
209 | use foo::bar::{barbaz}; | ||
210 | use foo::bar::baz::{qux, foobar}; | ||
211 | ", | ||
212 | ); | ||
213 | } | ||
214 | |||
215 | #[test] | ||
216 | fn unmerge_use_item_with_visibility() { | ||
217 | check_assist( | ||
218 | unmerge_use, | ||
219 | r" | ||
220 | pub use std::fmt::{Debug, Display$0}; | ||
221 | ", | ||
222 | r" | ||
223 | pub use std::fmt::{Debug}; | ||
224 | pub use std::fmt::Display; | ||
225 | ", | ||
226 | ); | ||
227 | } | ||
228 | } | ||