1 use ide_db::{famous_defs::FamousDefs, RootDatabase};
2 use syntax::ast::{self, AstNode, HasName};
4 use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
6 // Assist: generate_from_impl_for_enum
8 // Adds a From impl for this enum variant with one tuple field.
11 // enum A { $0One(u32) }
15 // enum A { One(u32) }
17 // impl From<u32> for A {
18 // fn from(v: u32) -> Self {
23 pub(crate) fn generate_from_impl_for_enum(
25 ctx: &AssistContext<'_>,
27 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
28 let variant_name = variant.name()?;
29 let enum_ = ast::Adt::Enum(variant.parent_enum());
30 let (field_name, field_type) = match variant.kind() {
31 ast::StructKind::Tuple(field_list) => {
32 if field_list.fields().count() != 1 {
35 (None, field_list.fields().next()?.ty()?)
37 ast::StructKind::Record(field_list) => {
38 if field_list.fields().count() != 1 {
41 let field = field_list.fields().next()?;
42 (Some(field.name()?), field.ty()?)
44 ast::StructKind::Unit => return None,
47 if existing_from_impl(&ctx.sema, &variant).is_some() {
48 cov_mark::hit!(test_add_from_impl_already_exists);
52 let target = variant.syntax().text_range();
54 AssistId("generate_from_impl_for_enum", AssistKind::Generate),
55 "Generate `From` impl for this enum variant",
58 let start_offset = variant.parent_enum().syntax().text_range().end();
59 let from_trait = format!("From<{field_type}>");
60 let impl_code = if let Some(name) = field_name {
62 r#" fn from({name}: {field_type}) -> Self {{
63 Self::{variant_name} {{ {name} }}
68 r#" fn from(v: {field_type}) -> Self {{
69 Self::{variant_name}(v)
73 let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
74 edit.insert(start_offset, from_impl);
79 fn existing_from_impl(
80 sema: &'_ hir::Semantics<'_, RootDatabase>,
81 variant: &ast::Variant,
83 let variant = sema.to_def(variant)?;
84 let enum_ = variant.parent_enum(sema.db);
85 let krate = enum_.module(sema.db).krate();
87 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
89 let enum_type = enum_.ty(sema.db);
91 let wrapped_type = variant.fields(sema.db).get(0)?.ty(sema.db);
93 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
102 use crate::tests::{check_assist, check_assist_not_applicable};
107 fn test_generate_from_impl_for_enum() {
109 generate_from_impl_for_enum,
112 enum A { $0One(u32) }
117 impl From<u32> for A {
118 fn from(v: u32) -> Self {
127 fn test_generate_from_impl_for_enum_complicated_path() {
129 generate_from_impl_for_enum,
132 enum A { $0One(foo::bar::baz::Boo) }
135 enum A { One(foo::bar::baz::Boo) }
137 impl From<foo::bar::baz::Boo> for A {
138 fn from(v: foo::bar::baz::Boo) -> Self {
147 fn test_add_from_impl_no_element() {
148 check_assist_not_applicable(
149 generate_from_impl_for_enum,
158 fn test_add_from_impl_more_than_one_element_in_tuple() {
159 check_assist_not_applicable(
160 generate_from_impl_for_enum,
163 enum A { $0One(u32, String) }
169 fn test_add_from_impl_struct_variant() {
171 generate_from_impl_for_enum,
174 enum A { $0One { x: u32 } }
177 enum A { One { x: u32 } }
179 impl From<u32> for A {
180 fn from(x: u32) -> Self {
189 fn test_add_from_impl_already_exists() {
190 cov_mark::check!(test_add_from_impl_already_exists);
191 check_assist_not_applicable(
192 generate_from_impl_for_enum,
195 enum A { $0One(u32), }
197 impl From<u32> for A {
198 fn from(v: u32) -> Self {
207 fn test_add_from_impl_different_variant_impl_exists() {
209 generate_from_impl_for_enum,
212 enum A { $0One(u32), Two(String), }
214 impl From<String> for A {
215 fn from(v: String) -> Self {
225 enum A { One(u32), Two(String), }
227 impl From<u32> for A {
228 fn from(v: u32) -> Self {
233 impl From<String> for A {
234 fn from(v: String) -> Self {
247 fn test_add_from_impl_static_str() {
249 generate_from_impl_for_enum,
252 enum A { $0One(&'static str) }
255 enum A { One(&'static str) }
257 impl From<&'static str> for A {
258 fn from(v: &'static str) -> Self {
267 fn test_add_from_impl_generic_enum() {
269 generate_from_impl_for_enum,
272 enum Generic<T, U: Clone> { $0One(T), Two(U) }
275 enum Generic<T, U: Clone> { One(T), Two(U) }
277 impl<T, U: Clone> From<T> for Generic<T, U> {
278 fn from(v: T) -> Self {
287 fn test_add_from_impl_with_lifetime() {
289 generate_from_impl_for_enum,
292 enum Generic<'a> { $0One(&'a i32) }
295 enum Generic<'a> { One(&'a i32) }
297 impl<'a> From<&'a i32> for Generic<'a> {
298 fn from(v: &'a i32) -> Self {