diff options
Diffstat (limited to 'crates/ra_assists/src/handlers/fill_match_arms.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/fill_match_arms.rs | 232 |
1 files changed, 115 insertions, 117 deletions
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 13c1e7e80..cc303285b 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -4,8 +4,12 @@ use hir::{Adt, HasSource, ModuleDef, Semantics}; | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; | 6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; |
7 | use test_utils::mark; | ||
7 | 8 | ||
8 | use crate::{AssistContext, AssistId, Assists}; | 9 | use crate::{ |
10 | utils::{render_snippet, Cursor, FamousDefs}, | ||
11 | AssistContext, AssistId, Assists, | ||
12 | }; | ||
9 | 13 | ||
10 | // Assist: fill_match_arms | 14 | // Assist: fill_match_arms |
11 | // | 15 | // |
@@ -26,7 +30,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
26 | // | 30 | // |
27 | // fn handle(action: Action) { | 31 | // fn handle(action: Action) { |
28 | // match action { | 32 | // match action { |
29 | // Action::Move { distance } => {} | 33 | // $0Action::Move { distance } => {} |
30 | // Action::Stop => {} | 34 | // Action::Stop => {} |
31 | // } | 35 | // } |
32 | // } | 36 | // } |
@@ -49,12 +53,18 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
49 | let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { | 53 | let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { |
50 | let variants = enum_def.variants(ctx.db); | 54 | let variants = enum_def.variants(ctx.db); |
51 | 55 | ||
52 | variants | 56 | let mut variants = variants |
53 | .into_iter() | 57 | .into_iter() |
54 | .filter_map(|variant| build_pat(ctx.db, module, variant)) | 58 | .filter_map(|variant| build_pat(ctx.db, module, variant)) |
55 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) | 59 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) |
56 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 60 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
57 | .collect() | 61 | .collect::<Vec<_>>(); |
62 | if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { | ||
63 | // Match `Some` variant first. | ||
64 | mark::hit!(option_order); | ||
65 | variants.reverse() | ||
66 | } | ||
67 | variants | ||
58 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { | 68 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { |
59 | // Partial fill not currently supported for tuple of enums. | 69 | // Partial fill not currently supported for tuple of enums. |
60 | if !arms.is_empty() { | 70 | if !arms.is_empty() { |
@@ -93,10 +103,23 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
93 | } | 103 | } |
94 | 104 | ||
95 | let target = match_expr.syntax().text_range(); | 105 | let target = match_expr.syntax().text_range(); |
96 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { | 106 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| { |
97 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); | 107 | let new_arm_list = match_arm_list.remove_placeholder(); |
98 | edit.set_cursor(expr.syntax().text_range().start()); | 108 | let n_old_arms = new_arm_list.arms().count(); |
99 | edit.replace_ast(match_arm_list, new_arm_list); | 109 | let new_arm_list = new_arm_list.append_arms(missing_arms); |
110 | let first_new_arm = new_arm_list.arms().nth(n_old_arms); | ||
111 | let old_range = match_arm_list.syntax().text_range(); | ||
112 | match (first_new_arm, ctx.config.snippet_cap) { | ||
113 | (Some(first_new_arm), Some(cap)) => { | ||
114 | let snippet = render_snippet( | ||
115 | cap, | ||
116 | new_arm_list.syntax(), | ||
117 | Cursor::Before(first_new_arm.syntax()), | ||
118 | ); | ||
119 | builder.replace_snippet(cap, old_range, snippet); | ||
120 | } | ||
121 | _ => builder.replace(old_range, new_arm_list.to_string()), | ||
122 | } | ||
100 | }) | 123 | }) |
101 | } | 124 | } |
102 | 125 | ||
@@ -167,7 +190,12 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O | |||
167 | 190 | ||
168 | #[cfg(test)] | 191 | #[cfg(test)] |
169 | mod tests { | 192 | mod tests { |
170 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 193 | use test_utils::mark; |
194 | |||
195 | use crate::{ | ||
196 | tests::{check_assist, check_assist_not_applicable, check_assist_target}, | ||
197 | utils::FamousDefs, | ||
198 | }; | ||
171 | 199 | ||
172 | use super::fill_match_arms; | 200 | use super::fill_match_arms; |
173 | 201 | ||
@@ -214,12 +242,12 @@ mod tests { | |||
214 | r#" | 242 | r#" |
215 | enum A { | 243 | enum A { |
216 | As, | 244 | As, |
217 | Bs{x:i32, y:Option<i32>}, | 245 | Bs { x: i32, y: Option<i32> }, |
218 | Cs(i32, Option<i32>), | 246 | Cs(i32, Option<i32>), |
219 | } | 247 | } |
220 | fn main() { | 248 | fn main() { |
221 | match A::As<|> { | 249 | match A::As<|> { |
222 | A::Bs{x,y:Some(_)} => {} | 250 | A::Bs { x, y: Some(_) } => {} |
223 | A::Cs(_, Some(_)) => {} | 251 | A::Cs(_, Some(_)) => {} |
224 | } | 252 | } |
225 | } | 253 | } |
@@ -227,14 +255,14 @@ mod tests { | |||
227 | r#" | 255 | r#" |
228 | enum A { | 256 | enum A { |
229 | As, | 257 | As, |
230 | Bs{x:i32, y:Option<i32>}, | 258 | Bs { x: i32, y: Option<i32> }, |
231 | Cs(i32, Option<i32>), | 259 | Cs(i32, Option<i32>), |
232 | } | 260 | } |
233 | fn main() { | 261 | fn main() { |
234 | match <|>A::As { | 262 | match A::As { |
235 | A::Bs{x,y:Some(_)} => {} | 263 | A::Bs { x, y: Some(_) } => {} |
236 | A::Cs(_, Some(_)) => {} | 264 | A::Cs(_, Some(_)) => {} |
237 | A::As => {} | 265 | $0A::As => {} |
238 | } | 266 | } |
239 | } | 267 | } |
240 | "#, | 268 | "#, |
@@ -264,9 +292,9 @@ mod tests { | |||
264 | Cs(Option<i32>), | 292 | Cs(Option<i32>), |
265 | } | 293 | } |
266 | fn main() { | 294 | fn main() { |
267 | match <|>A::As { | 295 | match A::As { |
268 | A::Cs(_) | A::Bs => {} | 296 | A::Cs(_) | A::Bs => {} |
269 | A::As => {} | 297 | $0A::As => {} |
270 | } | 298 | } |
271 | } | 299 | } |
272 | "#, | 300 | "#, |
@@ -310,11 +338,11 @@ mod tests { | |||
310 | Ys, | 338 | Ys, |
311 | } | 339 | } |
312 | fn main() { | 340 | fn main() { |
313 | match <|>A::As { | 341 | match A::As { |
314 | A::Bs if 0 < 1 => {} | 342 | A::Bs if 0 < 1 => {} |
315 | A::Ds(_value) => { let x = 1; } | 343 | A::Ds(_value) => { let x = 1; } |
316 | A::Es(B::Xs) => (), | 344 | A::Es(B::Xs) => (), |
317 | A::As => {} | 345 | $0A::As => {} |
318 | A::Cs => {} | 346 | A::Cs => {} |
319 | } | 347 | } |
320 | } | 348 | } |
@@ -332,7 +360,7 @@ mod tests { | |||
332 | Bs, | 360 | Bs, |
333 | Cs(String), | 361 | Cs(String), |
334 | Ds(String, String), | 362 | Ds(String, String), |
335 | Es{ x: usize, y: usize } | 363 | Es { x: usize, y: usize } |
336 | } | 364 | } |
337 | 365 | ||
338 | fn main() { | 366 | fn main() { |
@@ -346,13 +374,13 @@ mod tests { | |||
346 | Bs, | 374 | Bs, |
347 | Cs(String), | 375 | Cs(String), |
348 | Ds(String, String), | 376 | Ds(String, String), |
349 | Es{ x: usize, y: usize } | 377 | Es { x: usize, y: usize } |
350 | } | 378 | } |
351 | 379 | ||
352 | fn main() { | 380 | fn main() { |
353 | let a = A::As; | 381 | let a = A::As; |
354 | match <|>a { | 382 | match a { |
355 | A::As => {} | 383 | $0A::As => {} |
356 | A::Bs => {} | 384 | A::Bs => {} |
357 | A::Cs(_) => {} | 385 | A::Cs(_) => {} |
358 | A::Ds(_, _) => {} | 386 | A::Ds(_, _) => {} |
@@ -368,14 +396,8 @@ mod tests { | |||
368 | check_assist( | 396 | check_assist( |
369 | fill_match_arms, | 397 | fill_match_arms, |
370 | r#" | 398 | r#" |
371 | enum A { | 399 | enum A { One, Two } |
372 | One, | 400 | enum B { One, Two } |
373 | Two, | ||
374 | } | ||
375 | enum B { | ||
376 | One, | ||
377 | Two, | ||
378 | } | ||
379 | 401 | ||
380 | fn main() { | 402 | fn main() { |
381 | let a = A::One; | 403 | let a = A::One; |
@@ -384,20 +406,14 @@ mod tests { | |||
384 | } | 406 | } |
385 | "#, | 407 | "#, |
386 | r#" | 408 | r#" |
387 | enum A { | 409 | enum A { One, Two } |
388 | One, | 410 | enum B { One, Two } |
389 | Two, | ||
390 | } | ||
391 | enum B { | ||
392 | One, | ||
393 | Two, | ||
394 | } | ||
395 | 411 | ||
396 | fn main() { | 412 | fn main() { |
397 | let a = A::One; | 413 | let a = A::One; |
398 | let b = B::One; | 414 | let b = B::One; |
399 | match <|>(a, b) { | 415 | match (a, b) { |
400 | (A::One, B::One) => {} | 416 | $0(A::One, B::One) => {} |
401 | (A::One, B::Two) => {} | 417 | (A::One, B::Two) => {} |
402 | (A::Two, B::One) => {} | 418 | (A::Two, B::One) => {} |
403 | (A::Two, B::Two) => {} | 419 | (A::Two, B::Two) => {} |
@@ -412,14 +428,8 @@ mod tests { | |||
412 | check_assist( | 428 | check_assist( |
413 | fill_match_arms, | 429 | fill_match_arms, |
414 | r#" | 430 | r#" |
415 | enum A { | 431 | enum A { One, Two } |
416 | One, | 432 | enum B { One, Two } |
417 | Two, | ||
418 | } | ||
419 | enum B { | ||
420 | One, | ||
421 | Two, | ||
422 | } | ||
423 | 433 | ||
424 | fn main() { | 434 | fn main() { |
425 | let a = A::One; | 435 | let a = A::One; |
@@ -428,20 +438,14 @@ mod tests { | |||
428 | } | 438 | } |
429 | "#, | 439 | "#, |
430 | r#" | 440 | r#" |
431 | enum A { | 441 | enum A { One, Two } |
432 | One, | 442 | enum B { One, Two } |
433 | Two, | ||
434 | } | ||
435 | enum B { | ||
436 | One, | ||
437 | Two, | ||
438 | } | ||
439 | 443 | ||
440 | fn main() { | 444 | fn main() { |
441 | let a = A::One; | 445 | let a = A::One; |
442 | let b = B::One; | 446 | let b = B::One; |
443 | match <|>(&a, &b) { | 447 | match (&a, &b) { |
444 | (A::One, B::One) => {} | 448 | $0(A::One, B::One) => {} |
445 | (A::One, B::Two) => {} | 449 | (A::One, B::Two) => {} |
446 | (A::Two, B::One) => {} | 450 | (A::Two, B::One) => {} |
447 | (A::Two, B::Two) => {} | 451 | (A::Two, B::Two) => {} |
@@ -456,14 +460,8 @@ mod tests { | |||
456 | check_assist_not_applicable( | 460 | check_assist_not_applicable( |
457 | fill_match_arms, | 461 | fill_match_arms, |
458 | r#" | 462 | r#" |
459 | enum A { | 463 | enum A { One, Two } |
460 | One, | 464 | enum B { One, Two } |
461 | Two, | ||
462 | } | ||
463 | enum B { | ||
464 | One, | ||
465 | Two, | ||
466 | } | ||
467 | 465 | ||
468 | fn main() { | 466 | fn main() { |
469 | let a = A::One; | 467 | let a = A::One; |
@@ -481,14 +479,8 @@ mod tests { | |||
481 | check_assist_not_applicable( | 479 | check_assist_not_applicable( |
482 | fill_match_arms, | 480 | fill_match_arms, |
483 | r#" | 481 | r#" |
484 | enum A { | 482 | enum A { One, Two } |
485 | One, | 483 | enum B { One, Two } |
486 | Two, | ||
487 | } | ||
488 | enum B { | ||
489 | One, | ||
490 | Two, | ||
491 | } | ||
492 | 484 | ||
493 | fn main() { | 485 | fn main() { |
494 | let a = A::One; | 486 | let a = A::One; |
@@ -512,10 +504,7 @@ mod tests { | |||
512 | check_assist_not_applicable( | 504 | check_assist_not_applicable( |
513 | fill_match_arms, | 505 | fill_match_arms, |
514 | r#" | 506 | r#" |
515 | enum A { | 507 | enum A { One, Two } |
516 | One, | ||
517 | Two, | ||
518 | } | ||
519 | 508 | ||
520 | fn main() { | 509 | fn main() { |
521 | let a = A::One; | 510 | let a = A::One; |
@@ -531,9 +520,7 @@ mod tests { | |||
531 | check_assist( | 520 | check_assist( |
532 | fill_match_arms, | 521 | fill_match_arms, |
533 | r#" | 522 | r#" |
534 | enum A { | 523 | enum A { As } |
535 | As, | ||
536 | } | ||
537 | 524 | ||
538 | fn foo(a: &A) { | 525 | fn foo(a: &A) { |
539 | match a<|> { | 526 | match a<|> { |
@@ -541,13 +528,11 @@ mod tests { | |||
541 | } | 528 | } |
542 | "#, | 529 | "#, |
543 | r#" | 530 | r#" |
544 | enum A { | 531 | enum A { As } |
545 | As, | ||
546 | } | ||
547 | 532 | ||
548 | fn foo(a: &A) { | 533 | fn foo(a: &A) { |
549 | match <|>a { | 534 | match a { |
550 | A::As => {} | 535 | $0A::As => {} |
551 | } | 536 | } |
552 | } | 537 | } |
553 | "#, | 538 | "#, |
@@ -557,7 +542,7 @@ mod tests { | |||
557 | fill_match_arms, | 542 | fill_match_arms, |
558 | r#" | 543 | r#" |
559 | enum A { | 544 | enum A { |
560 | Es{ x: usize, y: usize } | 545 | Es { x: usize, y: usize } |
561 | } | 546 | } |
562 | 547 | ||
563 | fn foo(a: &mut A) { | 548 | fn foo(a: &mut A) { |
@@ -567,12 +552,12 @@ mod tests { | |||
567 | "#, | 552 | "#, |
568 | r#" | 553 | r#" |
569 | enum A { | 554 | enum A { |
570 | Es{ x: usize, y: usize } | 555 | Es { x: usize, y: usize } |
571 | } | 556 | } |
572 | 557 | ||
573 | fn foo(a: &mut A) { | 558 | fn foo(a: &mut A) { |
574 | match <|>a { | 559 | match a { |
575 | A::Es { x, y } => {} | 560 | $0A::Es { x, y } => {} |
576 | } | 561 | } |
577 | } | 562 | } |
578 | "#, | 563 | "#, |
@@ -611,8 +596,8 @@ mod tests { | |||
611 | enum E { X, Y } | 596 | enum E { X, Y } |
612 | 597 | ||
613 | fn main() { | 598 | fn main() { |
614 | match <|>E::X { | 599 | match E::X { |
615 | E::X => {} | 600 | $0E::X => {} |
616 | E::Y => {} | 601 | E::Y => {} |
617 | } | 602 | } |
618 | } | 603 | } |
@@ -639,8 +624,8 @@ mod tests { | |||
639 | use foo::E::X; | 624 | use foo::E::X; |
640 | 625 | ||
641 | fn main() { | 626 | fn main() { |
642 | match <|>X { | 627 | match X { |
643 | X => {} | 628 | $0X => {} |
644 | foo::E::Y => {} | 629 | foo::E::Y => {} |
645 | } | 630 | } |
646 | } | 631 | } |
@@ -653,10 +638,7 @@ mod tests { | |||
653 | check_assist( | 638 | check_assist( |
654 | fill_match_arms, | 639 | fill_match_arms, |
655 | r#" | 640 | r#" |
656 | enum A { | 641 | enum A { One, Two } |
657 | One, | ||
658 | Two, | ||
659 | } | ||
660 | fn foo(a: A) { | 642 | fn foo(a: A) { |
661 | match a { | 643 | match a { |
662 | // foo bar baz<|> | 644 | // foo bar baz<|> |
@@ -666,16 +648,13 @@ mod tests { | |||
666 | } | 648 | } |
667 | "#, | 649 | "#, |
668 | r#" | 650 | r#" |
669 | enum A { | 651 | enum A { One, Two } |
670 | One, | ||
671 | Two, | ||
672 | } | ||
673 | fn foo(a: A) { | 652 | fn foo(a: A) { |
674 | match <|>a { | 653 | match a { |
675 | // foo bar baz | 654 | // foo bar baz |
676 | A::One => {} | 655 | A::One => {} |
677 | // This is where the rest should be | 656 | // This is where the rest should be |
678 | A::Two => {} | 657 | $0A::Two => {} |
679 | } | 658 | } |
680 | } | 659 | } |
681 | "#, | 660 | "#, |
@@ -687,10 +666,7 @@ mod tests { | |||
687 | check_assist( | 666 | check_assist( |
688 | fill_match_arms, | 667 | fill_match_arms, |
689 | r#" | 668 | r#" |
690 | enum A { | 669 | enum A { One, Two } |
691 | One, | ||
692 | Two, | ||
693 | } | ||
694 | fn foo(a: A) { | 670 | fn foo(a: A) { |
695 | match a { | 671 | match a { |
696 | // foo bar baz<|> | 672 | // foo bar baz<|> |
@@ -698,14 +674,11 @@ mod tests { | |||
698 | } | 674 | } |
699 | "#, | 675 | "#, |
700 | r#" | 676 | r#" |
701 | enum A { | 677 | enum A { One, Two } |
702 | One, | ||
703 | Two, | ||
704 | } | ||
705 | fn foo(a: A) { | 678 | fn foo(a: A) { |
706 | match <|>a { | 679 | match a { |
707 | // foo bar baz | 680 | // foo bar baz |
708 | A::One => {} | 681 | $0A::One => {} |
709 | A::Two => {} | 682 | A::Two => {} |
710 | } | 683 | } |
711 | } | 684 | } |
@@ -728,12 +701,37 @@ mod tests { | |||
728 | r#" | 701 | r#" |
729 | enum A { One, Two, } | 702 | enum A { One, Two, } |
730 | fn foo(a: A) { | 703 | fn foo(a: A) { |
731 | match <|>a { | 704 | match a { |
732 | A::One => {} | 705 | $0A::One => {} |
733 | A::Two => {} | 706 | A::Two => {} |
734 | } | 707 | } |
735 | } | 708 | } |
736 | "#, | 709 | "#, |
737 | ); | 710 | ); |
738 | } | 711 | } |
712 | |||
713 | #[test] | ||
714 | fn option_order() { | ||
715 | mark::check!(option_order); | ||
716 | let before = r#" | ||
717 | fn foo(opt: Option<i32>) { | ||
718 | match opt<|> { | ||
719 | } | ||
720 | }"#; | ||
721 | let before = | ||
722 | &format!("//- main.rs crate:main deps:core\n{}{}", before, FamousDefs::FIXTURE); | ||
723 | |||
724 | check_assist( | ||
725 | fill_match_arms, | ||
726 | before, | ||
727 | r#" | ||
728 | fn foo(opt: Option<i32>) { | ||
729 | match opt { | ||
730 | $0Some(_) => {} | ||
731 | None => {} | ||
732 | } | ||
733 | } | ||
734 | "#, | ||
735 | ); | ||
736 | } | ||
739 | } | 737 | } |