diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_assists/src/assist_context.rs | 17 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/change_return_type_to_result.rs | 73 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | 16 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/move_guard.rs | 222 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_if_let_with_match.rs | 6 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/unwrap_block.rs | 3 | ||||
-rw-r--r-- | crates/ra_assists/src/tests/generated.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/utils.rs | 38 | ||||
-rw-r--r-- | crates/ra_assists/src/utils/insert_use.rs | 27 |
10 files changed, 223 insertions, 184 deletions
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index abc290463..83e44c124 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -17,7 +17,6 @@ stdx = { path = "../stdx" } | |||
17 | 17 | ||
18 | syntax = { path = "../syntax" } | 18 | syntax = { path = "../syntax" } |
19 | text_edit = { path = "../text_edit" } | 19 | text_edit = { path = "../text_edit" } |
20 | ra_fmt = { path = "../ra_fmt" } | ||
21 | profile = { path = "../profile" } | 20 | profile = { path = "../profile" } |
22 | ra_db = { path = "../ra_db" } | 21 | ra_db = { path = "../ra_db" } |
23 | ra_ide_db = { path = "../ra_ide_db" } | 22 | ra_ide_db = { path = "../ra_ide_db" } |
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index 217f692a4..368d48a71 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -5,14 +5,13 @@ use std::mem; | |||
5 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use ra_db::{FileId, FileRange}; | 7 | use ra_db::{FileId, FileRange}; |
8 | use ra_fmt::{leading_indent, reindent}; | ||
9 | use ra_ide_db::{ | 8 | use ra_ide_db::{ |
10 | source_change::{SourceChange, SourceFileEdit}, | 9 | source_change::{SourceChange, SourceFileEdit}, |
11 | RootDatabase, | 10 | RootDatabase, |
12 | }; | 11 | }; |
13 | use syntax::{ | 12 | use syntax::{ |
14 | algo::{self, find_node_at_offset, SyntaxRewriter}, | 13 | algo::{self, find_node_at_offset, SyntaxRewriter}, |
15 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, | 14 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange, TextSize, |
16 | TokenAtOffset, | 15 | TokenAtOffset, |
17 | }; | 16 | }; |
18 | use text_edit::{TextEdit, TextEditBuilder}; | 17 | use text_edit::{TextEdit, TextEditBuilder}; |
@@ -269,20 +268,6 @@ impl AssistBuilder { | |||
269 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | 268 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { |
270 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | 269 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) |
271 | } | 270 | } |
272 | /// Replaces specified `node` of text with a given string, reindenting the | ||
273 | /// string to maintain `node`'s existing indent. | ||
274 | // FIXME: remove in favor of syntax::edit::IndentLevel::increase_indent | ||
275 | pub(crate) fn replace_node_and_indent( | ||
276 | &mut self, | ||
277 | node: &SyntaxNode, | ||
278 | replace_with: impl Into<String>, | ||
279 | ) { | ||
280 | let mut replace_with = replace_with.into(); | ||
281 | if let Some(indent) = leading_indent(node) { | ||
282 | replace_with = reindent(&replace_with, &indent) | ||
283 | } | ||
284 | self.replace(node.text_range(), replace_with) | ||
285 | } | ||
286 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | 271 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { |
287 | let node = rewriter.rewrite_root().unwrap(); | 272 | let node = rewriter.rewrite_root().unwrap(); |
288 | let new = rewriter.rewrite(&node); | 273 | let new = rewriter.rewrite(&node); |
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs index d5a68a24c..be480943c 100644 --- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs +++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs | |||
@@ -1,10 +1,12 @@ | |||
1 | use std::iter; | ||
2 | |||
1 | use syntax::{ | 3 | use syntax::{ |
2 | ast::{self, BlockExpr, Expr, LoopBodyOwner}, | 4 | ast::{self, make, BlockExpr, Expr, LoopBodyOwner}, |
3 | AstNode, SyntaxNode, | 5 | AstNode, SyntaxNode, |
4 | }; | 6 | }; |
7 | use test_utils::mark; | ||
5 | 8 | ||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
7 | use test_utils::mark; | ||
8 | 10 | ||
9 | // Assist: change_return_type_to_result | 11 | // Assist: change_return_type_to_result |
10 | // | 12 | // |
@@ -44,7 +46,13 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex | |||
44 | tail_return_expr_collector.collect_tail_exprs(block_expr); | 46 | tail_return_expr_collector.collect_tail_exprs(block_expr); |
45 | 47 | ||
46 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { | 48 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { |
47 | builder.replace_node_and_indent(&ret_expr_arg, format!("Ok({})", ret_expr_arg)); | 49 | let ok_wrapped = make::expr_call( |
50 | make::expr_path(make::path_unqualified(make::path_segment(make::name_ref( | ||
51 | "Ok", | ||
52 | )))), | ||
53 | make::arg_list(iter::once(ret_expr_arg.clone())), | ||
54 | ); | ||
55 | builder.replace_ast(ret_expr_arg, ok_wrapped); | ||
48 | } | 56 | } |
49 | 57 | ||
50 | match ctx.config.snippet_cap { | 58 | match ctx.config.snippet_cap { |
@@ -60,7 +68,7 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex | |||
60 | } | 68 | } |
61 | 69 | ||
62 | struct TailReturnCollector { | 70 | struct TailReturnCollector { |
63 | exprs_to_wrap: Vec<SyntaxNode>, | 71 | exprs_to_wrap: Vec<ast::Expr>, |
64 | } | 72 | } |
65 | 73 | ||
66 | impl TailReturnCollector { | 74 | impl TailReturnCollector { |
@@ -86,7 +94,8 @@ impl TailReturnCollector { | |||
86 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { | 94 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { |
87 | for last_expr in last_exprs { | 95 | for last_expr in last_exprs { |
88 | let last_expr = match last_expr { | 96 | let last_expr = match last_expr { |
89 | NodeType::Node(expr) | NodeType::Leaf(expr) => expr, | 97 | NodeType::Node(expr) => expr, |
98 | NodeType::Leaf(expr) => expr.syntax().clone(), | ||
90 | }; | 99 | }; |
91 | 100 | ||
92 | if let Some(last_expr) = Expr::cast(last_expr.clone()) { | 101 | if let Some(last_expr) = Expr::cast(last_expr.clone()) { |
@@ -113,12 +122,12 @@ impl TailReturnCollector { | |||
113 | } | 122 | } |
114 | Expr::ReturnExpr(ret_expr) => { | 123 | Expr::ReturnExpr(ret_expr) => { |
115 | if let Some(ret_expr_arg) = &ret_expr.expr() { | 124 | if let Some(ret_expr_arg) = &ret_expr.expr() { |
116 | self.exprs_to_wrap.push(ret_expr_arg.syntax().clone()); | 125 | self.exprs_to_wrap.push(ret_expr_arg.clone()); |
117 | } | 126 | } |
118 | } | 127 | } |
119 | Expr::BreakExpr(break_expr) if collect_break => { | 128 | Expr::BreakExpr(break_expr) if collect_break => { |
120 | if let Some(break_expr_arg) = &break_expr.expr() { | 129 | if let Some(break_expr_arg) = &break_expr.expr() { |
121 | self.exprs_to_wrap.push(break_expr_arg.syntax().clone()); | 130 | self.exprs_to_wrap.push(break_expr_arg.clone()); |
122 | } | 131 | } |
123 | } | 132 | } |
124 | Expr::IfExpr(if_expr) => { | 133 | Expr::IfExpr(if_expr) => { |
@@ -166,14 +175,11 @@ impl TailReturnCollector { | |||
166 | NodeType::Leaf(expr) => { | 175 | NodeType::Leaf(expr) => { |
167 | self.exprs_to_wrap.push(expr.clone()); | 176 | self.exprs_to_wrap.push(expr.clone()); |
168 | } | 177 | } |
169 | NodeType::Node(expr) => match &Expr::cast(expr.clone()) { | 178 | NodeType::Node(expr) => { |
170 | Some(last_expr) => { | 179 | if let Some(last_expr) = Expr::cast(expr.clone()) { |
171 | self.fetch_tail_exprs(last_expr); | 180 | self.fetch_tail_exprs(&last_expr); |
172 | } | ||
173 | None => { | ||
174 | self.exprs_to_wrap.push(expr.clone()); | ||
175 | } | 181 | } |
176 | }, | 182 | } |
177 | } | 183 | } |
178 | } | 184 | } |
179 | } | 185 | } |
@@ -182,7 +188,7 @@ impl TailReturnCollector { | |||
182 | 188 | ||
183 | #[derive(Debug)] | 189 | #[derive(Debug)] |
184 | enum NodeType { | 190 | enum NodeType { |
185 | Leaf(SyntaxNode), | 191 | Leaf(ast::Expr), |
186 | Node(SyntaxNode), | 192 | Node(SyntaxNode), |
187 | } | 193 | } |
188 | 194 | ||
@@ -233,25 +239,26 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
233 | 239 | ||
234 | Some(arms) | 240 | Some(arms) |
235 | } | 241 | } |
236 | Expr::BreakExpr(expr) => expr.expr().map(|e| vec![NodeType::Leaf(e.syntax().clone())]), | 242 | Expr::BreakExpr(expr) => expr.expr().map(|e| vec![NodeType::Leaf(e)]), |
237 | Expr::ReturnExpr(ret_expr) => Some(vec![NodeType::Node(ret_expr.syntax().clone())]), | 243 | Expr::ReturnExpr(ret_expr) => Some(vec![NodeType::Node(ret_expr.syntax().clone())]), |
238 | Expr::CallExpr(call_expr) => Some(vec![NodeType::Leaf(call_expr.syntax().clone())]), | 244 | |
239 | Expr::Literal(lit_expr) => Some(vec![NodeType::Leaf(lit_expr.syntax().clone())]), | 245 | Expr::CallExpr(_) |
240 | Expr::TupleExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 246 | | Expr::Literal(_) |
241 | Expr::ArrayExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 247 | | Expr::TupleExpr(_) |
242 | Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 248 | | Expr::ArrayExpr(_) |
243 | Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 249 | | Expr::ParenExpr(_) |
244 | Expr::RecordExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 250 | | Expr::PathExpr(_) |
245 | Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 251 | | Expr::RecordExpr(_) |
246 | Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 252 | | Expr::IndexExpr(_) |
247 | Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 253 | | Expr::MethodCallExpr(_) |
248 | Expr::CastExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 254 | | Expr::AwaitExpr(_) |
249 | Expr::RefExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 255 | | Expr::CastExpr(_) |
250 | Expr::PrefixExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 256 | | Expr::RefExpr(_) |
251 | Expr::RangeExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 257 | | Expr::PrefixExpr(_) |
252 | Expr::BinExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 258 | | Expr::RangeExpr(_) |
253 | Expr::MacroCall(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 259 | | Expr::BinExpr(_) |
254 | Expr::BoxExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | 260 | | Expr::MacroCall(_) |
261 | | Expr::BoxExpr(_) => Some(vec![NodeType::Leaf(expr.clone())]), | ||
255 | _ => None, | 262 | _ => None, |
256 | } | 263 | } |
257 | } | 264 | } |
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 6e9f2d0fc..497f887cd 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use hir::{EnumVariant, Module, ModuleDef, Name}; | 1 | use hir::{EnumVariant, Module, ModuleDef, Name}; |
2 | use ra_db::FileId; | 2 | use ra_db::FileId; |
3 | use ra_fmt::leading_indent; | ||
4 | use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; | 3 | use ra_ide_db::{defs::Definition, search::Reference, RootDatabase}; |
5 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
6 | use syntax::{ | 5 | use syntax::{ |
7 | algo::find_node_at_offset, | 6 | algo::find_node_at_offset, |
8 | ast::{self, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, | 7 | ast::{self, edit::IndentLevel, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, |
9 | SourceFile, SyntaxNode, TextRange, TextSize, | 8 | SourceFile, TextRange, TextSize, |
10 | }; | 9 | }; |
11 | 10 | ||
12 | use crate::{ | 11 | use crate::{ |
@@ -72,7 +71,7 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
72 | } | 71 | } |
73 | extract_struct_def( | 72 | extract_struct_def( |
74 | builder, | 73 | builder, |
75 | enum_ast.syntax(), | 74 | &enum_ast, |
76 | &variant_name, | 75 | &variant_name, |
77 | &field_list.to_string(), | 76 | &field_list.to_string(), |
78 | start_offset, | 77 | start_offset, |
@@ -112,9 +111,10 @@ fn insert_import( | |||
112 | Some(()) | 111 | Some(()) |
113 | } | 112 | } |
114 | 113 | ||
114 | // FIXME: this should use strongly-typed `make`, rather than string manipulation. | ||
115 | fn extract_struct_def( | 115 | fn extract_struct_def( |
116 | builder: &mut AssistBuilder, | 116 | builder: &mut AssistBuilder, |
117 | enum_ast: &SyntaxNode, | 117 | enum_: &ast::Enum, |
118 | variant_name: &str, | 118 | variant_name: &str, |
119 | variant_list: &str, | 119 | variant_list: &str, |
120 | start_offset: TextSize, | 120 | start_offset: TextSize, |
@@ -126,11 +126,7 @@ fn extract_struct_def( | |||
126 | } else { | 126 | } else { |
127 | "".to_string() | 127 | "".to_string() |
128 | }; | 128 | }; |
129 | let indent = if let Some(indent) = leading_indent(enum_ast) { | 129 | let indent = IndentLevel::from_node(enum_.syntax()); |
130 | indent.to_string() | ||
131 | } else { | ||
132 | "".to_string() | ||
133 | }; | ||
134 | let struct_def = format!( | 130 | let struct_def = format!( |
135 | r#"{}struct {}{}; | 131 | r#"{}struct {}{}; |
136 | 132 | ||
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index c62ebc306..452115fe6 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{AstNode, IfExpr, MatchArm}, | 2 | ast::{edit::AstNodeEdit, make, AstNode, IfExpr, MatchArm}, |
3 | SyntaxKind::WHITESPACE, | 3 | SyntaxKind::WHITESPACE, |
4 | }; | 4 | }; |
5 | 5 | ||
@@ -25,7 +25,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
25 | // | 25 | // |
26 | // fn handle(action: Action) { | 26 | // fn handle(action: Action) { |
27 | // match action { | 27 | // match action { |
28 | // Action::Move { distance } => if distance > 10 { foo() }, | 28 | // Action::Move { distance } => if distance > 10 { |
29 | // foo() | ||
30 | // }, | ||
29 | // _ => (), | 31 | // _ => (), |
30 | // } | 32 | // } |
31 | // } | 33 | // } |
@@ -35,9 +37,13 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
35 | let guard = match_arm.guard()?; | 37 | let guard = match_arm.guard()?; |
36 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | 38 | let space_before_guard = guard.syntax().prev_sibling_or_token(); |
37 | 39 | ||
38 | let guard_conditions = guard.expr()?; | 40 | let guard_condition = guard.expr()?; |
39 | let arm_expr = match_arm.expr()?; | 41 | let arm_expr = match_arm.expr()?; |
40 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | 42 | let if_expr = make::expr_if( |
43 | make::condition(guard_condition, None), | ||
44 | make::block_expr(None, Some(arm_expr.clone())), | ||
45 | ) | ||
46 | .indent(arm_expr.indent_level()); | ||
41 | 47 | ||
42 | let target = guard.syntax().text_range(); | 48 | let target = guard.syntax().text_range(); |
43 | acc.add( | 49 | acc.add( |
@@ -53,7 +59,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) -> | |||
53 | }; | 59 | }; |
54 | 60 | ||
55 | edit.delete(guard.syntax().text_range()); | 61 | edit.delete(guard.syntax().text_range()); |
56 | edit.replace_node_and_indent(arm_expr.syntax(), buf); | 62 | edit.replace_ast(arm_expr, if_expr); |
57 | }, | 63 | }, |
58 | ) | 64 | ) |
59 | } | 65 | } |
@@ -134,16 +140,14 @@ mod tests { | |||
134 | check_assist_target( | 140 | check_assist_target( |
135 | move_guard_to_arm_body, | 141 | move_guard_to_arm_body, |
136 | r#" | 142 | r#" |
137 | fn f() { | 143 | fn main() { |
138 | let t = 'a'; | 144 | match 92 { |
139 | let chars = "abcd"; | 145 | x <|>if x > 10 => false, |
140 | match t { | 146 | _ => true |
141 | '\r' <|>if chars.clone().next() == Some('\n') => false, | 147 | } |
142 | _ => true | 148 | } |
143 | } | 149 | "#, |
144 | } | 150 | r#"if x > 10"#, |
145 | "#, | ||
146 | r#"if chars.clone().next() == Some('\n')"#, | ||
147 | ); | 151 | ); |
148 | } | 152 | } |
149 | 153 | ||
@@ -152,25 +156,23 @@ mod tests { | |||
152 | check_assist( | 156 | check_assist( |
153 | move_guard_to_arm_body, | 157 | move_guard_to_arm_body, |
154 | r#" | 158 | r#" |
155 | fn f() { | 159 | fn main() { |
156 | let t = 'a'; | 160 | match 92 { |
157 | let chars = "abcd"; | 161 | x <|>if x > 10 => false, |
158 | match t { | 162 | _ => true |
159 | '\r' <|>if chars.clone().next() == Some('\n') => false, | 163 | } |
160 | _ => true | 164 | } |
161 | } | 165 | "#, |
162 | } | ||
163 | "#, | ||
164 | r#" | 166 | r#" |
165 | fn f() { | 167 | fn main() { |
166 | let t = 'a'; | 168 | match 92 { |
167 | let chars = "abcd"; | 169 | x => if x > 10 { |
168 | match t { | 170 | false |
169 | '\r' => if chars.clone().next() == Some('\n') { false }, | 171 | }, |
170 | _ => true | 172 | _ => true |
171 | } | 173 | } |
172 | } | 174 | } |
173 | "#, | 175 | "#, |
174 | ); | 176 | ); |
175 | } | 177 | } |
176 | 178 | ||
@@ -179,21 +181,23 @@ mod tests { | |||
179 | check_assist( | 181 | check_assist( |
180 | move_guard_to_arm_body, | 182 | move_guard_to_arm_body, |
181 | r#" | 183 | r#" |
182 | fn f() { | 184 | fn main() { |
183 | match x { | 185 | match 92 { |
184 | <|>y @ 4 | y @ 5 if y > 5 => true, | 186 | <|>x @ 4 | x @ 5 if x > 5 => true, |
185 | _ => false | 187 | _ => false |
186 | } | 188 | } |
187 | } | 189 | } |
188 | "#, | 190 | "#, |
189 | r#" | 191 | r#" |
190 | fn f() { | 192 | fn main() { |
191 | match x { | 193 | match 92 { |
192 | y @ 4 | y @ 5 => if y > 5 { true }, | 194 | x @ 4 | x @ 5 => if x > 5 { |
193 | _ => false | 195 | true |
194 | } | 196 | }, |
195 | } | 197 | _ => false |
196 | "#, | 198 | } |
199 | } | ||
200 | "#, | ||
197 | ); | 201 | ); |
198 | } | 202 | } |
199 | 203 | ||
@@ -202,25 +206,21 @@ mod tests { | |||
202 | check_assist( | 206 | check_assist( |
203 | move_arm_cond_to_match_guard, | 207 | move_arm_cond_to_match_guard, |
204 | r#" | 208 | r#" |
205 | fn f() { | 209 | fn main() { |
206 | let t = 'a'; | 210 | match 92 { |
207 | let chars = "abcd"; | 211 | x => if x > 10 { <|>false }, |
208 | match t { | 212 | _ => true |
209 | '\r' => if chars.clone().next() == Some('\n') { <|>false }, | 213 | } |
210 | _ => true | 214 | } |
211 | } | 215 | "#, |
212 | } | ||
213 | "#, | ||
214 | r#" | 216 | r#" |
215 | fn f() { | 217 | fn main() { |
216 | let t = 'a'; | 218 | match 92 { |
217 | let chars = "abcd"; | 219 | x if x > 10 => false, |
218 | match t { | 220 | _ => true |
219 | '\r' if chars.clone().next() == Some('\n') => false, | 221 | } |
220 | _ => true | 222 | } |
221 | } | 223 | "#, |
222 | } | ||
223 | "#, | ||
224 | ); | 224 | ); |
225 | } | 225 | } |
226 | 226 | ||
@@ -229,15 +229,13 @@ mod tests { | |||
229 | check_assist_not_applicable( | 229 | check_assist_not_applicable( |
230 | move_arm_cond_to_match_guard, | 230 | move_arm_cond_to_match_guard, |
231 | r#" | 231 | r#" |
232 | fn f() { | 232 | fn main() { |
233 | let t = 'a'; | 233 | match 92 { |
234 | let chars = "abcd"; | 234 | x => if let 62 = x { <|>false }, |
235 | match t { | 235 | _ => true |
236 | '\r' => if let Some(_) = chars.clone().next() { <|>false }, | 236 | } |
237 | _ => true | 237 | } |
238 | } | 238 | "#, |
239 | } | ||
240 | "#, | ||
241 | ); | 239 | ); |
242 | } | 240 | } |
243 | 241 | ||
@@ -246,25 +244,21 @@ mod tests { | |||
246 | check_assist( | 244 | check_assist( |
247 | move_arm_cond_to_match_guard, | 245 | move_arm_cond_to_match_guard, |
248 | r#" | 246 | r#" |
249 | fn f() { | 247 | fn main() { |
250 | let t = 'a'; | 248 | match 92 { |
251 | let chars = "abcd"; | 249 | x => if x > 10 { <|> }, |
252 | match t { | 250 | _ => true |
253 | '\r' => if chars.clone().next().is_some() { <|> }, | 251 | } |
254 | _ => true | 252 | } |
255 | } | 253 | "#, |
256 | } | ||
257 | "#, | ||
258 | r#" | 254 | r#" |
259 | fn f() { | 255 | fn main() { |
260 | let t = 'a'; | 256 | match 92 { |
261 | let chars = "abcd"; | 257 | x if x > 10 => { }, |
262 | match t { | 258 | _ => true |
263 | '\r' if chars.clone().next().is_some() => { }, | 259 | } |
264 | _ => true | 260 | } |
265 | } | 261 | "#, |
266 | } | ||
267 | "#, | ||
268 | ); | 262 | ); |
269 | } | 263 | } |
270 | 264 | ||
@@ -273,31 +267,27 @@ mod tests { | |||
273 | check_assist( | 267 | check_assist( |
274 | move_arm_cond_to_match_guard, | 268 | move_arm_cond_to_match_guard, |
275 | r#" | 269 | r#" |
276 | fn f() { | 270 | fn main() { |
277 | let mut t = 'a'; | 271 | match 92 { |
278 | let chars = "abcd"; | 272 | x => if x > 10 { |
279 | match t { | 273 | 92;<|> |
280 | '\r' => if chars.clone().next().is_some() { | 274 | false |
281 | t = 'e';<|> | 275 | }, |
282 | false | 276 | _ => true |
283 | }, | 277 | } |
284 | _ => true | 278 | } |
285 | } | 279 | "#, |
286 | } | ||
287 | "#, | ||
288 | r#" | 280 | r#" |
289 | fn f() { | 281 | fn main() { |
290 | let mut t = 'a'; | 282 | match 92 { |
291 | let chars = "abcd"; | 283 | x if x > 10 => { |
292 | match t { | 284 | 92; |
293 | '\r' if chars.clone().next().is_some() => { | 285 | false |
294 | t = 'e'; | 286 | }, |
295 | false | 287 | _ => true |
296 | }, | 288 | } |
297 | _ => true | 289 | } |
298 | } | 290 | "#, |
299 | } | ||
300 | "#, | ||
301 | ); | 291 | ); |
302 | } | 292 | } |
303 | } | 293 | } |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 2442f049b..79097621e 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -1,4 +1,3 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | ||
2 | use syntax::{ | 1 | use syntax::{ |
3 | ast::{ | 2 | ast::{ |
4 | self, | 3 | self, |
@@ -8,7 +7,10 @@ use syntax::{ | |||
8 | AstNode, | 7 | AstNode, |
9 | }; | 8 | }; |
10 | 9 | ||
11 | use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; | 10 | use crate::{ |
11 | utils::{unwrap_trivial_block, TryEnum}, | ||
12 | AssistContext, AssistId, AssistKind, Assists, | ||
13 | }; | ||
12 | 14 | ||
13 | // Assist: replace_if_let_with_match | 15 | // Assist: replace_if_let_with_match |
14 | // | 16 | // |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 2879090b8..3851aeb3e 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,4 +1,3 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | ||
2 | use syntax::{ | 1 | use syntax::{ |
3 | ast::{ | 2 | ast::{ |
4 | self, | 3 | self, |
@@ -7,7 +6,7 @@ use syntax::{ | |||
7 | AstNode, TextRange, T, | 6 | AstNode, TextRange, T, |
8 | }; | 7 | }; |
9 | 8 | ||
10 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 9 | use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists}; |
11 | 10 | ||
12 | // Assist: unwrap_block | 11 | // Assist: unwrap_block |
13 | // | 12 | // |
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index 97978e7a2..d16e6fb0a 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs | |||
@@ -690,7 +690,9 @@ enum Action { Move { distance: u32 }, Stop } | |||
690 | 690 | ||
691 | fn handle(action: Action) { | 691 | fn handle(action: Action) { |
692 | match action { | 692 | match action { |
693 | Action::Move { distance } => if distance > 10 { foo() }, | 693 | Action::Move { distance } => if distance > 10 { |
694 | foo() | ||
695 | }, | ||
694 | _ => (), | 696 | _ => (), |
695 | } | 697 | } |
696 | } | 698 | } |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 6d85661c4..a20453dd8 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -4,6 +4,7 @@ pub(crate) mod insert_use; | |||
4 | use std::{iter, ops}; | 4 | use std::{iter, ops}; |
5 | 5 | ||
6 | use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; | 6 | use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; |
7 | use itertools::Itertools; | ||
7 | use ra_ide_db::RootDatabase; | 8 | use ra_ide_db::RootDatabase; |
8 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
9 | use syntax::{ | 10 | use syntax::{ |
@@ -17,6 +18,43 @@ use crate::assist_config::SnippetCap; | |||
17 | 18 | ||
18 | pub(crate) use insert_use::{find_insert_use_container, insert_use_statement}; | 19 | pub(crate) use insert_use::{find_insert_use_container, insert_use_statement}; |
19 | 20 | ||
21 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | ||
22 | extract_trivial_expression(&block) | ||
23 | .filter(|expr| !expr.syntax().text().contains_char('\n')) | ||
24 | .unwrap_or_else(|| block.into()) | ||
25 | } | ||
26 | |||
27 | pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | ||
28 | let has_anything_else = |thing: &SyntaxNode| -> bool { | ||
29 | let mut non_trivial_children = | ||
30 | block.syntax().children_with_tokens().filter(|it| match it.kind() { | ||
31 | WHITESPACE | T!['{'] | T!['}'] => false, | ||
32 | _ => it.as_node() != Some(thing), | ||
33 | }); | ||
34 | non_trivial_children.next().is_some() | ||
35 | }; | ||
36 | |||
37 | if let Some(expr) = block.expr() { | ||
38 | if has_anything_else(expr.syntax()) { | ||
39 | return None; | ||
40 | } | ||
41 | return Some(expr); | ||
42 | } | ||
43 | // Unwrap `{ continue; }` | ||
44 | let (stmt,) = block.statements().next_tuple()?; | ||
45 | if let ast::Stmt::ExprStmt(expr_stmt) = stmt { | ||
46 | if has_anything_else(expr_stmt.syntax()) { | ||
47 | return None; | ||
48 | } | ||
49 | let expr = expr_stmt.expr()?; | ||
50 | match expr.syntax().kind() { | ||
51 | CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), | ||
52 | _ => (), | ||
53 | } | ||
54 | } | ||
55 | None | ||
56 | } | ||
57 | |||
20 | #[derive(Clone, Copy, Debug)] | 58 | #[derive(Clone, Copy, Debug)] |
21 | pub(crate) enum Cursor<'a> { | 59 | pub(crate) enum Cursor<'a> { |
22 | Replace(&'a SyntaxNode), | 60 | Replace(&'a SyntaxNode), |
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index f89c288da..50a62ee82 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs | |||
@@ -2,13 +2,15 @@ | |||
2 | // FIXME: rewrite according to the plan, outlined in | 2 | // FIXME: rewrite according to the plan, outlined in |
3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 | 3 | // https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553 |
4 | 4 | ||
5 | use std::iter::successors; | ||
6 | |||
5 | use either::Either; | 7 | use either::Either; |
6 | use hir::{self, ModPath}; | 8 | use hir::{self, ModPath}; |
7 | use syntax::{ | 9 | use syntax::{ |
8 | ast::{self, NameOwner, VisibilityOwner}, | 10 | ast::{self, NameOwner, VisibilityOwner}, |
9 | AstNode, Direction, SmolStr, | 11 | AstNode, AstToken, Direction, SmolStr, |
10 | SyntaxKind::{PATH, PATH_SEGMENT}, | 12 | SyntaxKind::{PATH, PATH_SEGMENT}, |
11 | SyntaxNode, T, | 13 | SyntaxNode, SyntaxToken, T, |
12 | }; | 14 | }; |
13 | use text_edit::TextEditBuilder; | 15 | use text_edit::TextEditBuilder; |
14 | 16 | ||
@@ -442,7 +444,7 @@ fn make_assist_add_new_use( | |||
442 | edit: &mut TextEditBuilder, | 444 | edit: &mut TextEditBuilder, |
443 | ) { | 445 | ) { |
444 | if let Some(anchor) = anchor { | 446 | if let Some(anchor) = anchor { |
445 | let indent = ra_fmt::leading_indent(anchor); | 447 | let indent = leading_indent(anchor); |
446 | let mut buf = String::new(); | 448 | let mut buf = String::new(); |
447 | if after { | 449 | if after { |
448 | buf.push_str("\n"); | 450 | buf.push_str("\n"); |
@@ -524,3 +526,22 @@ fn make_assist_add_nested_import( | |||
524 | edit.insert(end, "}".to_string()); | 526 | edit.insert(end, "}".to_string()); |
525 | } | 527 | } |
526 | } | 528 | } |
529 | |||
530 | /// If the node is on the beginning of the line, calculate indent. | ||
531 | fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { | ||
532 | for token in prev_tokens(node.first_token()?) { | ||
533 | if let Some(ws) = ast::Whitespace::cast(token.clone()) { | ||
534 | let ws_text = ws.text(); | ||
535 | if let Some(pos) = ws_text.rfind('\n') { | ||
536 | return Some(ws_text[pos + 1..].into()); | ||
537 | } | ||
538 | } | ||
539 | if token.text().contains('\n') { | ||
540 | break; | ||
541 | } | ||
542 | } | ||
543 | return None; | ||
544 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | ||
545 | successors(token.prev_token(), |token| token.prev_token()) | ||
546 | } | ||
547 | } | ||