1 use ra_ide_db::RootDatabase;
3 ast::{self, AstNode, NameOwner},
8 use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId};
9 use test_utils::tested_by;
11 // Assist add_from_impl_for_enum
13 // Adds a From impl for an enum variant with one tuple field
16 // enum A { <|>One(u32) }
20 // enum A { One(u32) }
22 // impl From<u32> for A {
23 // fn from(v: u32) -> Self {
28 pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
29 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
30 let variant_name = variant.name()?;
31 let enum_name = variant.parent_enum().name()?;
32 let field_list = match variant.kind() {
33 ast::StructKind::Tuple(field_list) => field_list,
36 if field_list.fields().count() != 1 {
39 let field_type = field_list.fields().next()?.type_ref()?;
40 let path = match field_type {
41 ast::TypeRef::PathType(p) => p,
45 if existing_from_impl(ctx.sema, &variant).is_some() {
46 tested_by!(test_add_from_impl_already_exists);
50 let target = variant.syntax().text_range();
52 AssistId("add_from_impl_for_enum"),
53 "Add From impl for this enum variant",
56 let start_offset = variant.parent_enum().syntax().text_range().end();
57 let mut buf = String::new();
62 impl From<{0}> for {1} {{
63 fn from(v: {0}) -> Self {{
71 edit.insert(start_offset, buf);
72 edit.set_cursor(start_offset + TextSize::of("\n\n"));
77 fn existing_from_impl(
78 sema: &'_ hir::Semantics<'_, RootDatabase>,
79 variant: &ast::EnumVariant,
81 let variant = sema.to_def(variant)?;
82 let enum_ = variant.parent_enum(sema.db);
83 let krate = enum_.module(sema.db).krate();
85 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
87 let enum_type = enum_.ty(sema.db);
89 let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);
91 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
102 use crate::tests::{check_assist, check_assist_not_applicable};
103 use test_utils::covers;
106 fn test_add_from_impl_for_enum() {
108 add_from_impl_for_enum,
109 "enum A { <|>One(u32) }",
110 r#"enum A { One(u32) }
112 <|>impl From<u32> for A {
113 fn from(v: u32) -> Self {
121 fn test_add_from_impl_for_enum_complicated_path() {
123 add_from_impl_for_enum,
124 "enum A { <|>One(foo::bar::baz::Boo) }",
125 r#"enum A { One(foo::bar::baz::Boo) }
127 <|>impl From<foo::bar::baz::Boo> for A {
128 fn from(v: foo::bar::baz::Boo) -> Self {
135 fn check_not_applicable(ra_fixture: &str) {
137 format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
138 check_assist_not_applicable(add_from_impl_for_enum, &fixture)
142 fn test_add_from_impl_no_element() {
143 check_not_applicable("enum A { <|>One }");
147 fn test_add_from_impl_more_than_one_element_in_tuple() {
148 check_not_applicable("enum A { <|>One(u32, String) }");
152 fn test_add_from_impl_struct_variant() {
153 check_not_applicable("enum A { <|>One { x: u32 } }");
157 fn test_add_from_impl_already_exists() {
158 covers!(test_add_from_impl_already_exists);
159 check_not_applicable(
161 enum A { <|>One(u32), }
163 impl From<u32> for A {
164 fn from(v: u32) -> Self {
173 fn test_add_from_impl_different_variant_impl_exists() {
175 add_from_impl_for_enum,
176 r#"enum A { <|>One(u32), Two(String), }
178 impl From<String> for A {
179 fn from(v: String) -> Self {
187 r#"enum A { One(u32), Two(String), }
189 <|>impl From<u32> for A {
190 fn from(v: u32) -> Self {
195 impl From<String> for A {
196 fn from(v: String) -> Self {