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.rs163
1 files changed, 79 insertions, 84 deletions
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 4bd6040b2..810784ad5 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::{ 11use crate::{
12 assist_ctx::{Assist, AssistCtx}, 12 assist_context::{AssistContext, Assists},
13 utils::invert_boolean_expression, 13 utils::invert_boolean_expression,
14 AssistId, 14 AssistId,
15}; 15};
@@ -36,7 +36,7 @@ use crate::{
36// bar(); 36// bar();
37// } 37// }
38// ``` 38// ```
39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { 39pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; 40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
41 if if_expr.else_branch().is_some() { 41 if if_expr.else_branch().is_some() {
42 return None; 42 return None;
@@ -93,96 +93,91 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
93 } 93 }
94 94
95 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; 95 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
96 let cursor_position = ctx.frange.range.start(); 96 let cursor_position = ctx.offset();
97 97
98 let target = if_expr.syntax().text_range(); 98 let target = if_expr.syntax().text_range();
99 ctx.add_assist( 99 acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| {
100 AssistId("convert_to_guarded_return"), 100 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
101 "Convert to guarded return", 101 let new_block = match if_let_pat {
102 target, 102 None => {
103 |edit| { 103 // If.
104 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 104 let new_expr = {
105 let new_block = match if_let_pat { 105 let then_branch =
106 None => { 106 make::block_expr(once(make::expr_stmt(early_expression).into()), None);
107 // If. 107 let cond = invert_boolean_expression(cond_expr);
108 let new_expr = { 108 let e = make::expr_if(make::condition(cond, None), then_branch);
109 let then_branch = 109 if_indent_level.increase_indent(e)
110 make::block_expr(once(make::expr_stmt(early_expression).into()), None); 110 };
111 let cond = invert_boolean_expression(cond_expr); 111 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
112 let e = make::expr_if(make::condition(cond, None), then_branch); 112 }
113 if_indent_level.increase_indent(e) 113 Some((path, bound_ident)) => {
114 }; 114 // If-let.
115 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) 115 let match_expr = {
116 } 116 let happy_arm = {
117 Some((path, bound_ident)) => { 117 let pat = make::tuple_struct_pat(
118 // If-let. 118 path,
119 let match_expr = { 119 once(make::bind_pat(make::name("it")).into()),
120 let happy_arm = {
121 let pat = make::tuple_struct_pat(
122 path,
123 once(make::bind_pat(make::name("it")).into()),
124 );
125 let expr = {
126 let name_ref = make::name_ref("it");
127 let segment = make::path_segment(name_ref);
128 let path = make::path_unqualified(segment);
129 make::expr_path(path)
130 };
131 make::match_arm(once(pat.into()), expr)
132 };
133
134 let sad_arm = make::match_arm(
135 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
136 once(make::placeholder_pat().into()),
137 early_expression,
138 ); 120 );
139 121 let expr = {
140 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) 122 let name_ref = make::name_ref("it");
123 let segment = make::path_segment(name_ref);
124 let path = make::path_unqualified(segment);
125 make::expr_path(path)
126 };
127 make::match_arm(once(pat.into()), expr)
141 }; 128 };
142 129
143 let let_stmt = make::let_stmt( 130 let sad_arm = make::match_arm(
144 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 131 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
145 Some(match_expr), 132 once(make::placeholder_pat().into()),
133 early_expression,
146 ); 134 );
147 let let_stmt = if_indent_level.increase_indent(let_stmt); 135
148 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) 136 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
149 } 137 };
150 }; 138
151 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); 139 let let_stmt = make::let_stmt(
152 edit.set_cursor(cursor_position); 140 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
153 141 Some(match_expr),
154 fn replace(
155 new_expr: &SyntaxNode,
156 then_block: &ast::BlockExpr,
157 parent_block: &ast::BlockExpr,
158 if_expr: &ast::IfExpr,
159 ) -> SyntaxNode {
160 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
161 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
162 let end_of_then =
163 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
164 end_of_then.prev_sibling_or_token().unwrap()
165 } else {
166 end_of_then
167 };
168 let mut then_statements = new_expr.children_with_tokens().chain(
169 then_block_items
170 .syntax()
171 .children_with_tokens()
172 .skip(1)
173 .take_while(|i| *i != end_of_then),
174 ); 142 );
175 replace_children( 143 let let_stmt = if_indent_level.increase_indent(let_stmt);
176 &parent_block.syntax(), 144 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
177 RangeInclusive::new(
178 if_expr.clone().syntax().clone().into(),
179 if_expr.syntax().clone().into(),
180 ),
181 &mut then_statements,
182 )
183 } 145 }
184 }, 146 };
185 ) 147 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
148 edit.set_cursor(cursor_position);
149
150 fn replace(
151 new_expr: &SyntaxNode,
152 then_block: &ast::BlockExpr,
153 parent_block: &ast::BlockExpr,
154 if_expr: &ast::IfExpr,
155 ) -> SyntaxNode {
156 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
157 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
158 let end_of_then =
159 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
160 end_of_then.prev_sibling_or_token().unwrap()
161 } else {
162 end_of_then
163 };
164 let mut then_statements = new_expr.children_with_tokens().chain(
165 then_block_items
166 .syntax()
167 .children_with_tokens()
168 .skip(1)
169 .take_while(|i| *i != end_of_then),
170 );
171 replace_children(
172 &parent_block.syntax(),
173 RangeInclusive::new(
174 if_expr.clone().syntax().clone().into(),
175 if_expr.syntax().clone().into(),
176 ),
177 &mut then_statements,
178 )
179 }
180 })
186} 181}
187 182
188#[cfg(test)] 183#[cfg(test)]