1 use ide_db::helpers::FamousDefs;
2 use ide_db::RootDatabase;
3 use syntax::ast::{self, AstNode, HasName};
5 use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
7 // Assist: generate_from_impl_for_enum
9 // Adds a From impl for an enum variant with one tuple field.
12 // enum A { $0One(u32) }
16 // enum A { One(u32) }
18 // impl From<u32> for A {
19 // fn from(v: u32) -> Self {
24 pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
26 let variant_name = variant.name()?;
27 let enum_ = ast::Adt::Enum(variant.parent_enum());
28 let (field_name, field_type) = match variant.kind() {
29 ast::StructKind::Tuple(field_list) => {
30 if field_list.fields().count() != 1 {
33 (None, field_list.fields().next()?.ty()?)
35 ast::StructKind::Record(field_list) => {
36 if field_list.fields().count() != 1 {
39 let field = field_list.fields().next()?;
40 (Some(field.name()?), field.ty()?)
42 ast::StructKind::Unit => return None,
45 if existing_from_impl(&ctx.sema, &variant).is_some() {
46 cov_mark::hit!(test_add_from_impl_already_exists);
50 let target = variant.syntax().text_range();
52 AssistId("generate_from_impl_for_enum", AssistKind::Generate),
53 "Generate `From` impl for this enum variant",
56 let start_offset = variant.parent_enum().syntax().text_range().end();
57 let from_trait = format!("From<{}>", field_type.syntax());
58 let impl_code = if let Some(name) = field_name {
60 r#" fn from({0}: {1}) -> Self {{
69 r#" fn from(v: {}) -> Self {{
76 let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
77 edit.insert(start_offset, from_impl);
82 fn existing_from_impl(
83 sema: &'_ hir::Semantics<'_, RootDatabase>,
84 variant: &ast::Variant,
86 let variant = sema.to_def(variant)?;
87 let enum_ = variant.parent_enum(sema.db);
88 let krate = enum_.module(sema.db).krate();
90 let from_trait = FamousDefs(sema, Some(krate)).core_convert_From()?;
92 let enum_type = enum_.ty(sema.db);
94 let wrapped_type = variant.fields(sema.db).get(0)?.ty(sema.db);
96 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
105 use crate::tests::{check_assist, check_assist_not_applicable};
110 fn test_generate_from_impl_for_enum() {
112 generate_from_impl_for_enum,
115 enum A { $0One(u32) }
120 impl From<u32> for A {
121 fn from(v: u32) -> Self {
130 fn test_generate_from_impl_for_enum_complicated_path() {
132 generate_from_impl_for_enum,
135 enum A { $0One(foo::bar::baz::Boo) }
138 enum A { One(foo::bar::baz::Boo) }
140 impl From<foo::bar::baz::Boo> for A {
141 fn from(v: foo::bar::baz::Boo) -> Self {
150 fn test_add_from_impl_no_element() {
151 check_assist_not_applicable(
152 generate_from_impl_for_enum,
161 fn test_add_from_impl_more_than_one_element_in_tuple() {
162 check_assist_not_applicable(
163 generate_from_impl_for_enum,
166 enum A { $0One(u32, String) }
172 fn test_add_from_impl_struct_variant() {
174 generate_from_impl_for_enum,
177 enum A { $0One { x: u32 } }
180 enum A { One { x: u32 } }
182 impl From<u32> for A {
183 fn from(x: u32) -> Self {
192 fn test_add_from_impl_already_exists() {
193 cov_mark::check!(test_add_from_impl_already_exists);
194 check_assist_not_applicable(
195 generate_from_impl_for_enum,
198 enum A { $0One(u32), }
200 impl From<u32> for A {
201 fn from(v: u32) -> Self {
210 fn test_add_from_impl_different_variant_impl_exists() {
212 generate_from_impl_for_enum,
215 enum A { $0One(u32), Two(String), }
217 impl From<String> for A {
218 fn from(v: String) -> Self {
228 enum A { One(u32), Two(String), }
230 impl From<u32> for A {
231 fn from(v: u32) -> Self {
236 impl From<String> for A {
237 fn from(v: String) -> Self {
250 fn test_add_from_impl_static_str() {
252 generate_from_impl_for_enum,
255 enum A { $0One(&'static str) }
258 enum A { One(&'static str) }
260 impl From<&'static str> for A {
261 fn from(v: &'static str) -> Self {
270 fn test_add_from_impl_generic_enum() {
272 generate_from_impl_for_enum,
275 enum Generic<T, U: Clone> { $0One(T), Two(U) }
278 enum Generic<T, U: Clone> { One(T), Two(U) }
280 impl<T, U: Clone> From<T> for Generic<T, U> {
281 fn from(v: T) -> Self {
290 fn test_add_from_impl_with_lifetime() {
292 generate_from_impl_for_enum,
295 enum Generic<'a> { $0One(&'a i32) }
298 enum Generic<'a> { One(&'a i32) }
300 impl<'a> From<&'a i32> for Generic<'a> {
301 fn from(v: &'a i32) -> Self {