1
1
use stdx:: { format_to, to_lower_snake_case} ;
2
2
use syntax:: ast:: VisibilityOwner ;
3
3
use syntax:: ast:: { self , AstNode , NameOwner } ;
4
- use test_utils:: mark;
5
4
6
5
use crate :: {
7
6
utils:: { find_impl_block_end, find_struct_impl, generate_impl_text} ,
@@ -37,20 +36,17 @@ use crate::{
37
36
pub ( crate ) fn generate_enum_is_method ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
38
37
let variant = ctx. find_node_at_offset :: < ast:: Variant > ( ) ?;
39
38
let variant_name = variant. name ( ) ?;
40
- let parent_enum = variant. parent_enum ( ) ;
41
- if !matches ! ( variant. kind( ) , ast:: StructKind :: Unit ) {
42
- mark:: hit!( test_gen_enum_match_on_non_unit_variant_not_implemented) ;
43
- return None ;
44
- }
39
+ let parent_enum = ast:: Adt :: Enum ( variant. parent_enum ( ) ) ;
40
+ let variant_kind = variant_kind ( & variant) ;
45
41
46
42
let enum_lowercase_name = to_lower_snake_case ( & parent_enum. name ( ) ?. to_string ( ) ) ;
47
- let fn_name = to_lower_snake_case ( & variant_name. to_string ( ) ) ;
43
+ let fn_name = format ! ( "is_{}" , & to_lower_snake_case ( variant_name. text ( ) ) ) ;
48
44
49
45
// Return early if we've found an existing new fn
50
46
let impl_def = find_struct_impl (
51
47
& ctx,
52
- & ast :: Adt :: Enum ( parent_enum. clone ( ) ) ,
53
- format ! ( "is_{}" , fn_name) . as_str ( ) ,
48
+ & parent_enum,
49
+ & fn_name,
54
50
) ?;
55
51
56
52
let target = variant. syntax ( ) . text_range ( ) ;
@@ -69,20 +65,21 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
69
65
format_to ! (
70
66
buf,
71
67
" /// Returns `true` if the {} is [`{}`].
72
- {}fn is_ {}(&self) -> bool {{
73
- matches!(self, Self::{})
68
+ {}fn {}(&self) -> bool {{
69
+ matches!(self, Self::{}{} )
74
70
}}" ,
75
71
enum_lowercase_name,
76
72
variant_name,
77
73
vis,
78
74
fn_name,
79
- variant_name
75
+ variant_name,
76
+ variant_kind. pattern_suffix( ) ,
80
77
) ;
81
78
82
79
let start_offset = impl_def
83
80
. and_then ( |impl_def| find_impl_block_end ( impl_def, & mut buf) )
84
81
. unwrap_or_else ( || {
85
- buf = generate_impl_text ( & ast :: Adt :: Enum ( parent_enum. clone ( ) ) , & buf) ;
82
+ buf = generate_impl_text ( & parent_enum, & buf) ;
86
83
parent_enum. syntax ( ) . text_range ( ) . end ( )
87
84
} ) ;
88
85
@@ -91,10 +88,53 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
91
88
)
92
89
}
93
90
91
+ enum VariantKind {
92
+ Unit ,
93
+ /// Tuple with a single field
94
+ NewtypeTuple ,
95
+ /// Tuple with 0 or more than 2 fields
96
+ Tuple ,
97
+ /// Record with a single field
98
+ NewtypeRecord { field_name : Option < ast:: Name > } ,
99
+ /// Record with 0 or more than 2 fields
100
+ Record ,
101
+ }
102
+
103
+ impl VariantKind {
104
+ fn pattern_suffix ( & self ) -> & ' static str {
105
+ match self {
106
+ VariantKind :: Unit => "" ,
107
+ VariantKind :: NewtypeTuple |
108
+ VariantKind :: Tuple => "(..)" ,
109
+ VariantKind :: NewtypeRecord { .. } |
110
+ VariantKind :: Record => " { .. }" ,
111
+ }
112
+ }
113
+ }
114
+
115
+ fn variant_kind ( variant : & ast:: Variant ) -> VariantKind {
116
+ match variant. kind ( ) {
117
+ ast:: StructKind :: Record ( record) => {
118
+ if record. fields ( ) . count ( ) == 1 {
119
+ let field_name = record. fields ( ) . nth ( 0 ) . unwrap ( ) . name ( ) ;
120
+ VariantKind :: NewtypeRecord { field_name }
121
+ } else {
122
+ VariantKind :: Record
123
+ }
124
+ }
125
+ ast:: StructKind :: Tuple ( tuple) => {
126
+ if tuple. fields ( ) . count ( ) == 1 {
127
+ VariantKind :: NewtypeTuple
128
+ } else {
129
+ VariantKind :: Tuple
130
+ }
131
+ }
132
+ ast:: StructKind :: Unit => VariantKind :: Unit ,
133
+ }
134
+ }
135
+
94
136
#[ cfg( test) ]
95
137
mod tests {
96
- use test_utils:: mark;
97
-
98
138
use crate :: tests:: { check_assist, check_assist_not_applicable} ;
99
139
100
140
use super :: * ;
@@ -147,14 +187,51 @@ impl Variant {
147
187
}
148
188
149
189
#[ test]
150
- fn test_add_from_impl_no_element ( ) {
151
- mark :: check! ( test_gen_enum_match_on_non_unit_variant_not_implemented ) ;
152
- check_not_applicable (
190
+ fn test_generate_enum_match_from_tuple_variant ( ) {
191
+ check_assist (
192
+ generate_enum_is_method ,
153
193
r#"
154
194
enum Variant {
155
195
Undefined,
156
196
Minor(u32)$0,
157
197
Major,
198
+ }"# ,
199
+ r#"enum Variant {
200
+ Undefined,
201
+ Minor(u32),
202
+ Major,
203
+ }
204
+
205
+ impl Variant {
206
+ /// Returns `true` if the variant is [`Minor`].
207
+ fn is_minor(&self) -> bool {
208
+ matches!(self, Self::Minor(..))
209
+ }
210
+ }"# ,
211
+ ) ;
212
+ }
213
+
214
+ #[ test]
215
+ fn test_generate_enum_match_from_record_variant ( ) {
216
+ check_assist (
217
+ generate_enum_is_method,
218
+ r#"
219
+ enum Variant {
220
+ Undefined,
221
+ Minor { foo: i32 }$0,
222
+ Major,
223
+ }"# ,
224
+ r#"enum Variant {
225
+ Undefined,
226
+ Minor { foo: i32 },
227
+ Major,
228
+ }
229
+
230
+ impl Variant {
231
+ /// Returns `true` if the variant is [`Minor`].
232
+ fn is_minor(&self) -> bool {
233
+ matches!(self, Self::Minor { .. })
234
+ }
158
235
}"# ,
159
236
) ;
160
237
}
0 commit comments