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