aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/move_guard.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers/move_guard.rs')
-rw-r--r--crates/assists/src/handlers/move_guard.rs293
1 files changed, 293 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/move_guard.rs b/crates/assists/src/handlers/move_guard.rs
new file mode 100644
index 000000000..452115fe6
--- /dev/null
+++ b/crates/assists/src/handlers/move_guard.rs
@@ -0,0 +1,293 @@
1use syntax::{
2 ast::{edit::AstNodeEdit, make, AstNode, IfExpr, MatchArm},
3 SyntaxKind::WHITESPACE,
4};
5
6use 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 } <|>if 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// ```
35pub(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 )
46 .indent(arm_expr.indent_level());
47
48 let target = guard.syntax().text_range();
49 acc.add(
50 AssistId("move_guard_to_arm_body", AssistKind::RefactorRewrite),
51 "Move guard to arm body",
52 target,
53 |edit| {
54 match space_before_guard {
55 Some(element) if element.kind() == WHITESPACE => {
56 edit.delete(element.text_range());
57 }
58 _ => (),
59 };
60
61 edit.delete(guard.syntax().text_range());
62 edit.replace_ast(arm_expr, if_expr);
63 },
64 )
65}
66
67// Assist: move_arm_cond_to_match_guard
68//
69// Moves if expression from match arm body into a guard.
70//
71// ```
72// enum Action { Move { distance: u32 }, Stop }
73//
74// fn handle(action: Action) {
75// match action {
76// Action::Move { distance } => <|>if distance > 10 { foo() },
77// _ => (),
78// }
79// }
80// ```
81// ->
82// ```
83// enum Action { Move { distance: u32 }, Stop }
84//
85// fn handle(action: Action) {
86// match action {
87// Action::Move { distance } if distance > 10 => foo(),
88// _ => (),
89// }
90// }
91// ```
92pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
93 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
94 let match_pat = match_arm.pat()?;
95
96 let arm_body = match_arm.expr()?;
97 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?;
98 let cond = if_expr.condition()?;
99 let then_block = if_expr.then_branch()?;
100
101 // Not support if with else branch
102 if if_expr.else_branch().is_some() {
103 return None;
104 }
105 // Not support moving if let to arm guard
106 if cond.pat().is_some() {
107 return None;
108 }
109
110 let buf = format!(" if {}", cond.syntax().text());
111
112 let target = if_expr.syntax().text_range();
113 acc.add(
114 AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite),
115 "Move condition to match guard",
116 target,
117 |edit| {
118 let then_only_expr = then_block.statements().next().is_none();
119
120 match &then_block.expr() {
121 Some(then_expr) if then_only_expr => {
122 edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text())
123 }
124 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()),
125 }
126
127 edit.insert(match_pat.syntax().text_range().end(), buf);
128 },
129 )
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
137
138 #[test]
139 fn move_guard_to_arm_body_target() {
140 check_assist_target(
141 move_guard_to_arm_body,
142 r#"
143fn main() {
144 match 92 {
145 x <|>if x > 10 => false,
146 _ => true
147 }
148}
149"#,
150 r#"if x > 10"#,
151 );
152 }
153
154 #[test]
155 fn move_guard_to_arm_body_works() {
156 check_assist(
157 move_guard_to_arm_body,
158 r#"
159fn main() {
160 match 92 {
161 x <|>if x > 10 => false,
162 _ => true
163 }
164}
165"#,
166 r#"
167fn main() {
168 match 92 {
169 x => if x > 10 {
170 false
171 },
172 _ => true
173 }
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn move_guard_to_arm_body_works_complex_match() {
181 check_assist(
182 move_guard_to_arm_body,
183 r#"
184fn main() {
185 match 92 {
186 <|>x @ 4 | x @ 5 if x > 5 => true,
187 _ => false
188 }
189}
190"#,
191 r#"
192fn main() {
193 match 92 {
194 x @ 4 | x @ 5 => if x > 5 {
195 true
196 },
197 _ => false
198 }
199}
200"#,
201 );
202 }
203
204 #[test]
205 fn move_arm_cond_to_match_guard_works() {
206 check_assist(
207 move_arm_cond_to_match_guard,
208 r#"
209fn main() {
210 match 92 {
211 x => if x > 10 { <|>false },
212 _ => true
213 }
214}
215"#,
216 r#"
217fn main() {
218 match 92 {
219 x if x > 10 => false,
220 _ => true
221 }
222}
223"#,
224 );
225 }
226
227 #[test]
228 fn move_arm_cond_to_match_guard_if_let_not_works() {
229 check_assist_not_applicable(
230 move_arm_cond_to_match_guard,
231 r#"
232fn main() {
233 match 92 {
234 x => if let 62 = x { <|>false },
235 _ => true
236 }
237}
238"#,
239 );
240 }
241
242 #[test]
243 fn move_arm_cond_to_match_guard_if_empty_body_works() {
244 check_assist(
245 move_arm_cond_to_match_guard,
246 r#"
247fn main() {
248 match 92 {
249 x => if x > 10 { <|> },
250 _ => true
251 }
252}
253"#,
254 r#"
255fn main() {
256 match 92 {
257 x if x > 10 => { },
258 _ => true
259 }
260}
261"#,
262 );
263 }
264
265 #[test]
266 fn move_arm_cond_to_match_guard_if_multiline_body_works() {
267 check_assist(
268 move_arm_cond_to_match_guard,
269 r#"
270fn main() {
271 match 92 {
272 x => if x > 10 {
273 92;<|>
274 false
275 },
276 _ => true
277 }
278}
279"#,
280 r#"
281fn main() {
282 match 92 {
283 x if x > 10 => {
284 92;
285 false
286 },
287 _ => true
288 }
289}
290"#,
291 );
292 }
293}