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.syntax());
60 let impl_code = if let Some(name) = field_name {
62 r#" fn from({0}: {1}) -> Self {{
71 r#" fn from(v: {}) -> Self {{
78 let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
79 edit.insert(start_offset, from_impl);
84 fn existing_from_impl(
85 sema: &'_ hir::Semantics<'_, RootDatabase>,
86 variant: &ast::Variant,
88 let variant = sema.to_def(variant)?;
89 let enum_ = variant.parent_enum(sema.db);
90 let krate = enum_.module(sema.db).krate();
92 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
94 let enum_type = enum_.ty(sema.db);
96 let wrapped_type = variant.fields(sema.db).get(0)?.ty(sema.db);
98 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
107 use crate::tests::{check_assist, check_assist_not_applicable};
112 fn test_generate_from_impl_for_enum() {
114 generate_from_impl_for_enum,
117 enum A { $0One(u32) }
122 impl From<u32> for A {
123 fn from(v: u32) -> Self {
132 fn test_generate_from_impl_for_enum_complicated_path() {
134 generate_from_impl_for_enum,
137 enum A { $0One(foo::bar::baz::Boo) }
140 enum A { One(foo::bar::baz::Boo) }
142 impl From<foo::bar::baz::Boo> for A {
143 fn from(v: foo::bar::baz::Boo) -> Self {
152 fn test_add_from_impl_no_element() {
153 check_assist_not_applicable(
154 generate_from_impl_for_enum,
163 fn test_add_from_impl_more_than_one_element_in_tuple() {
164 check_assist_not_applicable(
165 generate_from_impl_for_enum,
168 enum A { $0One(u32, String) }
174 fn test_add_from_impl_struct_variant() {
176 generate_from_impl_for_enum,
179 enum A { $0One { x: u32 } }
182 enum A { One { x: u32 } }
184 impl From<u32> for A {
185 fn from(x: u32) -> Self {
194 fn test_add_from_impl_already_exists() {
195 cov_mark::check!(test_add_from_impl_already_exists);
196 check_assist_not_applicable(
197 generate_from_impl_for_enum,
200 enum A { $0One(u32), }
202 impl From<u32> for A {
203 fn from(v: u32) -> Self {
212 fn test_add_from_impl_different_variant_impl_exists() {
214 generate_from_impl_for_enum,
217 enum A { $0One(u32), Two(String), }
219 impl From<String> for A {
220 fn from(v: String) -> Self {
230 enum A { One(u32), Two(String), }
232 impl From<u32> for A {
233 fn from(v: u32) -> Self {
238 impl From<String> for A {
239 fn from(v: String) -> Self {
252 fn test_add_from_impl_static_str() {
254 generate_from_impl_for_enum,
257 enum A { $0One(&'static str) }
260 enum A { One(&'static str) }
262 impl From<&'static str> for A {
263 fn from(v: &'static str) -> Self {
272 fn test_add_from_impl_generic_enum() {
274 generate_from_impl_for_enum,
277 enum Generic<T, U: Clone> { $0One(T), Two(U) }
280 enum Generic<T, U: Clone> { One(T), Two(U) }
282 impl<T, U: Clone> From<T> for Generic<T, U> {
283 fn from(v: T) -> Self {
292 fn test_add_from_impl_with_lifetime() {
294 generate_from_impl_for_enum,
297 enum Generic<'a> { $0One(&'a i32) }
300 enum Generic<'a> { One(&'a i32) }
302 impl<'a> From<&'a i32> for Generic<'a> {
303 fn from(v: &'a i32) -> Self {