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