aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/handlers/change_return_type_to_result.rs33
-rw-r--r--crates/ra_assists/src/handlers/extract_variable.rs (renamed from crates/ra_assists/src/handlers/introduce_variable.rs)159
-rw-r--r--crates/ra_assists/src/lib.rs4
-rw-r--r--crates/ra_assists/src/tests/generated.rs36
4 files changed, 151 insertions, 81 deletions
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 c6baa0a57..855baf187 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
@@ -4,6 +4,7 @@ use ra_syntax::{
4}; 4};
5 5
6use crate::{AssistContext, AssistId, Assists}; 6use crate::{AssistContext, AssistId, Assists};
7use test_utils::mark;
7 8
8// Assist: change_return_type_to_result 9// Assist: change_return_type_to_result
9// 10//
@@ -22,8 +23,13 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex
22 let fn_def = ret_type.syntax().parent().and_then(ast::FnDef::cast)?; 23 let fn_def = ret_type.syntax().parent().and_then(ast::FnDef::cast)?;
23 24
24 let type_ref = &ret_type.type_ref()?; 25 let type_ref = &ret_type.type_ref()?;
25 if type_ref.syntax().text().to_string().starts_with("Result<") { 26 let ret_type_str = type_ref.syntax().text().to_string();
26 return None; 27 let first_part_ret_type = ret_type_str.splitn(2, '<').next();
28 if let Some(ret_type_first_part) = first_part_ret_type {
29 if ret_type_first_part.ends_with("Result") {
30 mark::hit!(change_return_type_to_result_simple_return_type_already_result);
31 return None;
32 }
27 } 33 }
28 34
29 let block_expr = &fn_def.body()?; 35 let block_expr = &fn_def.body()?;
@@ -297,6 +303,29 @@ mod tests {
297 } 303 }
298 304
299 #[test] 305 #[test]
306 fn change_return_type_to_result_simple_return_type_already_result_std() {
307 check_assist_not_applicable(
308 change_return_type_to_result,
309 r#"fn foo() -> std::result::Result<i32<|>, String> {
310 let test = "test";
311 return 42i32;
312 }"#,
313 );
314 }
315
316 #[test]
317 fn change_return_type_to_result_simple_return_type_already_result() {
318 mark::check!(change_return_type_to_result_simple_return_type_already_result);
319 check_assist_not_applicable(
320 change_return_type_to_result,
321 r#"fn foo() -> Result<i32<|>, String> {
322 let test = "test";
323 return 42i32;
324 }"#,
325 );
326 }
327
328 #[test]
300 fn change_return_type_to_result_simple_with_cursor() { 329 fn change_return_type_to_result_simple_with_cursor() {
301 check_assist( 330 check_assist(
302 change_return_type_to_result, 331 change_return_type_to_result,
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs
index 88b62278f..c4150d2bb 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/extract_variable.rs
@@ -11,7 +11,7 @@ use test_utils::mark;
11 11
12use crate::{AssistContext, AssistId, Assists}; 12use crate::{AssistContext, AssistId, Assists};
13 13
14// Assist: introduce_variable 14// Assist: extract_variable
15// 15//
16// Extracts subexpression into a variable. 16// Extracts subexpression into a variable.
17// 17//
@@ -27,13 +27,13 @@ use crate::{AssistContext, AssistId, Assists};
27// var_name * 4; 27// var_name * 4;
28// } 28// }
29// ``` 29// ```
30pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 30pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
31 if ctx.frange.range.is_empty() { 31 if ctx.frange.range.is_empty() {
32 return None; 32 return None;
33 } 33 }
34 let node = ctx.covering_element(); 34 let node = ctx.covering_element();
35 if node.kind() == COMMENT { 35 if node.kind() == COMMENT {
36 mark::hit!(introduce_var_in_comment_is_not_applicable); 36 mark::hit!(extract_var_in_comment_is_not_applicable);
37 return None; 37 return None;
38 } 38 }
39 let expr = node.ancestors().find_map(valid_target_expr)?; 39 let expr = node.ancestors().find_map(valid_target_expr)?;
@@ -43,13 +43,27 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
43 return None; 43 return None;
44 } 44 }
45 let target = expr.syntax().text_range(); 45 let target = expr.syntax().text_range();
46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { 46 acc.add(AssistId("extract_variable"), "Extract into variable", target, move |edit| {
47 let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) {
48 Some(field) => field.name_ref(),
49 None => None,
50 };
51
47 let mut buf = String::new(); 52 let mut buf = String::new();
48 53
54 let var_name = match &field_shorthand {
55 Some(it) => it.to_string(),
56 None => "var_name".to_string(),
57 };
58 let expr_range = match &field_shorthand {
59 Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()),
60 None => expr.syntax().text_range(),
61 };
62
49 if wrap_in_block { 63 if wrap_in_block {
50 buf.push_str("{ let var_name = "); 64 format_to!(buf, "{{ let {} = ", var_name);
51 } else { 65 } else {
52 buf.push_str("let var_name = "); 66 format_to!(buf, "let {} = ", var_name);
53 }; 67 };
54 format_to!(buf, "{}", expr.syntax()); 68 format_to!(buf, "{}", expr.syntax());
55 69
@@ -60,17 +74,17 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
60 false 74 false
61 }; 75 };
62 if is_full_stmt { 76 if is_full_stmt {
63 mark::hit!(test_introduce_var_expr_stmt); 77 mark::hit!(test_extract_var_expr_stmt);
64 if full_stmt.unwrap().semicolon_token().is_none() { 78 if full_stmt.unwrap().semicolon_token().is_none() {
65 buf.push_str(";"); 79 buf.push_str(";");
66 } 80 }
67 let offset = expr.syntax().text_range();
68 match ctx.config.snippet_cap { 81 match ctx.config.snippet_cap {
69 Some(cap) => { 82 Some(cap) => {
70 let snip = buf.replace("let var_name", "let $0var_name"); 83 let snip =
71 edit.replace_snippet(cap, offset, snip) 84 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
85 edit.replace_snippet(cap, expr_range, snip)
72 } 86 }
73 None => edit.replace(offset, buf), 87 None => edit.replace(expr_range, buf),
74 } 88 }
75 return; 89 return;
76 } 90 }
@@ -88,11 +102,12 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
88 buf.push_str(text); 102 buf.push_str(text);
89 } 103 }
90 104
91 edit.replace(expr.syntax().text_range(), "var_name".to_string()); 105 edit.replace(expr_range, var_name.clone());
92 let offset = anchor_stmt.text_range().start(); 106 let offset = anchor_stmt.text_range().start();
93 match ctx.config.snippet_cap { 107 match ctx.config.snippet_cap {
94 Some(cap) => { 108 Some(cap) => {
95 let snip = buf.replace("let var_name", "let $0var_name"); 109 let snip =
110 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
96 edit.insert_snippet(cap, offset, snip) 111 edit.insert_snippet(cap, offset, snip)
97 } 112 }
98 None => edit.insert(offset, buf), 113 None => edit.insert(offset, buf),
@@ -118,7 +133,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
118 } 133 }
119} 134}
120 135
121/// Returns the syntax node which will follow the freshly introduced var 136/// Returns the syntax node which will follow the freshly extractd var
122/// and a boolean indicating whether we have to wrap it within a { } block 137/// and a boolean indicating whether we have to wrap it within a { } block
123/// to produce correct code. 138/// to produce correct code.
124/// It can be a statement, the last in a block expression or a wanna be block 139/// It can be a statement, the last in a block expression or a wanna be block
@@ -127,7 +142,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
127 expr.syntax().ancestors().find_map(|node| { 142 expr.syntax().ancestors().find_map(|node| {
128 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { 143 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) {
129 if expr.syntax() == &node { 144 if expr.syntax() == &node {
130 mark::hit!(test_introduce_var_last_expr); 145 mark::hit!(test_extract_var_last_expr);
131 return Some((node, false)); 146 return Some((node, false));
132 } 147 }
133 } 148 }
@@ -155,9 +170,9 @@ mod tests {
155 use super::*; 170 use super::*;
156 171
157 #[test] 172 #[test]
158 fn test_introduce_var_simple() { 173 fn test_extract_var_simple() {
159 check_assist( 174 check_assist(
160 introduce_variable, 175 extract_variable,
161 r#" 176 r#"
162fn foo() { 177fn foo() {
163 foo(<|>1 + 1<|>); 178 foo(<|>1 + 1<|>);
@@ -171,16 +186,16 @@ fn foo() {
171 } 186 }
172 187
173 #[test] 188 #[test]
174 fn introduce_var_in_comment_is_not_applicable() { 189 fn extract_var_in_comment_is_not_applicable() {
175 mark::check!(introduce_var_in_comment_is_not_applicable); 190 mark::check!(extract_var_in_comment_is_not_applicable);
176 check_assist_not_applicable(introduce_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }"); 191 check_assist_not_applicable(extract_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }");
177 } 192 }
178 193
179 #[test] 194 #[test]
180 fn test_introduce_var_expr_stmt() { 195 fn test_extract_var_expr_stmt() {
181 mark::check!(test_introduce_var_expr_stmt); 196 mark::check!(test_extract_var_expr_stmt);
182 check_assist( 197 check_assist(
183 introduce_variable, 198 extract_variable,
184 r#" 199 r#"
185fn foo() { 200fn foo() {
186 <|>1 + 1<|>; 201 <|>1 + 1<|>;
@@ -191,7 +206,7 @@ fn foo() {
191}"#, 206}"#,
192 ); 207 );
193 check_assist( 208 check_assist(
194 introduce_variable, 209 extract_variable,
195 " 210 "
196fn foo() { 211fn foo() {
197 <|>{ let x = 0; x }<|> 212 <|>{ let x = 0; x }<|>
@@ -206,9 +221,9 @@ fn foo() {
206 } 221 }
207 222
208 #[test] 223 #[test]
209 fn test_introduce_var_part_of_expr_stmt() { 224 fn test_extract_var_part_of_expr_stmt() {
210 check_assist( 225 check_assist(
211 introduce_variable, 226 extract_variable,
212 " 227 "
213fn foo() { 228fn foo() {
214 <|>1<|> + 1; 229 <|>1<|> + 1;
@@ -222,10 +237,10 @@ fn foo() {
222 } 237 }
223 238
224 #[test] 239 #[test]
225 fn test_introduce_var_last_expr() { 240 fn test_extract_var_last_expr() {
226 mark::check!(test_introduce_var_last_expr); 241 mark::check!(test_extract_var_last_expr);
227 check_assist( 242 check_assist(
228 introduce_variable, 243 extract_variable,
229 r#" 244 r#"
230fn foo() { 245fn foo() {
231 bar(<|>1 + 1<|>) 246 bar(<|>1 + 1<|>)
@@ -239,7 +254,7 @@ fn foo() {
239"#, 254"#,
240 ); 255 );
241 check_assist( 256 check_assist(
242 introduce_variable, 257 extract_variable,
243 r#" 258 r#"
244fn foo() { 259fn foo() {
245 <|>bar(1 + 1)<|> 260 <|>bar(1 + 1)<|>
@@ -255,9 +270,9 @@ fn foo() {
255 } 270 }
256 271
257 #[test] 272 #[test]
258 fn test_introduce_var_in_match_arm_no_block() { 273 fn test_extract_var_in_match_arm_no_block() {
259 check_assist( 274 check_assist(
260 introduce_variable, 275 extract_variable,
261 " 276 "
262fn main() { 277fn main() {
263 let x = true; 278 let x = true;
@@ -280,9 +295,9 @@ fn main() {
280 } 295 }
281 296
282 #[test] 297 #[test]
283 fn test_introduce_var_in_match_arm_with_block() { 298 fn test_extract_var_in_match_arm_with_block() {
284 check_assist( 299 check_assist(
285 introduce_variable, 300 extract_variable,
286 " 301 "
287fn main() { 302fn main() {
288 let x = true; 303 let x = true;
@@ -312,9 +327,9 @@ fn main() {
312 } 327 }
313 328
314 #[test] 329 #[test]
315 fn test_introduce_var_in_closure_no_block() { 330 fn test_extract_var_in_closure_no_block() {
316 check_assist( 331 check_assist(
317 introduce_variable, 332 extract_variable,
318 " 333 "
319fn main() { 334fn main() {
320 let lambda = |x: u32| <|>x * 2<|>; 335 let lambda = |x: u32| <|>x * 2<|>;
@@ -329,9 +344,9 @@ fn main() {
329 } 344 }
330 345
331 #[test] 346 #[test]
332 fn test_introduce_var_in_closure_with_block() { 347 fn test_extract_var_in_closure_with_block() {
333 check_assist( 348 check_assist(
334 introduce_variable, 349 extract_variable,
335 " 350 "
336fn main() { 351fn main() {
337 let lambda = |x: u32| { <|>x * 2<|> }; 352 let lambda = |x: u32| { <|>x * 2<|> };
@@ -346,9 +361,9 @@ fn main() {
346 } 361 }
347 362
348 #[test] 363 #[test]
349 fn test_introduce_var_path_simple() { 364 fn test_extract_var_path_simple() {
350 check_assist( 365 check_assist(
351 introduce_variable, 366 extract_variable,
352 " 367 "
353fn main() { 368fn main() {
354 let o = <|>Some(true)<|>; 369 let o = <|>Some(true)<|>;
@@ -364,9 +379,9 @@ fn main() {
364 } 379 }
365 380
366 #[test] 381 #[test]
367 fn test_introduce_var_path_method() { 382 fn test_extract_var_path_method() {
368 check_assist( 383 check_assist(
369 introduce_variable, 384 extract_variable,
370 " 385 "
371fn main() { 386fn main() {
372 let v = <|>bar.foo()<|>; 387 let v = <|>bar.foo()<|>;
@@ -382,9 +397,9 @@ fn main() {
382 } 397 }
383 398
384 #[test] 399 #[test]
385 fn test_introduce_var_return() { 400 fn test_extract_var_return() {
386 check_assist( 401 check_assist(
387 introduce_variable, 402 extract_variable,
388 " 403 "
389fn foo() -> u32 { 404fn foo() -> u32 {
390 <|>return 2 + 2<|>; 405 <|>return 2 + 2<|>;
@@ -400,9 +415,9 @@ fn foo() -> u32 {
400 } 415 }
401 416
402 #[test] 417 #[test]
403 fn test_introduce_var_does_not_add_extra_whitespace() { 418 fn test_extract_var_does_not_add_extra_whitespace() {
404 check_assist( 419 check_assist(
405 introduce_variable, 420 extract_variable,
406 " 421 "
407fn foo() -> u32 { 422fn foo() -> u32 {
408 423
@@ -421,7 +436,7 @@ fn foo() -> u32 {
421 ); 436 );
422 437
423 check_assist( 438 check_assist(
424 introduce_variable, 439 extract_variable,
425 " 440 "
426fn foo() -> u32 { 441fn foo() -> u32 {
427 442
@@ -438,7 +453,7 @@ fn foo() -> u32 {
438 ); 453 );
439 454
440 check_assist( 455 check_assist(
441 introduce_variable, 456 extract_variable,
442 " 457 "
443fn foo() -> u32 { 458fn foo() -> u32 {
444 let foo = 1; 459 let foo = 1;
@@ -464,9 +479,9 @@ fn foo() -> u32 {
464 } 479 }
465 480
466 #[test] 481 #[test]
467 fn test_introduce_var_break() { 482 fn test_extract_var_break() {
468 check_assist( 483 check_assist(
469 introduce_variable, 484 extract_variable,
470 " 485 "
471fn main() { 486fn main() {
472 let result = loop { 487 let result = loop {
@@ -486,9 +501,9 @@ fn main() {
486 } 501 }
487 502
488 #[test] 503 #[test]
489 fn test_introduce_var_for_cast() { 504 fn test_extract_var_for_cast() {
490 check_assist( 505 check_assist(
491 introduce_variable, 506 extract_variable,
492 " 507 "
493fn main() { 508fn main() {
494 let v = <|>0f32 as u32<|>; 509 let v = <|>0f32 as u32<|>;
@@ -504,22 +519,48 @@ fn main() {
504 } 519 }
505 520
506 #[test] 521 #[test]
507 fn test_introduce_var_for_return_not_applicable() { 522 fn extract_var_field_shorthand() {
508 check_assist_not_applicable(introduce_variable, "fn foo() { <|>return<|>; } "); 523 check_assist(
524 extract_variable,
525 r#"
526struct S {
527 foo: i32
528}
529
530fn main() {
531 S { foo: <|>1 + 1<|> }
532}
533"#,
534 r#"
535struct S {
536 foo: i32
537}
538
539fn main() {
540 let $0foo = 1 + 1;
541 S { foo }
542}
543"#,
544 )
545 }
546
547 #[test]
548 fn test_extract_var_for_return_not_applicable() {
549 check_assist_not_applicable(extract_variable, "fn foo() { <|>return<|>; } ");
509 } 550 }
510 551
511 #[test] 552 #[test]
512 fn test_introduce_var_for_break_not_applicable() { 553 fn test_extract_var_for_break_not_applicable() {
513 check_assist_not_applicable(introduce_variable, "fn main() { loop { <|>break<|>; }; }"); 554 check_assist_not_applicable(extract_variable, "fn main() { loop { <|>break<|>; }; }");
514 } 555 }
515 556
516 // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic 557 // FIXME: This is not quite correct, but good enough(tm) for the sorting heuristic
517 #[test] 558 #[test]
518 fn introduce_var_target() { 559 fn extract_var_target() {
519 check_assist_target(introduce_variable, "fn foo() -> u32 { <|>return 2 + 2<|>; }", "2 + 2"); 560 check_assist_target(extract_variable, "fn foo() -> u32 { <|>return 2 + 2<|>; }", "2 + 2");
520 561
521 check_assist_target( 562 check_assist_target(
522 introduce_variable, 563 extract_variable,
523 " 564 "
524fn main() { 565fn main() {
525 let x = true; 566 let x = true;
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 185428bd5..1745f44a5 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -116,6 +116,7 @@ mod handlers {
116 mod change_visibility; 116 mod change_visibility;
117 mod early_return; 117 mod early_return;
118 mod extract_struct_from_enum_variant; 118 mod extract_struct_from_enum_variant;
119 mod extract_variable;
119 mod fill_match_arms; 120 mod fill_match_arms;
120 mod fix_visibility; 121 mod fix_visibility;
121 mod flip_binexpr; 122 mod flip_binexpr;
@@ -123,7 +124,6 @@ mod handlers {
123 mod flip_trait_bound; 124 mod flip_trait_bound;
124 mod inline_local_variable; 125 mod inline_local_variable;
125 mod introduce_named_lifetime; 126 mod introduce_named_lifetime;
126 mod introduce_variable;
127 mod invert_if; 127 mod invert_if;
128 mod merge_imports; 128 mod merge_imports;
129 mod merge_match_arms; 129 mod merge_match_arms;
@@ -157,6 +157,7 @@ mod handlers {
157 change_visibility::change_visibility, 157 change_visibility::change_visibility,
158 early_return::convert_to_guarded_return, 158 early_return::convert_to_guarded_return,
159 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 159 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
160 extract_variable::extract_variable,
160 fill_match_arms::fill_match_arms, 161 fill_match_arms::fill_match_arms,
161 fix_visibility::fix_visibility, 162 fix_visibility::fix_visibility,
162 flip_binexpr::flip_binexpr, 163 flip_binexpr::flip_binexpr,
@@ -164,7 +165,6 @@ mod handlers {
164 flip_trait_bound::flip_trait_bound, 165 flip_trait_bound::flip_trait_bound,
165 inline_local_variable::inline_local_variable, 166 inline_local_variable::inline_local_variable,
166 introduce_named_lifetime::introduce_named_lifetime, 167 introduce_named_lifetime::introduce_named_lifetime,
167 introduce_variable::introduce_variable,
168 invert_if::invert_if, 168 invert_if::invert_if,
169 merge_imports::merge_imports, 169 merge_imports::merge_imports,
170 merge_match_arms::merge_match_arms, 170 merge_match_arms::merge_match_arms,
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index 40a223727..31ea888c5 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -353,6 +353,24 @@ enum A { One(One) }
353} 353}
354 354
355#[test] 355#[test]
356fn doctest_extract_variable() {
357 check_doc_test(
358 "extract_variable",
359 r#####"
360fn main() {
361 <|>(1 + 2)<|> * 4;
362}
363"#####,
364 r#####"
365fn main() {
366 let $0var_name = (1 + 2);
367 var_name * 4;
368}
369"#####,
370 )
371}
372
373#[test]
356fn doctest_fill_match_arms() { 374fn doctest_fill_match_arms() {
357 check_doc_test( 375 check_doc_test(
358 "fill_match_arms", 376 "fill_match_arms",
@@ -492,24 +510,6 @@ impl<'a> Cursor<'a> {
492} 510}
493 511
494#[test] 512#[test]
495fn doctest_introduce_variable() {
496 check_doc_test(
497 "introduce_variable",
498 r#####"
499fn main() {
500 <|>(1 + 2)<|> * 4;
501}
502"#####,
503 r#####"
504fn main() {
505 let $0var_name = (1 + 2);
506 var_name * 4;
507}
508"#####,
509 )
510}
511
512#[test]
513fn doctest_invert_if() { 513fn doctest_invert_if() {
514 check_doc_test( 514 check_doc_test(
515 "invert_if", 515 "invert_if",