1use syntax::{
2 ast::{self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit},
3 syntax_editor::{Position, SyntaxEditor},
4};
5
6use crate::{
7 AssistContext, AssistId, Assists,
8 utils::{
9 self, DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl,
10 generate_trait_impl_intransitive,
11 },
12};
13
14fn insert_impl(editor: &SyntaxEditor, impl_: &ast::Impl, nominal: &impl AstNodeEdit) -> ast::Impl {
15 let make = editor.make();
16 let indent = nominal.indent_level();
17
18 let impl_ = impl_.indent(indent);
19 editor.insert_all(
20 Position::after(nominal.syntax()),
21 vec![
22 make.whitespace(&format!("\n\n{indent}")).into(),
24 impl_.syntax().clone().into(),
25 ],
26 );
27
28 impl_
29}
30
31pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
49 let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
50 let name = nominal.name()?;
51 let target = nominal.syntax().text_range();
52
53 if ctx.find_node_at_offset::<ast::RecordFieldList>().is_some() {
54 return None;
55 }
56
57 acc.add(
58 AssistId::generate("generate_impl"),
59 format!("Generate impl for `{name}`"),
60 target,
61 |edit| {
62 let editor = edit.make_editor(nominal.syntax());
63 let make = editor.make();
64 let impl_ = utils::generate_impl(make, &nominal);
65
66 let impl_ = insert_impl(&editor, &impl_, &nominal);
67 if let Some(cap) = ctx.config.snippet_cap
69 && let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token())
70 {
71 let tabstop = edit.make_tabstop_after(cap);
72 editor.add_annotation(l_curly, tabstop);
73 }
74 edit.add_file_edits(ctx.vfs_file_id(), editor);
75 },
76 )
77}
78
79pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
97 let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
98 let name = nominal.name()?;
99 let target = nominal.syntax().text_range();
100
101 if ctx.find_node_at_offset::<ast::RecordFieldList>().is_some() {
102 return None;
103 }
104
105 acc.add(
106 AssistId::generate("generate_trait_impl"),
107 format!("Generate trait impl for `{name}`"),
108 target,
109 |edit| {
110 let editor = edit.make_editor(nominal.syntax());
111 let make = editor.make();
112 let impl_ = generate_trait_impl_intransitive(make, &nominal, make.ty_placeholder());
113 let impl_ = insert_impl(&editor, &impl_, &nominal);
114 if let Some(cap) = ctx.config.snippet_cap {
116 if let Some(trait_) = impl_.trait_() {
117 let placeholder = edit.make_placeholder_snippet(cap);
118 editor.add_annotation(trait_.syntax(), placeholder);
119 }
120
121 if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) {
122 let tabstop = edit.make_tabstop_after(cap);
123 editor.add_annotation(l_curly, tabstop);
124 }
125 }
126 edit.add_file_edits(ctx.vfs_file_id(), editor);
127 },
128 )
129}
130
131pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
153 let name = ctx.find_node_at_offset::<ast::Name>()?;
154 let trait_ = ast::Trait::cast(name.syntax().parent()?)?;
155 let target_scope = ctx.sema.scope(trait_.syntax())?;
156 let hir_trait = ctx.sema.to_def(&trait_)?;
157
158 let target = trait_.syntax().text_range();
159 acc.add(
160 AssistId::generate("generate_impl_trait"),
161 format!("Generate `{name}` impl for type"),
162 target,
163 |edit| {
164 let editor = edit.make_editor(trait_.syntax());
165 let make = editor.make();
166
167 let holder_arg = ast::GenericArg::TypeArg(make.type_arg(make.ty_placeholder()));
168 let missing_items = utils::filter_assoc_items(
169 &ctx.sema,
170 &hir_trait.items(ctx.db()),
171 DefaultMethods::No,
172 IgnoreAssocItems::DocHiddenAttrPresent,
173 );
174
175 let trait_gen_args = trait_.generic_param_list().map(|list| {
176 make.generic_arg_list(list.generic_params().map(|_| holder_arg.clone()), false)
177 });
178
179 let make_impl_ = |body| {
180 make.impl_trait(
181 None,
182 trait_.unsafe_token().is_some(),
183 None,
184 trait_gen_args.clone(),
185 None,
186 None,
187 false,
188 make.ty(&name.text()),
189 make.ty_placeholder(),
190 None,
191 None,
192 body,
193 )
194 };
195
196 let impl_ = if missing_items.is_empty() {
197 make_impl_(None)
198 } else {
199 let impl_ = make_impl_(None);
200 let assoc_items = add_trait_assoc_items_to_impl(
201 make,
202 &ctx.sema,
203 ctx.config,
204 &missing_items,
205 hir_trait,
206 &impl_,
207 &target_scope,
208 );
209 let assoc_item_list = make.assoc_item_list(assoc_items);
210 make_impl_(Some(assoc_item_list))
211 };
212
213 let impl_ = insert_impl(&editor, &impl_, &trait_);
214
215 if let Some(cap) = ctx.config.snippet_cap {
216 if let Some(generics) = impl_.trait_().and_then(|it| it.generic_arg_list()) {
217 for generic in generics.generic_args() {
218 let placeholder = edit.make_placeholder_snippet(cap);
219 editor.add_annotation(generic.syntax(), placeholder);
220 }
221 }
222
223 if let Some(ty) = impl_.self_ty() {
224 let placeholder = edit.make_placeholder_snippet(cap);
225 editor.add_annotation(ty.syntax(), placeholder);
226 }
227
228 if let Some(expr) =
229 impl_.assoc_item_list().and_then(|it| it.assoc_items().find_map(extract_expr))
230 {
231 let tabstop = edit.make_tabstop_before(cap);
232 editor.add_annotation(expr.syntax(), tabstop);
233 } else if let Some(l_curly) =
234 impl_.assoc_item_list().and_then(|it| it.l_curly_token())
235 {
236 let tabstop = edit.make_tabstop_after(cap);
237 editor.add_annotation(l_curly, tabstop);
238 }
239 }
240
241 edit.add_file_edits(ctx.vfs_file_id(), editor);
242 },
243 )
244}
245
246fn extract_expr(item: ast::AssocItem) -> Option<ast::Expr> {
247 let ast::AssocItem::Fn(f) = item else {
248 return None;
249 };
250 f.body()?.tail_expr()
251}
252
253#[cfg(test)]
254mod tests {
255 use crate::tests::{check_assist, check_assist_target};
256
257 use super::*;
258
259 #[test]
260 fn test_add_impl() {
261 check_assist(
262 generate_impl,
263 r#"
264 struct Foo$0 {}
265 "#,
266 r#"
267 struct Foo {}
268
269 impl Foo {$0}
270 "#,
271 );
272 }
273
274 #[test]
275 fn test_add_impl_with_generics() {
276 check_assist(
277 generate_impl,
278 r#"
279 struct Foo$0<T: Clone> {}
280 "#,
281 r#"
282 struct Foo<T: Clone> {}
283
284 impl<T: Clone> Foo<T> {$0}
285 "#,
286 );
287 }
288
289 #[test]
290 fn test_add_impl_with_generics_and_lifetime_parameters() {
291 check_assist(
292 generate_impl,
293 r#"
294 struct Foo<'a, T: Foo<'a>>$0 {}
295 "#,
296 r#"
297 struct Foo<'a, T: Foo<'a>> {}
298
299 impl<'a, T: Foo<'a>> Foo<'a, T> {$0}
300 "#,
301 );
302 }
303
304 #[test]
305 fn test_add_impl_with_attributes() {
306 check_assist(
307 generate_impl,
308 r#"
309 #[cfg(feature = "foo")]
310 struct Foo<'a, T: Foo$0<'a>> {}
311 "#,
312 r#"
313 #[cfg(feature = "foo")]
314 struct Foo<'a, T: Foo<'a>> {}
315
316 #[cfg(feature = "foo")]
317 impl<'a, T: Foo<'a>> Foo<'a, T> {$0}
318 "#,
319 );
320 }
321
322 #[test]
323 fn test_add_impl_with_default_generic() {
324 check_assist(
325 generate_impl,
326 r#"
327 struct Defaulted$0<T = i32> {}
328 "#,
329 r#"
330 struct Defaulted<T = i32> {}
331
332 impl<T> Defaulted<T> {$0}
333 "#,
334 );
335 }
336
337 #[test]
338 fn test_add_impl_with_constrained_default_generic() {
339 check_assist(
340 generate_impl,
341 r#"
342 struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
343 "#,
344 r#"
345 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
346
347 impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {$0}
348 "#,
349 );
350 }
351
352 #[test]
353 fn test_add_impl_with_const_defaulted_generic() {
354 check_assist(
355 generate_impl,
356 r#"
357 struct Defaulted$0<const N: i32 = 0> {}
358 "#,
359 r#"
360 struct Defaulted<const N: i32 = 0> {}
361
362 impl<const N: i32> Defaulted<N> {$0}
363 "#,
364 );
365 }
366
367 #[test]
368 fn test_add_impl_with_trait_constraint() {
369 check_assist(
370 generate_impl,
371 r#"
372 pub trait Trait {}
373 struct Struct$0<T>
374 where
375 T: Trait,
376 {
377 inner: T,
378 }
379 "#,
380 r#"
381 pub trait Trait {}
382 struct Struct<T>
383 where
384 T: Trait,
385 {
386 inner: T,
387 }
388
389 impl<T> Struct<T>
390 where
391 T: Trait,
392 {$0
393 }
394 "#,
395 );
396 }
397
398 #[test]
399 fn add_impl_target() {
400 check_assist_target(
401 generate_impl,
402 r#"
403 struct SomeThingIrrelevant;
404 /// Has a lifetime parameter
405 struct Foo$0<'a, T: Foo<'a>> {}
406 struct EvenMoreIrrelevant;
407 "#,
408 "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
409 );
410 }
411
412 #[test]
413 fn test_add_trait_impl() {
414 check_assist(
415 generate_trait_impl,
416 r#"
417 struct Foo$0 {}
418 "#,
419 r#"
420 struct Foo {}
421
422 impl ${1:_} for Foo {$0}
423 "#,
424 );
425 }
426
427 #[test]
428 fn test_add_trait_impl_with_generics() {
429 check_assist(
430 generate_trait_impl,
431 r#"
432 struct Foo$0<T: Clone> {}
433 "#,
434 r#"
435 struct Foo<T: Clone> {}
436
437 impl<T: Clone> ${1:_} for Foo<T> {$0}
438 "#,
439 );
440 }
441
442 #[test]
443 fn test_add_trait_impl_with_generics_and_lifetime_parameters() {
444 check_assist(
445 generate_trait_impl,
446 r#"
447 struct Foo<'a, T: Foo<'a>>$0 {}
448 "#,
449 r#"
450 struct Foo<'a, T: Foo<'a>> {}
451
452 impl<'a, T: Foo<'a>> ${1:_} for Foo<'a, T> {$0}
453 "#,
454 );
455 }
456
457 #[test]
458 fn test_add_trait_impl_with_attributes() {
459 check_assist(
460 generate_trait_impl,
461 r#"
462 #[cfg(feature = "foo")]
463 struct Foo<'a, T: Foo$0<'a>> {}
464 "#,
465 r#"
466 #[cfg(feature = "foo")]
467 struct Foo<'a, T: Foo<'a>> {}
468
469 #[cfg(feature = "foo")]
470 impl<'a, T: Foo<'a>> ${1:_} for Foo<'a, T> {$0}
471 "#,
472 );
473 }
474
475 #[test]
476 fn test_add_trait_impl_with_default_generic() {
477 check_assist(
478 generate_trait_impl,
479 r#"
480 struct Defaulted$0<T = i32> {}
481 "#,
482 r#"
483 struct Defaulted<T = i32> {}
484
485 impl<T> ${1:_} for Defaulted<T> {$0}
486 "#,
487 );
488 }
489
490 #[test]
491 fn test_add_trait_impl_with_constrained_default_generic() {
492 check_assist(
493 generate_trait_impl,
494 r#"
495 struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
496 "#,
497 r#"
498 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
499
500 impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> ${1:_} for Defaulted<'a, 'b, T, S> {$0}
501 "#,
502 );
503 }
504
505 #[test]
506 fn test_add_trait_impl_with_const_defaulted_generic() {
507 check_assist(
508 generate_trait_impl,
509 r#"
510 struct Defaulted$0<const N: i32 = 0> {}
511 "#,
512 r#"
513 struct Defaulted<const N: i32 = 0> {}
514
515 impl<const N: i32> ${1:_} for Defaulted<N> {$0}
516 "#,
517 );
518 }
519
520 #[test]
521 fn test_add_trait_impl_with_trait_constraint() {
522 check_assist(
523 generate_trait_impl,
524 r#"
525 pub trait Trait {}
526 struct Struct$0<T>
527 where
528 T: Trait,
529 {
530 inner: T,
531 }
532 "#,
533 r#"
534 pub trait Trait {}
535 struct Struct<T>
536 where
537 T: Trait,
538 {
539 inner: T,
540 }
541
542 impl<T> ${1:_} for Struct<T>
543 where
544 T: Trait,
545 {$0
546 }
547 "#,
548 );
549 }
550
551 #[test]
552 fn add_trait_impl_target() {
553 check_assist_target(
554 generate_trait_impl,
555 r#"
556 struct SomeThingIrrelevant;
557 /// Has a lifetime parameter
558 struct Foo$0<'a, T: Foo<'a>> {}
559 struct EvenMoreIrrelevant;
560 "#,
561 "/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
562 );
563 }
564
565 #[test]
566 fn add_impl_with_indent() {
567 check_assist(
568 generate_impl,
569 r#"
570 mod foo {
571 struct Bar$0 {}
572 }
573 "#,
574 r#"
575 mod foo {
576 struct Bar {}
577
578 impl Bar {$0}
579 }
580 "#,
581 );
582 }
583
584 #[test]
585 fn add_impl_with_multiple_indent() {
586 check_assist(
587 generate_impl,
588 r#"
589 mod foo {
590 fn bar() {
591 struct Baz$0 {}
592 }
593 }
594 "#,
595 r#"
596 mod foo {
597 fn bar() {
598 struct Baz {}
599
600 impl Baz {$0}
601 }
602 }
603 "#,
604 );
605 }
606
607 #[test]
608 fn add_trait_impl_with_indent() {
609 check_assist(
610 generate_trait_impl,
611 r#"
612 mod foo {
613 struct Bar$0 {}
614 }
615 "#,
616 r#"
617 mod foo {
618 struct Bar {}
619
620 impl ${1:_} for Bar {$0}
621 }
622 "#,
623 );
624 }
625
626 #[test]
627 fn test_add_impl_trait() {
628 check_assist(
629 generate_impl_trait,
630 r#"
631 trait $0Foo {
632 fn foo(&self) -> i32;
633
634 fn bar(&self) -> i32 {
635 self.foo()
636 }
637 }
638 "#,
639 r#"
640 trait Foo {
641 fn foo(&self) -> i32;
642
643 fn bar(&self) -> i32 {
644 self.foo()
645 }
646 }
647
648 impl Foo for ${1:_} {
649 fn foo(&self) -> i32 {
650 $0todo!()
651 }
652 }
653 "#,
654 );
655 }
656
657 #[test]
658 fn test_add_impl_trait_use_generic() {
659 check_assist(
660 generate_impl_trait,
661 r#"
662 trait $0Foo<T> {
663 fn foo(&self) -> T;
664
665 fn bar(&self) -> T {
666 self.foo()
667 }
668 }
669 "#,
670 r#"
671 trait Foo<T> {
672 fn foo(&self) -> T;
673
674 fn bar(&self) -> T {
675 self.foo()
676 }
677 }
678
679 impl Foo<${1:_}> for ${2:_} {
680 fn foo(&self) -> _ {
681 $0todo!()
682 }
683 }
684 "#,
685 );
686 check_assist(
687 generate_impl_trait,
688 r#"
689 trait $0Foo<T, U> {
690 fn foo(&self) -> T;
691
692 fn bar(&self) -> T {
693 self.foo()
694 }
695 }
696 "#,
697 r#"
698 trait Foo<T, U> {
699 fn foo(&self) -> T;
700
701 fn bar(&self) -> T {
702 self.foo()
703 }
704 }
705
706 impl Foo<${1:_}, ${2:_}> for ${3:_} {
707 fn foo(&self) -> _ {
708 $0todo!()
709 }
710 }
711 "#,
712 );
713 }
714
715 #[test]
716 fn test_add_impl_trait_docs() {
717 check_assist(
718 generate_impl_trait,
719 r#"
720 /// foo
721 trait $0Foo {
722 /// foo method
723 fn foo(&self) -> i32;
724
725 fn bar(&self) -> i32 {
726 self.foo()
727 }
728 }
729 "#,
730 r#"
731 /// foo
732 trait Foo {
733 /// foo method
734 fn foo(&self) -> i32;
735
736 fn bar(&self) -> i32 {
737 self.foo()
738 }
739 }
740
741 impl Foo for ${1:_} {
742 fn foo(&self) -> i32 {
743 $0todo!()
744 }
745 }
746 "#,
747 );
748 }
749
750 #[test]
751 fn test_add_impl_trait_assoc_types() {
752 check_assist(
753 generate_impl_trait,
754 r#"
755 trait $0Foo {
756 type Output;
757
758 fn foo(&self) -> Self::Output;
759 }
760 "#,
761 r#"
762 trait Foo {
763 type Output;
764
765 fn foo(&self) -> Self::Output;
766 }
767
768 impl Foo for ${1:_} {
769 type Output;
770
771 fn foo(&self) -> Self::Output {
772 $0todo!()
773 }
774 }
775 "#,
776 );
777 }
778
779 #[test]
780 fn test_add_impl_trait_indent() {
781 check_assist(
782 generate_impl_trait,
783 r#"
784 mod foo {
785 mod bar {
786 trait $0Foo {
787 type Output;
788
789 fn foo(&self) -> Self::Output;
790 }
791 }
792 }
793 "#,
794 r#"
795 mod foo {
796 mod bar {
797 trait Foo {
798 type Output;
799
800 fn foo(&self) -> Self::Output;
801 }
802
803 impl Foo for ${1:_} {
804 type Output;
805
806 fn foo(&self) -> Self::Output {
807 $0todo!()
808 }
809 }
810 }
811 }
812 "#,
813 );
814 }
815
816 #[test]
817 fn test_add_impl_trait_empty() {
818 check_assist(
819 generate_impl_trait,
820 r#"
821 trait $0Foo {}
822 "#,
823 r#"
824 trait Foo {}
825
826 impl Foo for ${1:_} {$0}
827 "#,
828 );
829 }
830}