diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-22 20:28:17 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-22 20:28:17 +0000 |
commit | 27ed1ebf8997cea55fb446ce249b390607b84105 (patch) | |
tree | a49a763fee848041fd607f449ad13a0b1040636e /crates/ide_assists/src/handlers/move_guard.rs | |
parent | 8687053b118f47ce1a4962d0baa19b22d40d2758 (diff) | |
parent | eb6cfa7f157690480fca5d55c69dba3fae87ad4f (diff) |
Merge #7759
7759: 7526: Rename ide related crates r=Veykril a=chetankhilosiya
renamed assists -> ide_assists and ssr -> ide_ssr.
the completion crate is already renamed.
Co-authored-by: Chetan Khilosiya <[email protected]>
Diffstat (limited to 'crates/ide_assists/src/handlers/move_guard.rs')
-rw-r--r-- | crates/ide_assists/src/handlers/move_guard.rs | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/move_guard.rs b/crates/ide_assists/src/handlers/move_guard.rs new file mode 100644 index 000000000..3f22302a9 --- /dev/null +++ b/crates/ide_assists/src/handlers/move_guard.rs | |||
@@ -0,0 +1,367 @@ | |||
1 | use syntax::{ | ||
2 | ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, Expr, IfExpr, MatchArm}, | ||
3 | SyntaxKind::WHITESPACE, | ||
4 | }; | ||
5 | |||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
7 | |||
8 | // Assist: move_guard_to_arm_body | ||
9 | // | ||
10 | // Moves match guard into match arm body. | ||
11 | // | ||
12 | // ``` | ||
13 | // enum Action { Move { distance: u32 }, Stop } | ||
14 | // | ||
15 | // fn handle(action: Action) { | ||
16 | // match action { | ||
17 | // Action::Move { distance } $0if distance > 10 => foo(), | ||
18 | // _ => (), | ||
19 | // } | ||
20 | // } | ||
21 | // ``` | ||
22 | // -> | ||
23 | // ``` | ||
24 | // enum Action { Move { distance: u32 }, Stop } | ||
25 | // | ||
26 | // fn handle(action: Action) { | ||
27 | // match action { | ||
28 | // Action::Move { distance } => if distance > 10 { | ||
29 | // foo() | ||
30 | // }, | ||
31 | // _ => (), | ||
32 | // } | ||
33 | // } | ||
34 | // ``` | ||
35 | pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
36 | let match_arm = ctx.find_node_at_offset::<MatchArm>()?; | ||
37 | let guard = match_arm.guard()?; | ||
38 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | ||
39 | |||
40 | let guard_condition = guard.expr()?; | ||
41 | let arm_expr = match_arm.expr()?; | ||
42 | let if_expr = make::expr_if( | ||
43 | make::condition(guard_condition, None), | ||
44 | make::block_expr(None, Some(arm_expr.clone())), | ||
45 | None, | ||
46 | ) | ||
47 | .indent(arm_expr.indent_level()); | ||
48 | |||
49 | let target = guard.syntax().text_range(); | ||
50 | acc.add( | ||
51 | AssistId("move_guard_to_arm_body", AssistKind::RefactorRewrite), | ||
52 | "Move guard to arm body", | ||
53 | target, | ||
54 | |edit| { | ||
55 | match space_before_guard { | ||
56 | Some(element) if element.kind() == WHITESPACE => { | ||
57 | edit.delete(element.text_range()); | ||
58 | } | ||
59 | _ => (), | ||
60 | }; | ||
61 | |||
62 | edit.delete(guard.syntax().text_range()); | ||
63 | edit.replace_ast(arm_expr, if_expr); | ||
64 | }, | ||
65 | ) | ||
66 | } | ||
67 | |||
68 | // Assist: move_arm_cond_to_match_guard | ||
69 | // | ||
70 | // Moves if expression from match arm body into a guard. | ||
71 | // | ||
72 | // ``` | ||
73 | // enum Action { Move { distance: u32 }, Stop } | ||
74 | // | ||
75 | // fn handle(action: Action) { | ||
76 | // match action { | ||
77 | // Action::Move { distance } => $0if distance > 10 { foo() }, | ||
78 | // _ => (), | ||
79 | // } | ||
80 | // } | ||
81 | // ``` | ||
82 | // -> | ||
83 | // ``` | ||
84 | // enum Action { Move { distance: u32 }, Stop } | ||
85 | // | ||
86 | // fn handle(action: Action) { | ||
87 | // match action { | ||
88 | // Action::Move { distance } if distance > 10 => foo(), | ||
89 | // _ => (), | ||
90 | // } | ||
91 | // } | ||
92 | // ``` | ||
93 | pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
94 | let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; | ||
95 | let match_pat = match_arm.pat()?; | ||
96 | let arm_body = match_arm.expr()?; | ||
97 | |||
98 | let mut replace_node = None; | ||
99 | let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { | ||
100 | let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; | ||
101 | if let Expr::IfExpr(e) = block_expr.tail_expr()? { | ||
102 | replace_node = Some(block_expr.syntax().clone()); | ||
103 | Some(e) | ||
104 | } else { | ||
105 | None | ||
106 | } | ||
107 | })?; | ||
108 | let replace_node = replace_node.unwrap_or_else(|| if_expr.syntax().clone()); | ||
109 | |||
110 | let cond = if_expr.condition()?; | ||
111 | let then_block = if_expr.then_branch()?; | ||
112 | |||
113 | // Not support if with else branch | ||
114 | if if_expr.else_branch().is_some() { | ||
115 | return None; | ||
116 | } | ||
117 | // Not support moving if let to arm guard | ||
118 | if cond.pat().is_some() { | ||
119 | return None; | ||
120 | } | ||
121 | |||
122 | let buf = format!(" if {}", cond.syntax().text()); | ||
123 | |||
124 | acc.add( | ||
125 | AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite), | ||
126 | "Move condition to match guard", | ||
127 | replace_node.text_range(), | ||
128 | |edit| { | ||
129 | let then_only_expr = then_block.statements().next().is_none(); | ||
130 | |||
131 | match &then_block.tail_expr() { | ||
132 | Some(then_expr) if then_only_expr => { | ||
133 | edit.replace(replace_node.text_range(), then_expr.syntax().text()) | ||
134 | } | ||
135 | _ if replace_node != *if_expr.syntax() => { | ||
136 | // Dedent because if_expr is in a BlockExpr | ||
137 | let replace_with = then_block.dedent(1.into()).syntax().text(); | ||
138 | edit.replace(replace_node.text_range(), replace_with) | ||
139 | } | ||
140 | _ => edit.replace(replace_node.text_range(), then_block.syntax().text()), | ||
141 | } | ||
142 | |||
143 | edit.insert(match_pat.syntax().text_range().end(), buf); | ||
144 | }, | ||
145 | ) | ||
146 | } | ||
147 | |||
148 | #[cfg(test)] | ||
149 | mod tests { | ||
150 | use super::*; | ||
151 | |||
152 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
153 | |||
154 | #[test] | ||
155 | fn move_guard_to_arm_body_target() { | ||
156 | check_assist_target( | ||
157 | move_guard_to_arm_body, | ||
158 | r#" | ||
159 | fn main() { | ||
160 | match 92 { | ||
161 | x $0if x > 10 => false, | ||
162 | _ => true | ||
163 | } | ||
164 | } | ||
165 | "#, | ||
166 | r#"if x > 10"#, | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn move_guard_to_arm_body_works() { | ||
172 | check_assist( | ||
173 | move_guard_to_arm_body, | ||
174 | r#" | ||
175 | fn main() { | ||
176 | match 92 { | ||
177 | x $0if x > 10 => false, | ||
178 | _ => true | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | r#" | ||
183 | fn main() { | ||
184 | match 92 { | ||
185 | x => if x > 10 { | ||
186 | false | ||
187 | }, | ||
188 | _ => true | ||
189 | } | ||
190 | } | ||
191 | "#, | ||
192 | ); | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn move_guard_to_arm_body_works_complex_match() { | ||
197 | check_assist( | ||
198 | move_guard_to_arm_body, | ||
199 | r#" | ||
200 | fn main() { | ||
201 | match 92 { | ||
202 | $0x @ 4 | x @ 5 if x > 5 => true, | ||
203 | _ => false | ||
204 | } | ||
205 | } | ||
206 | "#, | ||
207 | r#" | ||
208 | fn main() { | ||
209 | match 92 { | ||
210 | x @ 4 | x @ 5 => if x > 5 { | ||
211 | true | ||
212 | }, | ||
213 | _ => false | ||
214 | } | ||
215 | } | ||
216 | "#, | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn move_arm_cond_to_match_guard_works() { | ||
222 | check_assist( | ||
223 | move_arm_cond_to_match_guard, | ||
224 | r#" | ||
225 | fn main() { | ||
226 | match 92 { | ||
227 | x => if x > 10 { $0false }, | ||
228 | _ => true | ||
229 | } | ||
230 | } | ||
231 | "#, | ||
232 | r#" | ||
233 | fn main() { | ||
234 | match 92 { | ||
235 | x if x > 10 => false, | ||
236 | _ => true | ||
237 | } | ||
238 | } | ||
239 | "#, | ||
240 | ); | ||
241 | } | ||
242 | |||
243 | #[test] | ||
244 | fn move_arm_cond_in_block_to_match_guard_works() { | ||
245 | check_assist( | ||
246 | move_arm_cond_to_match_guard, | ||
247 | r#" | ||
248 | fn main() { | ||
249 | match 92 { | ||
250 | x => { | ||
251 | $0if x > 10 { | ||
252 | false | ||
253 | } | ||
254 | }, | ||
255 | _ => true | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | r#" | ||
260 | fn main() { | ||
261 | match 92 { | ||
262 | x if x > 10 => false, | ||
263 | _ => true | ||
264 | } | ||
265 | } | ||
266 | "#, | ||
267 | ); | ||
268 | } | ||
269 | |||
270 | #[test] | ||
271 | fn move_arm_cond_to_match_guard_if_let_not_works() { | ||
272 | check_assist_not_applicable( | ||
273 | move_arm_cond_to_match_guard, | ||
274 | r#" | ||
275 | fn main() { | ||
276 | match 92 { | ||
277 | x => if let 62 = x { $0false }, | ||
278 | _ => true | ||
279 | } | ||
280 | } | ||
281 | "#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn move_arm_cond_to_match_guard_if_empty_body_works() { | ||
287 | check_assist( | ||
288 | move_arm_cond_to_match_guard, | ||
289 | r#" | ||
290 | fn main() { | ||
291 | match 92 { | ||
292 | x => if x > 10 { $0 }, | ||
293 | _ => true | ||
294 | } | ||
295 | } | ||
296 | "#, | ||
297 | r#" | ||
298 | fn main() { | ||
299 | match 92 { | ||
300 | x if x > 10 => { }, | ||
301 | _ => true | ||
302 | } | ||
303 | } | ||
304 | "#, | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn move_arm_cond_to_match_guard_if_multiline_body_works() { | ||
310 | check_assist( | ||
311 | move_arm_cond_to_match_guard, | ||
312 | r#" | ||
313 | fn main() { | ||
314 | match 92 { | ||
315 | x => if x > 10 { | ||
316 | 92;$0 | ||
317 | false | ||
318 | }, | ||
319 | _ => true | ||
320 | } | ||
321 | } | ||
322 | "#, | ||
323 | r#" | ||
324 | fn main() { | ||
325 | match 92 { | ||
326 | x if x > 10 => { | ||
327 | 92; | ||
328 | false | ||
329 | }, | ||
330 | _ => true | ||
331 | } | ||
332 | } | ||
333 | "#, | ||
334 | ); | ||
335 | } | ||
336 | |||
337 | #[test] | ||
338 | fn move_arm_cond_in_block_to_match_guard_if_multiline_body_works() { | ||
339 | check_assist( | ||
340 | move_arm_cond_to_match_guard, | ||
341 | r#" | ||
342 | fn main() { | ||
343 | match 92 { | ||
344 | x => { | ||
345 | if x > 10 { | ||
346 | 92;$0 | ||
347 | false | ||
348 | } | ||
349 | } | ||
350 | _ => true | ||
351 | } | ||
352 | } | ||
353 | "#, | ||
354 | r#" | ||
355 | fn main() { | ||
356 | match 92 { | ||
357 | x if x > 10 => { | ||
358 | 92; | ||
359 | false | ||
360 | } | ||
361 | _ => true | ||
362 | } | ||
363 | } | ||
364 | "#, | ||
365 | ) | ||
366 | } | ||
367 | } | ||