1use ide_db::famous_defs::FamousDefs;
2use syntax::{
3 AstNode,
4 ast::{
5 self, HasGenericParams, HasName, HasTypeBounds, Impl,
6 edit::{AstNodeEdit, IndentLevel},
7 syntax_factory::SyntaxFactory,
8 },
9 syntax_editor::Position,
10};
11
12use crate::{
13 AssistId,
14 assist_context::{AssistContext, Assists},
15};
16
17pub(crate) fn generate_default_from_new(
48 acc: &mut Assists,
49 ctx: &AssistContext<'_, '_>,
50) -> Option<()> {
51 let fn_node = ctx.find_node_at_offset::<ast::Fn>()?;
52 let fn_name = fn_node.name()?;
53
54 if fn_name.text() != "new" {
55 cov_mark::hit!(other_function_than_new);
56 return None;
57 }
58
59 if fn_node.param_list()?.params().next().is_some() {
60 cov_mark::hit!(new_function_with_parameters);
61 return None;
62 }
63
64 let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
65 let self_ty = impl_.self_ty()?;
66 if is_default_implemented(ctx, &impl_) {
67 cov_mark::hit!(default_block_is_already_present);
68 cov_mark::hit!(struct_in_module_with_default);
69 return None;
70 }
71
72 let target = impl_.syntax().text_range();
73
74 acc.add(
75 AssistId::generate("generate_default_from_new"),
76 "Generate a Default impl from a new fn",
77 target,
78 move |builder| {
79 let editor = builder.make_editor(impl_.syntax());
80 let make = editor.make();
81 let default_impl = generate_default_impl(make, &impl_, self_ty);
82 let indent = IndentLevel::from_node(impl_.syntax());
83 let default_impl = default_impl.indent(indent);
84
85 editor.insert_all(
86 Position::after(impl_.syntax()),
87 vec![
88 make.whitespace(&format!("\n\n{indent}")).into(),
89 default_impl.syntax().clone().into(),
90 ],
91 );
92 builder.add_file_edits(ctx.vfs_file_id(), editor);
93 },
94 )
95}
96
97fn generate_default_impl(make: &SyntaxFactory, impl_: &ast::Impl, self_ty: ast::Type) -> ast::Impl {
98 let generic_params = impl_.generic_param_list().map(|generic_params| {
99 let lifetime_params =
100 generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
101 let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
102 let param = match param {
104 ast::TypeOrConstParam::Type(param) => {
105 let param = make.type_param(param.name()?, param.type_bound_list());
106 ast::GenericParam::TypeParam(param)
107 }
108 ast::TypeOrConstParam::Const(param) => {
109 let param = make.const_param(param.name()?, param.ty()?);
110 ast::GenericParam::ConstParam(param)
111 }
112 };
113 Some(param)
114 });
115
116 make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
117 });
118
119 let trait_ty: ast::Type = make.ty_path(make.ident_path("Default")).into();
120
121 let self_new_path = make.path_concat(make.ident_path("Self"), make.ident_path("new"));
122 let self_new_call =
123 make.expr_call(make.expr_path(self_new_path), make.arg_list(std::iter::empty()));
124 let fn_body = make.block_expr(std::iter::empty(), Some(self_new_call.into()));
125 let self_ty_ret: ast::Type = make.ty_path(make.ident_path("Self")).into();
126 let default_fn = make
127 .fn_(
128 [],
129 None,
130 make.name("default"),
131 None,
132 None,
133 make.param_list(None, std::iter::empty()),
134 fn_body,
135 Some(make.ret_type(self_ty_ret)),
136 false,
137 false,
138 false,
139 false,
140 )
141 .indent(1.into());
142 let body = make.assoc_item_list(Some(ast::AssocItem::from(default_fn)));
143
144 make.impl_trait(
145 [],
146 false,
147 None,
148 None,
149 generic_params,
150 None,
151 false,
152 trait_ty,
153 self_ty,
154 None,
155 impl_.where_clause(),
156 Some(body),
157 )
158}
159
160fn is_default_implemented(ctx: &AssistContext<'_, '_>, impl_: &Impl) -> bool {
161 let db = ctx.sema.db;
162 let impl_ = ctx.sema.to_def(impl_);
163 let impl_def = match impl_ {
164 Some(value) => value,
165 None => return false,
166 };
167
168 let ty = impl_def.self_ty(db);
169 let krate = impl_def.module(db).krate(ctx.db());
170 let default = FamousDefs(&ctx.sema, krate).core_default_Default();
171 let default_trait = match default {
172 Some(value) => value,
173 None => return true,
176 };
177
178 ty.impls_trait(db, default_trait, &[])
179}
180
181#[cfg(test)]
182mod tests {
183 use crate::tests::{check_assist, check_assist_not_applicable};
184
185 use super::*;
186
187 #[test]
188 fn generate_default() {
189 check_assist(
190 generate_default_from_new,
191 r#"
192//- minicore: default
193struct Example { _inner: () }
194
195impl Example {
196 pub fn ne$0w() -> Self {
197 Self { _inner: () }
198 }
199}
200
201fn main() {}
202"#,
203 r#"
204struct Example { _inner: () }
205
206impl Example {
207 pub fn new() -> Self {
208 Self { _inner: () }
209 }
210}
211
212impl Default for Example {
213 fn default() -> Self {
214 Self::new()
215 }
216}
217
218fn main() {}
219"#,
220 );
221 }
222
223 #[test]
224 fn generate_default2() {
225 check_assist(
226 generate_default_from_new,
227 r#"
228//- minicore: default
229struct Test { value: u32 }
230
231impl Test {
232 pub fn ne$0w() -> Self {
233 Self { value: 0 }
234 }
235}
236"#,
237 r#"
238struct Test { value: u32 }
239
240impl Test {
241 pub fn new() -> Self {
242 Self { value: 0 }
243 }
244}
245
246impl Default for Test {
247 fn default() -> Self {
248 Self::new()
249 }
250}
251"#,
252 );
253 }
254
255 #[test]
256 fn new_function_with_generic() {
257 check_assist(
258 generate_default_from_new,
259 r#"
260//- minicore: default
261pub struct Foo<T> {
262 _bar: *mut T,
263}
264
265impl<T> Foo<T> {
266 pub fn ne$0w() -> Self {
267 unimplemented!()
268 }
269}
270"#,
271 r#"
272pub struct Foo<T> {
273 _bar: *mut T,
274}
275
276impl<T> Foo<T> {
277 pub fn new() -> Self {
278 unimplemented!()
279 }
280}
281
282impl<T> Default for Foo<T> {
283 fn default() -> Self {
284 Self::new()
285 }
286}
287"#,
288 );
289 }
290
291 #[test]
292 fn new_function_with_generics() {
293 check_assist(
294 generate_default_from_new,
295 r#"
296//- minicore: default
297pub struct Foo<T, B> {
298 _tars: *mut T,
299 _bar: *mut B,
300}
301
302impl<T, B> Foo<T, B> {
303 pub fn ne$0w() -> Self {
304 unimplemented!()
305 }
306}
307"#,
308 r#"
309pub struct Foo<T, B> {
310 _tars: *mut T,
311 _bar: *mut B,
312}
313
314impl<T, B> Foo<T, B> {
315 pub fn new() -> Self {
316 unimplemented!()
317 }
318}
319
320impl<T, B> Default for Foo<T, B> {
321 fn default() -> Self {
322 Self::new()
323 }
324}
325"#,
326 );
327 }
328
329 #[test]
330 fn new_function_with_generic_and_bound() {
331 check_assist(
332 generate_default_from_new,
333 r#"
334//- minicore: default
335pub struct Foo<T> {
336 t: T,
337}
338
339impl<T: From<i32>> Foo<T> {
340 pub fn ne$0w() -> Self {
341 Foo { t: 0.into() }
342 }
343}
344"#,
345 r#"
346pub struct Foo<T> {
347 t: T,
348}
349
350impl<T: From<i32>> Foo<T> {
351 pub fn new() -> Self {
352 Foo { t: 0.into() }
353 }
354}
355
356impl<T: From<i32>> Default for Foo<T> {
357 fn default() -> Self {
358 Self::new()
359 }
360}
361"#,
362 );
363 }
364
365 #[test]
366 fn new_function_with_generics_and_bounds() {
367 check_assist(
368 generate_default_from_new,
369 r#"
370//- minicore: default
371pub struct Foo<T, B> {
372 _tars: T,
373 _bar: B,
374}
375
376impl<T: From<i32>, B: From<i64>> Foo<T, B> {
377 pub fn ne$0w() -> Self {
378 unimplemented!()
379 }
380}
381"#,
382 r#"
383pub struct Foo<T, B> {
384 _tars: T,
385 _bar: B,
386}
387
388impl<T: From<i32>, B: From<i64>> Foo<T, B> {
389 pub fn new() -> Self {
390 unimplemented!()
391 }
392}
393
394impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
395 fn default() -> Self {
396 Self::new()
397 }
398}
399"#,
400 );
401 }
402
403 #[test]
404 fn new_function_with_generic_and_where() {
405 check_assist(
406 generate_default_from_new,
407 r#"
408//- minicore: default
409pub struct Foo<T> {
410 t: T,
411}
412
413impl<T: From<i32>> Foo<T>
414where
415 Option<T>: Debug
416{
417 pub fn ne$0w() -> Self {
418 Foo { t: 0.into() }
419 }
420}
421"#,
422 r#"
423pub struct Foo<T> {
424 t: T,
425}
426
427impl<T: From<i32>> Foo<T>
428where
429 Option<T>: Debug
430{
431 pub fn new() -> Self {
432 Foo { t: 0.into() }
433 }
434}
435
436impl<T: From<i32>> Default for Foo<T>
437where
438 Option<T>: Debug
439{
440 fn default() -> Self {
441 Self::new()
442 }
443}
444"#,
445 );
446 }
447
448 #[test]
449 fn new_function_with_generics_and_where() {
450 check_assist(
451 generate_default_from_new,
452 r#"
453//- minicore: default
454pub struct Foo<T, B> {
455 _tars: T,
456 _bar: B,
457}
458
459impl<T: From<i32>, B: From<i64>> Foo<T, B>
460where
461 Option<T>: Debug, Option<B>: Debug,
462{
463 pub fn ne$0w() -> Self {
464 unimplemented!()
465 }
466}
467"#,
468 r#"
469pub struct Foo<T, B> {
470 _tars: T,
471 _bar: B,
472}
473
474impl<T: From<i32>, B: From<i64>> Foo<T, B>
475where
476 Option<T>: Debug, Option<B>: Debug,
477{
478 pub fn new() -> Self {
479 unimplemented!()
480 }
481}
482
483impl<T: From<i32>, B: From<i64>> Default for Foo<T, B>
484where
485 Option<T>: Debug, Option<B>: Debug,
486{
487 fn default() -> Self {
488 Self::new()
489 }
490}
491"#,
492 );
493 }
494
495 #[test]
496 fn new_function_with_parameters() {
497 cov_mark::check!(new_function_with_parameters);
498 check_assist_not_applicable(
499 generate_default_from_new,
500 r#"
501//- minicore: default
502struct Example { _inner: () }
503
504impl Example {
505 pub fn $0new(value: ()) -> Self {
506 Self { _inner: value }
507 }
508}
509"#,
510 );
511 }
512
513 #[test]
514 fn other_function_than_new() {
515 cov_mark::check!(other_function_than_new);
516 check_assist_not_applicable(
517 generate_default_from_new,
518 r#"
519//- minicore: default
520struct Example { _inner: () }
521
522impl Example {
523 pub fn a$0dd() -> Self {
524 Self { _inner: () }
525 }
526}
527
528"#,
529 );
530 }
531
532 #[test]
533 fn default_block_is_already_present() {
534 cov_mark::check!(default_block_is_already_present);
535 check_assist_not_applicable(
536 generate_default_from_new,
537 r#"
538//- minicore: default
539struct Example { _inner: () }
540
541impl Example {
542 pub fn n$0ew() -> Self {
543 Self { _inner: () }
544 }
545}
546
547impl Default for Example {
548 fn default() -> Self {
549 Self::new()
550 }
551}
552"#,
553 );
554 }
555
556 #[test]
557 fn standalone_new_function() {
558 check_assist_not_applicable(
559 generate_default_from_new,
560 r#"
561fn n$0ew() -> u32 {
562 0
563}
564"#,
565 );
566 }
567
568 #[test]
569 fn multiple_struct_blocks() {
570 check_assist(
571 generate_default_from_new,
572 r#"
573//- minicore: default
574struct Example { _inner: () }
575struct Test { value: u32 }
576
577impl Example {
578 pub fn new$0() -> Self {
579 Self { _inner: () }
580 }
581}
582"#,
583 r#"
584struct Example { _inner: () }
585struct Test { value: u32 }
586
587impl Example {
588 pub fn new() -> Self {
589 Self { _inner: () }
590 }
591}
592
593impl Default for Example {
594 fn default() -> Self {
595 Self::new()
596 }
597}
598"#,
599 );
600 }
601
602 #[test]
603 fn when_struct_is_after_impl() {
604 check_assist(
605 generate_default_from_new,
606 r#"
607//- minicore: default
608impl Example {
609 pub fn $0new() -> Self {
610 Self { _inner: () }
611 }
612}
613
614struct Example { _inner: () }
615"#,
616 r#"
617impl Example {
618 pub fn new() -> Self {
619 Self { _inner: () }
620 }
621}
622
623impl Default for Example {
624 fn default() -> Self {
625 Self::new()
626 }
627}
628
629struct Example { _inner: () }
630"#,
631 );
632 }
633
634 #[test]
635 fn struct_in_module() {
636 check_assist(
637 generate_default_from_new,
638 r#"
639//- minicore: default
640mod test {
641 struct Example { _inner: () }
642
643 impl Example {
644 pub fn n$0ew() -> Self {
645 Self { _inner: () }
646 }
647 }
648}
649"#,
650 r#"
651mod test {
652 struct Example { _inner: () }
653
654 impl Example {
655 pub fn new() -> Self {
656 Self { _inner: () }
657 }
658 }
659
660 impl Default for Example {
661 fn default() -> Self {
662 Self::new()
663 }
664 }
665}
666"#,
667 );
668 }
669
670 #[test]
671 fn struct_in_module_with_default() {
672 cov_mark::check!(struct_in_module_with_default);
673 check_assist_not_applicable(
674 generate_default_from_new,
675 r#"
676//- minicore: default
677mod test {
678 struct Example { _inner: () }
679
680 impl Example {
681 pub fn n$0ew() -> Self {
682 Self { _inner: () }
683 }
684 }
685
686 impl Default for Example {
687 fn default() -> Self {
688 Self::new()
689 }
690 }
691}
692"#,
693 );
694 }
695
696 #[test]
697 fn not_applicable_when_default_lang_item_is_missing() {
698 check_assist_not_applicable(
699 generate_default_from_new,
700 r#"
701struct S;
702impl S {
703 fn new$0() -> Self {}
704}
705"#,
706 );
707 }
708
709 #[test]
710 fn not_applicable_for_missing_self_ty() {
711 check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }");
713 }
714}