aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists/move_guard.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-09-25 12:29:41 +0100
committerAleksey Kladov <[email protected]>2019-09-25 12:29:41 +0100
commitf32081fa185b3a9df021f277c2c27fbd123d0951 (patch)
tree0032bc2f09dc0f323ae5b77bbc2b7d891173f398 /crates/ra_assists/src/assists/move_guard.rs
parentd9b4835625ac96c7628e2ef66ef6e26cc48d231f (diff)
move assists to subdir
Diffstat (limited to 'crates/ra_assists/src/assists/move_guard.rs')
-rw-r--r--crates/ra_assists/src/assists/move_guard.rs261
1 files changed, 261 insertions, 0 deletions
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs
new file mode 100644
index 000000000..699221e33
--- /dev/null
+++ b/crates/ra_assists/src/assists/move_guard.rs
@@ -0,0 +1,261 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 ast,
4 ast::{AstNode, AstToken, IfExpr, MatchArm},
5 TextUnit,
6};
7
8use crate::{Assist, AssistCtx, AssistId};
9
10pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let match_arm = ctx.node_at_offset::<MatchArm>()?;
12 let guard = match_arm.guard()?;
13 let space_before_guard = guard.syntax().prev_sibling_or_token();
14
15 let guard_conditions = guard.expr()?;
16 let arm_expr = match_arm.expr()?;
17 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
18
19 ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| {
20 edit.target(guard.syntax().text_range());
21 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) {
22 Some(tok) => {
23 if let Some(_) = ast::Whitespace::cast(tok.clone()) {
24 let ele = tok.text_range();
25 edit.delete(ele);
26 ele.len()
27 } else {
28 TextUnit::from(0)
29 }
30 }
31 _ => TextUnit::from(0),
32 };
33
34 edit.delete(guard.syntax().text_range());
35 edit.replace_node_and_indent(arm_expr.syntax(), buf);
36 edit.set_cursor(
37 arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount,
38 );
39 });
40 ctx.build()
41}
42
43pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
44 let match_arm: MatchArm = ctx.node_at_offset::<MatchArm>()?;
45 let last_match_pat = match_arm.pats().last()?;
46
47 let arm_body = match_arm.expr()?;
48 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?;
49 let cond = if_expr.condition()?;
50 let then_block = if_expr.then_branch()?;
51
52 // Not support if with else branch
53 if let Some(_) = if_expr.else_branch() {
54 return None;
55 }
56 // Not support moving if let to arm guard
57 if let Some(_) = cond.pat() {
58 return None;
59 }
60
61 let buf = format!(" if {}", cond.syntax().text());
62
63 ctx.add_action(
64 AssistId("move_arm_cond_to_match_guard"),
65 "move condition to match guard",
66 |edit| {
67 edit.target(if_expr.syntax().text_range());
68 let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none();
69
70 match &then_block.block().and_then(|it| it.expr()) {
71 Some(then_expr) if then_only_expr => {
72 edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text())
73 }
74 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()),
75 }
76
77 edit.insert(last_match_pat.syntax().text_range().end(), buf);
78 edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1));
79 },
80 );
81 ctx.build()
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
89
90 #[test]
91 fn move_guard_to_arm_body_target() {
92 check_assist_target(
93 move_guard_to_arm_body,
94 r#"
95 fn f() {
96 let t = 'a';
97 let chars = "abcd";
98 match t {
99 '\r' <|>if chars.clone().next() == Some('\n') => false,
100 _ => true
101 }
102 }
103 "#,
104 r#"if chars.clone().next() == Some('\n')"#,
105 );
106 }
107
108 #[test]
109 fn move_guard_to_arm_body_works() {
110 check_assist(
111 move_guard_to_arm_body,
112 r#"
113 fn f() {
114 let t = 'a';
115 let chars = "abcd";
116 match t {
117 '\r' <|>if chars.clone().next() == Some('\n') => false,
118 _ => true
119 }
120 }
121 "#,
122 r#"
123 fn f() {
124 let t = 'a';
125 let chars = "abcd";
126 match t {
127 '\r' => if chars.clone().next() == Some('\n') { <|>false },
128 _ => true
129 }
130 }
131 "#,
132 );
133 }
134
135 #[test]
136 fn move_guard_to_arm_body_works_complex_match() {
137 check_assist(
138 move_guard_to_arm_body,
139 r#"
140 fn f() {
141 match x {
142 <|>y @ 4 | y @ 5 if y > 5 => true,
143 _ => false
144 }
145 }
146 "#,
147 r#"
148 fn f() {
149 match x {
150 y @ 4 | y @ 5 => if y > 5 { <|>true },
151 _ => false
152 }
153 }
154 "#,
155 );
156 }
157
158 #[test]
159 fn move_arm_cond_to_match_guard_works() {
160 check_assist(
161 move_arm_cond_to_match_guard,
162 r#"
163 fn f() {
164 let t = 'a';
165 let chars = "abcd";
166 match t {
167 '\r' => if chars.clone().next() == Some('\n') { <|>false },
168 _ => true
169 }
170 }
171 "#,
172 r#"
173 fn f() {
174 let t = 'a';
175 let chars = "abcd";
176 match t {
177 '\r' <|>if chars.clone().next() == Some('\n') => false,
178 _ => true
179 }
180 }
181 "#,
182 );
183 }
184
185 #[test]
186 fn move_arm_cond_to_match_guard_if_let_not_works() {
187 check_assist_not_applicable(
188 move_arm_cond_to_match_guard,
189 r#"
190 fn f() {
191 let t = 'a';
192 let chars = "abcd";
193 match t {
194 '\r' => if let Some(_) = chars.clone().next() { <|>false },
195 _ => true
196 }
197 }
198 "#,
199 );
200 }
201
202 #[test]
203 fn move_arm_cond_to_match_guard_if_empty_body_works() {
204 check_assist(
205 move_arm_cond_to_match_guard,
206 r#"
207 fn f() {
208 let t = 'a';
209 let chars = "abcd";
210 match t {
211 '\r' => if chars.clone().next().is_some() { <|> },
212 _ => true
213 }
214 }
215 "#,
216 r#"
217 fn f() {
218 let t = 'a';
219 let chars = "abcd";
220 match t {
221 '\r' <|>if chars.clone().next().is_some() => { },
222 _ => true
223 }
224 }
225 "#,
226 );
227 }
228
229 #[test]
230 fn move_arm_cond_to_match_guard_if_multiline_body_works() {
231 check_assist(
232 move_arm_cond_to_match_guard,
233 r#"
234 fn f() {
235 let mut t = 'a';
236 let chars = "abcd";
237 match t {
238 '\r' => if chars.clone().next().is_some() {
239 t = 'e';<|>
240 false
241 },
242 _ => true
243 }
244 }
245 "#,
246 r#"
247 fn f() {
248 let mut t = 'a';
249 let chars = "abcd";
250 match t {
251 '\r' <|>if chars.clone().next().is_some() => {
252 t = 'e';
253 false
254 },
255 _ => true
256 }
257 }
258 "#,
259 );
260 }
261}