aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r--crates/ide_assists/src/handlers/generate_enum_match_method.rs113
1 files changed, 95 insertions, 18 deletions
diff --git a/crates/ide_assists/src/handlers/generate_enum_match_method.rs b/crates/ide_assists/src/handlers/generate_enum_match_method.rs
index 3a7177dbf..38aca0c88 100644
--- a/crates/ide_assists/src/handlers/generate_enum_match_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_match_method.rs
@@ -1,7 +1,6 @@
1use stdx::{format_to, to_lower_snake_case}; 1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::VisibilityOwner; 2use syntax::ast::VisibilityOwner;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5 4
6use crate::{ 5use crate::{
7 utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, 6 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
@@ -37,20 +36,17 @@ use crate::{
37pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 36pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let variant = ctx.find_node_at_offset::<ast::Variant>()?; 37 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
39 let variant_name = variant.name()?; 38 let variant_name = variant.name()?;
40 let parent_enum = variant.parent_enum(); 39 let parent_enum = ast::Adt::Enum(variant.parent_enum());
41 if !matches!(variant.kind(), ast::StructKind::Unit) { 40 let variant_kind = variant_kind(&variant);
42 mark::hit!(test_gen_enum_match_on_non_unit_variant_not_implemented);
43 return None;
44 }
45 41
46 let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string()); 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 // Return early if we've found an existing new fn 45 // Return early if we've found an existing new fn
50 let impl_def = find_struct_impl( 46 let impl_def = find_struct_impl(
51 &ctx, 47 &ctx,
52 &ast::Adt::Enum(parent_enum.clone()), 48 &parent_enum,
53 format!("is_{}", fn_name).as_str(), 49 &fn_name,
54 )?; 50 )?;
55 51
56 let target = variant.syntax().text_range(); 52 let target = variant.syntax().text_range();
@@ -69,20 +65,21 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
69 format_to!( 65 format_to!(
70 buf, 66 buf,
71 " /// Returns `true` if the {} is [`{}`]. 67 " /// Returns `true` if the {} is [`{}`].
72 {}fn is_{}(&self) -> bool {{ 68 {}fn {}(&self) -> bool {{
73 matches!(self, Self::{}) 69 matches!(self, Self::{}{})
74 }}", 70 }}",
75 enum_lowercase_name, 71 enum_lowercase_name,
76 variant_name, 72 variant_name,
77 vis, 73 vis,
78 fn_name, 74 fn_name,
79 variant_name 75 variant_name,
76 variant_kind.pattern_suffix(),
80 ); 77 );
81 78
82 let start_offset = impl_def 79 let start_offset = impl_def
83 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) 80 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
84 .unwrap_or_else(|| { 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 parent_enum.syntax().text_range().end() 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
91enum 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
103impl 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
115fn 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#[cfg(test)] 136#[cfg(test)]
95mod tests { 137mod tests {
96 use test_utils::mark;
97
98 use crate::tests::{check_assist, check_assist_not_applicable}; 138 use crate::tests::{check_assist, check_assist_not_applicable};
99 139
100 use super::*; 140 use super::*;
@@ -147,15 +187,52 @@ impl Variant {
147 } 187 }
148 188
149 #[test] 189 #[test]
150 fn test_add_from_impl_no_element() { 190 fn test_generate_enum_match_from_tuple_variant() {
151 mark::check!(test_gen_enum_match_on_non_unit_variant_not_implemented); 191 check_assist(
152 check_not_applicable( 192 generate_enum_is_method,
153 r#" 193 r#"
154enum Variant { 194enum Variant {
155 Undefined, 195 Undefined,
156 Minor(u32)$0, 196 Minor(u32)$0,
157 Major, 197 Major,
158}"#, 198}"#,
199 r#"enum Variant {
200 Undefined,
201 Minor(u32),
202 Major,
203}
204
205impl 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#"
219enum 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
230impl Variant {
231 /// Returns `true` if the variant is [`Minor`].
232 fn is_minor(&self) -> bool {
233 matches!(self, Self::Minor { .. })
234 }
235}"#,
159 ); 236 );
160 } 237 }
161 238