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