ide_assists/handlers/
generate_default_from_new.rs

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