Skip to main content

ide_assists/handlers/
generate_blanket_trait_impl.rs

1use crate::{
2    AssistConfig,
3    assist_context::{AssistContext, Assists},
4};
5use hir::{HasCrate, Semantics};
6use ide_db::{
7    RootDatabase,
8    assists::{AssistId, AssistKind},
9    famous_defs::FamousDefs,
10    syntax_helpers::suggest_name,
11};
12use syntax::{
13    AstNode,
14    ast::{
15        self, AssocItem, GenericParam, HasAttrs, HasGenericParams, HasName, HasTypeBounds,
16        HasVisibility, edit::AstNodeEdit, syntax_factory::SyntaxFactory,
17    },
18    syntax_editor::Position,
19};
20
21// Assist: generate_blanket_trait_impl
22//
23// Generate blanket trait implementation.
24//
25// ```
26// trait $0Foo<T: Send>: ToOwned
27// where
28//     Self::Owned: Default,
29// {
30//     fn foo(&self) -> T;
31//
32//     fn print_foo(&self) {
33//         println!("{}", self.foo());
34//     }
35// }
36// ```
37// ->
38// ```
39// trait Foo<T: Send>: ToOwned
40// where
41//     Self::Owned: Default,
42// {
43//     fn foo(&self) -> T;
44//
45//     fn print_foo(&self) {
46//         println!("{}", self.foo());
47//     }
48// }
49//
50// impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
51// where
52//     Self::Owned: Default,
53// {
54//     fn foo(&self) -> T {
55//         todo!()
56//     }
57// }
58// ```
59pub(crate) fn generate_blanket_trait_impl(
60    acc: &mut Assists,
61    ctx: &AssistContext<'_, '_>,
62) -> Option<()> {
63    let name = ctx.find_node_at_offset::<ast::Name>()?;
64    let traitd = ast::Trait::cast(name.syntax().parent()?)?;
65
66    if existing_any_impl(&traitd, &ctx.sema).is_some() {
67        cov_mark::hit!(existing_any_impl);
68        return None;
69    }
70
71    acc.add(
72        AssistId("generate_blanket_trait_impl", AssistKind::Generate, None),
73        "Generate blanket trait implementation",
74        name.syntax().text_range(),
75        |builder| {
76            let editor = builder.make_editor(traitd.syntax());
77            let make = editor.make();
78            let namety = make.ty_path(make.path_from_text(&name.text()));
79            let trait_where_clause = traitd.where_clause().map(|it| it.reset_indent());
80            let bounds = traitd.type_bound_list().and_then(|list| exclude_sized(make, list));
81            let is_unsafe = traitd.unsafe_token().is_some();
82            let thisname = this_name(make, &traitd);
83            let thisty = make.ty_path(make.path_from_text(&thisname.text()));
84            let indent = traitd.indent_level();
85
86            let gendecl = make.generic_param_list([GenericParam::TypeParam(make.type_param(
87                thisname.clone(),
88                apply_sized(make, has_sized(&traitd, &ctx.sema), bounds),
89            ))]);
90
91            let trait_gen_args =
92                traitd.generic_param_list().map(|param_list| param_list.to_generic_args(make));
93
94            let body = traitd.assoc_item_list().and_then(|trait_assoc_list| {
95                let items = trait_assoc_list
96                    .assoc_items()
97                    .filter_map(|item| {
98                        let item = match item {
99                            ast::AssocItem::Fn(method) if method.body().is_none() => {
100                                todo_fn(make, &method, ctx.config).into()
101                            }
102                            ast::AssocItem::Const(_) | ast::AssocItem::TypeAlias(_) => item,
103                            _ => return None,
104                        };
105                        Some(item.reset_indent().indent(1.into()))
106                    })
107                    .collect::<Vec<_>>();
108                (!items.is_empty()).then(|| make.assoc_item_list(items))
109            });
110
111            let impl_ = make.impl_trait(
112                cfg_attrs(&traitd),
113                is_unsafe,
114                traitd.generic_param_list(),
115                trait_gen_args,
116                Some(gendecl),
117                None,
118                false,
119                namety.into(),
120                thisty.into(),
121                trait_where_clause,
122                None,
123                body,
124            );
125
126            let impl_ = impl_.indent(indent);
127
128            editor.insert_all(
129                Position::after(traitd.syntax()),
130                vec![
131                    make.whitespace(&format!("\n\n{indent}")).into(),
132                    impl_.syntax().clone().into(),
133                ],
134            );
135
136            if let Some(cap) = ctx.config.snippet_cap
137                && let Some(self_ty) = impl_.self_ty()
138            {
139                builder.add_tabstop_before(cap, self_ty);
140            }
141            builder.add_file_edits(ctx.vfs_file_id(), editor);
142        },
143    );
144
145    Some(())
146}
147
148fn existing_any_impl(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> Option<hir::Impl> {
149    let db = sema.db;
150    let traitd = sema.to_def(traitd)?;
151    traitd
152        .module(db)
153        .impl_defs(db)
154        .into_iter()
155        .find(|impl_| impl_.trait_(db).is_some_and(|it| it == traitd))
156}
157
158fn has_sized(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> bool {
159    if let Some(sized) = find_bound("Sized", traitd.type_bound_list()) {
160        sized.question_mark_token().is_none()
161    } else if let Some(is_sized) = where_clause_sized(traitd.where_clause()) {
162        is_sized
163    } else {
164        contained_owned_self_method(traitd.assoc_item_list())
165            || super_traits_has_sized(traitd, sema) == Some(true)
166    }
167}
168
169fn super_traits_has_sized(traitd: &ast::Trait, sema: &Semantics<'_, RootDatabase>) -> Option<bool> {
170    let traitd = sema.to_def(traitd)?;
171    let sized = FamousDefs(sema, traitd.krate(sema.db)).core_marker_Sized()?;
172
173    Some(traitd.all_supertraits(sema.db).contains(&sized))
174}
175
176fn contained_owned_self_method(item_list: Option<ast::AssocItemList>) -> bool {
177    item_list.into_iter().flat_map(|assoc_item_list| assoc_item_list.assoc_items()).any(|item| {
178        match item {
179            AssocItem::Fn(f) => {
180                has_owned_self(&f) && where_clause_sized(f.where_clause()).is_none()
181            }
182            _ => false,
183        }
184    })
185}
186
187fn has_owned_self(f: &ast::Fn) -> bool {
188    has_owned_self_param(f) || has_ret_owned_self(f)
189}
190
191fn has_owned_self_param(f: &ast::Fn) -> bool {
192    f.param_list()
193        .and_then(|param_list| param_list.self_param())
194        .is_some_and(|sp| sp.amp_token().is_none() && sp.colon_token().is_none())
195}
196
197fn has_ret_owned_self(f: &ast::Fn) -> bool {
198    f.ret_type()
199        .and_then(|ret| match ret.ty() {
200            Some(ast::Type::PathType(ty)) => ty.path(),
201            _ => None,
202        })
203        .is_some_and(|path| {
204            path.segment()
205                .and_then(|seg| seg.name_ref())
206                .is_some_and(|name| path.qualifier().is_none() && name.text() == "Self")
207        })
208}
209
210fn where_clause_sized(where_clause: Option<ast::WhereClause>) -> Option<bool> {
211    where_clause?.predicates().find_map(|pred| {
212        find_bound("Sized", pred.type_bound_list())
213            .map(|bound| bound.question_mark_token().is_none())
214    })
215}
216
217fn apply_sized(
218    make: &SyntaxFactory,
219    has_sized: bool,
220    bounds: Option<ast::TypeBoundList>,
221) -> Option<ast::TypeBoundList> {
222    if has_sized {
223        return bounds;
224    }
225    let bounds = bounds
226        .into_iter()
227        .flat_map(|bounds| bounds.bounds())
228        .chain([make.type_bound_text("?Sized")]);
229    make.type_bound_list(bounds)
230}
231
232fn exclude_sized(make: &SyntaxFactory, bounds: ast::TypeBoundList) -> Option<ast::TypeBoundList> {
233    make.type_bound_list(bounds.bounds().filter(|bound| !ty_bound_is(bound, "Sized")))
234}
235
236fn this_name(make: &SyntaxFactory, traitd: &ast::Trait) -> ast::Name {
237    let has_iter = find_bound("Iterator", traitd.type_bound_list()).is_some();
238
239    let params = traitd
240        .generic_param_list()
241        .into_iter()
242        .flat_map(|param_list| param_list.generic_params())
243        .filter_map(|param| match param {
244            GenericParam::LifetimeParam(_) => None,
245            GenericParam::ConstParam(cp) => cp.name(),
246            GenericParam::TypeParam(tp) => tp.name(),
247        })
248        .map(|name| name.to_string())
249        .collect::<Vec<_>>();
250
251    let mut name_gen =
252        suggest_name::NameGenerator::new_with_names(params.iter().map(String::as_str));
253
254    make.name(&name_gen.suggest_name(if has_iter { "I" } else { "T" }))
255}
256
257fn find_bound(s: &str, bounds: Option<ast::TypeBoundList>) -> Option<ast::TypeBound> {
258    bounds.into_iter().flat_map(|bounds| bounds.bounds()).find(|bound| ty_bound_is(bound, s))
259}
260
261fn ty_bound_is(bound: &ast::TypeBound, s: &str) -> bool {
262    matches!(bound.ty(),
263        Some(ast::Type::PathType(ty)) if ty.path()
264            .and_then(|path| path.segment())
265            .and_then(|segment| segment.name_ref())
266            .is_some_and(|name| name.text() == s))
267}
268
269fn todo_fn(make: &SyntaxFactory, f: &ast::Fn, config: &AssistConfig) -> ast::Fn {
270    let params = f.param_list().unwrap_or_else(|| make.param_list(None, None));
271    make.fn_(
272        cfg_attrs(f),
273        f.visibility(),
274        f.name().unwrap_or_else(|| make.name("unnamed")),
275        f.generic_param_list(),
276        f.where_clause(),
277        params,
278        make.block_expr(None, Some(crate::utils::expr_fill_default(config))),
279        f.ret_type(),
280        f.async_token().is_some(),
281        f.const_token().is_some(),
282        f.unsafe_token().is_some(),
283        f.gen_token().is_some(),
284    )
285}
286
287fn cfg_attrs(node: &impl HasAttrs) -> impl Iterator<Item = ast::Attr> {
288    node.attrs().filter(|attr| matches!(attr.meta(), Some(ast::Meta::CfgMeta(_))))
289}
290
291#[cfg(test)]
292mod test {
293
294    use super::*;
295    use crate::tests::{check_assist, check_assist_not_applicable};
296
297    #[test]
298    fn test_gen_blanket_works() {
299        check_assist(
300            generate_blanket_trait_impl,
301            r#"
302trait $0Foo<T: Send>: ToOwned
303where
304    Self::Owned: Default,
305{
306    fn foo(&self) -> T;
307
308    fn print_foo(&self) {
309        println!("{}", self.foo());
310    }
311}
312"#,
313            r#"
314trait Foo<T: Send>: ToOwned
315where
316    Self::Owned: Default,
317{
318    fn foo(&self) -> T;
319
320    fn print_foo(&self) {
321        println!("{}", self.foo());
322    }
323}
324
325impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
326where
327    Self::Owned: Default,
328{
329    fn foo(&self) -> T {
330        todo!()
331    }
332}
333"#,
334        );
335    }
336
337    #[test]
338    fn test_gen_blanket_sized() {
339        check_assist(
340            generate_blanket_trait_impl,
341            r#"
342trait $0Foo: Iterator + Sized {
343    fn foo(mut self) -> Self::Item {
344        self.next().unwrap()
345    }
346}
347"#,
348            r#"
349trait Foo: Iterator + Sized {
350    fn foo(mut self) -> Self::Item {
351        self.next().unwrap()
352    }
353}
354
355impl<I: Iterator> Foo for $0I {}
356"#,
357        );
358
359        check_assist(
360            generate_blanket_trait_impl,
361            r#"
362trait $0Foo: Iterator {
363    fn foo(self) -> Self::Item;
364}
365"#,
366            r#"
367trait Foo: Iterator {
368    fn foo(self) -> Self::Item;
369}
370
371impl<I: Iterator> Foo for $0I {
372    fn foo(self) -> Self::Item {
373        todo!()
374    }
375}
376"#,
377        );
378
379        check_assist(
380            generate_blanket_trait_impl,
381            r#"
382trait $0Foo {
383    fn foo(&self) -> Self;
384}
385"#,
386            r#"
387trait Foo {
388    fn foo(&self) -> Self;
389}
390
391impl<T> Foo for $0T {
392    fn foo(&self) -> Self {
393        todo!()
394    }
395}
396"#,
397        );
398    }
399
400    #[test]
401    fn test_gen_blanket_super_sized() {
402        check_assist(
403            generate_blanket_trait_impl,
404            r#"
405//- minicore: default
406trait $0Foo: Default {
407    fn foo(&self);
408}
409"#,
410            r#"
411trait Foo: Default {
412    fn foo(&self);
413}
414
415impl<T: Default> Foo for $0T {
416    fn foo(&self) {
417        todo!()
418    }
419}
420"#,
421        );
422    }
423
424    #[test]
425    fn test_gen_blanket_non_sized() {
426        check_assist(
427            generate_blanket_trait_impl,
428            r#"
429trait $0Foo: Iterator {
430    fn foo(&self) -> Self::Item;
431}
432"#,
433            r#"
434trait Foo: Iterator {
435    fn foo(&self) -> Self::Item;
436}
437
438impl<I: Iterator + ?Sized> Foo for $0I {
439    fn foo(&self) -> Self::Item {
440        todo!()
441    }
442}
443"#,
444        );
445        check_assist(
446            generate_blanket_trait_impl,
447            r#"
448trait $0Foo: Iterator {
449    fn foo(&self) -> Self::Item;
450
451    fn each(self) where Self: Sized;
452}
453"#,
454            r#"
455trait Foo: Iterator {
456    fn foo(&self) -> Self::Item;
457
458    fn each(self) where Self: Sized;
459}
460
461impl<I: Iterator + ?Sized> Foo for $0I {
462    fn foo(&self) -> Self::Item {
463        todo!()
464    }
465
466    fn each(self) where Self: Sized {
467        todo!()
468    }
469}
470"#,
471        );
472        check_assist(
473            generate_blanket_trait_impl,
474            r#"
475trait $0Foo: Iterator {
476    fn foo(&self) -> Self::Item;
477
478    fn each(&self) -> Self where Self: Sized;
479}
480"#,
481            r#"
482trait Foo: Iterator {
483    fn foo(&self) -> Self::Item;
484
485    fn each(&self) -> Self where Self: Sized;
486}
487
488impl<I: Iterator + ?Sized> Foo for $0I {
489    fn foo(&self) -> Self::Item {
490        todo!()
491    }
492
493    fn each(&self) -> Self where Self: Sized {
494        todo!()
495    }
496}
497"#,
498        );
499    }
500
501    #[test]
502    fn test_gen_blanket_other_assoc_items() {
503        check_assist(
504            generate_blanket_trait_impl,
505            r#"
506trait $0Foo {
507    type Item;
508
509    const N: usize;
510
511    fn foo(&self);
512}
513"#,
514            r#"
515trait Foo {
516    type Item;
517
518    const N: usize;
519
520    fn foo(&self);
521}
522
523impl<T: ?Sized> Foo for $0T {
524    type Item;
525
526    const N: usize;
527
528    fn foo(&self) {
529        todo!()
530    }
531}
532"#,
533        );
534    }
535
536    #[test]
537    fn test_gen_blanket_indent() {
538        check_assist(
539            generate_blanket_trait_impl,
540            r#"
541mod foo {
542    trait $0Foo<T: Send>: ToOwned
543    where
544        Self::Owned: Default,
545    {
546        fn foo(&self) -> T;
547
548        fn print_foo(&self) {
549            println!("{}", self.foo());
550        }
551    }
552}
553        "#,
554            r#"
555mod foo {
556    trait Foo<T: Send>: ToOwned
557    where
558        Self::Owned: Default,
559    {
560        fn foo(&self) -> T;
561
562        fn print_foo(&self) {
563            println!("{}", self.foo());
564        }
565    }
566
567    impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
568    where
569        Self::Owned: Default,
570    {
571        fn foo(&self) -> T {
572            todo!()
573        }
574    }
575}
576        "#,
577        );
578        check_assist(
579            generate_blanket_trait_impl,
580            r#"
581mod foo {
582    trait $0Foo<T: Send>: ToOwned
583    where
584        Self::Owned: Default,
585        Self: Send,
586    {
587        fn foo(&self) -> T;
588
589        fn print_foo(&self) {
590            println!("{}", self.foo());
591        }
592    }
593}
594        "#,
595            r#"
596mod foo {
597    trait Foo<T: Send>: ToOwned
598    where
599        Self::Owned: Default,
600        Self: Send,
601    {
602        fn foo(&self) -> T;
603
604        fn print_foo(&self) {
605            println!("{}", self.foo());
606        }
607    }
608
609    impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
610    where
611        Self::Owned: Default,
612        Self: Send,
613    {
614        fn foo(&self) -> T {
615            todo!()
616        }
617    }
618}
619        "#,
620        );
621        check_assist(
622            generate_blanket_trait_impl,
623            r#"
624mod foo {
625    mod bar {
626        trait $0Foo<T: Send>: ToOwned
627        where
628            Self::Owned: Default,
629            Self: Send,
630        {
631            fn foo(&self) -> T;
632
633            fn print_foo(&self) {
634                println!("{}", self.foo());
635            }
636        }
637    }
638}
639        "#,
640            r#"
641mod foo {
642    mod bar {
643        trait Foo<T: Send>: ToOwned
644        where
645            Self::Owned: Default,
646            Self: Send,
647        {
648            fn foo(&self) -> T;
649
650            fn print_foo(&self) {
651                println!("{}", self.foo());
652            }
653        }
654
655        impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
656        where
657            Self::Owned: Default,
658            Self: Send,
659        {
660            fn foo(&self) -> T {
661                todo!()
662            }
663        }
664    }
665}
666        "#,
667        );
668        check_assist(
669            generate_blanket_trait_impl,
670            r#"
671mod foo {
672    trait $0Foo {
673        fn foo(&self) -> i32;
674
675        fn print_foo(&self) {
676            println!("{}", self.foo());
677        }
678    }
679}
680        "#,
681            r#"
682mod foo {
683    trait Foo {
684        fn foo(&self) -> i32;
685
686        fn print_foo(&self) {
687            println!("{}", self.foo());
688        }
689    }
690
691    impl<T: ?Sized> Foo for $0T {
692        fn foo(&self) -> i32 {
693            todo!()
694        }
695    }
696}
697        "#,
698        );
699        check_assist(
700            generate_blanket_trait_impl,
701            r#"
702mod foo {
703    mod bar {
704        trait $0Foo {
705            fn foo(&self) -> i32;
706
707            fn print_foo(&self) {
708                println!("{}", self.foo());
709            }
710        }
711    }
712}
713        "#,
714            r#"
715mod foo {
716    mod bar {
717        trait Foo {
718            fn foo(&self) -> i32;
719
720            fn print_foo(&self) {
721                println!("{}", self.foo());
722            }
723        }
724
725        impl<T: ?Sized> Foo for $0T {
726            fn foo(&self) -> i32 {
727                todo!()
728            }
729        }
730    }
731}
732        "#,
733        );
734        check_assist(
735            generate_blanket_trait_impl,
736            r#"
737mod foo {
738    mod bar {
739        #[cfg(test)]
740        trait $0Foo {
741            fn foo(&self) -> i32;
742
743            fn print_foo(&self) {
744                println!("{}", self.foo());
745            }
746        }
747    }
748}
749        "#,
750            r#"
751mod foo {
752    mod bar {
753        #[cfg(test)]
754        trait Foo {
755            fn foo(&self) -> i32;
756
757            fn print_foo(&self) {
758                println!("{}", self.foo());
759            }
760        }
761
762        #[cfg(test)]
763        impl<T: ?Sized> Foo for $0T {
764            fn foo(&self) -> i32 {
765                todo!()
766            }
767        }
768    }
769}
770        "#,
771        );
772        check_assist(
773            generate_blanket_trait_impl,
774            r#"
775mod foo {
776    mod bar {
777        trait $0Foo {
778            type Item: Bar<
779                Self,
780            >;
781
782            const N: Baz<
783                Self,
784            >;
785        }
786    }
787}
788        "#,
789            r#"
790mod foo {
791    mod bar {
792        trait Foo {
793            type Item: Bar<
794                Self,
795            >;
796
797            const N: Baz<
798                Self,
799            >;
800        }
801
802        impl<T: ?Sized> Foo for $0T {
803            type Item: Bar<
804                Self,
805            >;
806
807            const N: Baz<
808                Self,
809            >;
810        }
811    }
812}
813        "#,
814        );
815    }
816
817    #[test]
818    fn test_gen_blanket_remove_attribute() {
819        check_assist(
820            generate_blanket_trait_impl,
821            r#"
822trait $0Foo<T: Send>: ToOwned
823where
824    Self::Owned: Default,
825{
826    #[doc(hidden)]
827    fn foo(&self) -> T;
828
829    /// foo
830    fn print_foo(&self) {
831        println!("{}", self.foo());
832    }
833}
834"#,
835            r#"
836trait Foo<T: Send>: ToOwned
837where
838    Self::Owned: Default,
839{
840    #[doc(hidden)]
841    fn foo(&self) -> T;
842
843    /// foo
844    fn print_foo(&self) {
845        println!("{}", self.foo());
846    }
847}
848
849impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
850where
851    Self::Owned: Default,
852{
853    fn foo(&self) -> T {
854        todo!()
855    }
856}
857"#,
858        );
859    }
860
861    #[test]
862    fn test_gen_blanket_not_gen_type_alias() {
863        check_assist(
864            generate_blanket_trait_impl,
865            r#"
866trait $0Foo<T: Send>: ToOwned
867where
868    Self::Owned: Default,
869{
870    type X: Sync;
871
872    fn foo(&self, x: Self::X) -> T;
873
874    fn print_foo(&self) {
875        println!("{}", self.foo());
876    }
877}
878"#,
879            r#"
880trait Foo<T: Send>: ToOwned
881where
882    Self::Owned: Default,
883{
884    type X: Sync;
885
886    fn foo(&self, x: Self::X) -> T;
887
888    fn print_foo(&self) {
889        println!("{}", self.foo());
890    }
891}
892
893impl<T: Send, T1: ToOwned + ?Sized> Foo<T> for $0T1
894where
895    Self::Owned: Default,
896{
897    type X: Sync;
898
899    fn foo(&self, x: Self::X) -> T {
900        todo!()
901    }
902}
903"#,
904        );
905    }
906
907    #[test]
908    fn test_gen_blanket_no_quick_bound() {
909        check_assist(
910            generate_blanket_trait_impl,
911            r#"
912trait $0Foo<T: Send>
913where
914    Self: ToOwned,
915    Self::Owned: Default,
916{
917    type X: Sync;
918
919    fn foo(&self, x: Self::X) -> T;
920
921    fn print_foo(&self) {
922        println!("{}", self.foo());
923    }
924}
925"#,
926            r#"
927trait Foo<T: Send>
928where
929    Self: ToOwned,
930    Self::Owned: Default,
931{
932    type X: Sync;
933
934    fn foo(&self, x: Self::X) -> T;
935
936    fn print_foo(&self) {
937        println!("{}", self.foo());
938    }
939}
940
941impl<T: Send, T1: ?Sized> Foo<T> for $0T1
942where
943    Self: ToOwned,
944    Self::Owned: Default,
945{
946    type X: Sync;
947
948    fn foo(&self, x: Self::X) -> T {
949        todo!()
950    }
951}
952"#,
953        );
954    }
955
956    #[test]
957    fn test_gen_blanket_no_where_clause() {
958        check_assist(
959            generate_blanket_trait_impl,
960            r#"
961trait $0Foo<T: Send> {
962    type X: Sync;
963
964    fn foo(&self, x: Self::X) -> T;
965
966    fn print_foo(&self) {
967        println!("{}", self.foo());
968    }
969}
970"#,
971            r#"
972trait Foo<T: Send> {
973    type X: Sync;
974
975    fn foo(&self, x: Self::X) -> T;
976
977    fn print_foo(&self) {
978        println!("{}", self.foo());
979    }
980}
981
982impl<T: Send, T1: ?Sized> Foo<T> for $0T1 {
983    type X: Sync;
984
985    fn foo(&self, x: Self::X) -> T {
986        todo!()
987    }
988}
989"#,
990        );
991    }
992
993    #[test]
994    fn test_gen_blanket_basic() {
995        check_assist(
996            generate_blanket_trait_impl,
997            r#"
998trait $0Foo {
999    type X: Sync;
1000
1001    fn foo(&self, x: Self::X) -> i32;
1002
1003    fn print_foo(&self) {
1004        println!("{}", self.foo());
1005    }
1006}
1007"#,
1008            r#"
1009trait Foo {
1010    type X: Sync;
1011
1012    fn foo(&self, x: Self::X) -> i32;
1013
1014    fn print_foo(&self) {
1015        println!("{}", self.foo());
1016    }
1017}
1018
1019impl<T: ?Sized> Foo for $0T {
1020    type X: Sync;
1021
1022    fn foo(&self, x: Self::X) -> i32 {
1023        todo!()
1024    }
1025}
1026"#,
1027        );
1028    }
1029
1030    #[test]
1031    fn test_gen_blanket_cfg_attrs() {
1032        check_assist(
1033            generate_blanket_trait_impl,
1034            r#"
1035#[cfg(test)]
1036trait $0Foo {
1037    fn foo(&self, x: i32) -> i32;
1038
1039    fn print_foo(&self) {
1040        println!("{}", self.foo());
1041    }
1042}
1043"#,
1044            r#"
1045#[cfg(test)]
1046trait Foo {
1047    fn foo(&self, x: i32) -> i32;
1048
1049    fn print_foo(&self) {
1050        println!("{}", self.foo());
1051    }
1052}
1053
1054#[cfg(test)]
1055impl<T: ?Sized> Foo for $0T {
1056    fn foo(&self, x: i32) -> i32 {
1057        todo!()
1058    }
1059}
1060"#,
1061        );
1062        check_assist(
1063            generate_blanket_trait_impl,
1064            r#"
1065#[cfg(test)]
1066trait $0Foo {
1067    /// ...
1068    #[cfg(test)]
1069    fn foo(&self, x: i32) -> i32;
1070
1071    fn print_foo(&self) {
1072        println!("{}", self.foo());
1073    }
1074}
1075"#,
1076            r#"
1077#[cfg(test)]
1078trait Foo {
1079    /// ...
1080    #[cfg(test)]
1081    fn foo(&self, x: i32) -> i32;
1082
1083    fn print_foo(&self) {
1084        println!("{}", self.foo());
1085    }
1086}
1087
1088#[cfg(test)]
1089impl<T: ?Sized> Foo for $0T {
1090    #[cfg(test)]
1091    fn foo(&self, x: i32) -> i32 {
1092        todo!()
1093    }
1094}
1095"#,
1096        );
1097    }
1098
1099    #[test]
1100    fn test_gen_blanket_empty_trait() {
1101        check_assist(
1102            generate_blanket_trait_impl,
1103            r#"
1104trait $0Foo {}
1105"#,
1106            r#"
1107trait Foo {}
1108
1109impl<T: ?Sized> Foo for $0T {}
1110"#,
1111        );
1112    }
1113
1114    #[test]
1115    fn test_gen_blanket_empty_trait_with_quick_bounds() {
1116        check_assist(
1117            generate_blanket_trait_impl,
1118            r#"
1119trait $0Foo: Copy {}
1120"#,
1121            r#"
1122trait Foo: Copy {}
1123
1124impl<T: Copy + ?Sized> Foo for $0T {}
1125"#,
1126        );
1127    }
1128
1129    #[test]
1130    fn test_gen_blanket_empty_trait_with_where_clause() {
1131        check_assist(
1132            generate_blanket_trait_impl,
1133            r#"
1134trait $0Foo where Self: Copy {}
1135"#,
1136            r#"
1137trait Foo where Self: Copy {}
1138
1139impl<T: ?Sized> Foo for $0T
1140where Self: Copy
1141{
1142}
1143"#,
1144        );
1145    }
1146
1147    #[test]
1148    fn test_gen_blanket_empty_trait_with_where_clause_comma() {
1149        check_assist(
1150            generate_blanket_trait_impl,
1151            r#"
1152trait $0Foo where Self: Copy, {}
1153"#,
1154            r#"
1155trait Foo where Self: Copy, {}
1156
1157impl<T: ?Sized> Foo for $0T
1158where Self: Copy,
1159{
1160}
1161"#,
1162        );
1163    }
1164
1165    #[test]
1166    fn test_gen_blanket_empty_trait_with_where_clause_newline() {
1167        check_assist(
1168            generate_blanket_trait_impl,
1169            r#"
1170trait $0Foo
1171where Self: Copy
1172{}
1173"#,
1174            r#"
1175trait Foo
1176where Self: Copy
1177{}
1178
1179impl<T: ?Sized> Foo for $0T
1180where Self: Copy
1181{
1182}
1183"#,
1184        );
1185    }
1186
1187    #[test]
1188    fn test_gen_blanket_empty_trait_with_where_clause_newline_newline() {
1189        check_assist(
1190            generate_blanket_trait_impl,
1191            r#"
1192trait $0Foo
1193where
1194    Self: Copy
1195{}
1196"#,
1197            r#"
1198trait Foo
1199where
1200    Self: Copy
1201{}
1202
1203impl<T: ?Sized> Foo for $0T
1204where
1205    Self: Copy
1206{
1207}
1208"#,
1209        );
1210    }
1211
1212    #[test]
1213    fn test_gen_blanket_empty_trait_with_where_clause_newline_newline_comma() {
1214        check_assist(
1215            generate_blanket_trait_impl,
1216            r#"
1217trait $0Foo
1218where
1219    Self: Copy,
1220{}
1221"#,
1222            r#"
1223trait Foo
1224where
1225    Self: Copy,
1226{}
1227
1228impl<T: ?Sized> Foo for $0T
1229where
1230    Self: Copy,
1231{
1232}
1233"#,
1234        );
1235    }
1236
1237    #[test]
1238    fn test_gen_blanket_empty_trait_with_multiple_where_clause() {
1239        check_assist(
1240            generate_blanket_trait_impl,
1241            r#"
1242trait $0Foo
1243where
1244    Self: Copy,
1245    (): Into<Self>,
1246{}
1247"#,
1248            r#"
1249trait Foo
1250where
1251    Self: Copy,
1252    (): Into<Self>,
1253{}
1254
1255impl<T: ?Sized> Foo for $0T
1256where
1257    Self: Copy,
1258    (): Into<Self>,
1259{
1260}
1261"#,
1262        );
1263    }
1264
1265    #[test]
1266    fn test_gen_blanket_empty_trait_with_multiple_bounds_where_clause() {
1267        check_assist(
1268            generate_blanket_trait_impl,
1269            r#"
1270trait $0Foo
1271where
1272    Self: Copy + Sync,
1273    (): Into<Self>,
1274{}
1275"#,
1276            r#"
1277trait Foo
1278where
1279    Self: Copy + Sync,
1280    (): Into<Self>,
1281{}
1282
1283impl<T: ?Sized> Foo for $0T
1284where
1285    Self: Copy + Sync,
1286    (): Into<Self>,
1287{
1288}
1289"#,
1290        );
1291    }
1292
1293    #[test]
1294    fn test_gen_blanket_empty_generate() {
1295        check_assist(
1296            generate_blanket_trait_impl,
1297            r#"
1298trait $0Foo {
1299    fn foo(&self) {}
1300}
1301"#,
1302            r#"
1303trait Foo {
1304    fn foo(&self) {}
1305}
1306
1307impl<T: ?Sized> Foo for $0T {}
1308"#,
1309        );
1310    }
1311
1312    #[test]
1313    fn test_gen_blanket_trait_with_doc() {
1314        check_assist(
1315            generate_blanket_trait_impl,
1316            r#"
1317/// some docs
1318trait $0Foo {}
1319"#,
1320            r#"
1321/// some docs
1322trait Foo {}
1323
1324impl<T: ?Sized> Foo for $0T {}
1325"#,
1326        );
1327    }
1328
1329    #[test]
1330    fn test_gen_blanket_multiple_method() {
1331        check_assist(
1332            generate_blanket_trait_impl,
1333            r#"
1334trait $0Foo {
1335    fn foo(&self);
1336    fn bar(&self);
1337}
1338"#,
1339            r#"
1340trait Foo {
1341    fn foo(&self);
1342    fn bar(&self);
1343}
1344
1345impl<T: ?Sized> Foo for $0T {
1346    fn foo(&self) {
1347        todo!()
1348    }
1349
1350    fn bar(&self) {
1351        todo!()
1352    }
1353}
1354"#,
1355        );
1356    }
1357
1358    #[test]
1359    fn test_gen_blanket_method_with_generic() {
1360        check_assist(
1361            generate_blanket_trait_impl,
1362            r#"
1363trait $0Foo {
1364    fn foo<T>(&self, value: i32) -> i32;
1365    fn bar<T>(&self, value: i32) -> i32 { todo!() }
1366}
1367"#,
1368            r#"
1369trait Foo {
1370    fn foo<T>(&self, value: i32) -> i32;
1371    fn bar<T>(&self, value: i32) -> i32 { todo!() }
1372}
1373
1374impl<T: ?Sized> Foo for $0T {
1375    fn foo<T>(&self, value: i32) -> i32 {
1376        todo!()
1377    }
1378}
1379"#,
1380        );
1381    }
1382
1383    #[test]
1384    fn test_gen_blanket_method_with_lifetimes() {
1385        check_assist(
1386            generate_blanket_trait_impl,
1387            r#"
1388trait $0Foo<'a> {
1389    fn foo(&self) -> &'a str;
1390}
1391"#,
1392            r#"
1393trait Foo<'a> {
1394    fn foo(&self) -> &'a str;
1395}
1396
1397impl<'a, T: ?Sized> Foo<'a> for $0T {
1398    fn foo(&self) -> &'a str {
1399        todo!()
1400    }
1401}
1402"#,
1403        );
1404    }
1405
1406    #[test]
1407    fn test_gen_blanket_method_with_lifetime_bounds() {
1408        check_assist(
1409            generate_blanket_trait_impl,
1410            r#"
1411trait $0Foo<'a: 'static> {
1412    fn foo(&self) -> &'a str;
1413}
1414"#,
1415            r#"
1416trait Foo<'a: 'static> {
1417    fn foo(&self) -> &'a str;
1418}
1419
1420impl<'a: 'static, T: ?Sized> Foo<'a> for $0T {
1421    fn foo(&self) -> &'a str {
1422        todo!()
1423    }
1424}
1425"#,
1426        );
1427    }
1428
1429    #[test]
1430    fn test_gen_blanket_method_with_lifetime_quick_bounds() {
1431        check_assist(
1432            generate_blanket_trait_impl,
1433            r#"
1434trait $0Foo<'a>: 'a {
1435    fn foo(&self) -> &'a str;
1436}
1437"#,
1438            r#"
1439trait Foo<'a>: 'a {
1440    fn foo(&self) -> &'a str;
1441}
1442
1443impl<'a, T: 'a + ?Sized> Foo<'a> for $0T {
1444    fn foo(&self) -> &'a str {
1445        todo!()
1446    }
1447}
1448"#,
1449        );
1450    }
1451
1452    #[test]
1453    fn test_gen_blanket_method_with_multiple_lifetimes() {
1454        check_assist(
1455            generate_blanket_trait_impl,
1456            r#"
1457trait $0Foo<'a, 'b> {
1458    fn foo(&self) -> &'a &'b str;
1459}
1460"#,
1461            r#"
1462trait Foo<'a, 'b> {
1463    fn foo(&self) -> &'a &'b str;
1464}
1465
1466impl<'a, 'b, T: ?Sized> Foo<'a, 'b> for $0T {
1467    fn foo(&self) -> &'a &'b str {
1468        todo!()
1469    }
1470}
1471"#,
1472        );
1473    }
1474
1475    #[test]
1476    fn test_gen_blanket_method_with_lifetime_bounds_at_where_clause() {
1477        check_assist(
1478            generate_blanket_trait_impl,
1479            r#"
1480trait $0Foo<'a>
1481where 'a: 'static,
1482{
1483    fn foo(&self) -> &'a str;
1484}
1485"#,
1486            r#"
1487trait Foo<'a>
1488where 'a: 'static,
1489{
1490    fn foo(&self) -> &'a str;
1491}
1492
1493impl<'a, T: ?Sized> Foo<'a> for $0T
1494where 'a: 'static,
1495{
1496    fn foo(&self) -> &'a str {
1497        todo!()
1498    }
1499}
1500"#,
1501        );
1502    }
1503
1504    #[test]
1505    fn test_gen_blanket_not_on_name() {
1506        check_assist_not_applicable(
1507            generate_blanket_trait_impl,
1508            r#"
1509trait Foo<T: Send>: $0ToOwned
1510where
1511    Self::Owned: Default,
1512{
1513    fn foo(&self) -> T;
1514
1515    fn print_foo(&self) {
1516        println!("{}", self.foo());
1517    }
1518}
1519"#,
1520        );
1521
1522        check_assist_not_applicable(
1523            generate_blanket_trait_impl,
1524            r#"
1525trait Foo<T: Send>: ToOwned
1526where
1527    Self::Owned: Default,
1528{
1529    $0fn foo(&self) -> T;
1530
1531    fn print_foo(&self) {
1532        println!("{}", self.foo());
1533    }
1534}
1535"#,
1536        );
1537
1538        check_assist_not_applicable(
1539            generate_blanket_trait_impl,
1540            r#"
1541trait Foo<T: Send>: ToOwned
1542where
1543    Self::Owned: Default,
1544{
1545    fn $0foo(&self) -> T;
1546
1547    fn print_foo(&self) {
1548        println!("{}", self.foo());
1549    }
1550}
1551"#,
1552        );
1553    }
1554
1555    #[test]
1556    fn test_gen_blanket_existing_impl() {
1557        cov_mark::check!(existing_any_impl);
1558        check_assist_not_applicable(
1559            generate_blanket_trait_impl,
1560            r#"
1561trait $0Foo: Default {
1562    fn foo(&self) -> Self;
1563}
1564impl Foo for () {}
1565"#,
1566        );
1567    }
1568
1569    #[test]
1570    fn test_gen_blanket_existing_other_impl() {
1571        check_assist(
1572            generate_blanket_trait_impl,
1573            r#"
1574trait $0Foo: Default {
1575    fn foo(&self) -> Self;
1576}
1577trait Bar: Default {
1578    fn bar(&self) -> Self;
1579}
1580impl Bar for () {}
1581"#,
1582            r#"
1583trait Foo: Default {
1584    fn foo(&self) -> Self;
1585}
1586
1587impl<T: Default> Foo for $0T {
1588    fn foo(&self) -> Self {
1589        todo!()
1590    }
1591}
1592trait Bar: Default {
1593    fn bar(&self) -> Self;
1594}
1595impl Bar for () {}
1596"#,
1597        );
1598    }
1599
1600    #[test]
1601    fn test_gen_blanket_apply_on_other_impl_block() {
1602        check_assist(
1603            generate_blanket_trait_impl,
1604            r#"
1605trait $0Foo {
1606    fn foo(&self) -> i32;
1607
1608    fn print_foo(&self) {
1609        println!("{}", self.foo());
1610    }
1611}
1612
1613trait Bar {}
1614impl Bar for i32 {}
1615"#,
1616            r#"
1617trait Foo {
1618    fn foo(&self) -> i32;
1619
1620    fn print_foo(&self) {
1621        println!("{}", self.foo());
1622    }
1623}
1624
1625impl<T: ?Sized> Foo for $0T {
1626    fn foo(&self) -> i32 {
1627        todo!()
1628    }
1629}
1630
1631trait Bar {}
1632impl Bar for i32 {}
1633"#,
1634        );
1635    }
1636
1637    #[test]
1638    fn test_gen_blanket_apply_on_other_blanket_impl_block() {
1639        check_assist(
1640            generate_blanket_trait_impl,
1641            r#"
1642trait $0Foo {
1643    fn foo(&self) -> i32;
1644
1645    fn print_foo(&self) {
1646        println!("{}", self.foo());
1647    }
1648}
1649
1650trait Bar {}
1651impl<T> Bar for T {}
1652"#,
1653            r#"
1654trait Foo {
1655    fn foo(&self) -> i32;
1656
1657    fn print_foo(&self) {
1658        println!("{}", self.foo());
1659    }
1660}
1661
1662impl<T: ?Sized> Foo for $0T {
1663    fn foo(&self) -> i32 {
1664        todo!()
1665    }
1666}
1667
1668trait Bar {}
1669impl<T> Bar for T {}
1670"#,
1671        );
1672    }
1673}