diff options
Diffstat (limited to 'crates/assists/src/handlers/generate_from_impl_for_enum.rs')
-rw-r--r-- | crates/assists/src/handlers/generate_from_impl_for_enum.rs | 131 |
1 files changed, 99 insertions, 32 deletions
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs index d9af6ab11..d9388a737 100644 --- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs | |||
@@ -3,7 +3,7 @@ use ide_db::RootDatabase; | |||
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | use test_utils::mark; | 4 | use test_utils::mark; |
5 | 5 | ||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; |
7 | 7 | ||
8 | // Assist: generate_from_impl_for_enum | 8 | // Assist: generate_from_impl_for_enum |
9 | // | 9 | // |
@@ -18,25 +18,29 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
18 | // | 18 | // |
19 | // impl From<u32> for A { | 19 | // impl From<u32> for A { |
20 | // fn from(v: u32) -> Self { | 20 | // fn from(v: u32) -> Self { |
21 | // A::One(v) | 21 | // Self::One(v) |
22 | // } | 22 | // } |
23 | // } | 23 | // } |
24 | // ``` | 24 | // ``` |
25 | pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; | 26 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; |
27 | let variant_name = variant.name()?; | 27 | let variant_name = variant.name()?; |
28 | let enum_name = variant.parent_enum().name()?; | 28 | let enum_ = ast::Adt::Enum(variant.parent_enum()); |
29 | let field_list = match variant.kind() { | 29 | let (field_name, field_type) = match variant.kind() { |
30 | ast::StructKind::Tuple(field_list) => field_list, | 30 | ast::StructKind::Tuple(field_list) => { |
31 | _ => return None, | 31 | if field_list.fields().count() != 1 { |
32 | }; | 32 | return None; |
33 | if field_list.fields().count() != 1 { | 33 | } |
34 | return None; | 34 | (None, field_list.fields().next()?.ty()?) |
35 | } | 35 | } |
36 | let field_type = field_list.fields().next()?.ty()?; | 36 | ast::StructKind::Record(field_list) => { |
37 | let path = match field_type { | 37 | if field_list.fields().count() != 1 { |
38 | ast::Type::PathType(it) => it, | 38 | return None; |
39 | _ => return None, | 39 | } |
40 | let field = field_list.fields().next()?; | ||
41 | (Some(field.name()?), field.ty()?) | ||
42 | } | ||
43 | ast::StructKind::Unit => return None, | ||
40 | }; | 44 | }; |
41 | 45 | ||
42 | if existing_from_impl(&ctx.sema, &variant).is_some() { | 46 | if existing_from_impl(&ctx.sema, &variant).is_some() { |
@@ -51,19 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext | |||
51 | target, | 55 | target, |
52 | |edit| { | 56 | |edit| { |
53 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 57 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
54 | let buf = format!( | 58 | let from_trait = format!("From<{}>", field_type.syntax()); |
55 | r#" | 59 | let impl_code = if let Some(name) = field_name { |
56 | 60 | format!( | |
57 | impl From<{0}> for {1} {{ | 61 | r#" fn from({0}: {1}) -> Self {{ |
58 | fn from(v: {0}) -> Self {{ | 62 | Self::{2} {{ {0} }} |
59 | {1}::{2}(v) | 63 | }}"#, |
60 | }} | 64 | name.text(), |
61 | }}"#, | 65 | field_type.syntax(), |
62 | path.syntax(), | 66 | variant_name, |
63 | enum_name, | 67 | ) |
64 | variant_name | 68 | } else { |
65 | ); | 69 | format!( |
66 | edit.insert(start_offset, buf); | 70 | r#" fn from(v: {}) -> Self {{ |
71 | Self::{}(v) | ||
72 | }}"#, | ||
73 | field_type.syntax(), | ||
74 | variant_name, | ||
75 | ) | ||
76 | }; | ||
77 | let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code); | ||
78 | edit.insert(start_offset, from_impl); | ||
67 | }, | 79 | }, |
68 | ) | 80 | ) |
69 | } | 81 | } |
@@ -106,7 +118,7 @@ mod tests { | |||
106 | 118 | ||
107 | impl From<u32> for A { | 119 | impl From<u32> for A { |
108 | fn from(v: u32) -> Self { | 120 | fn from(v: u32) -> Self { |
109 | A::One(v) | 121 | Self::One(v) |
110 | } | 122 | } |
111 | }"#, | 123 | }"#, |
112 | ); | 124 | ); |
@@ -121,7 +133,7 @@ impl From<u32> for A { | |||
121 | 133 | ||
122 | impl From<foo::bar::baz::Boo> for A { | 134 | impl From<foo::bar::baz::Boo> for A { |
123 | fn from(v: foo::bar::baz::Boo) -> Self { | 135 | fn from(v: foo::bar::baz::Boo) -> Self { |
124 | A::One(v) | 136 | Self::One(v) |
125 | } | 137 | } |
126 | }"#, | 138 | }"#, |
127 | ); | 139 | ); |
@@ -145,7 +157,17 @@ impl From<foo::bar::baz::Boo> for A { | |||
145 | 157 | ||
146 | #[test] | 158 | #[test] |
147 | fn test_add_from_impl_struct_variant() { | 159 | fn test_add_from_impl_struct_variant() { |
148 | check_not_applicable("enum A { $0One { x: u32 } }"); | 160 | check_assist( |
161 | generate_from_impl_for_enum, | ||
162 | "enum A { $0One { x: u32 } }", | ||
163 | r#"enum A { One { x: u32 } } | ||
164 | |||
165 | impl From<u32> for A { | ||
166 | fn from(x: u32) -> Self { | ||
167 | Self::One { x } | ||
168 | } | ||
169 | }"#, | ||
170 | ); | ||
149 | } | 171 | } |
150 | 172 | ||
151 | #[test] | 173 | #[test] |
@@ -157,7 +179,7 @@ enum A { $0One(u32), } | |||
157 | 179 | ||
158 | impl From<u32> for A { | 180 | impl From<u32> for A { |
159 | fn from(v: u32) -> Self { | 181 | fn from(v: u32) -> Self { |
160 | A::One(v) | 182 | Self::One(v) |
161 | } | 183 | } |
162 | } | 184 | } |
163 | "#, | 185 | "#, |
@@ -183,7 +205,7 @@ pub trait From<T> { | |||
183 | 205 | ||
184 | impl From<u32> for A { | 206 | impl From<u32> for A { |
185 | fn from(v: u32) -> Self { | 207 | fn from(v: u32) -> Self { |
186 | A::One(v) | 208 | Self::One(v) |
187 | } | 209 | } |
188 | } | 210 | } |
189 | 211 | ||
@@ -198,4 +220,49 @@ pub trait From<T> { | |||
198 | }"#, | 220 | }"#, |
199 | ); | 221 | ); |
200 | } | 222 | } |
223 | |||
224 | #[test] | ||
225 | fn test_add_from_impl_static_str() { | ||
226 | check_assist( | ||
227 | generate_from_impl_for_enum, | ||
228 | "enum A { $0One(&'static str) }", | ||
229 | r#"enum A { One(&'static str) } | ||
230 | |||
231 | impl From<&'static str> for A { | ||
232 | fn from(v: &'static str) -> Self { | ||
233 | Self::One(v) | ||
234 | } | ||
235 | }"#, | ||
236 | ); | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn test_add_from_impl_generic_enum() { | ||
241 | check_assist( | ||
242 | generate_from_impl_for_enum, | ||
243 | "enum Generic<T, U: Clone> { $0One(T), Two(U) }", | ||
244 | r#"enum Generic<T, U: Clone> { One(T), Two(U) } | ||
245 | |||
246 | impl<T, U: Clone> From<T> for Generic<T, U> { | ||
247 | fn from(v: T) -> Self { | ||
248 | Self::One(v) | ||
249 | } | ||
250 | }"#, | ||
251 | ); | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn test_add_from_impl_with_lifetime() { | ||
256 | check_assist( | ||
257 | generate_from_impl_for_enum, | ||
258 | "enum Generic<'a> { $0One(&'a i32) }", | ||
259 | r#"enum Generic<'a> { One(&'a i32) } | ||
260 | |||
261 | impl<'a> From<&'a i32> for Generic<'a> { | ||
262 | fn from(v: &'a i32) -> Self { | ||
263 | Self::One(v) | ||
264 | } | ||
265 | }"#, | ||
266 | ); | ||
267 | } | ||
201 | } | 268 | } |