1 use ra_ide_db::RootDatabase;
2 use ra_syntax::ast::{self, AstNode, NameOwner};
5 use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};
7 // Assist: add_from_impl_for_enum
9 // Adds a From impl for an enum variant with one tuple field.
12 // enum A { <|>One(u32) }
16 // enum A { One(u32) }
18 // impl From<u32> for A {
19 // fn from(v: u32) -> Self {
24 pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
26 let variant_name = variant.name()?;
27 let enum_name = variant.parent_enum().name()?;
28 let field_list = match variant.kind() {
29 ast::StructKind::Tuple(field_list) => field_list,
32 if field_list.fields().count() != 1 {
35 let field_type = field_list.fields().next()?.type_ref()?;
36 let path = match field_type {
37 ast::TypeRef::PathType(it) => it,
41 if existing_from_impl(&ctx.sema, &variant).is_some() {
42 mark::hit!(test_add_from_impl_already_exists);
46 let target = variant.syntax().text_range();
48 AssistId("add_from_impl_for_enum"),
49 "Add From impl for this enum variant",
52 let start_offset = variant.parent_enum().syntax().text_range().end();
56 impl From<{0}> for {1} {{
57 fn from(v: {0}) -> Self {{
65 edit.insert(start_offset, buf);
70 fn existing_from_impl(
71 sema: &'_ hir::Semantics<'_, RootDatabase>,
72 variant: &ast::EnumVariant,
74 let variant = sema.to_def(variant)?;
75 let enum_ = variant.parent_enum(sema.db);
76 let krate = enum_.module(sema.db).krate();
78 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
80 let enum_type = enum_.ty(sema.db);
82 let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);
84 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
95 use crate::tests::{check_assist, check_assist_not_applicable};
100 fn test_add_from_impl_for_enum() {
102 add_from_impl_for_enum,
103 "enum A { <|>One(u32) }",
104 r#"enum A { One(u32) }
106 impl From<u32> for A {
107 fn from(v: u32) -> Self {
115 fn test_add_from_impl_for_enum_complicated_path() {
117 add_from_impl_for_enum,
118 r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
119 r#"enum A { One(foo::bar::baz::Boo) }
121 impl From<foo::bar::baz::Boo> for A {
122 fn from(v: foo::bar::baz::Boo) -> Self {
129 fn check_not_applicable(ra_fixture: &str) {
131 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
132 check_assist_not_applicable(add_from_impl_for_enum, &fixture)
136 fn test_add_from_impl_no_element() {
137 check_not_applicable("enum A { <|>One }");
141 fn test_add_from_impl_more_than_one_element_in_tuple() {
142 check_not_applicable("enum A { <|>One(u32, String) }");
146 fn test_add_from_impl_struct_variant() {
147 check_not_applicable("enum A { <|>One { x: u32 } }");
151 fn test_add_from_impl_already_exists() {
152 mark::check!(test_add_from_impl_already_exists);
153 check_not_applicable(
155 enum A { <|>One(u32), }
157 impl From<u32> for A {
158 fn from(v: u32) -> Self {
167 fn test_add_from_impl_different_variant_impl_exists() {
169 add_from_impl_for_enum,
170 r#"enum A { <|>One(u32), Two(String), }
172 impl From<String> for A {
173 fn from(v: String) -> Self {
181 r#"enum A { One(u32), Two(String), }
183 impl From<u32> for A {
184 fn from(v: u32) -> Self {
189 impl From<String> for A {
190 fn from(v: String) -> Self {