aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/early_return.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/early_return.rs')
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs55
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
3use ra_syntax::{ 3use 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
11use crate::{ 15use 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// ```
39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { 43pub(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)]
184mod tests { 185mod 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 };