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