diff options
Diffstat (limited to 'crates/ide_assists')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_default_from_new.rs | 287 |
1 files changed, 275 insertions, 12 deletions
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index dc14552d6..bad826366 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs | |||
@@ -3,8 +3,10 @@ use crate::{ | |||
3 | AssistId, | 3 | AssistId, |
4 | }; | 4 | }; |
5 | use ide_db::helpers::FamousDefs; | 5 | use ide_db::helpers::FamousDefs; |
6 | use itertools::Itertools; | ||
7 | use stdx::format_to; | ||
6 | use syntax::{ | 8 | use syntax::{ |
7 | ast::{self, Impl, NameOwner}, | 9 | ast::{self, GenericParamsOwner, Impl, NameOwner, TypeBoundsOwner}, |
8 | AstNode, | 10 | AstNode, |
9 | }; | 11 | }; |
10 | 12 | ||
@@ -65,23 +67,56 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) | |||
65 | "Generate a Default impl from a new fn", | 67 | "Generate a Default impl from a new fn", |
66 | insert_location, | 68 | insert_location, |
67 | move |builder| { | 69 | move |builder| { |
68 | let code = default_fn_node_for_new(impl_); | 70 | let default_code = " fn default() -> Self { |
71 | Self::new() | ||
72 | }"; | ||
73 | let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code); | ||
69 | builder.insert(insert_location.end(), code); | 74 | builder.insert(insert_location.end(), code); |
70 | }, | 75 | }, |
71 | ) | 76 | ) |
72 | } | 77 | } |
73 | 78 | ||
74 | fn default_fn_node_for_new(impl_: Impl) -> String { | 79 | fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String { |
75 | format!( | 80 | let generic_params = impl_.generic_param_list(); |
76 | " | 81 | let mut buf = String::with_capacity(code.len()); |
82 | buf.push_str("\n\n"); | ||
83 | buf.push_str("impl"); | ||
84 | |||
85 | if let Some(generic_params) = &generic_params { | ||
86 | let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax())); | ||
87 | let type_params = generic_params.type_params().map(|type_param| { | ||
88 | let mut buf = String::new(); | ||
89 | if let Some(it) = type_param.name() { | ||
90 | format_to!(buf, "{}", it.syntax()); | ||
91 | } | ||
92 | if let Some(it) = type_param.colon_token() { | ||
93 | format_to!(buf, "{} ", it); | ||
94 | } | ||
95 | if let Some(it) = type_param.type_bound_list() { | ||
96 | format_to!(buf, "{}", it.syntax()); | ||
97 | } | ||
98 | buf | ||
99 | }); | ||
100 | let const_params = generic_params.const_params().map(|t| t.syntax().to_string()); | ||
101 | let generics = lifetimes.chain(type_params).chain(const_params).format(", "); | ||
102 | format_to!(buf, "<{}>", generics); | ||
103 | } | ||
104 | |||
105 | buf.push(' '); | ||
106 | buf.push_str(trait_text); | ||
107 | buf.push_str(" for "); | ||
108 | buf.push_str(&impl_.self_ty().unwrap().syntax().text().to_string()); | ||
109 | |||
110 | match impl_.where_clause() { | ||
111 | Some(where_clause) => { | ||
112 | format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code); | ||
113 | } | ||
114 | None => { | ||
115 | format_to!(buf, " {{\n{}\n}}", code); | ||
116 | } | ||
117 | } | ||
77 | 118 | ||
78 | impl Default for {} {{ | 119 | buf |
79 | fn default() -> Self {{ | ||
80 | Self::new() | ||
81 | }} | ||
82 | }}", | ||
83 | impl_.self_ty().unwrap().syntax().text() | ||
84 | ) | ||
85 | } | 120 | } |
86 | 121 | ||
87 | fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { | 122 | fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { |
@@ -176,6 +211,234 @@ impl Default for Test { | |||
176 | } | 211 | } |
177 | 212 | ||
178 | #[test] | 213 | #[test] |
214 | fn new_function_with_generic() { | ||
215 | check_pass( | ||
216 | r#" | ||
217 | pub struct Foo<T> { | ||
218 | _bar: *mut T, | ||
219 | } | ||
220 | |||
221 | impl<T> Foo<T> { | ||
222 | pub fn ne$0w() -> Self { | ||
223 | unimplemented!() | ||
224 | } | ||
225 | } | ||
226 | "#, | ||
227 | r#" | ||
228 | pub struct Foo<T> { | ||
229 | _bar: *mut T, | ||
230 | } | ||
231 | |||
232 | impl<T> Foo<T> { | ||
233 | pub fn new() -> Self { | ||
234 | unimplemented!() | ||
235 | } | ||
236 | } | ||
237 | |||
238 | impl<T> Default for Foo<T> { | ||
239 | fn default() -> Self { | ||
240 | Self::new() | ||
241 | } | ||
242 | } | ||
243 | "#, | ||
244 | ); | ||
245 | } | ||
246 | |||
247 | #[test] | ||
248 | fn new_function_with_generics() { | ||
249 | check_pass( | ||
250 | r#" | ||
251 | pub struct Foo<T, B> { | ||
252 | _tars: *mut T, | ||
253 | _bar: *mut B, | ||
254 | } | ||
255 | |||
256 | impl<T, B> Foo<T, B> { | ||
257 | pub fn ne$0w() -> Self { | ||
258 | unimplemented!() | ||
259 | } | ||
260 | } | ||
261 | "#, | ||
262 | r#" | ||
263 | pub struct Foo<T, B> { | ||
264 | _tars: *mut T, | ||
265 | _bar: *mut B, | ||
266 | } | ||
267 | |||
268 | impl<T, B> Foo<T, B> { | ||
269 | pub fn new() -> Self { | ||
270 | unimplemented!() | ||
271 | } | ||
272 | } | ||
273 | |||
274 | impl<T, B> Default for Foo<T, B> { | ||
275 | fn default() -> Self { | ||
276 | Self::new() | ||
277 | } | ||
278 | } | ||
279 | "#, | ||
280 | ); | ||
281 | } | ||
282 | |||
283 | #[test] | ||
284 | fn new_function_with_generic_and_bound() { | ||
285 | check_pass( | ||
286 | r#" | ||
287 | pub struct Foo<T> { | ||
288 | t: T, | ||
289 | } | ||
290 | |||
291 | impl<T: From<i32>> Foo<T> { | ||
292 | pub fn ne$0w() -> Self { | ||
293 | Foo { t: 0.into() } | ||
294 | } | ||
295 | } | ||
296 | "#, | ||
297 | r#" | ||
298 | pub struct Foo<T> { | ||
299 | t: T, | ||
300 | } | ||
301 | |||
302 | impl<T: From<i32>> Foo<T> { | ||
303 | pub fn new() -> Self { | ||
304 | Foo { t: 0.into() } | ||
305 | } | ||
306 | } | ||
307 | |||
308 | impl<T: From<i32>> Default for Foo<T> { | ||
309 | fn default() -> Self { | ||
310 | Self::new() | ||
311 | } | ||
312 | } | ||
313 | "#, | ||
314 | ); | ||
315 | } | ||
316 | |||
317 | #[test] | ||
318 | fn new_function_with_generics_and_bounds() { | ||
319 | check_pass( | ||
320 | r#" | ||
321 | pub struct Foo<T, B> { | ||
322 | _tars: T, | ||
323 | _bar: B, | ||
324 | } | ||
325 | |||
326 | impl<T: From<i32>, B: From<i64>> Foo<T, B> { | ||
327 | pub fn ne$0w() -> Self { | ||
328 | unimplemented!() | ||
329 | } | ||
330 | } | ||
331 | "#, | ||
332 | r#" | ||
333 | pub struct Foo<T, B> { | ||
334 | _tars: T, | ||
335 | _bar: B, | ||
336 | } | ||
337 | |||
338 | impl<T: From<i32>, B: From<i64>> Foo<T, B> { | ||
339 | pub fn new() -> Self { | ||
340 | unimplemented!() | ||
341 | } | ||
342 | } | ||
343 | |||
344 | impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> { | ||
345 | fn default() -> Self { | ||
346 | Self::new() | ||
347 | } | ||
348 | } | ||
349 | "#, | ||
350 | ); | ||
351 | } | ||
352 | |||
353 | #[test] | ||
354 | fn new_function_with_generic_and_where() { | ||
355 | check_pass( | ||
356 | r#" | ||
357 | pub struct Foo<T> { | ||
358 | t: T, | ||
359 | } | ||
360 | |||
361 | impl<T: From<i32>> Foo<T> | ||
362 | where | ||
363 | Option<T>: Debug | ||
364 | { | ||
365 | pub fn ne$0w() -> Self { | ||
366 | Foo { t: 0.into() } | ||
367 | } | ||
368 | } | ||
369 | "#, | ||
370 | r#" | ||
371 | pub struct Foo<T> { | ||
372 | t: T, | ||
373 | } | ||
374 | |||
375 | impl<T: From<i32>> Foo<T> | ||
376 | where | ||
377 | Option<T>: Debug | ||
378 | { | ||
379 | pub fn new() -> Self { | ||
380 | Foo { t: 0.into() } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | impl<T: From<i32>> Default for Foo<T> | ||
385 | where | ||
386 | Option<T>: Debug | ||
387 | { | ||
388 | fn default() -> Self { | ||
389 | Self::new() | ||
390 | } | ||
391 | } | ||
392 | "#, | ||
393 | ); | ||
394 | } | ||
395 | |||
396 | #[test] | ||
397 | fn new_function_with_generics_and_wheres() { | ||
398 | check_pass( | ||
399 | r#" | ||
400 | pub struct Foo<T, B> { | ||
401 | _tars: T, | ||
402 | _bar: B, | ||
403 | } | ||
404 | |||
405 | impl<T: From<i32>, B: From<i64>> Foo<T, B> | ||
406 | where | ||
407 | Option<T>: Debug, Option<B>: Debug, | ||
408 | { | ||
409 | pub fn ne$0w() -> Self { | ||
410 | unimplemented!() | ||
411 | } | ||
412 | } | ||
413 | "#, | ||
414 | r#" | ||
415 | pub struct Foo<T, B> { | ||
416 | _tars: T, | ||
417 | _bar: B, | ||
418 | } | ||
419 | |||
420 | impl<T: From<i32>, B: From<i64>> Foo<T, B> | ||
421 | where | ||
422 | Option<T>: Debug, Option<B>: Debug, | ||
423 | { | ||
424 | pub fn new() -> Self { | ||
425 | unimplemented!() | ||
426 | } | ||
427 | } | ||
428 | |||
429 | impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> | ||
430 | where | ||
431 | Option<T>: Debug, Option<B>: Debug, | ||
432 | { | ||
433 | fn default() -> Self { | ||
434 | Self::new() | ||
435 | } | ||
436 | } | ||
437 | "#, | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
179 | fn new_function_with_parameters() { | 442 | fn new_function_with_parameters() { |
180 | cov_mark::check!(new_function_with_parameters); | 443 | cov_mark::check!(new_function_with_parameters); |
181 | check_not_applicable( | 444 | check_not_applicable( |