aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/fill_match_arms.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/fill_match_arms.rs')
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs237
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};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
7use test_utils::mark;
7 8
8use crate::{Assist, AssistCtx, AssistId}; 9use 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// ```
34pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { 38pub(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)]
170mod tests { 192mod 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#"
717fn 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#"
728fn foo(opt: Option<i32>) {
729 match opt {
730 $0Some(_) => {}
731 None => {}
732 }
733}
734"#,
735 );
736 }
740} 737}