]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/fill_match_arms.rs
Compute missing arms lazily.
[rust.git] / crates / ide_assists / src / handlers / fill_match_arms.rs
1 use std::iter::{self, Peekable};
2
3 use either::Either;
4 use hir::{Adt, HasSource, ModuleDef, Semantics};
5 use ide_db::helpers::{mod_path_to_ast, FamousDefs};
6 use ide_db::RootDatabase;
7 use itertools::Itertools;
8 use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
9
10 use crate::{
11     utils::{self, render_snippet, Cursor},
12     AssistContext, AssistId, AssistKind, Assists,
13 };
14
15 // Assist: fill_match_arms
16 //
17 // Adds missing clauses to a `match` expression.
18 //
19 // ```
20 // enum Action { Move { distance: u32 }, Stop }
21 //
22 // fn handle(action: Action) {
23 //     match action {
24 //         $0
25 //     }
26 // }
27 // ```
28 // ->
29 // ```
30 // enum Action { Move { distance: u32 }, Stop }
31 //
32 // fn handle(action: Action) {
33 //     match action {
34 //         $0Action::Move { distance } => {}
35 //         Action::Stop => {}
36 //     }
37 // }
38 // ```
39 pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40     let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?;
41     let match_arm_list = match_expr.match_arm_list()?;
42
43     let expr = match_expr.expr()?;
44
45     let mut arms: Vec<MatchArm> = match_arm_list.arms().collect();
46     if arms.len() == 1 {
47         if let Some(Pat::WildcardPat(..)) = arms[0].pat() {
48             arms.clear();
49         }
50     }
51
52     let top_lvl_pats: Vec<_> = arms
53         .iter()
54         .filter_map(ast::MatchArm::pat)
55         .flat_map(|pat| match pat {
56             // Special case OrPat as separate top-level pats
57             Pat::OrPat(or_pat) => Either::Left(or_pat.pats()),
58             _ => Either::Right(iter::once(pat)),
59         })
60         // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
61         .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
62         .collect();
63
64     let module = ctx.sema.scope(expr.syntax()).module()?;
65
66     let mut missing_pats: Peekable<Box<dyn Iterator<Item = ast::Pat>>> = if let Some(enum_def) =
67         resolve_enum_def(&ctx.sema, &expr)
68     {
69         let variants = enum_def.variants(ctx.db());
70
71         let missing_pats = variants
72             .into_iter()
73             .filter_map(|variant| build_pat(ctx.db(), module, variant))
74             .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat));
75
76         let missing_pats: Box<dyn Iterator<Item = _>> = if Some(enum_def)
77             == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option().map(lift_enum)
78         {
79             // Match `Some` variant first.
80             cov_mark::hit!(option_order);
81             Box::new(missing_pats.rev())
82         } else {
83             Box::new(missing_pats)
84         };
85         missing_pats.peekable()
86     } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
87         // When calculating the match arms for a tuple of enums, we want
88         // to create a match arm for each possible combination of enum
89         // values. The `multi_cartesian_product` method transforms
90         // Vec<Vec<EnumVariant>> into Vec<(EnumVariant, .., EnumVariant)>
91         // where each tuple represents a proposed match arm.
92         let missing_pats = enum_defs
93             .into_iter()
94             .map(|enum_def| enum_def.variants(ctx.db()))
95             .multi_cartesian_product()
96             .map(|variants| {
97                 let patterns =
98                     variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
99                 ast::Pat::from(make::tuple_pat(patterns))
100             })
101             .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat));
102         (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable()
103     } else {
104         return None;
105     };
106
107     if missing_pats.peek().is_none() {
108         return None;
109     }
110
111     let target = ctx.sema.original_range(match_expr.syntax()).range;
112     acc.add(
113         AssistId("fill_match_arms", AssistKind::QuickFix),
114         "Fill match arms",
115         target,
116         |builder| {
117             let new_match_arm_list = match_arm_list.clone_for_update();
118             let missing_arms = missing_pats
119                 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
120                 .map(|it| it.clone_for_update());
121
122             let catch_all_arm = new_match_arm_list
123                 .arms()
124                 .find(|arm| matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))));
125             if let Some(arm) = catch_all_arm {
126                 arm.remove()
127             }
128             let mut first_new_arm = None;
129             for arm in missing_arms {
130                 first_new_arm.get_or_insert_with(|| arm.clone());
131                 new_match_arm_list.add_arm(arm);
132             }
133
134             let old_range = ctx.sema.original_range(match_arm_list.syntax()).range;
135             match (first_new_arm, ctx.config.snippet_cap) {
136                 (Some(first_new_arm), Some(cap)) => {
137                     let extend_lifetime;
138                     let cursor =
139                         match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast)
140                         {
141                             Some(it) => {
142                                 extend_lifetime = it.syntax().clone();
143                                 Cursor::Replace(&extend_lifetime)
144                             }
145                             None => Cursor::Before(first_new_arm.syntax()),
146                         };
147                     let snippet = render_snippet(cap, new_match_arm_list.syntax(), cursor);
148                     builder.replace_snippet(cap, old_range, snippet);
149                 }
150                 _ => builder.replace(old_range, new_match_arm_list.to_string()),
151             }
152         },
153     )
154 }
155
156 fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool {
157     !existing_pats.iter().any(|pat| does_pat_match_variant(pat, var))
158 }
159
160 // Fixme: this is still somewhat limited, use hir_ty::diagnostics::match_check?
161 fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
162     match (pat, var) {
163         (Pat::WildcardPat(_), _) => true,
164         (Pat::TuplePat(tpat), Pat::TuplePat(tvar)) => {
165             tpat.fields().zip(tvar.fields()).all(|(p, v)| does_pat_match_variant(&p, &v))
166         }
167         _ => utils::does_pat_match_variant(pat, var),
168     }
169 }
170
171 #[derive(Eq, PartialEq, Clone, Copy)]
172 enum ExtendedEnum {
173     Bool,
174     Enum(hir::Enum),
175 }
176
177 #[derive(Eq, PartialEq, Clone, Copy)]
178 enum ExtendedVariant {
179     True,
180     False,
181     Variant(hir::Variant),
182 }
183
184 fn lift_enum(e: hir::Enum) -> ExtendedEnum {
185     ExtendedEnum::Enum(e)
186 }
187
188 impl ExtendedEnum {
189     fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> {
190         match self {
191             ExtendedEnum::Enum(e) => {
192                 e.variants(db).into_iter().map(|x| ExtendedVariant::Variant(x)).collect::<Vec<_>>()
193             }
194             ExtendedEnum::Bool => {
195                 Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False])
196             }
197         }
198     }
199 }
200
201 fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> {
202     sema.type_of_expr(&expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
203         Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)),
204         _ => {
205             if ty.is_bool() {
206                 Some(ExtendedEnum::Bool)
207             } else {
208                 None
209             }
210         }
211     })
212 }
213
214 fn resolve_tuple_of_enum_def(
215     sema: &Semantics<RootDatabase>,
216     expr: &ast::Expr,
217 ) -> Option<Vec<ExtendedEnum>> {
218     sema.type_of_expr(&expr)?
219         .tuple_fields(sema.db)
220         .iter()
221         .map(|ty| {
222             ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
223                 Some(Adt::Enum(e)) => Some(lift_enum(e)),
224                 // For now we only handle expansion for a tuple of enums. Here
225                 // we map non-enum items to None and rely on `collect` to
226                 // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>.
227                 _ => {
228                     if ty.is_bool() {
229                         Some(ExtendedEnum::Bool)
230                     } else {
231                         None
232                     }
233                 }
234             })
235         })
236         .collect()
237 }
238
239 fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option<ast::Pat> {
240     match var {
241         ExtendedVariant::Variant(var) => {
242             let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
243
244             // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
245             let pat: ast::Pat = match var.source(db)?.value.kind() {
246                 ast::StructKind::Tuple(field_list) => {
247                     let pats =
248                         iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
249                     make::tuple_struct_pat(path, pats).into()
250                 }
251                 ast::StructKind::Record(field_list) => {
252                     let pats =
253                         field_list.fields().map(|f| make::ident_pat(f.name().unwrap()).into());
254                     make::record_pat(path, pats).into()
255                 }
256                 ast::StructKind::Unit => make::path_pat(path),
257             };
258
259             Some(pat)
260         }
261         ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
262         ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
263     }
264 }
265
266 #[cfg(test)]
267 mod tests {
268     use ide_db::helpers::FamousDefs;
269
270     use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
271
272     use super::fill_match_arms;
273
274     #[test]
275     fn all_match_arms_provided() {
276         check_assist_not_applicable(
277             fill_match_arms,
278             r#"
279 enum A {
280     As,
281     Bs{x:i32, y:Option<i32>},
282     Cs(i32, Option<i32>),
283 }
284 fn main() {
285     match A::As$0 {
286         A::As,
287         A::Bs{x,y:Some(_)} => {}
288         A::Cs(_, Some(_)) => {}
289     }
290 }
291             "#,
292         );
293     }
294
295     #[test]
296     fn all_boolean_match_arms_provided() {
297         check_assist_not_applicable(
298             fill_match_arms,
299             r#"
300 fn foo(a: bool) {
301     match a$0 {
302         true => {}
303         false => {}
304     }
305 }
306 "#,
307         )
308     }
309
310     #[test]
311     fn tuple_of_non_enum() {
312         // for now this case is not handled, although it potentially could be
313         // in the future
314         check_assist_not_applicable(
315             fill_match_arms,
316             r#"
317 fn main() {
318     match (0, false)$0 {
319     }
320 }
321 "#,
322         );
323     }
324
325     #[test]
326     fn fill_match_arms_boolean() {
327         check_assist(
328             fill_match_arms,
329             r#"
330 fn foo(a: bool) {
331     match a$0 {
332     }
333 }
334 "#,
335             r#"
336 fn foo(a: bool) {
337     match a {
338         $0true => {}
339         false => {}
340     }
341 }
342 "#,
343         )
344     }
345
346     #[test]
347     fn partial_fill_boolean() {
348         check_assist(
349             fill_match_arms,
350             r#"
351 fn foo(a: bool) {
352     match a$0 {
353         true => {}
354     }
355 }
356 "#,
357             r#"
358 fn foo(a: bool) {
359     match a {
360         true => {}
361         $0false => {}
362     }
363 }
364 "#,
365         )
366     }
367
368     #[test]
369     fn all_boolean_tuple_arms_provided() {
370         check_assist_not_applicable(
371             fill_match_arms,
372             r#"
373 fn foo(a: bool) {
374     match (a, a)$0 {
375         (true, true) => {}
376         (true, false) => {}
377         (false, true) => {}
378         (false, false) => {}
379     }
380 }
381 "#,
382         )
383     }
384
385     #[test]
386     fn fill_boolean_tuple() {
387         check_assist(
388             fill_match_arms,
389             r#"
390 fn foo(a: bool) {
391     match (a, a)$0 {
392     }
393 }
394 "#,
395             r#"
396 fn foo(a: bool) {
397     match (a, a) {
398         $0(true, true) => {}
399         (true, false) => {}
400         (false, true) => {}
401         (false, false) => {}
402     }
403 }
404 "#,
405         )
406     }
407
408     #[test]
409     fn partial_fill_boolean_tuple() {
410         check_assist(
411             fill_match_arms,
412             r#"
413 fn foo(a: bool) {
414     match (a, a)$0 {
415         (false, true) => {}
416     }
417 }
418 "#,
419             r#"
420 fn foo(a: bool) {
421     match (a, a) {
422         (false, true) => {}
423         $0(true, true) => {}
424         (true, false) => {}
425         (false, false) => {}
426     }
427 }
428 "#,
429         )
430     }
431
432     #[test]
433     fn partial_fill_record_tuple() {
434         check_assist(
435             fill_match_arms,
436             r#"
437 enum A {
438     As,
439     Bs { x: i32, y: Option<i32> },
440     Cs(i32, Option<i32>),
441 }
442 fn main() {
443     match A::As$0 {
444         A::Bs { x, y: Some(_) } => {}
445         A::Cs(_, Some(_)) => {}
446     }
447 }
448 "#,
449             r#"
450 enum A {
451     As,
452     Bs { x: i32, y: Option<i32> },
453     Cs(i32, Option<i32>),
454 }
455 fn main() {
456     match A::As {
457         A::Bs { x, y: Some(_) } => {}
458         A::Cs(_, Some(_)) => {}
459         $0A::As => {}
460     }
461 }
462 "#,
463         );
464     }
465
466     #[test]
467     fn partial_fill_option() {
468         check_assist(
469             fill_match_arms,
470             r#"
471 enum Option<T> { Some(T), None }
472 use Option::*;
473
474 fn main() {
475     match None$0 {
476         None => {}
477     }
478 }
479             "#,
480             r#"
481 enum Option<T> { Some(T), None }
482 use Option::*;
483
484 fn main() {
485     match None {
486         None => {}
487         Some(${0:_}) => {}
488     }
489 }
490             "#,
491         );
492     }
493
494     #[test]
495     fn partial_fill_or_pat() {
496         check_assist(
497             fill_match_arms,
498             r#"
499 enum A { As, Bs, Cs(Option<i32>) }
500 fn main() {
501     match A::As$0 {
502         A::Cs(_) | A::Bs => {}
503     }
504 }
505 "#,
506             r#"
507 enum A { As, Bs, Cs(Option<i32>) }
508 fn main() {
509     match A::As {
510         A::Cs(_) | A::Bs => {}
511         $0A::As => {}
512     }
513 }
514 "#,
515         );
516     }
517
518     #[test]
519     fn partial_fill() {
520         check_assist(
521             fill_match_arms,
522             r#"
523 enum A { As, Bs, Cs, Ds(String), Es(B) }
524 enum B { Xs, Ys }
525 fn main() {
526     match A::As$0 {
527         A::Bs if 0 < 1 => {}
528         A::Ds(_value) => { let x = 1; }
529         A::Es(B::Xs) => (),
530     }
531 }
532 "#,
533             r#"
534 enum A { As, Bs, Cs, Ds(String), Es(B) }
535 enum B { Xs, Ys }
536 fn main() {
537     match A::As {
538         A::Bs if 0 < 1 => {}
539         A::Ds(_value) => { let x = 1; }
540         A::Es(B::Xs) => (),
541         $0A::As => {}
542         A::Cs => {}
543     }
544 }
545 "#,
546         );
547     }
548
549     #[test]
550     fn partial_fill_bind_pat() {
551         check_assist(
552             fill_match_arms,
553             r#"
554 enum A { As, Bs, Cs(Option<i32>) }
555 fn main() {
556     match A::As$0 {
557         A::As(_) => {}
558         a @ A::Bs(_) => {}
559     }
560 }
561 "#,
562             r#"
563 enum A { As, Bs, Cs(Option<i32>) }
564 fn main() {
565     match A::As {
566         A::As(_) => {}
567         a @ A::Bs(_) => {}
568         A::Cs(${0:_}) => {}
569     }
570 }
571 "#,
572         );
573     }
574
575     #[test]
576     fn fill_match_arms_empty_body() {
577         check_assist(
578             fill_match_arms,
579             r#"
580 enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
581
582 fn main() {
583     let a = A::As;
584     match a$0 {}
585 }
586 "#,
587             r#"
588 enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
589
590 fn main() {
591     let a = A::As;
592     match a {
593         $0A::As => {}
594         A::Bs => {}
595         A::Cs(_) => {}
596         A::Ds(_, _) => {}
597         A::Es { x, y } => {}
598     }
599 }
600 "#,
601         );
602     }
603
604     #[test]
605     fn fill_match_arms_tuple_of_enum() {
606         check_assist(
607             fill_match_arms,
608             r#"
609 enum A { One, Two }
610 enum B { One, Two }
611
612 fn main() {
613     let a = A::One;
614     let b = B::One;
615     match (a$0, b) {}
616 }
617 "#,
618             r#"
619 enum A { One, Two }
620 enum B { One, Two }
621
622 fn main() {
623     let a = A::One;
624     let b = B::One;
625     match (a, b) {
626         $0(A::One, B::One) => {}
627         (A::One, B::Two) => {}
628         (A::Two, B::One) => {}
629         (A::Two, B::Two) => {}
630     }
631 }
632 "#,
633         );
634     }
635
636     #[test]
637     fn fill_match_arms_tuple_of_enum_ref() {
638         check_assist(
639             fill_match_arms,
640             r#"
641 enum A { One, Two }
642 enum B { One, Two }
643
644 fn main() {
645     let a = A::One;
646     let b = B::One;
647     match (&a$0, &b) {}
648 }
649 "#,
650             r#"
651 enum A { One, Two }
652 enum B { One, Two }
653
654 fn main() {
655     let a = A::One;
656     let b = B::One;
657     match (&a, &b) {
658         $0(A::One, B::One) => {}
659         (A::One, B::Two) => {}
660         (A::Two, B::One) => {}
661         (A::Two, B::Two) => {}
662     }
663 }
664 "#,
665         );
666     }
667
668     #[test]
669     fn fill_match_arms_tuple_of_enum_partial() {
670         check_assist(
671             fill_match_arms,
672             r#"
673 enum A { One, Two }
674 enum B { One, Two }
675
676 fn main() {
677     let a = A::One;
678     let b = B::One;
679     match (a$0, b) {
680         (A::Two, B::One) => {}
681     }
682 }
683 "#,
684             r#"
685 enum A { One, Two }
686 enum B { One, Two }
687
688 fn main() {
689     let a = A::One;
690     let b = B::One;
691     match (a, b) {
692         (A::Two, B::One) => {}
693         $0(A::One, B::One) => {}
694         (A::One, B::Two) => {}
695         (A::Two, B::Two) => {}
696     }
697 }
698 "#,
699         );
700     }
701
702     #[test]
703     fn fill_match_arms_tuple_of_enum_partial_with_wildcards() {
704         let ra_fixture = r#"
705 fn main() {
706     let a = Some(1);
707     let b = Some(());
708     match (a$0, b) {
709         (Some(_), _) => {}
710         (None, Some(_)) => {}
711     }
712 }
713 "#;
714         check_assist(
715             fill_match_arms,
716             &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
717             r#"
718 fn main() {
719     let a = Some(1);
720     let b = Some(());
721     match (a, b) {
722         (Some(_), _) => {}
723         (None, Some(_)) => {}
724         $0(None, None) => {}
725     }
726 }
727 "#,
728         );
729     }
730
731     #[test]
732     fn fill_match_arms_partial_with_deep_pattern() {
733         // Fixme: cannot handle deep patterns
734         let ra_fixture = r#"
735 fn main() {
736     match $0Some(true) {
737         Some(true) => {}
738         None => {}
739     }
740 }
741 "#;
742         check_assist_not_applicable(
743             fill_match_arms,
744             &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
745         );
746     }
747
748     #[test]
749     fn fill_match_arms_tuple_of_enum_not_applicable() {
750         check_assist_not_applicable(
751             fill_match_arms,
752             r#"
753 enum A { One, Two }
754 enum B { One, Two }
755
756 fn main() {
757     let a = A::One;
758     let b = B::One;
759     match (a$0, b) {
760         (A::Two, B::One) => {}
761         (A::One, B::One) => {}
762         (A::One, B::Two) => {}
763         (A::Two, B::Two) => {}
764     }
765 }
766 "#,
767         );
768     }
769
770     #[test]
771     fn fill_match_arms_single_element_tuple_of_enum() {
772         check_assist(
773             fill_match_arms,
774             r#"
775 enum A { One, Two }
776
777 fn main() {
778     let a = A::One;
779     match (a$0, ) {
780     }
781 }
782 "#,
783             r#"
784 enum A { One, Two }
785
786 fn main() {
787     let a = A::One;
788     match (a, ) {
789         $0(A::One,) => {}
790         (A::Two,) => {}
791     }
792 }
793 "#,
794         );
795     }
796
797     #[test]
798     fn test_fill_match_arm_refs() {
799         check_assist(
800             fill_match_arms,
801             r#"
802 enum A { As }
803
804 fn foo(a: &A) {
805     match a$0 {
806     }
807 }
808 "#,
809             r#"
810 enum A { As }
811
812 fn foo(a: &A) {
813     match a {
814         $0A::As => {}
815     }
816 }
817 "#,
818         );
819
820         check_assist(
821             fill_match_arms,
822             r#"
823 enum A {
824     Es { x: usize, y: usize }
825 }
826
827 fn foo(a: &mut A) {
828     match a$0 {
829     }
830 }
831 "#,
832             r#"
833 enum A {
834     Es { x: usize, y: usize }
835 }
836
837 fn foo(a: &mut A) {
838     match a {
839         $0A::Es { x, y } => {}
840     }
841 }
842 "#,
843         );
844     }
845
846     #[test]
847     fn fill_match_arms_target() {
848         check_assist_target(
849             fill_match_arms,
850             r#"
851 enum E { X, Y }
852
853 fn main() {
854     match E::X$0 {}
855 }
856 "#,
857             "match E::X {}",
858         );
859     }
860
861     #[test]
862     fn fill_match_arms_trivial_arm() {
863         check_assist(
864             fill_match_arms,
865             r#"
866 enum E { X, Y }
867
868 fn main() {
869     match E::X {
870         $0_ => {}
871     }
872 }
873 "#,
874             r#"
875 enum E { X, Y }
876
877 fn main() {
878     match E::X {
879         $0E::X => {}
880         E::Y => {}
881     }
882 }
883 "#,
884         );
885     }
886
887     #[test]
888     fn fill_match_arms_qualifies_path() {
889         check_assist(
890             fill_match_arms,
891             r#"
892 mod foo { pub enum E { X, Y } }
893 use foo::E::X;
894
895 fn main() {
896     match X {
897         $0
898     }
899 }
900 "#,
901             r#"
902 mod foo { pub enum E { X, Y } }
903 use foo::E::X;
904
905 fn main() {
906     match X {
907         $0X => {}
908         foo::E::Y => {}
909     }
910 }
911 "#,
912         );
913     }
914
915     #[test]
916     fn fill_match_arms_preserves_comments() {
917         check_assist(
918             fill_match_arms,
919             r#"
920 enum A { One, Two }
921 fn foo(a: A) {
922     match a {
923         // foo bar baz$0
924         A::One => {}
925         // This is where the rest should be
926     }
927 }
928 "#,
929             r#"
930 enum A { One, Two }
931 fn foo(a: A) {
932     match a {
933         // foo bar baz
934         A::One => {}
935         $0A::Two => {}
936         // This is where the rest should be
937     }
938 }
939 "#,
940         );
941     }
942
943     #[test]
944     fn fill_match_arms_preserves_comments_empty() {
945         check_assist(
946             fill_match_arms,
947             r#"
948 enum A { One, Two }
949 fn foo(a: A) {
950     match a {
951         // foo bar baz$0
952     }
953 }
954 "#,
955             r#"
956 enum A { One, Two }
957 fn foo(a: A) {
958     match a {
959         $0A::One => {}
960         A::Two => {}
961         // foo bar baz
962     }
963 }
964 "#,
965         );
966     }
967
968     #[test]
969     fn fill_match_arms_placeholder() {
970         check_assist(
971             fill_match_arms,
972             r#"
973 enum A { One, Two, }
974 fn foo(a: A) {
975     match a$0 {
976         _ => (),
977     }
978 }
979 "#,
980             r#"
981 enum A { One, Two, }
982 fn foo(a: A) {
983     match a {
984         $0A::One => {}
985         A::Two => {}
986     }
987 }
988 "#,
989         );
990     }
991
992     #[test]
993     fn option_order() {
994         cov_mark::check!(option_order);
995         let before = r#"
996 fn foo(opt: Option<i32>) {
997     match opt$0 {
998     }
999 }
1000 "#;
1001         let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
1002
1003         check_assist(
1004             fill_match_arms,
1005             before,
1006             r#"
1007 fn foo(opt: Option<i32>) {
1008     match opt {
1009         Some(${0:_}) => {}
1010         None => {}
1011     }
1012 }
1013 "#,
1014         );
1015     }
1016
1017     #[test]
1018     fn works_inside_macro_call() {
1019         check_assist(
1020             fill_match_arms,
1021             r#"
1022 macro_rules! m { ($expr:expr) => {$expr}}
1023 enum Test {
1024     A,
1025     B,
1026     C,
1027 }
1028
1029 fn foo(t: Test) {
1030     m!(match t$0 {});
1031 }"#,
1032             r#"
1033 macro_rules! m { ($expr:expr) => {$expr}}
1034 enum Test {
1035     A,
1036     B,
1037     C,
1038 }
1039
1040 fn foo(t: Test) {
1041     m!(match t {
1042     $0Test::A => {}
1043     Test::B => {}
1044     Test::C => {}
1045 });
1046 }"#,
1047         );
1048     }
1049 }