aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/add_missing_impl_members.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/add_missing_impl_members.rs')
-rw-r--r--crates/ide_assists/src/handlers/add_missing_impl_members.rs814
1 files changed, 814 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
new file mode 100644
index 000000000..63cea754d
--- /dev/null
+++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
@@ -0,0 +1,814 @@
1use ide_db::traits::resolve_target_trait;
2use syntax::ast::{self, AstNode};
3
4use crate::{
5 assist_context::{AssistContext, Assists},
6 utils::add_trait_assoc_items_to_impl,
7 utils::DefaultMethods,
8 utils::{filter_assoc_items, render_snippet, Cursor},
9 AssistId, AssistKind,
10};
11
12// Assist: add_impl_missing_members
13//
14// Adds scaffold for required impl members.
15//
16// ```
17// trait Trait<T> {
18// type X;
19// fn foo(&self) -> T;
20// fn bar(&self) {}
21// }
22//
23// impl Trait<u32> for () {$0
24//
25// }
26// ```
27// ->
28// ```
29// trait Trait<T> {
30// type X;
31// fn foo(&self) -> T;
32// fn bar(&self) {}
33// }
34//
35// impl Trait<u32> for () {
36// $0type X;
37//
38// fn foo(&self) -> u32 {
39// todo!()
40// }
41// }
42// ```
43pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
44 add_missing_impl_members_inner(
45 acc,
46 ctx,
47 DefaultMethods::No,
48 "add_impl_missing_members",
49 "Implement missing members",
50 )
51}
52
53// Assist: add_impl_default_members
54//
55// Adds scaffold for overriding default impl members.
56//
57// ```
58// trait Trait {
59// type X;
60// fn foo(&self);
61// fn bar(&self) {}
62// }
63//
64// impl Trait for () {
65// type X = ();
66// fn foo(&self) {}$0
67//
68// }
69// ```
70// ->
71// ```
72// trait Trait {
73// type X;
74// fn foo(&self);
75// fn bar(&self) {}
76// }
77//
78// impl Trait for () {
79// type X = ();
80// fn foo(&self) {}
81//
82// $0fn bar(&self) {}
83// }
84// ```
85pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
86 add_missing_impl_members_inner(
87 acc,
88 ctx,
89 DefaultMethods::Only,
90 "add_impl_default_members",
91 "Implement default members",
92 )
93}
94
95fn add_missing_impl_members_inner(
96 acc: &mut Assists,
97 ctx: &AssistContext,
98 mode: DefaultMethods,
99 assist_id: &'static str,
100 label: &'static str,
101) -> Option<()> {
102 let _p = profile::span("add_missing_impl_members_inner");
103 let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
104 let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
105
106 let missing_items = filter_assoc_items(
107 ctx.db(),
108 &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def),
109 mode,
110 );
111
112 if missing_items.is_empty() {
113 return None;
114 }
115
116 let target = impl_def.syntax().text_range();
117 acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
118 let target_scope = ctx.sema.scope(impl_def.syntax());
119 let (new_impl_def, first_new_item) =
120 add_trait_assoc_items_to_impl(&ctx.sema, missing_items, trait_, impl_def, target_scope);
121 match ctx.config.snippet_cap {
122 None => builder.replace(target, new_impl_def.to_string()),
123 Some(cap) => {
124 let mut cursor = Cursor::Before(first_new_item.syntax());
125 let placeholder;
126 if let ast::AssocItem::Fn(func) = &first_new_item {
127 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) {
128 if m.syntax().text() == "todo!()" {
129 placeholder = m;
130 cursor = Cursor::Replace(placeholder.syntax());
131 }
132 }
133 }
134 builder.replace_snippet(
135 cap,
136 target,
137 render_snippet(cap, new_impl_def.syntax(), cursor),
138 )
139 }
140 };
141 })
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::tests::{check_assist, check_assist_not_applicable};
147
148 use super::*;
149
150 #[test]
151 fn test_add_missing_impl_members() {
152 check_assist(
153 add_missing_impl_members,
154 r#"
155trait Foo {
156 type Output;
157
158 const CONST: usize = 42;
159
160 fn foo(&self);
161 fn bar(&self);
162 fn baz(&self);
163}
164
165struct S;
166
167impl Foo for S {
168 fn bar(&self) {}
169$0
170}"#,
171 r#"
172trait Foo {
173 type Output;
174
175 const CONST: usize = 42;
176
177 fn foo(&self);
178 fn bar(&self);
179 fn baz(&self);
180}
181
182struct S;
183
184impl Foo for S {
185 fn bar(&self) {}
186
187 $0type Output;
188
189 const CONST: usize = 42;
190
191 fn foo(&self) {
192 todo!()
193 }
194
195 fn baz(&self) {
196 todo!()
197 }
198}"#,
199 );
200 }
201
202 #[test]
203 fn test_copied_overriden_members() {
204 check_assist(
205 add_missing_impl_members,
206 r#"
207trait Foo {
208 fn foo(&self);
209 fn bar(&self) -> bool { true }
210 fn baz(&self) -> u32 { 42 }
211}
212
213struct S;
214
215impl Foo for S {
216 fn bar(&self) {}
217$0
218}"#,
219 r#"
220trait Foo {
221 fn foo(&self);
222 fn bar(&self) -> bool { true }
223 fn baz(&self) -> u32 { 42 }
224}
225
226struct S;
227
228impl Foo for S {
229 fn bar(&self) {}
230
231 fn foo(&self) {
232 ${0:todo!()}
233 }
234}"#,
235 );
236 }
237
238 #[test]
239 fn test_empty_impl_def() {
240 check_assist(
241 add_missing_impl_members,
242 r#"
243trait Foo { fn foo(&self); }
244struct S;
245impl Foo for S { $0 }"#,
246 r#"
247trait Foo { fn foo(&self); }
248struct S;
249impl Foo for S {
250 fn foo(&self) {
251 ${0:todo!()}
252 }
253}"#,
254 );
255 }
256
257 #[test]
258 fn test_impl_def_without_braces() {
259 check_assist(
260 add_missing_impl_members,
261 r#"
262trait Foo { fn foo(&self); }
263struct S;
264impl Foo for S$0"#,
265 r#"
266trait Foo { fn foo(&self); }
267struct S;
268impl Foo for S {
269 fn foo(&self) {
270 ${0:todo!()}
271 }
272}"#,
273 );
274 }
275
276 #[test]
277 fn fill_in_type_params_1() {
278 check_assist(
279 add_missing_impl_members,
280 r#"
281trait Foo<T> { fn foo(&self, t: T) -> &T; }
282struct S;
283impl Foo<u32> for S { $0 }"#,
284 r#"
285trait Foo<T> { fn foo(&self, t: T) -> &T; }
286struct S;
287impl Foo<u32> for S {
288 fn foo(&self, t: u32) -> &u32 {
289 ${0:todo!()}
290 }
291}"#,
292 );
293 }
294
295 #[test]
296 fn fill_in_type_params_2() {
297 check_assist(
298 add_missing_impl_members,
299 r#"
300trait Foo<T> { fn foo(&self, t: T) -> &T; }
301struct S;
302impl<U> Foo<U> for S { $0 }"#,
303 r#"
304trait Foo<T> { fn foo(&self, t: T) -> &T; }
305struct S;
306impl<U> Foo<U> for S {
307 fn foo(&self, t: U) -> &U {
308 ${0:todo!()}
309 }
310}"#,
311 );
312 }
313
314 #[test]
315 fn test_cursor_after_empty_impl_def() {
316 check_assist(
317 add_missing_impl_members,
318 r#"
319trait Foo { fn foo(&self); }
320struct S;
321impl Foo for S {}$0"#,
322 r#"
323trait Foo { fn foo(&self); }
324struct S;
325impl Foo for S {
326 fn foo(&self) {
327 ${0:todo!()}
328 }
329}"#,
330 )
331 }
332
333 #[test]
334 fn test_qualify_path_1() {
335 check_assist(
336 add_missing_impl_members,
337 r#"
338mod foo {
339 pub struct Bar;
340 trait Foo { fn foo(&self, bar: Bar); }
341}
342struct S;
343impl foo::Foo for S { $0 }"#,
344 r#"
345mod foo {
346 pub struct Bar;
347 trait Foo { fn foo(&self, bar: Bar); }
348}
349struct S;
350impl foo::Foo for S {
351 fn foo(&self, bar: foo::Bar) {
352 ${0:todo!()}
353 }
354}"#,
355 );
356 }
357
358 #[test]
359 fn test_qualify_path_2() {
360 check_assist(
361 add_missing_impl_members,
362 r#"
363mod foo {
364 pub mod bar {
365 pub struct Bar;
366 pub trait Foo { fn foo(&self, bar: Bar); }
367 }
368}
369
370use foo::bar;
371
372struct S;
373impl bar::Foo for S { $0 }"#,
374 r#"
375mod foo {
376 pub mod bar {
377 pub struct Bar;
378 pub trait Foo { fn foo(&self, bar: Bar); }
379 }
380}
381
382use foo::bar;
383
384struct S;
385impl bar::Foo for S {
386 fn foo(&self, bar: bar::Bar) {
387 ${0:todo!()}
388 }
389}"#,
390 );
391 }
392
393 #[test]
394 fn test_qualify_path_generic() {
395 check_assist(
396 add_missing_impl_members,
397 r#"
398mod foo {
399 pub struct Bar<T>;
400 trait Foo { fn foo(&self, bar: Bar<u32>); }
401}
402struct S;
403impl foo::Foo for S { $0 }"#,
404 r#"
405mod foo {
406 pub struct Bar<T>;
407 trait Foo { fn foo(&self, bar: Bar<u32>); }
408}
409struct S;
410impl foo::Foo for S {
411 fn foo(&self, bar: foo::Bar<u32>) {
412 ${0:todo!()}
413 }
414}"#,
415 );
416 }
417
418 #[test]
419 fn test_qualify_path_and_substitute_param() {
420 check_assist(
421 add_missing_impl_members,
422 r#"
423mod foo {
424 pub struct Bar<T>;
425 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
426}
427struct S;
428impl foo::Foo<u32> for S { $0 }"#,
429 r#"
430mod foo {
431 pub struct Bar<T>;
432 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
433}
434struct S;
435impl foo::Foo<u32> for S {
436 fn foo(&self, bar: foo::Bar<u32>) {
437 ${0:todo!()}
438 }
439}"#,
440 );
441 }
442
443 #[test]
444 fn test_substitute_param_no_qualify() {
445 // when substituting params, the substituted param should not be qualified!
446 check_assist(
447 add_missing_impl_members,
448 r#"
449mod foo {
450 trait Foo<T> { fn foo(&self, bar: T); }
451 pub struct Param;
452}
453struct Param;
454struct S;
455impl foo::Foo<Param> for S { $0 }"#,
456 r#"
457mod foo {
458 trait Foo<T> { fn foo(&self, bar: T); }
459 pub struct Param;
460}
461struct Param;
462struct S;
463impl foo::Foo<Param> for S {
464 fn foo(&self, bar: Param) {
465 ${0:todo!()}
466 }
467}"#,
468 );
469 }
470
471 #[test]
472 fn test_qualify_path_associated_item() {
473 check_assist(
474 add_missing_impl_members,
475 r#"
476mod foo {
477 pub struct Bar<T>;
478 impl Bar<T> { type Assoc = u32; }
479 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
480}
481struct S;
482impl foo::Foo for S { $0 }"#,
483 r#"
484mod foo {
485 pub struct Bar<T>;
486 impl Bar<T> { type Assoc = u32; }
487 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
488}
489struct S;
490impl foo::Foo for S {
491 fn foo(&self, bar: foo::Bar<u32>::Assoc) {
492 ${0:todo!()}
493 }
494}"#,
495 );
496 }
497
498 #[test]
499 fn test_qualify_path_nested() {
500 check_assist(
501 add_missing_impl_members,
502 r#"
503mod foo {
504 pub struct Bar<T>;
505 pub struct Baz;
506 trait Foo { fn foo(&self, bar: Bar<Baz>); }
507}
508struct S;
509impl foo::Foo for S { $0 }"#,
510 r#"
511mod foo {
512 pub struct Bar<T>;
513 pub struct Baz;
514 trait Foo { fn foo(&self, bar: Bar<Baz>); }
515}
516struct S;
517impl foo::Foo for S {
518 fn foo(&self, bar: foo::Bar<foo::Baz>) {
519 ${0:todo!()}
520 }
521}"#,
522 );
523 }
524
525 #[test]
526 fn test_qualify_path_fn_trait_notation() {
527 check_assist(
528 add_missing_impl_members,
529 r#"
530mod foo {
531 pub trait Fn<Args> { type Output; }
532 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
533}
534struct S;
535impl foo::Foo for S { $0 }"#,
536 r#"
537mod foo {
538 pub trait Fn<Args> { type Output; }
539 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
540}
541struct S;
542impl foo::Foo for S {
543 fn foo(&self, bar: dyn Fn(u32) -> i32) {
544 ${0:todo!()}
545 }
546}"#,
547 );
548 }
549
550 #[test]
551 fn test_empty_trait() {
552 check_assist_not_applicable(
553 add_missing_impl_members,
554 r#"
555trait Foo;
556struct S;
557impl Foo for S { $0 }"#,
558 )
559 }
560
561 #[test]
562 fn test_ignore_unnamed_trait_members_and_default_methods() {
563 check_assist_not_applicable(
564 add_missing_impl_members,
565 r#"
566trait Foo {
567 fn (arg: u32);
568 fn valid(some: u32) -> bool { false }
569}
570struct S;
571impl Foo for S { $0 }"#,
572 )
573 }
574
575 #[test]
576 fn test_with_docstring_and_attrs() {
577 check_assist(
578 add_missing_impl_members,
579 r#"
580#[doc(alias = "test alias")]
581trait Foo {
582 /// doc string
583 type Output;
584
585 #[must_use]
586 fn foo(&self);
587}
588struct S;
589impl Foo for S {}$0"#,
590 r#"
591#[doc(alias = "test alias")]
592trait Foo {
593 /// doc string
594 type Output;
595
596 #[must_use]
597 fn foo(&self);
598}
599struct S;
600impl Foo for S {
601 $0type Output;
602
603 fn foo(&self) {
604 todo!()
605 }
606}"#,
607 )
608 }
609
610 #[test]
611 fn test_default_methods() {
612 check_assist(
613 add_missing_default_members,
614 r#"
615trait Foo {
616 type Output;
617
618 const CONST: usize = 42;
619
620 fn valid(some: u32) -> bool { false }
621 fn foo(some: u32) -> bool;
622}
623struct S;
624impl Foo for S { $0 }"#,
625 r#"
626trait Foo {
627 type Output;
628
629 const CONST: usize = 42;
630
631 fn valid(some: u32) -> bool { false }
632 fn foo(some: u32) -> bool;
633}
634struct S;
635impl Foo for S {
636 $0fn valid(some: u32) -> bool { false }
637}"#,
638 )
639 }
640
641 #[test]
642 fn test_generic_single_default_parameter() {
643 check_assist(
644 add_missing_impl_members,
645 r#"
646trait Foo<T = Self> {
647 fn bar(&self, other: &T);
648}
649
650struct S;
651impl Foo for S { $0 }"#,
652 r#"
653trait Foo<T = Self> {
654 fn bar(&self, other: &T);
655}
656
657struct S;
658impl Foo for S {
659 fn bar(&self, other: &Self) {
660 ${0:todo!()}
661 }
662}"#,
663 )
664 }
665
666 #[test]
667 fn test_generic_default_parameter_is_second() {
668 check_assist(
669 add_missing_impl_members,
670 r#"
671trait Foo<T1, T2 = Self> {
672 fn bar(&self, this: &T1, that: &T2);
673}
674
675struct S<T>;
676impl Foo<T> for S<T> { $0 }"#,
677 r#"
678trait Foo<T1, T2 = Self> {
679 fn bar(&self, this: &T1, that: &T2);
680}
681
682struct S<T>;
683impl Foo<T> for S<T> {
684 fn bar(&self, this: &T, that: &Self) {
685 ${0:todo!()}
686 }
687}"#,
688 )
689 }
690
691 #[test]
692 fn test_assoc_type_bounds_are_removed() {
693 check_assist(
694 add_missing_impl_members,
695 r#"
696trait Tr {
697 type Ty: Copy + 'static;
698}
699
700impl Tr for ()$0 {
701}"#,
702 r#"
703trait Tr {
704 type Ty: Copy + 'static;
705}
706
707impl Tr for () {
708 $0type Ty;
709}"#,
710 )
711 }
712
713 #[test]
714 fn test_whitespace_fixup_preserves_bad_tokens() {
715 check_assist(
716 add_missing_impl_members,
717 r#"
718trait Tr {
719 fn foo();
720}
721
722impl Tr for ()$0 {
723 +++
724}"#,
725 r#"
726trait Tr {
727 fn foo();
728}
729
730impl Tr for () {
731 fn foo() {
732 ${0:todo!()}
733 }
734 +++
735}"#,
736 )
737 }
738
739 #[test]
740 fn test_whitespace_fixup_preserves_comments() {
741 check_assist(
742 add_missing_impl_members,
743 r#"
744trait Tr {
745 fn foo();
746}
747
748impl Tr for ()$0 {
749 // very important
750}"#,
751 r#"
752trait Tr {
753 fn foo();
754}
755
756impl Tr for () {
757 fn foo() {
758 ${0:todo!()}
759 }
760 // very important
761}"#,
762 )
763 }
764
765 #[test]
766 fn weird_path() {
767 check_assist(
768 add_missing_impl_members,
769 r#"
770trait Test {
771 fn foo(&self, x: crate)
772}
773impl Test for () {
774 $0
775}
776"#,
777 r#"
778trait Test {
779 fn foo(&self, x: crate)
780}
781impl Test for () {
782 fn foo(&self, x: crate) {
783 ${0:todo!()}
784 }
785}
786"#,
787 )
788 }
789
790 #[test]
791 fn missing_generic_type() {
792 check_assist(
793 add_missing_impl_members,
794 r#"
795trait Foo<BAR> {
796 fn foo(&self, bar: BAR);
797}
798impl Foo for () {
799 $0
800}
801"#,
802 r#"
803trait Foo<BAR> {
804 fn foo(&self, bar: BAR);
805}
806impl Foo for () {
807 fn foo(&self, bar: BAR) {
808 ${0:todo!()}
809 }
810}
811"#,
812 )
813 }
814}