1
+ use either:: Either ;
1
2
use ide_db:: defs:: { Definition , NameRefClass } ;
2
3
use syntax:: {
3
4
ast:: { self , AstNode , GenericParamsOwner , VisibilityOwner } ,
@@ -8,7 +9,7 @@ use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind,
8
9
9
10
// Assist: convert_tuple_struct_to_named_struct
10
11
//
11
- // Converts tuple struct to struct with named fields.
12
+ // Converts tuple struct to struct with named fields, and analogously for tuple enum variants .
12
13
//
13
14
// ```
14
15
// struct Point$0(f32, f32);
@@ -49,14 +50,21 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
49
50
acc : & mut Assists ,
50
51
ctx : & AssistContext ,
51
52
) -> Option < ( ) > {
52
- let strukt = ctx. find_node_at_offset :: < ast:: Struct > ( ) ?;
53
- let tuple_fields = match strukt. field_list ( ) ? {
53
+ let strukt = ctx
54
+ . find_node_at_offset :: < ast:: Struct > ( )
55
+ . map ( Either :: Left )
56
+ . or_else ( || ctx. find_node_at_offset :: < ast:: Variant > ( ) . map ( Either :: Right ) ) ?;
57
+ let field_list = strukt. as_ref ( ) . either ( |s| s. field_list ( ) , |v| v. field_list ( ) ) ?;
58
+ let tuple_fields = match field_list {
54
59
ast:: FieldList :: TupleFieldList ( it) => it,
55
60
ast:: FieldList :: RecordFieldList ( _) => return None ,
56
61
} ;
57
- let strukt_def = ctx. sema . to_def ( & strukt) ?;
62
+ let strukt_def = match & strukt {
63
+ Either :: Left ( s) => Either :: Left ( ctx. sema . to_def ( s) ?) ,
64
+ Either :: Right ( v) => Either :: Right ( ctx. sema . to_def ( v) ?) ,
65
+ } ;
66
+ let target = strukt. as_ref ( ) . either ( |s| s. syntax ( ) , |v| v. syntax ( ) ) . text_range ( ) ;
58
67
59
- let target = strukt. syntax ( ) . text_range ( ) ;
60
68
acc. add (
61
69
AssistId ( "convert_tuple_struct_to_named_struct" , AssistKind :: RefactorRewrite ) ,
62
70
"Convert to named struct" ,
@@ -73,7 +81,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
73
81
fn edit_struct_def (
74
82
ctx : & AssistContext ,
75
83
edit : & mut AssistBuilder ,
76
- strukt : & ast:: Struct ,
84
+ strukt : & Either < ast:: Struct , ast :: Variant > ,
77
85
tuple_fields : ast:: TupleFieldList ,
78
86
names : Vec < ast:: Name > ,
79
87
) {
@@ -86,27 +94,34 @@ fn edit_struct_def(
86
94
87
95
edit. edit_file ( ctx. frange . file_id ) ;
88
96
89
- if let Some ( w) = strukt. where_clause ( ) {
90
- edit. delete ( w. syntax ( ) . text_range ( ) ) ;
91
- edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_newline ( ) . text ( ) ) ;
92
- edit. insert ( tuple_fields_text_range. start ( ) , w. syntax ( ) . text ( ) ) ;
93
- edit. insert ( tuple_fields_text_range. start ( ) , "," ) ;
94
- edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_newline ( ) . text ( ) ) ;
97
+ if let Either :: Left ( strukt) = strukt {
98
+ if let Some ( w) = strukt. where_clause ( ) {
99
+ edit. delete ( w. syntax ( ) . text_range ( ) ) ;
100
+ edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_newline ( ) . text ( ) ) ;
101
+ edit. insert ( tuple_fields_text_range. start ( ) , w. syntax ( ) . text ( ) ) ;
102
+ edit. insert ( tuple_fields_text_range. start ( ) , "," ) ;
103
+ edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_newline ( ) . text ( ) ) ;
104
+ } else {
105
+ edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_space ( ) . text ( ) ) ;
106
+ }
107
+ strukt. semicolon_token ( ) . map ( |t| edit. delete ( t. text_range ( ) ) ) ;
95
108
} else {
96
109
edit. insert ( tuple_fields_text_range. start ( ) , ast:: make:: tokens:: single_space ( ) . text ( ) ) ;
97
110
}
98
111
99
112
edit. replace ( tuple_fields_text_range, record_fields. to_string ( ) ) ;
100
- strukt. semicolon_token ( ) . map ( |t| edit. delete ( t. text_range ( ) ) ) ;
101
113
}
102
114
103
115
fn edit_struct_references (
104
116
ctx : & AssistContext ,
105
117
edit : & mut AssistBuilder ,
106
- strukt : hir:: Struct ,
118
+ strukt : Either < hir:: Struct , hir :: Variant > ,
107
119
names : & [ ast:: Name ] ,
108
120
) {
109
- let strukt_def = Definition :: ModuleDef ( hir:: ModuleDef :: Adt ( hir:: Adt :: Struct ( strukt) ) ) ;
121
+ let strukt_def = match strukt {
122
+ Either :: Left ( s) => Definition :: ModuleDef ( hir:: ModuleDef :: Adt ( hir:: Adt :: Struct ( s) ) ) ,
123
+ Either :: Right ( v) => Definition :: ModuleDef ( hir:: ModuleDef :: Variant ( v) ) ,
124
+ } ;
110
125
let usages = strukt_def. usages ( & ctx. sema ) . include_self_refs ( ) . all ( ) ;
111
126
112
127
let edit_node = |edit : & mut AssistBuilder , node : SyntaxNode | -> Option < ( ) > {
@@ -510,6 +525,304 @@ where
510
525
T: Display,
511
526
{ field1: T }
512
527
528
+ "# ,
529
+ ) ;
530
+ }
531
+ #[ test]
532
+ fn not_applicable_other_than_tuple_variant ( ) {
533
+ check_assist_not_applicable (
534
+ convert_tuple_struct_to_named_struct,
535
+ r#"enum Enum { Variant$0 { value: usize } };"# ,
536
+ ) ;
537
+ check_assist_not_applicable ( convert_tuple_struct_to_named_struct, r#"enum Enum { Variant$0 }"# ) ;
538
+ }
539
+
540
+ #[ test]
541
+ fn convert_simple_variant ( ) {
542
+ check_assist (
543
+ convert_tuple_struct_to_named_struct,
544
+ r#"
545
+ enum A {
546
+ $0Variant(usize),
547
+ }
548
+
549
+ impl A {
550
+ fn new(value: usize) -> A {
551
+ A::Variant(value)
552
+ }
553
+
554
+ fn new_with_default() -> A {
555
+ A::new(Default::default())
556
+ }
557
+
558
+ fn value(self) -> usize {
559
+ match self {
560
+ A::Variant(value) => value,
561
+ }
562
+ }
563
+ }"# ,
564
+ r#"
565
+ enum A {
566
+ Variant { field1: usize },
567
+ }
568
+
569
+ impl A {
570
+ fn new(value: usize) -> A {
571
+ A::Variant { field1: value }
572
+ }
573
+
574
+ fn new_with_default() -> A {
575
+ A::new(Default::default())
576
+ }
577
+
578
+ fn value(self) -> usize {
579
+ match self {
580
+ A::Variant { field1: value } => value,
581
+ }
582
+ }
583
+ }"# ,
584
+ ) ;
585
+ }
586
+
587
+ #[ test]
588
+ fn convert_variant_referenced_via_self_kw ( ) {
589
+ check_assist (
590
+ convert_tuple_struct_to_named_struct,
591
+ r#"
592
+ enum A {
593
+ $0Variant(usize),
594
+ }
595
+
596
+ impl A {
597
+ fn new(value: usize) -> A {
598
+ Self::Variant(value)
599
+ }
600
+
601
+ fn new_with_default() -> A {
602
+ Self::new(Default::default())
603
+ }
604
+
605
+ fn value(self) -> usize {
606
+ match self {
607
+ Self::Variant(value) => value,
608
+ }
609
+ }
610
+ }"# ,
611
+ r#"
612
+ enum A {
613
+ Variant { field1: usize },
614
+ }
615
+
616
+ impl A {
617
+ fn new(value: usize) -> A {
618
+ Self::Variant { field1: value }
619
+ }
620
+
621
+ fn new_with_default() -> A {
622
+ Self::new(Default::default())
623
+ }
624
+
625
+ fn value(self) -> usize {
626
+ match self {
627
+ Self::Variant { field1: value } => value,
628
+ }
629
+ }
630
+ }"# ,
631
+ ) ;
632
+ }
633
+
634
+ #[ test]
635
+ fn convert_destructured_variant ( ) {
636
+ check_assist (
637
+ convert_tuple_struct_to_named_struct,
638
+ r#"
639
+ enum A {
640
+ $0Variant(usize),
641
+ }
642
+
643
+ impl A {
644
+ fn into_inner(self) -> usize {
645
+ let A::Variant(first) = self;
646
+ first
647
+ }
648
+
649
+ fn into_inner_via_self(self) -> usize {
650
+ let Self::Variant(first) = self;
651
+ first
652
+ }
653
+ }"# ,
654
+ r#"
655
+ enum A {
656
+ Variant { field1: usize },
657
+ }
658
+
659
+ impl A {
660
+ fn into_inner(self) -> usize {
661
+ let A::Variant { field1: first } = self;
662
+ first
663
+ }
664
+
665
+ fn into_inner_via_self(self) -> usize {
666
+ let Self::Variant { field1: first } = self;
667
+ first
668
+ }
669
+ }"# ,
670
+ ) ;
671
+ }
672
+
673
+ #[ test]
674
+ fn convert_variant_with_wrapped_references ( ) {
675
+ check_assist (
676
+ convert_tuple_struct_to_named_struct,
677
+ r#"
678
+ enum Inner {
679
+ $0Variant(usize),
680
+ }
681
+ enum Outer {
682
+ Variant(Inner),
683
+ }
684
+
685
+ impl Outer {
686
+ fn new() -> Self {
687
+ Self::Variant(Inner::Variant(42))
688
+ }
689
+
690
+ fn into_inner_destructed(self) -> u32 {
691
+ let Outer::Variant(Inner::Variant(x)) = self;
692
+ x
693
+ }
694
+ }"# ,
695
+ r#"
696
+ enum Inner {
697
+ Variant { field1: usize },
698
+ }
699
+ enum Outer {
700
+ Variant(Inner),
701
+ }
702
+
703
+ impl Outer {
704
+ fn new() -> Self {
705
+ Self::Variant(Inner::Variant { field1: 42 })
706
+ }
707
+
708
+ fn into_inner_destructed(self) -> u32 {
709
+ let Outer::Variant(Inner::Variant { field1: x }) = self;
710
+ x
711
+ }
712
+ }"# ,
713
+ ) ;
714
+
715
+ check_assist (
716
+ convert_tuple_struct_to_named_struct,
717
+ r#"
718
+ enum Inner {
719
+ Variant(usize),
720
+ }
721
+ enum Outer {
722
+ $0Variant(Inner),
723
+ }
724
+
725
+ impl Outer {
726
+ fn new() -> Self {
727
+ Self::Variant(Inner::Variant(42))
728
+ }
729
+
730
+ fn into_inner_destructed(self) -> u32 {
731
+ let Outer::Variant(Inner::Variant(x)) = self;
732
+ x
733
+ }
734
+ }"# ,
735
+ r#"
736
+ enum Inner {
737
+ Variant(usize),
738
+ }
739
+ enum Outer {
740
+ Variant { field1: Inner },
741
+ }
742
+
743
+ impl Outer {
744
+ fn new() -> Self {
745
+ Self::Variant { field1: Inner::Variant(42) }
746
+ }
747
+
748
+ fn into_inner_destructed(self) -> u32 {
749
+ let Outer::Variant { field1: Inner::Variant(x) } = self;
750
+ x
751
+ }
752
+ }"# ,
753
+ ) ;
754
+ }
755
+
756
+ #[ test]
757
+ fn convert_variant_with_multi_file_references ( ) {
758
+ check_assist (
759
+ convert_tuple_struct_to_named_struct,
760
+ r#"
761
+ //- /main.rs
762
+ struct Inner;
763
+ enum A {
764
+ $0Variant(Inner),
765
+ }
766
+
767
+ mod foo;
768
+
769
+ //- /foo.rs
770
+ use crate::{A, Inner};
771
+ fn f() {
772
+ let a = A::Variant(Inner);
773
+ }
774
+ "# ,
775
+ r#"
776
+ //- /main.rs
777
+ struct Inner;
778
+ enum A {
779
+ Variant { field1: Inner },
780
+ }
781
+
782
+ mod foo;
783
+
784
+ //- /foo.rs
785
+ use crate::{A, Inner};
786
+ fn f() {
787
+ let a = A::Variant { field1: Inner };
788
+ }
789
+ "# ,
790
+ ) ;
791
+ }
792
+
793
+ #[ test]
794
+ fn convert_directly_used_variant ( ) {
795
+ check_assist (
796
+ convert_tuple_struct_to_named_struct,
797
+ r#"
798
+ //- /main.rs
799
+ struct Inner;
800
+ enum A {
801
+ $0Variant(Inner),
802
+ }
803
+
804
+ mod foo;
805
+
806
+ //- /foo.rs
807
+ use crate::{A::Variant, Inner};
808
+ fn f() {
809
+ let a = Variant(Inner);
810
+ }
811
+ "# ,
812
+ r#"
813
+ //- /main.rs
814
+ struct Inner;
815
+ enum A {
816
+ Variant { field1: Inner },
817
+ }
818
+
819
+ mod foo;
820
+
821
+ //- /foo.rs
822
+ use crate::{A::Variant, Inner};
823
+ fn f() {
824
+ let a = Variant { field1: Inner };
825
+ }
513
826
"# ,
514
827
) ;
515
828
}
0 commit comments