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