aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/generate_from_impl_for_enum.rs
diff options
context:
space:
mode:
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.rs131
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;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use 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// ```
25pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(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!(
57impl 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
107impl From<u32> for A { 119impl 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
122impl From<foo::bar::baz::Boo> for A { 134impl 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
165impl 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
158impl From<u32> for A { 180impl 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
184impl From<u32> for A { 206impl 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
231impl 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
246impl<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
261impl<'a> From<&'a i32> for Generic<'a> {
262 fn from(v: &'a i32) -> Self {
263 Self::One(v)
264 }
265}"#,
266 );
267 }
201} 268}