Skip to content

Commit 67d5927

Browse files
Merge #1281
1281: Move arm cond to match guard r=matklad a=unrealhoang I did split the rename to another commit, yet Github UI still show entirely new file change. Please review using commits. Co-authored-by: Unreal Hoang <[email protected]>
2 parents 4199f4e + 079ed60 commit 67d5927

File tree

4 files changed

+294
-119
lines changed

4 files changed

+294
-119
lines changed

crates/ra_assists/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ mod split_import;
100100
mod remove_dbg;
101101
pub mod auto_import;
102102
mod add_missing_impl_members;
103-
mod move_guard_to_arm_body;
103+
mod move_guard;
104104

105105
fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
106106
&[
@@ -119,7 +119,8 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
119119
add_missing_impl_members::add_missing_impl_members,
120120
add_missing_impl_members::add_missing_default_members,
121121
inline_local_variable::inline_local_varialbe,
122-
move_guard_to_arm_body::move_guard_to_arm_body,
122+
move_guard::move_guard_to_arm_body,
123+
move_guard::move_arm_cond_to_match_guard,
123124
]
124125
}
125126

crates/ra_assists/src/move_guard.rs

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use hir::db::HirDatabase;
2+
use ra_syntax::{
3+
TextUnit,
4+
SyntaxElement,
5+
ast::{MatchArm, AstNode, AstToken, IfExpr},
6+
ast,
7+
};
8+
9+
use crate::{AssistCtx, Assist, AssistId};
10+
11+
pub(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+
pub(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)]
84+
mod 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+
}

crates/ra_assists/src/move_guard_to_arm_body.rs

-115
This file was deleted.

0 commit comments

Comments
 (0)