aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/generate_from_impl_for_enum.rs
diff options
context:
space:
mode:
authorChetan Khilosiya <[email protected]>2021-02-22 18:47:48 +0000
committerChetan Khilosiya <[email protected]>2021-02-22 19:29:16 +0000
commite4756cb4f6e66097638b9d101589358976be2ba8 (patch)
treeb6ca0ae6b45b57834476ae0f9985cec3a6bd9090 /crates/assists/src/handlers/generate_from_impl_for_enum.rs
parent8687053b118f47ce1a4962d0baa19b22d40d2758 (diff)
7526: Rename crate assists to ide_assists.
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.rs268
1 files changed, 0 insertions, 268 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
deleted file mode 100644
index d9388a737..000000000
--- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs
+++ /dev/null
@@ -1,268 +0,0 @@
1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5
6use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
7
8// Assist: generate_from_impl_for_enum
9//
10// Adds a From impl for an enum variant with one tuple field.
11//
12// ```
13// enum A { $0One(u32) }
14// ```
15// ->
16// ```
17// enum A { One(u32) }
18//
19// impl From<u32> for A {
20// fn from(v: u32) -> Self {
21// Self::One(v)
22// }
23// }
24// ```
25pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
27 let variant_name = variant.name()?;
28 let enum_ = ast::Adt::Enum(variant.parent_enum());
29 let (field_name, field_type) = match variant.kind() {
30 ast::StructKind::Tuple(field_list) => {
31 if field_list.fields().count() != 1 {
32 return None;
33 }
34 (None, field_list.fields().next()?.ty()?)
35 }
36 ast::StructKind::Record(field_list) => {
37 if field_list.fields().count() != 1 {
38 return None;
39 }
40 let field = field_list.fields().next()?;
41 (Some(field.name()?), field.ty()?)
42 }
43 ast::StructKind::Unit => return None,
44 };
45
46 if existing_from_impl(&ctx.sema, &variant).is_some() {
47 mark::hit!(test_add_from_impl_already_exists);
48 return None;
49 }
50
51 let target = variant.syntax().text_range();
52 acc.add(
53 AssistId("generate_from_impl_for_enum", AssistKind::Generate),
54 "Generate `From` impl for this enum variant",
55 target,
56 |edit| {
57 let start_offset = variant.parent_enum().syntax().text_range().end();
58 let from_trait = format!("From<{}>", field_type.syntax());
59 let impl_code = if let Some(name) = field_name {
60 format!(
61 r#" fn from({0}: {1}) -> Self {{
62 Self::{2} {{ {0} }}
63 }}"#,
64 name.text(),
65 field_type.syntax(),
66 variant_name,
67 )
68 } else {
69 format!(
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);
79 },
80 )
81}
82
83fn existing_from_impl(
84 sema: &'_ hir::Semantics<'_, RootDatabase>,
85 variant: &ast::Variant,
86) -> Option<()> {
87 let variant = sema.to_def(variant)?;
88 let enum_ = variant.parent_enum(sema.db);
89 let krate = enum_.module(sema.db).krate();
90
91 let from_trait = FamousDefs(sema, Some(krate)).core_convert_From()?;
92
93 let enum_type = enum_.ty(sema.db);
94
95 let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);
96
97 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
98 Some(())
99 } else {
100 None
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use test_utils::mark;
107
108 use crate::tests::{check_assist, check_assist_not_applicable};
109
110 use super::*;
111
112 #[test]
113 fn test_generate_from_impl_for_enum() {
114 check_assist(
115 generate_from_impl_for_enum,
116 "enum A { $0One(u32) }",
117 r#"enum A { One(u32) }
118
119impl From<u32> for A {
120 fn from(v: u32) -> Self {
121 Self::One(v)
122 }
123}"#,
124 );
125 }
126
127 #[test]
128 fn test_generate_from_impl_for_enum_complicated_path() {
129 check_assist(
130 generate_from_impl_for_enum,
131 r#"enum A { $0One(foo::bar::baz::Boo) }"#,
132 r#"enum A { One(foo::bar::baz::Boo) }
133
134impl From<foo::bar::baz::Boo> for A {
135 fn from(v: foo::bar::baz::Boo) -> Self {
136 Self::One(v)
137 }
138}"#,
139 );
140 }
141
142 fn check_not_applicable(ra_fixture: &str) {
143 let fixture =
144 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
145 check_assist_not_applicable(generate_from_impl_for_enum, &fixture)
146 }
147
148 #[test]
149 fn test_add_from_impl_no_element() {
150 check_not_applicable("enum A { $0One }");
151 }
152
153 #[test]
154 fn test_add_from_impl_more_than_one_element_in_tuple() {
155 check_not_applicable("enum A { $0One(u32, String) }");
156 }
157
158 #[test]
159 fn test_add_from_impl_struct_variant() {
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 );
171 }
172
173 #[test]
174 fn test_add_from_impl_already_exists() {
175 mark::check!(test_add_from_impl_already_exists);
176 check_not_applicable(
177 r#"
178enum A { $0One(u32), }
179
180impl From<u32> for A {
181 fn from(v: u32) -> Self {
182 Self::One(v)
183 }
184}
185"#,
186 );
187 }
188
189 #[test]
190 fn test_add_from_impl_different_variant_impl_exists() {
191 check_assist(
192 generate_from_impl_for_enum,
193 r#"enum A { $0One(u32), Two(String), }
194
195impl From<String> for A {
196 fn from(v: String) -> Self {
197 A::Two(v)
198 }
199}
200
201pub trait From<T> {
202 fn from(T) -> Self;
203}"#,
204 r#"enum A { One(u32), Two(String), }
205
206impl From<u32> for A {
207 fn from(v: u32) -> Self {
208 Self::One(v)
209 }
210}
211
212impl From<String> for A {
213 fn from(v: String) -> Self {
214 A::Two(v)
215 }
216}
217
218pub trait From<T> {
219 fn from(T) -> Self;
220}"#,
221 );
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 }
268}