diff options
-rw-r--r-- | crates/ra_assists/src/assists/early_return.rs | 64 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 5 |
2 files changed, 59 insertions, 10 deletions
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 4322d3737..8536b015b 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs | |||
@@ -3,7 +3,7 @@ use std::ops::RangeInclusive; | |||
3 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | algo::replace_children, | 5 | algo::replace_children, |
6 | ast::{self, edit::IndentLevel, make}, | 6 | ast::{self, edit::IndentLevel, make, Pat::TupleStructPat}, |
7 | AstNode, | 7 | AstNode, |
8 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, | 8 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, |
9 | }; | 9 | }; |
@@ -38,6 +38,21 @@ use crate::{ | |||
38 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 38 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
39 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | 39 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; |
40 | let cond = if_expr.condition()?; | 40 | let cond = if_expr.condition()?; |
41 | let mut if_let_ident: Option<String> = None; | ||
42 | |||
43 | // Check if there is an IfLet that we can handle. | ||
44 | match cond.pat() { | ||
45 | None => {} // No IfLet, supported. | ||
46 | Some(TupleStructPat(ref pat)) if pat.args().count() == 1usize => match &pat.path() { | ||
47 | Some(p) => match p.qualifier() { | ||
48 | None => if_let_ident = Some(p.syntax().text().to_string()), | ||
49 | _ => return None, | ||
50 | }, | ||
51 | _ => return None, | ||
52 | }, | ||
53 | _ => return None, // Unsupported IfLet. | ||
54 | }; | ||
55 | |||
41 | let expr = cond.expr()?; | 56 | let expr = cond.expr()?; |
42 | let then_block = if_expr.then_branch()?.block()?; | 57 | let then_block = if_expr.then_branch()?.block()?; |
43 | if if_expr.else_branch().is_some() { | 58 | if if_expr.else_branch().is_some() { |
@@ -78,7 +93,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
78 | 93 | ||
79 | ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { | 94 | ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { |
80 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 95 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
81 | let new_block = match cond.pat() { | 96 | let new_block = match if_let_ident { |
82 | None => { | 97 | None => { |
83 | // If. | 98 | // If. |
84 | let early_expression = &(early_expression.to_owned() + ";"); | 99 | let early_expression = &(early_expression.to_owned() + ";"); |
@@ -109,10 +124,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
109 | &mut new_if_and_then_statements, | 124 | &mut new_if_and_then_statements, |
110 | ) | 125 | ) |
111 | } | 126 | } |
112 | _ => { | 127 | Some(if_let_ident) => { |
113 | // If-let. | 128 | // If-let. |
114 | let new_match_expr = | 129 | let new_match_expr = if_indent_level.increase_indent(make::let_match_early( |
115 | if_indent_level.increase_indent(make::let_match_early(expr, early_expression)); | 130 | expr, |
131 | &if_let_ident, | ||
132 | early_expression, | ||
133 | )); | ||
116 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | 134 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); |
117 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | 135 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); |
118 | let end_of_then = | 136 | let end_of_then = |
@@ -128,15 +146,14 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
128 | .skip(1) | 146 | .skip(1) |
129 | .take_while(|i| *i != end_of_then), | 147 | .take_while(|i| *i != end_of_then), |
130 | ); | 148 | ); |
131 | let new_block = replace_children( | 149 | replace_children( |
132 | &parent_block.syntax(), | 150 | &parent_block.syntax(), |
133 | RangeInclusive::new( | 151 | RangeInclusive::new( |
134 | if_expr.clone().syntax().clone().into(), | 152 | if_expr.clone().syntax().clone().into(), |
135 | if_expr.syntax().clone().into(), | 153 | if_expr.syntax().clone().into(), |
136 | ), | 154 | ), |
137 | &mut then_statements, | 155 | &mut then_statements, |
138 | ); | 156 | ) |
139 | new_block | ||
140 | } | 157 | } |
141 | }; | 158 | }; |
142 | edit.target(if_expr.syntax().text_range()); | 159 | edit.target(if_expr.syntax().text_range()); |
@@ -212,6 +229,37 @@ mod tests { | |||
212 | } | 229 | } |
213 | 230 | ||
214 | #[test] | 231 | #[test] |
232 | fn convert_let_ok_inside_fn() { | ||
233 | check_assist( | ||
234 | convert_to_guarded_return, | ||
235 | r#" | ||
236 | fn main(n: Option<String>) { | ||
237 | bar(); | ||
238 | if<|> let Ok(n) = n { | ||
239 | foo(n); | ||
240 | |||
241 | //comment | ||
242 | bar(); | ||
243 | } | ||
244 | } | ||
245 | "#, | ||
246 | r#" | ||
247 | fn main(n: Option<String>) { | ||
248 | bar(); | ||
249 | le<|>t n = match n { | ||
250 | Ok(it) => it, | ||
251 | None => return, | ||
252 | }; | ||
253 | foo(n); | ||
254 | |||
255 | //comment | ||
256 | bar(); | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
215 | fn convert_inside_while() { | 263 | fn convert_inside_while() { |
216 | check_assist( | 264 | check_assist( |
217 | convert_to_guarded_return, | 265 | convert_to_guarded_return, |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 979819d4b..95062ef6c 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -110,14 +110,15 @@ pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchAr | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | pub fn let_match_early(expr: ast::Expr, early_expression: &str) -> ast::LetStmt { | 113 | pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt { |
114 | return from_text(&format!( | 114 | return from_text(&format!( |
115 | r#"let {} = match {} {{ | 115 | r#"let {} = match {} {{ |
116 | Some(it) => it, | 116 | {}(it) => it, |
117 | None => {}, | 117 | None => {}, |
118 | }};"#, | 118 | }};"#, |
119 | expr.syntax().text(), | 119 | expr.syntax().text(), |
120 | expr.syntax().text(), | 120 | expr.syntax().text(), |
121 | path, | ||
121 | early_expression | 122 | early_expression |
122 | )); | 123 | )); |
123 | 124 | ||