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
21pub(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}