aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assists')
-rw-r--r--crates/ra_assists/src/assists/early_return.rs95
1 files changed, 71 insertions, 24 deletions
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index 8507a60fb..264412526 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -1,4 +1,4 @@
1use std::ops::RangeInclusive; 1use std::{iter::once, ops::RangeInclusive};
2 2
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ 4use ra_syntax::{
@@ -45,19 +45,22 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
45 let cond = if_expr.condition()?; 45 let cond = if_expr.condition()?;
46 46
47 // Check if there is an IfLet that we can handle. 47 // Check if there is an IfLet that we can handle.
48 let bound_ident = match cond.pat() { 48 let if_let_pat = match cond.pat() {
49 None => None, // No IfLet, supported. 49 None => None, // No IfLet, supported.
50 Some(TupleStructPat(pat)) if pat.args().count() == 1 => { 50 Some(TupleStructPat(pat)) if pat.args().count() == 1 => {
51 let path = pat.path()?; 51 let path = pat.path()?;
52 match path.qualifier() { 52 match path.qualifier() {
53 None => Some(path.segment()?.name_ref()?), 53 None => {
54 let bound_ident = pat.args().next().unwrap();
55 Some((path, bound_ident))
56 }
54 Some(_) => return None, 57 Some(_) => return None,
55 } 58 }
56 } 59 }
57 Some(_) => return None, // Unsupported IfLet. 60 Some(_) => return None, // Unsupported IfLet.
58 }; 61 };
59 62
60 let expr = cond.expr()?; 63 let cond_expr = cond.expr()?;
61 let then_block = if_expr.then_branch()?.block()?; 64 let then_block = if_expr.then_branch()?.block()?;
62 65
63 let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; 66 let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?;
@@ -79,11 +82,11 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
79 82
80 let parent_container = parent_block.syntax().parent()?.parent()?; 83 let parent_container = parent_block.syntax().parent()?.parent()?;
81 84
82 let early_expression = match parent_container.kind() { 85 let early_expression: ast::Expr = match parent_container.kind() {
83 WHILE_EXPR | LOOP_EXPR => Some("continue"), 86 WHILE_EXPR | LOOP_EXPR => make::expr_continue().into(),
84 FN_DEF => Some("return"), 87 FN_DEF => make::expr_return().into(),
85 _ => None, 88 _ => return None,
86 }?; 89 };
87 90
88 if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() { 91 if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
89 return None; 92 return None;
@@ -94,22 +97,43 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
94 97
95 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { 98 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
96 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 99 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
97 let new_block = match bound_ident { 100 let new_block = match if_let_pat {
98 None => { 101 None => {
99 // If. 102 // If.
100 let early_expression = &(early_expression.to_owned() + ";"); 103 let early_expression = &(early_expression.syntax().to_string() + ";");
101 let new_expr = 104 let new_expr = if_indent_level
102 if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); 105 .increase_indent(make::if_expression(&cond_expr, early_expression));
103 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) 106 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
104 } 107 }
105 Some(bound_ident) => { 108 Some((path, bound_ident)) => {
106 // If-let. 109 // If-let.
107 let new_expr = if_indent_level.increase_indent(make::let_match_early( 110 let match_expr = {
108 expr, 111 let happy_arm = make::match_arm(
109 &bound_ident.syntax().to_string(), 112 once(
110 early_expression, 113 make::tuple_struct_pat(
111 )); 114 path,
112 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) 115 once(make::bind_pat(make::name("it")).into()),
116 )
117 .into(),
118 ),
119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(),
120 );
121
122 let sad_arm = make::match_arm(
123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
124 once(make::placeholder_pat().into()),
125 early_expression.into(),
126 );
127
128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
129 };
130
131 let let_stmt = make::let_stmt(
132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
133 Some(match_expr.into()),
134 );
135 let let_stmt = if_indent_level.increase_indent(let_stmt);
136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
113 } 137 }
114 }; 138 };
115 edit.target(if_expr.syntax().text_range()); 139 edit.target(if_expr.syntax().text_range());
@@ -205,7 +229,7 @@ mod tests {
205 bar(); 229 bar();
206 le<|>t n = match n { 230 le<|>t n = match n {
207 Some(it) => it, 231 Some(it) => it,
208 None => return, 232 _ => return,
209 }; 233 };
210 foo(n); 234 foo(n);
211 235
@@ -217,6 +241,29 @@ mod tests {
217 } 241 }
218 242
219 #[test] 243 #[test]
244 fn convert_if_let_result() {
245 check_assist(
246 convert_to_guarded_return,
247 r#"
248 fn main() {
249 if<|> let Ok(x) = Err(92) {
250 foo(x);
251 }
252 }
253 "#,
254 r#"
255 fn main() {
256 le<|>t x = match Err(92) {
257 Ok(it) => it,
258 _ => return,
259 };
260 foo(x);
261 }
262 "#,
263 );
264 }
265
266 #[test]
220 fn convert_let_ok_inside_fn() { 267 fn convert_let_ok_inside_fn() {
221 check_assist( 268 check_assist(
222 convert_to_guarded_return, 269 convert_to_guarded_return,
@@ -236,7 +283,7 @@ mod tests {
236 bar(); 283 bar();
237 le<|>t n = match n { 284 le<|>t n = match n {
238 Ok(it) => it, 285 Ok(it) => it,
239 None => return, 286 _ => return,
240 }; 287 };
241 foo(n); 288 foo(n);
242 289
@@ -294,7 +341,7 @@ mod tests {
294 while true { 341 while true {
295 le<|>t n = match n { 342 le<|>t n = match n {
296 Some(it) => it, 343 Some(it) => it,
297 None => continue, 344 _ => continue,
298 }; 345 };
299 foo(n); 346 foo(n);
300 bar(); 347 bar();
@@ -351,7 +398,7 @@ mod tests {
351 loop { 398 loop {
352 le<|>t n = match n { 399 le<|>t n = match n {
353 Some(it) => it, 400 Some(it) => it,
354 None => continue, 401 _ => continue,
355 }; 402 };
356 foo(n); 403 foo(n);
357 bar(); 404 bar();