diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/extract_struct_from_enum_variant.rs | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index dddab255e..1bf5a4214 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -31,19 +31,27 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
31 | ctx: &AssistContext, | 31 | ctx: &AssistContext, |
32 | ) -> Option<()> { | 32 | ) -> Option<()> { |
33 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; | 33 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; |
34 | |||
35 | fn is_applicable_variant(variant: &ast::Variant) -> bool { | ||
36 | 1 < match variant.kind() { | ||
37 | ast::StructKind::Record(field_list) => field_list.fields().count(), | ||
38 | ast::StructKind::Tuple(field_list) => field_list.fields().count(), | ||
39 | ast::StructKind::Unit => 0, | ||
40 | } | ||
41 | } | ||
42 | |||
43 | if !is_applicable_variant(&variant) { | ||
44 | return None; | ||
45 | } | ||
46 | |||
34 | let field_list = match variant.kind() { | 47 | let field_list = match variant.kind() { |
35 | ast::StructKind::Tuple(field_list) => field_list, | 48 | ast::StructKind::Tuple(field_list) => field_list, |
36 | _ => return None, | 49 | _ => return None, |
37 | }; | 50 | }; |
38 | 51 | ||
39 | // skip 1-tuple variants | ||
40 | if field_list.fields().count() == 1 { | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let variant_name = variant.name()?; | 52 | let variant_name = variant.name()?; |
45 | let variant_hir = ctx.sema.to_def(&variant)?; | 53 | let variant_hir = ctx.sema.to_def(&variant)?; |
46 | if existing_struct_def(ctx.db(), &variant_name, &variant_hir) { | 54 | if existing_definition(ctx.db(), &variant_name, &variant_hir) { |
47 | return None; | 55 | return None; |
48 | } | 56 | } |
49 | let enum_ast = variant.parent_enum(); | 57 | let enum_ast = variant.parent_enum(); |
@@ -100,12 +108,21 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
100 | ) | 108 | ) |
101 | } | 109 | } |
102 | 110 | ||
103 | fn existing_struct_def(db: &RootDatabase, variant_name: &ast::Name, variant: &EnumVariant) -> bool { | 111 | fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &EnumVariant) -> bool { |
104 | variant | 112 | variant |
105 | .parent_enum(db) | 113 | .parent_enum(db) |
106 | .module(db) | 114 | .module(db) |
107 | .scope(db, None) | 115 | .scope(db, None) |
108 | .into_iter() | 116 | .into_iter() |
117 | .filter(|(_, def)| match def { | ||
118 | // only check type-namespace | ||
119 | hir::ScopeDef::ModuleDef(def) => matches!(def, | ||
120 | ModuleDef::Module(_) | ModuleDef::Adt(_) | | ||
121 | ModuleDef::EnumVariant(_) | ModuleDef::Trait(_) | | ||
122 | ModuleDef::TypeAlias(_) | ModuleDef::BuiltinType(_) | ||
123 | ), | ||
124 | _ => false, | ||
125 | }) | ||
109 | .any(|(name, _)| name == variant_name.as_name()) | 126 | .any(|(name, _)| name == variant_name.as_name()) |
110 | } | 127 | } |
111 | 128 | ||
@@ -211,7 +228,7 @@ mod tests { | |||
211 | use super::*; | 228 | use super::*; |
212 | 229 | ||
213 | #[test] | 230 | #[test] |
214 | fn test_extract_struct_several_fields() { | 231 | fn test_extract_struct_several_fields_tuple() { |
215 | check_assist( | 232 | check_assist( |
216 | extract_struct_from_enum_variant, | 233 | extract_struct_from_enum_variant, |
217 | "enum A { <|>One(u32, u32) }", | 234 | "enum A { <|>One(u32, u32) }", |
@@ -222,6 +239,33 @@ enum A { One(One) }"#, | |||
222 | } | 239 | } |
223 | 240 | ||
224 | #[test] | 241 | #[test] |
242 | fn test_extract_struct_several_fields_named() { | ||
243 | check_assist( | ||
244 | extract_struct_from_enum_variant, | ||
245 | "enum A { <|>One { foo: u32, bar: u32 } }", | ||
246 | r#"struct One { | ||
247 | pub foo: u32, | ||
248 | pub bar: u32 | ||
249 | } | ||
250 | |||
251 | enum A { One(One) }"#, | ||
252 | ); | ||
253 | } | ||
254 | |||
255 | #[test] | ||
256 | fn test_extract_enum_variant_name_value_namespace() { | ||
257 | check_assist( | ||
258 | extract_struct_from_enum_variant, | ||
259 | r#"const One: () = (); | ||
260 | enum A { <|>One(u32, u32) }"#, | ||
261 | r#"const One: () = (); | ||
262 | struct One(pub u32, pub u32); | ||
263 | |||
264 | enum A { One(One) }"#, | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
225 | fn test_extract_struct_pub_visibility() { | 269 | fn test_extract_struct_pub_visibility() { |
226 | check_assist( | 270 | check_assist( |
227 | extract_struct_from_enum_variant, | 271 | extract_struct_from_enum_variant, |
@@ -298,7 +342,7 @@ fn another_fn() { | |||
298 | fn test_extract_enum_not_applicable_if_struct_exists() { | 342 | fn test_extract_enum_not_applicable_if_struct_exists() { |
299 | check_not_applicable( | 343 | check_not_applicable( |
300 | r#"struct One; | 344 | r#"struct One; |
301 | enum A { <|>One(u8) }"#, | 345 | enum A { <|>One(u8, u32) }"#, |
302 | ); | 346 | ); |
303 | } | 347 | } |
304 | 348 | ||