diff options
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_enum_projection_method.rs | 108 |
1 files changed, 66 insertions, 42 deletions
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs index 71447f310..871bcab50 100644 --- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs | |||
@@ -8,9 +8,9 @@ use crate::{ | |||
8 | AssistContext, AssistId, AssistKind, Assists, | 8 | AssistContext, AssistId, AssistKind, Assists, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | // Assist: generate_enum_into_method | 11 | // Assist: generate_enum_try_into_method |
12 | // | 12 | // |
13 | // Generate an `into_` method for an enum variant. | 13 | // Generate an `try_into_` method for an enum variant. |
14 | // | 14 | // |
15 | // ``` | 15 | // ``` |
16 | // enum Value { | 16 | // enum Value { |
@@ -26,23 +26,29 @@ use crate::{ | |||
26 | // } | 26 | // } |
27 | // | 27 | // |
28 | // impl Value { | 28 | // impl Value { |
29 | // fn into_text(self) -> Option<String> { | 29 | // fn try_into_text(self) -> Result<String, Self> { |
30 | // if let Self::Text(v) = self { | 30 | // if let Self::Text(v) = self { |
31 | // Some(v) | 31 | // Ok(v) |
32 | // } else { | 32 | // } else { |
33 | // None | 33 | // Err(self) |
34 | // } | 34 | // } |
35 | // } | 35 | // } |
36 | // } | 36 | // } |
37 | // ``` | 37 | // ``` |
38 | pub(crate) fn generate_enum_into_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 38 | pub(crate) fn generate_enum_try_into_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
39 | generate_enum_projection_method( | 39 | generate_enum_projection_method( |
40 | acc, | 40 | acc, |
41 | ctx, | 41 | ctx, |
42 | "generate_enum_into_method", | 42 | "generate_enum_try_into_method", |
43 | "Generate an `into_` method for an enum variant", | 43 | "Generate an `try_into_` method for an enum variant", |
44 | "into", | 44 | ProjectionProps { |
45 | "", | 45 | fn_name_prefix: "try_into", |
46 | self_param: "self", | ||
47 | return_prefix: "Result<", | ||
48 | return_suffix: ", Self>", | ||
49 | happy_case: "Ok", | ||
50 | sad_case: "Err(self)", | ||
51 | }, | ||
46 | ) | 52 | ) |
47 | } | 53 | } |
48 | 54 | ||
@@ -79,18 +85,32 @@ pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) -> | |||
79 | ctx, | 85 | ctx, |
80 | "generate_enum_as_method", | 86 | "generate_enum_as_method", |
81 | "Generate an `as_` method for an enum variant", | 87 | "Generate an `as_` method for an enum variant", |
82 | "as", | 88 | ProjectionProps { |
83 | "&", | 89 | fn_name_prefix: "as", |
90 | self_param: "&self", | ||
91 | return_prefix: "Option<&", | ||
92 | return_suffix: ">", | ||
93 | happy_case: "Some", | ||
94 | sad_case: "None", | ||
95 | }, | ||
84 | ) | 96 | ) |
85 | } | 97 | } |
86 | 98 | ||
87 | pub(crate) fn generate_enum_projection_method( | 99 | struct ProjectionProps { |
100 | fn_name_prefix: &'static str, | ||
101 | self_param: &'static str, | ||
102 | return_prefix: &'static str, | ||
103 | return_suffix: &'static str, | ||
104 | happy_case: &'static str, | ||
105 | sad_case: &'static str, | ||
106 | } | ||
107 | |||
108 | fn generate_enum_projection_method( | ||
88 | acc: &mut Assists, | 109 | acc: &mut Assists, |
89 | ctx: &AssistContext, | 110 | ctx: &AssistContext, |
90 | assist_id: &'static str, | 111 | assist_id: &'static str, |
91 | assist_description: &str, | 112 | assist_description: &str, |
92 | fn_name_prefix: &str, | 113 | props: ProjectionProps, |
93 | ref_prefix: &str, | ||
94 | ) -> Option<()> { | 114 | ) -> Option<()> { |
95 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; | 115 | let variant = ctx.find_node_at_offset::<ast::Variant>()?; |
96 | let variant_name = variant.name()?; | 116 | let variant_name = variant.name()?; |
@@ -112,7 +132,7 @@ pub(crate) fn generate_enum_projection_method( | |||
112 | ast::StructKind::Unit => return None, | 132 | ast::StructKind::Unit => return None, |
113 | }; | 133 | }; |
114 | 134 | ||
115 | let fn_name = format!("{}_{}", fn_name_prefix, &to_lower_snake_case(variant_name.text())); | 135 | let fn_name = format!("{}_{}", props.fn_name_prefix, &to_lower_snake_case(variant_name.text())); |
116 | 136 | ||
117 | // Return early if we've found an existing new fn | 137 | // Return early if we've found an existing new fn |
118 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; | 138 | let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?; |
@@ -121,20 +141,24 @@ pub(crate) fn generate_enum_projection_method( | |||
121 | acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| { | 141 | acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| { |
122 | let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v)); | 142 | let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v)); |
123 | let method = format!( | 143 | let method = format!( |
124 | " {0}fn {1}({2}self) -> Option<{2}{3}> {{ | 144 | " {0}fn {1}({2}) -> {3}{4}{5} {{ |
125 | if let Self::{4}{5} = self {{ | 145 | if let Self::{6}{7} = self {{ |
126 | Some({6}) | 146 | {8}({9}) |
127 | }} else {{ | 147 | }} else {{ |
128 | None | 148 | {10} |
129 | }} | 149 | }} |
130 | }}", | 150 | }}", |
131 | vis, | 151 | vis, |
132 | fn_name, | 152 | fn_name, |
133 | ref_prefix, | 153 | props.self_param, |
154 | props.return_prefix, | ||
134 | field_type.syntax(), | 155 | field_type.syntax(), |
156 | props.return_suffix, | ||
135 | variant_name, | 157 | variant_name, |
136 | pattern_suffix, | 158 | pattern_suffix, |
159 | props.happy_case, | ||
137 | bound_name, | 160 | bound_name, |
161 | props.sad_case, | ||
138 | ); | 162 | ); |
139 | 163 | ||
140 | add_method_to_adt(builder, &parent_enum, impl_def, &method); | 164 | add_method_to_adt(builder, &parent_enum, impl_def, &method); |
@@ -148,9 +172,9 @@ mod tests { | |||
148 | use super::*; | 172 | use super::*; |
149 | 173 | ||
150 | #[test] | 174 | #[test] |
151 | fn test_generate_enum_into_tuple_variant() { | 175 | fn test_generate_enum_try_into_tuple_variant() { |
152 | check_assist( | 176 | check_assist( |
153 | generate_enum_into_method, | 177 | generate_enum_try_into_method, |
154 | r#" | 178 | r#" |
155 | enum Value { | 179 | enum Value { |
156 | Number(i32), | 180 | Number(i32), |
@@ -162,11 +186,11 @@ enum Value { | |||
162 | } | 186 | } |
163 | 187 | ||
164 | impl Value { | 188 | impl Value { |
165 | fn into_text(self) -> Option<String> { | 189 | fn try_into_text(self) -> Result<String, Self> { |
166 | if let Self::Text(v) = self { | 190 | if let Self::Text(v) = self { |
167 | Some(v) | 191 | Ok(v) |
168 | } else { | 192 | } else { |
169 | None | 193 | Err(self) |
170 | } | 194 | } |
171 | } | 195 | } |
172 | }"#, | 196 | }"#, |
@@ -174,20 +198,20 @@ impl Value { | |||
174 | } | 198 | } |
175 | 199 | ||
176 | #[test] | 200 | #[test] |
177 | fn test_generate_enum_into_already_implemented() { | 201 | fn test_generate_enum_try_into_already_implemented() { |
178 | check_assist_not_applicable( | 202 | check_assist_not_applicable( |
179 | generate_enum_into_method, | 203 | generate_enum_try_into_method, |
180 | r#"enum Value { | 204 | r#"enum Value { |
181 | Number(i32), | 205 | Number(i32), |
182 | Text(String)$0, | 206 | Text(String)$0, |
183 | } | 207 | } |
184 | 208 | ||
185 | impl Value { | 209 | impl Value { |
186 | fn into_text(self) -> Option<String> { | 210 | fn try_into_text(self) -> Result<String, Self> { |
187 | if let Self::Text(v) = self { | 211 | if let Self::Text(v) = self { |
188 | Some(v) | 212 | Ok(v) |
189 | } else { | 213 | } else { |
190 | None | 214 | Err(self) |
191 | } | 215 | } |
192 | } | 216 | } |
193 | }"#, | 217 | }"#, |
@@ -195,9 +219,9 @@ impl Value { | |||
195 | } | 219 | } |
196 | 220 | ||
197 | #[test] | 221 | #[test] |
198 | fn test_generate_enum_into_unit_variant() { | 222 | fn test_generate_enum_try_into_unit_variant() { |
199 | check_assist_not_applicable( | 223 | check_assist_not_applicable( |
200 | generate_enum_into_method, | 224 | generate_enum_try_into_method, |
201 | r#"enum Value { | 225 | r#"enum Value { |
202 | Number(i32), | 226 | Number(i32), |
203 | Text(String), | 227 | Text(String), |
@@ -207,9 +231,9 @@ impl Value { | |||
207 | } | 231 | } |
208 | 232 | ||
209 | #[test] | 233 | #[test] |
210 | fn test_generate_enum_into_record_with_multiple_fields() { | 234 | fn test_generate_enum_try_into_record_with_multiple_fields() { |
211 | check_assist_not_applicable( | 235 | check_assist_not_applicable( |
212 | generate_enum_into_method, | 236 | generate_enum_try_into_method, |
213 | r#"enum Value { | 237 | r#"enum Value { |
214 | Number(i32), | 238 | Number(i32), |
215 | Text(String), | 239 | Text(String), |
@@ -219,9 +243,9 @@ impl Value { | |||
219 | } | 243 | } |
220 | 244 | ||
221 | #[test] | 245 | #[test] |
222 | fn test_generate_enum_into_tuple_with_multiple_fields() { | 246 | fn test_generate_enum_try_into_tuple_with_multiple_fields() { |
223 | check_assist_not_applicable( | 247 | check_assist_not_applicable( |
224 | generate_enum_into_method, | 248 | generate_enum_try_into_method, |
225 | r#"enum Value { | 249 | r#"enum Value { |
226 | Number(i32), | 250 | Number(i32), |
227 | Text(String, String)$0, | 251 | Text(String, String)$0, |
@@ -230,9 +254,9 @@ impl Value { | |||
230 | } | 254 | } |
231 | 255 | ||
232 | #[test] | 256 | #[test] |
233 | fn test_generate_enum_into_record_variant() { | 257 | fn test_generate_enum_try_into_record_variant() { |
234 | check_assist( | 258 | check_assist( |
235 | generate_enum_into_method, | 259 | generate_enum_try_into_method, |
236 | r#"enum Value { | 260 | r#"enum Value { |
237 | Number(i32), | 261 | Number(i32), |
238 | Text { text: String }$0, | 262 | Text { text: String }$0, |
@@ -243,11 +267,11 @@ impl Value { | |||
243 | } | 267 | } |
244 | 268 | ||
245 | impl Value { | 269 | impl Value { |
246 | fn into_text(self) -> Option<String> { | 270 | fn try_into_text(self) -> Result<String, Self> { |
247 | if let Self::Text { text } = self { | 271 | if let Self::Text { text } = self { |
248 | Some(text) | 272 | Ok(text) |
249 | } else { | 273 | } else { |
250 | None | 274 | Err(self) |
251 | } | 275 | } |
252 | } | 276 | } |
253 | }"#, | 277 | }"#, |