@@ -2,7 +2,7 @@ use hir::db::HirDatabase;
22use ra_syntax:: {
33 TextUnit ,
44 SyntaxElement ,
5- ast:: { MatchArm , AstNode , AstToken } ,
5+ ast:: { MatchArm , AstNode , AstToken , IfExpr } ,
66 ast,
77} ;
88
@@ -39,6 +39,41 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op
3939 ctx. build ( )
4040}
4141
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+
56+ let buf = format ! ( " if {}" , cond. syntax( ) . text( ) ) ;
57+
58+ ctx. add_action (
59+ AssistId ( "move_arm_cond_to_match_guard" ) ,
60+ "move condition to match guard" ,
61+ |edit| {
62+ edit. target ( last_match_pat. syntax ( ) . range ( ) ) ;
63+
64+ if then_block. statements ( ) . next ( ) . is_none ( ) && then_block. expr ( ) . is_some ( ) {
65+ edit. replace ( if_expr. syntax ( ) . range ( ) , then_block. expr ( ) . unwrap ( ) . syntax ( ) . text ( ) ) ;
66+ } else {
67+ edit. replace ( if_expr. syntax ( ) . range ( ) , then_block. syntax ( ) . text ( ) ) ;
68+ }
69+
70+ edit. insert ( last_match_pat. syntax ( ) . range ( ) . end ( ) , buf) ;
71+ edit. set_cursor ( last_match_pat. syntax ( ) . range ( ) . end ( ) + TextUnit :: from ( 1 ) ) ;
72+ } ,
73+ ) ;
74+ ctx. build ( )
75+ }
76+
4277#[ cfg( test) ]
4378mod tests {
4479 use super :: * ;
@@ -112,4 +147,118 @@ mod tests {
112147 "# ,
113148 ) ;
114149 }
150+
151+ #[ test]
152+ fn move_arm_cond_to_match_guard_works ( ) {
153+ check_assist (
154+ move_arm_cond_to_match_guard,
155+ r#"
156+ fn f() {
157+ let t = 'a';
158+ let chars = "abcd";
159+ match t {
160+ '\r' => if chars.clone().next() == Some('\n') { <|>false },
161+ _ => true
162+ }
163+ }
164+ "# ,
165+ r#"
166+ fn f() {
167+ let t = 'a';
168+ let chars = "abcd";
169+ match t {
170+ '\r' <|>if chars.clone().next() == Some('\n') => false,
171+ _ => true
172+ }
173+ }
174+ "# ,
175+ ) ;
176+ }
177+
178+ #[ test]
179+ fn move_arm_cond_to_match_guard_if_let_works ( ) {
180+ check_assist (
181+ move_arm_cond_to_match_guard,
182+ r#"
183+ fn f() {
184+ let t = 'a';
185+ let chars = "abcd";
186+ match t {
187+ '\r' => if let Some(_) = chars.clone().next() { <|>false },
188+ _ => true
189+ }
190+ }
191+ "# ,
192+ r#"
193+ fn f() {
194+ let t = 'a';
195+ let chars = "abcd";
196+ match t {
197+ '\r' <|>if let Some(_) = chars.clone().next() => false,
198+ _ => true
199+ }
200+ }
201+ "# ,
202+ ) ;
203+ }
204+
205+ #[ test]
206+ fn move_arm_cond_to_match_guard_if_empty_body_works ( ) {
207+ check_assist (
208+ move_arm_cond_to_match_guard,
209+ r#"
210+ fn f() {
211+ let t = 'a';
212+ let chars = "abcd";
213+ match t {
214+ '\r' => if let Some(_) = chars.clone().next() { <|> },
215+ _ => true
216+ }
217+ }
218+ "# ,
219+ r#"
220+ fn f() {
221+ let t = 'a';
222+ let chars = "abcd";
223+ match t {
224+ '\r' <|>if let Some(_) = chars.clone().next() => { },
225+ _ => true
226+ }
227+ }
228+ "# ,
229+ ) ;
230+ }
231+
232+ #[ test]
233+ fn move_arm_cond_to_match_guard_if_multiline_body_works ( ) {
234+ check_assist (
235+ move_arm_cond_to_match_guard,
236+ r#"
237+ fn f() {
238+ let mut t = 'a';
239+ let chars = "abcd";
240+ match t {
241+ '\r' => if let Some(_) = chars.clone().next() {
242+ t = 'e';<|>
243+ false
244+ },
245+ _ => true
246+ }
247+ }
248+ "# ,
249+ r#"
250+ fn f() {
251+ let mut t = 'a';
252+ let chars = "abcd";
253+ match t {
254+ '\r' <|>if let Some(_) = chars.clone().next() => {
255+ t = 'e';
256+ false
257+ },
258+ _ => true
259+ }
260+ }
261+ "# ,
262+ ) ;
263+ }
115264}
0 commit comments