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 | 237 |
1 files changed, 117 insertions, 120 deletions
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 8d1af9933..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::{Assist, AssistCtx, AssistId}; | 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,12 +30,12 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
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 | // } |
33 | // ``` | 37 | // ``` |
34 | pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | 38 | pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
35 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; | 39 | let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; |
36 | let match_arm_list = match_expr.match_arm_list()?; | 40 | let match_arm_list = match_expr.match_arm_list()?; |
37 | 41 | ||
@@ -49,12 +53,18 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
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() { |
@@ -92,12 +102,24 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
92 | return None; | 102 | return None; |
93 | } | 103 | } |
94 | 104 | ||
95 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| { | 105 | let target = match_expr.syntax().text_range(); |
96 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); | 106 | acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| { |
97 | 107 | let new_arm_list = match_arm_list.remove_placeholder(); | |
98 | edit.target(match_expr.syntax().text_range()); | 108 | let n_old_arms = new_arm_list.arms().count(); |
99 | edit.set_cursor(expr.syntax().text_range().start()); | 109 | let new_arm_list = new_arm_list.append_arms(missing_arms); |
100 | edit.replace_ast(match_arm_list, new_arm_list); | 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 | } | ||
101 | }) | 123 | }) |
102 | } | 124 | } |
103 | 125 | ||
@@ -168,7 +190,12 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O | |||
168 | 190 | ||
169 | #[cfg(test)] | 191 | #[cfg(test)] |
170 | mod tests { | 192 | mod tests { |
171 | use crate::helpers::{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 | }; | ||
172 | 199 | ||
173 | use super::fill_match_arms; | 200 | use super::fill_match_arms; |
174 | 201 | ||
@@ -215,12 +242,12 @@ mod tests { | |||
215 | r#" | 242 | r#" |
216 | enum A { | 243 | enum A { |
217 | As, | 244 | As, |
218 | Bs{x:i32, y:Option<i32>}, | 245 | Bs { x: i32, y: Option<i32> }, |
219 | Cs(i32, Option<i32>), | 246 | Cs(i32, Option<i32>), |
220 | } | 247 | } |
221 | fn main() { | 248 | fn main() { |
222 | match A::As<|> { | 249 | match A::As<|> { |
223 | A::Bs{x,y:Some(_)} => {} | 250 | A::Bs { x, y: Some(_) } => {} |
224 | A::Cs(_, Some(_)) => {} | 251 | A::Cs(_, Some(_)) => {} |
225 | } | 252 | } |
226 | } | 253 | } |
@@ -228,14 +255,14 @@ mod tests { | |||
228 | r#" | 255 | r#" |
229 | enum A { | 256 | enum A { |
230 | As, | 257 | As, |
231 | Bs{x:i32, y:Option<i32>}, | 258 | Bs { x: i32, y: Option<i32> }, |
232 | Cs(i32, Option<i32>), | 259 | Cs(i32, Option<i32>), |
233 | } | 260 | } |
234 | fn main() { | 261 | fn main() { |
235 | match <|>A::As { | 262 | match A::As { |
236 | A::Bs{x,y:Some(_)} => {} | 263 | A::Bs { x, y: Some(_) } => {} |
237 | A::Cs(_, Some(_)) => {} | 264 | A::Cs(_, Some(_)) => {} |
238 | A::As => {} | 265 | $0A::As => {} |
239 | } | 266 | } |
240 | } | 267 | } |
241 | "#, | 268 | "#, |
@@ -265,9 +292,9 @@ mod tests { | |||
265 | Cs(Option<i32>), | 292 | Cs(Option<i32>), |
266 | } | 293 | } |
267 | fn main() { | 294 | fn main() { |
268 | match <|>A::As { | 295 | match A::As { |
269 | A::Cs(_) | A::Bs => {} | 296 | A::Cs(_) | A::Bs => {} |
270 | A::As => {} | 297 | $0A::As => {} |
271 | } | 298 | } |
272 | } | 299 | } |
273 | "#, | 300 | "#, |
@@ -311,11 +338,11 @@ mod tests { | |||
311 | Ys, | 338 | Ys, |
312 | } | 339 | } |
313 | fn main() { | 340 | fn main() { |
314 | match <|>A::As { | 341 | match A::As { |
315 | A::Bs if 0 < 1 => {} | 342 | A::Bs if 0 < 1 => {} |
316 | A::Ds(_value) => { let x = 1; } | 343 | A::Ds(_value) => { let x = 1; } |
317 | A::Es(B::Xs) => (), | 344 | A::Es(B::Xs) => (), |
318 | A::As => {} | 345 | $0A::As => {} |
319 | A::Cs => {} | 346 | A::Cs => {} |
320 | } | 347 | } |
321 | } | 348 | } |
@@ -333,7 +360,7 @@ mod tests { | |||
333 | Bs, | 360 | Bs, |
334 | Cs(String), | 361 | Cs(String), |
335 | Ds(String, String), | 362 | Ds(String, String), |
336 | Es{ x: usize, y: usize } | 363 | Es { x: usize, y: usize } |
337 | } | 364 | } |
338 | 365 | ||
339 | fn main() { | 366 | fn main() { |
@@ -347,13 +374,13 @@ mod tests { | |||
347 | Bs, | 374 | Bs, |
348 | Cs(String), | 375 | Cs(String), |
349 | Ds(String, String), | 376 | Ds(String, String), |
350 | Es{ x: usize, y: usize } | 377 | Es { x: usize, y: usize } |
351 | } | 378 | } |
352 | 379 | ||
353 | fn main() { | 380 | fn main() { |
354 | let a = A::As; | 381 | let a = A::As; |
355 | match <|>a { | 382 | match a { |
356 | A::As => {} | 383 | $0A::As => {} |
357 | A::Bs => {} | 384 | A::Bs => {} |
358 | A::Cs(_) => {} | 385 | A::Cs(_) => {} |
359 | A::Ds(_, _) => {} | 386 | A::Ds(_, _) => {} |
@@ -369,14 +396,8 @@ mod tests { | |||
369 | check_assist( | 396 | check_assist( |
370 | fill_match_arms, | 397 | fill_match_arms, |
371 | r#" | 398 | r#" |
372 | enum A { | 399 | enum A { One, Two } |
373 | One, | 400 | enum B { One, Two } |
374 | Two, | ||
375 | } | ||
376 | enum B { | ||
377 | One, | ||
378 | Two, | ||
379 | } | ||
380 | 401 | ||
381 | fn main() { | 402 | fn main() { |
382 | let a = A::One; | 403 | let a = A::One; |
@@ -385,20 +406,14 @@ mod tests { | |||
385 | } | 406 | } |
386 | "#, | 407 | "#, |
387 | r#" | 408 | r#" |
388 | enum A { | 409 | enum A { One, Two } |
389 | One, | 410 | enum B { One, Two } |
390 | Two, | ||
391 | } | ||
392 | enum B { | ||
393 | One, | ||
394 | Two, | ||
395 | } | ||
396 | 411 | ||
397 | fn main() { | 412 | fn main() { |
398 | let a = A::One; | 413 | let a = A::One; |
399 | let b = B::One; | 414 | let b = B::One; |
400 | match <|>(a, b) { | 415 | match (a, b) { |
401 | (A::One, B::One) => {} | 416 | $0(A::One, B::One) => {} |
402 | (A::One, B::Two) => {} | 417 | (A::One, B::Two) => {} |
403 | (A::Two, B::One) => {} | 418 | (A::Two, B::One) => {} |
404 | (A::Two, B::Two) => {} | 419 | (A::Two, B::Two) => {} |
@@ -413,14 +428,8 @@ mod tests { | |||
413 | check_assist( | 428 | check_assist( |
414 | fill_match_arms, | 429 | fill_match_arms, |
415 | r#" | 430 | r#" |
416 | enum A { | 431 | enum A { One, Two } |
417 | One, | 432 | enum B { One, Two } |
418 | Two, | ||
419 | } | ||
420 | enum B { | ||
421 | One, | ||
422 | Two, | ||
423 | } | ||
424 | 433 | ||
425 | fn main() { | 434 | fn main() { |
426 | let a = A::One; | 435 | let a = A::One; |
@@ -429,20 +438,14 @@ mod tests { | |||
429 | } | 438 | } |
430 | "#, | 439 | "#, |
431 | r#" | 440 | r#" |
432 | enum A { | 441 | enum A { One, Two } |
433 | One, | 442 | enum B { One, Two } |
434 | Two, | ||
435 | } | ||
436 | enum B { | ||
437 | One, | ||
438 | Two, | ||
439 | } | ||
440 | 443 | ||
441 | fn main() { | 444 | fn main() { |
442 | let a = A::One; | 445 | let a = A::One; |
443 | let b = B::One; | 446 | let b = B::One; |
444 | match <|>(&a, &b) { | 447 | match (&a, &b) { |
445 | (A::One, B::One) => {} | 448 | $0(A::One, B::One) => {} |
446 | (A::One, B::Two) => {} | 449 | (A::One, B::Two) => {} |
447 | (A::Two, B::One) => {} | 450 | (A::Two, B::One) => {} |
448 | (A::Two, B::Two) => {} | 451 | (A::Two, B::Two) => {} |
@@ -457,14 +460,8 @@ mod tests { | |||
457 | check_assist_not_applicable( | 460 | check_assist_not_applicable( |
458 | fill_match_arms, | 461 | fill_match_arms, |
459 | r#" | 462 | r#" |
460 | enum A { | 463 | enum A { One, Two } |
461 | One, | 464 | enum B { One, Two } |
462 | Two, | ||
463 | } | ||
464 | enum B { | ||
465 | One, | ||
466 | Two, | ||
467 | } | ||
468 | 465 | ||
469 | fn main() { | 466 | fn main() { |
470 | let a = A::One; | 467 | let a = A::One; |
@@ -482,14 +479,8 @@ mod tests { | |||
482 | check_assist_not_applicable( | 479 | check_assist_not_applicable( |
483 | fill_match_arms, | 480 | fill_match_arms, |
484 | r#" | 481 | r#" |
485 | enum A { | 482 | enum A { One, Two } |
486 | One, | 483 | enum B { One, Two } |
487 | Two, | ||
488 | } | ||
489 | enum B { | ||
490 | One, | ||
491 | Two, | ||
492 | } | ||
493 | 484 | ||
494 | fn main() { | 485 | fn main() { |
495 | let a = A::One; | 486 | let a = A::One; |
@@ -513,10 +504,7 @@ mod tests { | |||
513 | check_assist_not_applicable( | 504 | check_assist_not_applicable( |
514 | fill_match_arms, | 505 | fill_match_arms, |
515 | r#" | 506 | r#" |
516 | enum A { | 507 | enum A { One, Two } |
517 | One, | ||
518 | Two, | ||
519 | } | ||
520 | 508 | ||
521 | fn main() { | 509 | fn main() { |
522 | let a = A::One; | 510 | let a = A::One; |
@@ -532,9 +520,7 @@ mod tests { | |||
532 | check_assist( | 520 | check_assist( |
533 | fill_match_arms, | 521 | fill_match_arms, |
534 | r#" | 522 | r#" |
535 | enum A { | 523 | enum A { As } |
536 | As, | ||
537 | } | ||
538 | 524 | ||
539 | fn foo(a: &A) { | 525 | fn foo(a: &A) { |
540 | match a<|> { | 526 | match a<|> { |
@@ -542,13 +528,11 @@ mod tests { | |||
542 | } | 528 | } |
543 | "#, | 529 | "#, |
544 | r#" | 530 | r#" |
545 | enum A { | 531 | enum A { As } |
546 | As, | ||
547 | } | ||
548 | 532 | ||
549 | fn foo(a: &A) { | 533 | fn foo(a: &A) { |
550 | match <|>a { | 534 | match a { |
551 | A::As => {} | 535 | $0A::As => {} |
552 | } | 536 | } |
553 | } | 537 | } |
554 | "#, | 538 | "#, |
@@ -558,7 +542,7 @@ mod tests { | |||
558 | fill_match_arms, | 542 | fill_match_arms, |
559 | r#" | 543 | r#" |
560 | enum A { | 544 | enum A { |
561 | Es{ x: usize, y: usize } | 545 | Es { x: usize, y: usize } |
562 | } | 546 | } |
563 | 547 | ||
564 | fn foo(a: &mut A) { | 548 | fn foo(a: &mut A) { |
@@ -568,12 +552,12 @@ mod tests { | |||
568 | "#, | 552 | "#, |
569 | r#" | 553 | r#" |
570 | enum A { | 554 | enum A { |
571 | Es{ x: usize, y: usize } | 555 | Es { x: usize, y: usize } |
572 | } | 556 | } |
573 | 557 | ||
574 | fn foo(a: &mut A) { | 558 | fn foo(a: &mut A) { |
575 | match <|>a { | 559 | match a { |
576 | A::Es { x, y } => {} | 560 | $0A::Es { x, y } => {} |
577 | } | 561 | } |
578 | } | 562 | } |
579 | "#, | 563 | "#, |
@@ -612,8 +596,8 @@ mod tests { | |||
612 | enum E { X, Y } | 596 | enum E { X, Y } |
613 | 597 | ||
614 | fn main() { | 598 | fn main() { |
615 | match <|>E::X { | 599 | match E::X { |
616 | E::X => {} | 600 | $0E::X => {} |
617 | E::Y => {} | 601 | E::Y => {} |
618 | } | 602 | } |
619 | } | 603 | } |
@@ -640,8 +624,8 @@ mod tests { | |||
640 | use foo::E::X; | 624 | use foo::E::X; |
641 | 625 | ||
642 | fn main() { | 626 | fn main() { |
643 | match <|>X { | 627 | match X { |
644 | X => {} | 628 | $0X => {} |
645 | foo::E::Y => {} | 629 | foo::E::Y => {} |
646 | } | 630 | } |
647 | } | 631 | } |
@@ -654,10 +638,7 @@ mod tests { | |||
654 | check_assist( | 638 | check_assist( |
655 | fill_match_arms, | 639 | fill_match_arms, |
656 | r#" | 640 | r#" |
657 | enum A { | 641 | enum A { One, Two } |
658 | One, | ||
659 | Two, | ||
660 | } | ||
661 | fn foo(a: A) { | 642 | fn foo(a: A) { |
662 | match a { | 643 | match a { |
663 | // foo bar baz<|> | 644 | // foo bar baz<|> |
@@ -667,16 +648,13 @@ mod tests { | |||
667 | } | 648 | } |
668 | "#, | 649 | "#, |
669 | r#" | 650 | r#" |
670 | enum A { | 651 | enum A { One, Two } |
671 | One, | ||
672 | Two, | ||
673 | } | ||
674 | fn foo(a: A) { | 652 | fn foo(a: A) { |
675 | match <|>a { | 653 | match a { |
676 | // foo bar baz | 654 | // foo bar baz |
677 | A::One => {} | 655 | A::One => {} |
678 | // This is where the rest should be | 656 | // This is where the rest should be |
679 | A::Two => {} | 657 | $0A::Two => {} |
680 | } | 658 | } |
681 | } | 659 | } |
682 | "#, | 660 | "#, |
@@ -688,10 +666,7 @@ mod tests { | |||
688 | check_assist( | 666 | check_assist( |
689 | fill_match_arms, | 667 | fill_match_arms, |
690 | r#" | 668 | r#" |
691 | enum A { | 669 | enum A { One, Two } |
692 | One, | ||
693 | Two, | ||
694 | } | ||
695 | fn foo(a: A) { | 670 | fn foo(a: A) { |
696 | match a { | 671 | match a { |
697 | // foo bar baz<|> | 672 | // foo bar baz<|> |
@@ -699,14 +674,11 @@ mod tests { | |||
699 | } | 674 | } |
700 | "#, | 675 | "#, |
701 | r#" | 676 | r#" |
702 | enum A { | 677 | enum A { One, Two } |
703 | One, | ||
704 | Two, | ||
705 | } | ||
706 | fn foo(a: A) { | 678 | fn foo(a: A) { |
707 | match <|>a { | 679 | match a { |
708 | // foo bar baz | 680 | // foo bar baz |
709 | A::One => {} | 681 | $0A::One => {} |
710 | A::Two => {} | 682 | A::Two => {} |
711 | } | 683 | } |
712 | } | 684 | } |
@@ -729,12 +701,37 @@ mod tests { | |||
729 | r#" | 701 | r#" |
730 | enum A { One, Two, } | 702 | enum A { One, Two, } |
731 | fn foo(a: A) { | 703 | fn foo(a: A) { |
732 | match <|>a { | 704 | match a { |
733 | A::One => {} | 705 | $0A::One => {} |
734 | A::Two => {} | 706 | A::Two => {} |
735 | } | 707 | } |
736 | } | 708 | } |
737 | "#, | 709 | "#, |
738 | ); | 710 | ); |
739 | } | 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 | } | ||
740 | } | 737 | } |