diff options
Diffstat (limited to 'crates/ra_assists/src/handlers/early_return.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/early_return.rs | 55 |
1 files changed, 28 insertions, 27 deletions
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index ea6c56f8c..4cc75a7ce 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -2,14 +2,18 @@ use std::{iter::once, ops::RangeInclusive}; | |||
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::replace_children, | 4 | algo::replace_children, |
5 | ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, | 5 | ast::{ |
6 | self, | ||
7 | edit::{AstNodeEdit, IndentLevel}, | ||
8 | make, | ||
9 | }, | ||
6 | AstNode, | 10 | AstNode, |
7 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, | 11 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, |
8 | SyntaxNode, | 12 | SyntaxNode, |
9 | }; | 13 | }; |
10 | 14 | ||
11 | use crate::{ | 15 | use crate::{ |
12 | assist_ctx::{Assist, AssistCtx}, | 16 | assist_context::{AssistContext, Assists}, |
13 | utils::invert_boolean_expression, | 17 | utils::invert_boolean_expression, |
14 | AssistId, | 18 | AssistId, |
15 | }; | 19 | }; |
@@ -36,7 +40,7 @@ use crate::{ | |||
36 | // bar(); | 40 | // bar(); |
37 | // } | 41 | // } |
38 | // ``` | 42 | // ``` |
39 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | 43 | pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
40 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 44 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
41 | if if_expr.else_branch().is_some() { | 45 | if if_expr.else_branch().is_some() { |
42 | return None; | 46 | return None; |
@@ -47,7 +51,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
47 | // Check if there is an IfLet that we can handle. | 51 | // Check if there is an IfLet that we can handle. |
48 | let if_let_pat = match cond.pat() { | 52 | let if_let_pat = match cond.pat() { |
49 | None => None, // No IfLet, supported. | 53 | None => None, // No IfLet, supported. |
50 | Some(TupleStructPat(pat)) if pat.args().count() == 1 => { | 54 | Some(ast::Pat::TupleStructPat(pat)) if pat.args().count() == 1 => { |
51 | let path = pat.path()?; | 55 | let path = pat.path()?; |
52 | match path.qualifier() { | 56 | match path.qualifier() { |
53 | None => { | 57 | None => { |
@@ -61,9 +65,9 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
61 | }; | 65 | }; |
62 | 66 | ||
63 | let cond_expr = cond.expr()?; | 67 | let cond_expr = cond.expr()?; |
64 | let then_block = if_expr.then_branch()?.block()?; | 68 | let then_block = if_expr.then_branch()?; |
65 | 69 | ||
66 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; | 70 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; |
67 | 71 | ||
68 | if parent_block.expr()? != if_expr.clone().into() { | 72 | if parent_block.expr()? != if_expr.clone().into() { |
69 | return None; | 73 | return None; |
@@ -80,7 +84,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
80 | return None; | 84 | return None; |
81 | } | 85 | } |
82 | 86 | ||
83 | let parent_container = parent_block.syntax().parent()?.parent()?; | 87 | let parent_container = parent_block.syntax().parent()?; |
84 | 88 | ||
85 | let early_expression: ast::Expr = match parent_container.kind() { | 89 | let early_expression: ast::Expr = match parent_container.kind() { |
86 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), | 90 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), |
@@ -93,9 +97,9 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
93 | } | 97 | } |
94 | 98 | ||
95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 99 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
96 | let cursor_position = ctx.frange.range.start(); | ||
97 | 100 | ||
98 | ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| { | 101 | let target = if_expr.syntax().text_range(); |
102 | acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { | ||
99 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 103 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
100 | let new_block = match if_let_pat { | 104 | let new_block = match if_let_pat { |
101 | None => { | 105 | None => { |
@@ -104,8 +108,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
104 | let then_branch = | 108 | let then_branch = |
105 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 109 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
106 | let cond = invert_boolean_expression(cond_expr); | 110 | let cond = invert_boolean_expression(cond_expr); |
107 | let e = make::expr_if(make::condition(cond, None), then_branch); | 111 | make::expr_if(make::condition(cond, None), then_branch).indent(if_indent_level) |
108 | if_indent_level.increase_indent(e) | ||
109 | }; | 112 | }; |
110 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 113 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) |
111 | } | 114 | } |
@@ -139,21 +142,19 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
139 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 142 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
140 | Some(match_expr), | 143 | Some(match_expr), |
141 | ); | 144 | ); |
142 | let let_stmt = if_indent_level.increase_indent(let_stmt); | 145 | let let_stmt = let_stmt.indent(if_indent_level); |
143 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 146 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) |
144 | } | 147 | } |
145 | }; | 148 | }; |
146 | edit.target(if_expr.syntax().text_range()); | 149 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
147 | edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); | ||
148 | edit.set_cursor(cursor_position); | ||
149 | 150 | ||
150 | fn replace( | 151 | fn replace( |
151 | new_expr: &SyntaxNode, | 152 | new_expr: &SyntaxNode, |
152 | then_block: &Block, | 153 | then_block: &ast::BlockExpr, |
153 | parent_block: &Block, | 154 | parent_block: &ast::BlockExpr, |
154 | if_expr: &ast::IfExpr, | 155 | if_expr: &ast::IfExpr, |
155 | ) -> SyntaxNode { | 156 | ) -> SyntaxNode { |
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | 157 | let then_block_items = then_block.dedent(IndentLevel::from(1)); |
157 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | 158 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); |
158 | let end_of_then = | 159 | let end_of_then = |
159 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | 160 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { |
@@ -182,7 +183,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
182 | 183 | ||
183 | #[cfg(test)] | 184 | #[cfg(test)] |
184 | mod tests { | 185 | mod tests { |
185 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 186 | use crate::tests::{check_assist, check_assist_not_applicable}; |
186 | 187 | ||
187 | use super::*; | 188 | use super::*; |
188 | 189 | ||
@@ -204,7 +205,7 @@ mod tests { | |||
204 | r#" | 205 | r#" |
205 | fn main() { | 206 | fn main() { |
206 | bar(); | 207 | bar(); |
207 | if<|> !true { | 208 | if !true { |
208 | return; | 209 | return; |
209 | } | 210 | } |
210 | foo(); | 211 | foo(); |
@@ -234,7 +235,7 @@ mod tests { | |||
234 | r#" | 235 | r#" |
235 | fn main(n: Option<String>) { | 236 | fn main(n: Option<String>) { |
236 | bar(); | 237 | bar(); |
237 | le<|>t n = match n { | 238 | let n = match n { |
238 | Some(it) => it, | 239 | Some(it) => it, |
239 | _ => return, | 240 | _ => return, |
240 | }; | 241 | }; |
@@ -260,7 +261,7 @@ mod tests { | |||
260 | "#, | 261 | "#, |
261 | r#" | 262 | r#" |
262 | fn main() { | 263 | fn main() { |
263 | le<|>t x = match Err(92) { | 264 | let x = match Err(92) { |
264 | Ok(it) => it, | 265 | Ok(it) => it, |
265 | _ => return, | 266 | _ => return, |
266 | }; | 267 | }; |
@@ -288,7 +289,7 @@ mod tests { | |||
288 | r#" | 289 | r#" |
289 | fn main(n: Option<String>) { | 290 | fn main(n: Option<String>) { |
290 | bar(); | 291 | bar(); |
291 | le<|>t n = match n { | 292 | let n = match n { |
292 | Ok(it) => it, | 293 | Ok(it) => it, |
293 | _ => return, | 294 | _ => return, |
294 | }; | 295 | }; |
@@ -318,7 +319,7 @@ mod tests { | |||
318 | r#" | 319 | r#" |
319 | fn main() { | 320 | fn main() { |
320 | while true { | 321 | while true { |
321 | if<|> !true { | 322 | if !true { |
322 | continue; | 323 | continue; |
323 | } | 324 | } |
324 | foo(); | 325 | foo(); |
@@ -346,7 +347,7 @@ mod tests { | |||
346 | r#" | 347 | r#" |
347 | fn main() { | 348 | fn main() { |
348 | while true { | 349 | while true { |
349 | le<|>t n = match n { | 350 | let n = match n { |
350 | Some(it) => it, | 351 | Some(it) => it, |
351 | _ => continue, | 352 | _ => continue, |
352 | }; | 353 | }; |
@@ -375,7 +376,7 @@ mod tests { | |||
375 | r#" | 376 | r#" |
376 | fn main() { | 377 | fn main() { |
377 | loop { | 378 | loop { |
378 | if<|> !true { | 379 | if !true { |
379 | continue; | 380 | continue; |
380 | } | 381 | } |
381 | foo(); | 382 | foo(); |
@@ -403,7 +404,7 @@ mod tests { | |||
403 | r#" | 404 | r#" |
404 | fn main() { | 405 | fn main() { |
405 | loop { | 406 | loop { |
406 | le<|>t n = match n { | 407 | let n = match n { |
407 | Some(it) => it, | 408 | Some(it) => it, |
408 | _ => continue, | 409 | _ => continue, |
409 | }; | 410 | }; |