aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api_light/src/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api_light/src/assists')
-rw-r--r--crates/ra_ide_api_light/src/assists/add_derive.rs84
-rw-r--r--crates/ra_ide_api_light/src/assists/add_impl.rs66
-rw-r--r--crates/ra_ide_api_light/src/assists/change_visibility.rs165
-rw-r--r--crates/ra_ide_api_light/src/assists/flip_comma.rs31
-rw-r--r--crates/ra_ide_api_light/src/assists/introduce_variable.rs431
-rw-r--r--crates/ra_ide_api_light/src/assists/replace_if_let_with_match.rs81
-rw-r--r--crates/ra_ide_api_light/src/assists/split_import.rs56
7 files changed, 0 insertions, 914 deletions
diff --git a/crates/ra_ide_api_light/src/assists/add_derive.rs b/crates/ra_ide_api_light/src/assists/add_derive.rs
deleted file mode 100644
index 6e964d011..000000000
--- a/crates/ra_ide_api_light/src/assists/add_derive.rs
+++ /dev/null
@@ -1,84 +0,0 @@
1use ra_syntax::{
2 ast::{self, AstNode, AttrsOwner},
3 SyntaxKind::{WHITESPACE, COMMENT},
4 TextUnit,
5};
6
7use crate::assists::{AssistCtx, Assist};
8
9pub fn add_derive(ctx: AssistCtx) -> Option<Assist> {
10 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
11 let node_start = derive_insertion_offset(nominal)?;
12 ctx.build("add `#[derive]`", |edit| {
13 let derive_attr = nominal
14 .attrs()
15 .filter_map(|x| x.as_call())
16 .filter(|(name, _arg)| name == "derive")
17 .map(|(_name, arg)| arg)
18 .next();
19 let offset = match derive_attr {
20 None => {
21 edit.insert(node_start, "#[derive()]\n");
22 node_start + TextUnit::of_str("#[derive(")
23 }
24 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
25 };
26 edit.set_cursor(offset)
27 })
28}
29
30// Insert `derive` after doc comments.
31fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
32 let non_ws_child = nominal
33 .syntax()
34 .children()
35 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
36 Some(non_ws_child.range().start())
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use crate::assists::check_assist;
43
44 #[test]
45 fn add_derive_new() {
46 check_assist(
47 add_derive,
48 "struct Foo { a: i32, <|>}",
49 "#[derive(<|>)]\nstruct Foo { a: i32, }",
50 );
51 check_assist(
52 add_derive,
53 "struct Foo { <|> a: i32, }",
54 "#[derive(<|>)]\nstruct Foo { a: i32, }",
55 );
56 }
57
58 #[test]
59 fn add_derive_existing() {
60 check_assist(
61 add_derive,
62 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
63 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
64 );
65 }
66
67 #[test]
68 fn add_derive_new_with_doc_comment() {
69 check_assist(
70 add_derive,
71 "
72/// `Foo` is a pretty important struct.
73/// It does stuff.
74struct Foo { a: i32<|>, }
75 ",
76 "
77/// `Foo` is a pretty important struct.
78/// It does stuff.
79#[derive(<|>)]
80struct Foo { a: i32, }
81 ",
82 );
83 }
84}
diff --git a/crates/ra_ide_api_light/src/assists/add_impl.rs b/crates/ra_ide_api_light/src/assists/add_impl.rs
deleted file mode 100644
index 2eda7cae2..000000000
--- a/crates/ra_ide_api_light/src/assists/add_impl.rs
+++ /dev/null
@@ -1,66 +0,0 @@
1use join_to_string::join;
2use ra_syntax::{
3 ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner},
4 TextUnit,
5};
6
7use crate::assists::{AssistCtx, Assist};
8
9pub fn add_impl(ctx: AssistCtx) -> Option<Assist> {
10 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
11 let name = nominal.name()?;
12 ctx.build("add impl", |edit| {
13 let type_params = nominal.type_param_list();
14 let start_offset = nominal.syntax().range().end();
15 let mut buf = String::new();
16 buf.push_str("\n\nimpl");
17 if let Some(type_params) = type_params {
18 type_params.syntax().text().push_to(&mut buf);
19 }
20 buf.push_str(" ");
21 buf.push_str(name.text().as_str());
22 if let Some(type_params) = type_params {
23 let lifetime_params = type_params
24 .lifetime_params()
25 .filter_map(|it| it.lifetime())
26 .map(|it| it.text());
27 let type_params = type_params
28 .type_params()
29 .filter_map(|it| it.name())
30 .map(|it| it.text());
31 join(lifetime_params.chain(type_params))
32 .surround_with("<", ">")
33 .to_buf(&mut buf);
34 }
35 buf.push_str(" {\n");
36 edit.set_cursor(start_offset + TextUnit::of_str(&buf));
37 buf.push_str("\n}");
38 edit.insert(start_offset, buf);
39 })
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use crate::assists::check_assist;
46
47 #[test]
48 fn test_add_impl() {
49 check_assist(
50 add_impl,
51 "struct Foo {<|>}\n",
52 "struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
53 );
54 check_assist(
55 add_impl,
56 "struct Foo<T: Clone> {<|>}",
57 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
58 );
59 check_assist(
60 add_impl,
61 "struct Foo<'a, T: Foo<'a>> {<|>}",
62 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}",
63 );
64 }
65
66}
diff --git a/crates/ra_ide_api_light/src/assists/change_visibility.rs b/crates/ra_ide_api_light/src/assists/change_visibility.rs
deleted file mode 100644
index 6e8bc2632..000000000
--- a/crates/ra_ide_api_light/src/assists/change_visibility.rs
+++ /dev/null
@@ -1,165 +0,0 @@
1use ra_syntax::{
2 AstNode, SyntaxNode, TextUnit,
3 ast::{self, VisibilityOwner, NameOwner},
4 SyntaxKind::{VISIBILITY, FN_KW, MOD_KW, STRUCT_KW, ENUM_KW, TRAIT_KW, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF, IDENT, WHITESPACE, COMMENT, ATTR},
5};
6
7use crate::assists::{AssistCtx, Assist};
8
9pub fn change_visibility(ctx: AssistCtx) -> Option<Assist> {
10 if let Some(vis) = ctx.node_at_offset::<ast::Visibility>() {
11 return change_vis(ctx, vis);
12 }
13 add_vis(ctx)
14}
15
16fn add_vis(ctx: AssistCtx) -> Option<Assist> {
17 let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() {
18 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
19 _ => false,
20 });
21
22 let offset = if let Some(keyword) = item_keyword {
23 let parent = keyword.parent()?;
24 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
25 // Parent is not a definition, can't add visibility
26 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
27 return None;
28 }
29 // Already have visibility, do nothing
30 if parent.children().any(|child| child.kind() == VISIBILITY) {
31 return None;
32 }
33 vis_offset(parent)
34 } else {
35 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?;
36 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?;
37 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
38 return None;
39 }
40 vis_offset(field.syntax())
41 };
42
43 ctx.build("make pub(crate)", |edit| {
44 edit.insert(offset, "pub(crate) ");
45 edit.set_cursor(offset);
46 })
47}
48
49fn vis_offset(node: &SyntaxNode) -> TextUnit {
50 node.children()
51 .skip_while(|it| match it.kind() {
52 WHITESPACE | COMMENT | ATTR => true,
53 _ => false,
54 })
55 .next()
56 .map(|it| it.range().start())
57 .unwrap_or(node.range().start())
58}
59
60fn change_vis(ctx: AssistCtx, vis: &ast::Visibility) -> Option<Assist> {
61 if vis.syntax().text() == "pub" {
62 return ctx.build("chage to pub(crate)", |edit| {
63 edit.replace(vis.syntax().range(), "pub(crate)");
64 edit.set_cursor(vis.syntax().range().start());
65 });
66 }
67 if vis.syntax().text() == "pub(crate)" {
68 return ctx.build("chage to pub", |edit| {
69 edit.replace(vis.syntax().range(), "pub");
70 edit.set_cursor(vis.syntax().range().start());
71 });
72 }
73 None
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::assists::check_assist;
80
81 #[test]
82 fn change_visibility_adds_pub_crate_to_items() {
83 check_assist(
84 change_visibility,
85 "<|>fn foo() {}",
86 "<|>pub(crate) fn foo() {}",
87 );
88 check_assist(
89 change_visibility,
90 "f<|>n foo() {}",
91 "<|>pub(crate) fn foo() {}",
92 );
93 check_assist(
94 change_visibility,
95 "<|>struct Foo {}",
96 "<|>pub(crate) struct Foo {}",
97 );
98 check_assist(
99 change_visibility,
100 "<|>mod foo {}",
101 "<|>pub(crate) mod foo {}",
102 );
103 check_assist(
104 change_visibility,
105 "<|>trait Foo {}",
106 "<|>pub(crate) trait Foo {}",
107 );
108 check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
109 check_assist(
110 change_visibility,
111 "unsafe f<|>n foo() {}",
112 "<|>pub(crate) unsafe fn foo() {}",
113 );
114 }
115
116 #[test]
117 fn change_visibility_works_with_struct_fields() {
118 check_assist(
119 change_visibility,
120 "struct S { <|>field: u32 }",
121 "struct S { <|>pub(crate) field: u32 }",
122 )
123 }
124
125 #[test]
126 fn change_visibility_pub_to_pub_crate() {
127 check_assist(
128 change_visibility,
129 "<|>pub fn foo() {}",
130 "<|>pub(crate) fn foo() {}",
131 )
132 }
133
134 #[test]
135 fn change_visibility_pub_crate_to_pub() {
136 check_assist(
137 change_visibility,
138 "<|>pub(crate) fn foo() {}",
139 "<|>pub fn foo() {}",
140 )
141 }
142
143 #[test]
144 fn change_visibility_handles_comment_attrs() {
145 check_assist(
146 change_visibility,
147 "
148 /// docs
149
150 // comments
151
152 #[derive(Debug)]
153 <|>struct Foo;
154 ",
155 "
156 /// docs
157
158 // comments
159
160 #[derive(Debug)]
161 <|>pub(crate) struct Foo;
162 ",
163 )
164 }
165}
diff --git a/crates/ra_ide_api_light/src/assists/flip_comma.rs b/crates/ra_ide_api_light/src/assists/flip_comma.rs
deleted file mode 100644
index a343413cc..000000000
--- a/crates/ra_ide_api_light/src/assists/flip_comma.rs
+++ /dev/null
@@ -1,31 +0,0 @@
1use ra_syntax::{
2 Direction,
3 SyntaxKind::COMMA,
4};
5
6use crate::assists::{non_trivia_sibling, AssistCtx, Assist};
7
8pub fn flip_comma(ctx: AssistCtx) -> Option<Assist> {
9 let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?;
10 let prev = non_trivia_sibling(comma, Direction::Prev)?;
11 let next = non_trivia_sibling(comma, Direction::Next)?;
12 ctx.build("flip comma", |edit| {
13 edit.replace(prev.range(), next.text());
14 edit.replace(next.range(), prev.text());
15 })
16}
17
18#[cfg(test)]
19mod tests {
20 use super::*;
21 use crate::assists::check_assist;
22
23 #[test]
24 fn flip_comma_works_for_function_parameters() {
25 check_assist(
26 flip_comma,
27 "fn foo(x: i32,<|> y: Result<(), ()>) {}",
28 "fn foo(y: Result<(), ()>,<|> x: i32) {}",
29 )
30 }
31}
diff --git a/crates/ra_ide_api_light/src/assists/introduce_variable.rs b/crates/ra_ide_api_light/src/assists/introduce_variable.rs
deleted file mode 100644
index ed13bddc4..000000000
--- a/crates/ra_ide_api_light/src/assists/introduce_variable.rs
+++ /dev/null
@@ -1,431 +0,0 @@
1use ra_syntax::{
2 ast::{self, AstNode},
3 SyntaxKind::{
4 WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT
5 }, SyntaxNode, TextUnit,
6};
7
8use crate::assists::{AssistCtx, Assist};
9
10pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
11 let node = ctx.covering_node();
12 if !valid_covering_node(node) {
13 return None;
14 }
15 let expr = node.ancestors().filter_map(valid_target_expr).next()?;
16 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?;
17 let indent = anchor_stmt.prev_sibling()?;
18 if indent.kind() != WHITESPACE {
19 return None;
20 }
21 ctx.build("introduce variable", move |edit| {
22 let mut buf = String::new();
23
24 let cursor_offset = if wrap_in_block {
25 buf.push_str("{ let var_name = ");
26 TextUnit::of_str("{ let ")
27 } else {
28 buf.push_str("let var_name = ");
29 TextUnit::of_str("let ")
30 };
31
32 expr.syntax().text().push_to(&mut buf);
33 let full_stmt = ast::ExprStmt::cast(anchor_stmt);
34 let is_full_stmt = if let Some(expr_stmt) = full_stmt {
35 Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
36 } else {
37 false
38 };
39 if is_full_stmt {
40 if !full_stmt.unwrap().has_semi() {
41 buf.push_str(";");
42 }
43 edit.replace(expr.syntax().range(), buf);
44 } else {
45 buf.push_str(";");
46 indent.text().push_to(&mut buf);
47 edit.replace(expr.syntax().range(), "var_name".to_string());
48 edit.insert(anchor_stmt.range().start(), buf);
49 if wrap_in_block {
50 edit.insert(anchor_stmt.range().end(), " }");
51 }
52 }
53 edit.set_cursor(anchor_stmt.range().start() + cursor_offset);
54 })
55}
56
57fn valid_covering_node(node: &SyntaxNode) -> bool {
58 node.kind() != COMMENT
59}
60/// Check wether the node is a valid expression which can be extracted to a variable.
61/// In general that's true for any expression, but in some cases that would produce invalid code.
62fn valid_target_expr(node: &SyntaxNode) -> Option<&ast::Expr> {
63 return match node.kind() {
64 PATH_EXPR => None,
65 BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
66 RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
67 LOOP_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
68 _ => ast::Expr::cast(node),
69 };
70}
71
72/// Returns the syntax node which will follow the freshly introduced var
73/// and a boolean indicating whether we have to wrap it within a { } block
74/// to produce correct code.
75/// It can be a statement, the last in a block expression or a wanna be block
76/// expression like a lamba or match arm.
77fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> {
78 expr.syntax().ancestors().find_map(|node| {
79 if ast::Stmt::cast(node).is_some() {
80 return Some((node, false));
81 }
82
83 if let Some(expr) = node
84 .parent()
85 .and_then(ast::Block::cast)
86 .and_then(|it| it.expr())
87 {
88 if expr.syntax() == node {
89 return Some((node, false));
90 }
91 }
92
93 if let Some(parent) = node.parent() {
94 if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR {
95 return Some((node, true));
96 }
97 }
98
99 None
100 })
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::assists::{ check_assist, check_assist_not_applicable, check_assist_range };
107
108 #[test]
109 fn test_introduce_var_simple() {
110 check_assist_range(
111 introduce_variable,
112 "
113fn foo() {
114 foo(<|>1 + 1<|>);
115}",
116 "
117fn foo() {
118 let <|>var_name = 1 + 1;
119 foo(var_name);
120}",
121 );
122 }
123
124 #[test]
125 fn test_introduce_var_expr_stmt() {
126 check_assist_range(
127 introduce_variable,
128 "
129fn foo() {
130 <|>1 + 1<|>;
131}",
132 "
133fn foo() {
134 let <|>var_name = 1 + 1;
135}",
136 );
137 }
138
139 #[test]
140 fn test_introduce_var_part_of_expr_stmt() {
141 check_assist_range(
142 introduce_variable,
143 "
144fn foo() {
145 <|>1<|> + 1;
146}",
147 "
148fn foo() {
149 let <|>var_name = 1;
150 var_name + 1;
151}",
152 );
153 }
154
155 #[test]
156 fn test_introduce_var_last_expr() {
157 check_assist_range(
158 introduce_variable,
159 "
160fn foo() {
161 bar(<|>1 + 1<|>)
162}",
163 "
164fn foo() {
165 let <|>var_name = 1 + 1;
166 bar(var_name)
167}",
168 );
169 }
170
171 #[test]
172 fn test_introduce_var_last_full_expr() {
173 check_assist_range(
174 introduce_variable,
175 "
176fn foo() {
177 <|>bar(1 + 1)<|>
178}",
179 "
180fn foo() {
181 let <|>var_name = bar(1 + 1);
182 var_name
183}",
184 );
185 }
186
187 #[test]
188 fn test_introduce_var_block_expr_second_to_last() {
189 check_assist_range(
190 introduce_variable,
191 "
192fn foo() {
193 <|>{ let x = 0; x }<|>
194 something_else();
195}",
196 "
197fn foo() {
198 let <|>var_name = { let x = 0; x };
199 something_else();
200}",
201 );
202 }
203
204 #[test]
205 fn test_introduce_var_in_match_arm_no_block() {
206 check_assist_range(
207 introduce_variable,
208 "
209fn main() {
210 let x = true;
211 let tuple = match x {
212 true => (<|>2 + 2<|>, true)
213 _ => (0, false)
214 };
215}
216",
217 "
218fn main() {
219 let x = true;
220 let tuple = match x {
221 true => { let <|>var_name = 2 + 2; (var_name, true) }
222 _ => (0, false)
223 };
224}
225",
226 );
227 }
228
229 #[test]
230 fn test_introduce_var_in_match_arm_with_block() {
231 check_assist_range(
232 introduce_variable,
233 "
234fn main() {
235 let x = true;
236 let tuple = match x {
237 true => {
238 let y = 1;
239 (<|>2 + y<|>, true)
240 }
241 _ => (0, false)
242 };
243}
244",
245 "
246fn main() {
247 let x = true;
248 let tuple = match x {
249 true => {
250 let y = 1;
251 let <|>var_name = 2 + y;
252 (var_name, true)
253 }
254 _ => (0, false)
255 };
256}
257",
258 );
259 }
260
261 #[test]
262 fn test_introduce_var_in_closure_no_block() {
263 check_assist_range(
264 introduce_variable,
265 "
266fn main() {
267 let lambda = |x: u32| <|>x * 2<|>;
268}
269",
270 "
271fn main() {
272 let lambda = |x: u32| { let <|>var_name = x * 2; var_name };
273}
274",
275 );
276 }
277
278 #[test]
279 fn test_introduce_var_in_closure_with_block() {
280 check_assist_range(
281 introduce_variable,
282 "
283fn main() {
284 let lambda = |x: u32| { <|>x * 2<|> };
285}
286",
287 "
288fn main() {
289 let lambda = |x: u32| { let <|>var_name = x * 2; var_name };
290}
291",
292 );
293 }
294
295 #[test]
296 fn test_introduce_var_path_simple() {
297 check_assist(
298 introduce_variable,
299 "
300fn main() {
301 let o = S<|>ome(true);
302}
303",
304 "
305fn main() {
306 let <|>var_name = Some(true);
307 let o = var_name;
308}
309",
310 );
311 }
312
313 #[test]
314 fn test_introduce_var_path_method() {
315 check_assist(
316 introduce_variable,
317 "
318fn main() {
319 let v = b<|>ar.foo();
320}
321",
322 "
323fn main() {
324 let <|>var_name = bar.foo();
325 let v = var_name;
326}
327",
328 );
329 }
330
331 #[test]
332 fn test_introduce_var_return() {
333 check_assist(
334 introduce_variable,
335 "
336fn foo() -> u32 {
337 r<|>eturn 2 + 2;
338}
339",
340 "
341fn foo() -> u32 {
342 let <|>var_name = 2 + 2;
343 return var_name;
344}
345",
346 );
347 }
348
349 #[test]
350 fn test_introduce_var_break() {
351 check_assist(
352 introduce_variable,
353 "
354fn main() {
355 let result = loop {
356 b<|>reak 2 + 2;
357 };
358}
359",
360 "
361fn main() {
362 let result = loop {
363 let <|>var_name = 2 + 2;
364 break var_name;
365 };
366}
367",
368 );
369 }
370
371 #[test]
372 fn test_introduce_var_for_cast() {
373 check_assist(
374 introduce_variable,
375 "
376fn main() {
377 let v = 0f32 a<|>s u32;
378}
379",
380 "
381fn main() {
382 let <|>var_name = 0f32 as u32;
383 let v = var_name;
384}
385",
386 );
387 }
388
389 #[test]
390 fn test_introduce_var_for_return_not_applicable() {
391 check_assist_not_applicable(
392 introduce_variable,
393 "
394fn foo() {
395 r<|>eturn;
396}
397",
398 );
399 }
400
401 #[test]
402 fn test_introduce_var_for_break_not_applicable() {
403 check_assist_not_applicable(
404 introduce_variable,
405 "
406fn main() {
407 loop {
408 b<|>reak;
409 };
410}
411",
412 );
413 }
414
415 #[test]
416 fn test_introduce_var_in_comment_not_applicable() {
417 check_assist_not_applicable(
418 introduce_variable,
419 "
420fn main() {
421 let x = true;
422 let tuple = match x {
423 // c<|>omment
424 true => (2 + 2, true)
425 _ => (0, false)
426 };
427}
428",
429 );
430 }
431}
diff --git a/crates/ra_ide_api_light/src/assists/replace_if_let_with_match.rs b/crates/ra_ide_api_light/src/assists/replace_if_let_with_match.rs
deleted file mode 100644
index 71880b919..000000000
--- a/crates/ra_ide_api_light/src/assists/replace_if_let_with_match.rs
+++ /dev/null
@@ -1,81 +0,0 @@
1use ra_syntax::{AstNode, ast};
2
3use crate::{
4 assists::{AssistCtx, Assist},
5 formatting::extract_trivial_expression,
6};
7
8pub fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
9 let if_expr: &ast::IfExpr = ctx.node_at_offset()?;
10 let cond = if_expr.condition()?;
11 let pat = cond.pat()?;
12 let expr = cond.expr()?;
13 let then_block = if_expr.then_branch()?;
14 let else_block = match if_expr.else_branch()? {
15 ast::ElseBranchFlavor::Block(it) => it,
16 ast::ElseBranchFlavor::IfExpr(_) => return None,
17 };
18
19 ctx.build("replace with match", |edit| {
20 let match_expr = build_match_expr(expr, pat, then_block, else_block);
21 edit.replace_node_and_indent(if_expr.syntax(), match_expr);
22 edit.set_cursor(if_expr.syntax().range().start())
23 })
24}
25
26fn build_match_expr(
27 expr: &ast::Expr,
28 pat1: &ast::Pat,
29 arm1: &ast::Block,
30 arm2: &ast::Block,
31) -> String {
32 let mut buf = String::new();
33 buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
34 buf.push_str(&format!(
35 " {} => {}\n",
36 pat1.syntax().text(),
37 format_arm(arm1)
38 ));
39 buf.push_str(&format!(" _ => {}\n", format_arm(arm2)));
40 buf.push_str("}");
41 buf
42}
43
44fn format_arm(block: &ast::Block) -> String {
45 match extract_trivial_expression(block) {
46 None => block.syntax().text().to_string(),
47 Some(e) => format!("{},", e.syntax().text()),
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::assists::check_assist;
55
56 #[test]
57 fn test_replace_if_let_with_match_unwraps_simple_expressions() {
58 check_assist(
59 replace_if_let_with_match,
60 "
61impl VariantData {
62 pub fn is_struct(&self) -> bool {
63 if <|>let VariantData::Struct(..) = *self {
64 true
65 } else {
66 false
67 }
68 }
69} ",
70 "
71impl VariantData {
72 pub fn is_struct(&self) -> bool {
73 <|>match *self {
74 VariantData::Struct(..) => true,
75 _ => false,
76 }
77 }
78} ",
79 )
80 }
81}
diff --git a/crates/ra_ide_api_light/src/assists/split_import.rs b/crates/ra_ide_api_light/src/assists/split_import.rs
deleted file mode 100644
index e4015f07d..000000000
--- a/crates/ra_ide_api_light/src/assists/split_import.rs
+++ /dev/null
@@ -1,56 +0,0 @@
1use ra_syntax::{
2 TextUnit, AstNode, SyntaxKind::COLONCOLON,
3 ast,
4 algo::generate,
5};
6
7use crate::assists::{AssistCtx, Assist};
8
9pub fn split_import(ctx: AssistCtx) -> Option<Assist> {
10 let colon_colon = ctx
11 .leaf_at_offset()
12 .find(|leaf| leaf.kind() == COLONCOLON)?;
13 let path = colon_colon.parent().and_then(ast::Path::cast)?;
14 let top_path = generate(Some(path), |it| it.parent_path()).last()?;
15
16 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
17 if use_tree.is_none() {
18 return None;
19 }
20
21 let l_curly = colon_colon.range().end();
22 let r_curly = match top_path.syntax().parent().and_then(ast::UseTree::cast) {
23 Some(tree) => tree.syntax().range().end(),
24 None => top_path.syntax().range().end(),
25 };
26
27 ctx.build("split import", |edit| {
28 edit.insert(l_curly, "{");
29 edit.insert(r_curly, "}");
30 edit.set_cursor(l_curly + TextUnit::of_str("{"));
31 })
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::assists::check_assist;
38
39 #[test]
40 fn test_split_import() {
41 check_assist(
42 split_import,
43 "use crate::<|>db::RootDatabase;",
44 "use crate::{<|>db::RootDatabase};",
45 )
46 }
47
48 #[test]
49 fn split_import_works_with_trees() {
50 check_assist(
51 split_import,
52 "use algo:<|>:visitor::{Visitor, visit}",
53 "use algo::{<|>visitor::{Visitor, visit}}",
54 )
55 }
56}