Skip to main content

ide_assists/handlers/
generate_default_from_new.rs

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
17// Assist: generate_default_from_new
18//
19// Generates default implementation from new method.
20//
21// ```
22// # //- minicore: default
23// struct Example { _inner: () }
24//
25// impl Example {
26//     pub fn n$0ew() -> Self {
27//         Self { _inner: () }
28//     }
29// }
30// ```
31// ->
32// ```
33// struct Example { _inner: () }
34//
35// impl Example {
36//     pub fn new() -> Self {
37//         Self { _inner: () }
38//     }
39// }
40//
41// impl Default for Example {
42//     fn default() -> Self {
43//         Self::new()
44//     }
45// }
46// ```
47pub(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            // remove defaults since they can't be specified in impls
103            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        // Return `true` to avoid providing the assist because it makes no sense
174        // to impl `Default` when it's missing.
175        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        // Regression test for #15398.
712        check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }");
713    }
714}