aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs62
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
103fn existing_struct_def(db: &RootDatabase, variant_name: &ast::Name, variant: &EnumVariant) -> bool { 111fn 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
251enum 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: () = ();
260enum A { <|>One(u32, u32) }"#,
261 r#"const One: () = ();
262struct One(pub u32, pub u32);
263
264enum 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