aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/early_return.rs64
-rw-r--r--crates/ra_syntax/src/ast/make.rs5
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;
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ 4use 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::{
38pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 38pub(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
113pub fn let_match_early(expr: ast::Expr, early_expression: &str) -> ast::LetStmt { 113pub 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