]> git.lizzy.rs Git - rust.git/blob - crates/ide_assists/src/handlers/add_missing_impl_members.rs
Merge #8159
[rust.git] / crates / ide_assists / src / handlers / add_missing_impl_members.rs
1 use ide_db::traits::resolve_target_trait;
2 use syntax::ast::{self, AstNode};
3
4 use crate::{
5     assist_context::{AssistContext, Assists},
6     utils::{
7         add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods,
8     },
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 // ```
43 pub(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 // ```
85 pub(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
95 fn 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)]
145 mod 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#"
155 trait 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
165 struct S;
166
167 impl Foo for S {
168     fn bar(&self) {}
169 $0
170 }"#,
171             r#"
172 trait 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
182 struct S;
183
184 impl 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#"
207 trait Foo {
208     fn foo(&self);
209     fn bar(&self) -> bool { true }
210     fn baz(&self) -> u32 { 42 }
211 }
212
213 struct S;
214
215 impl Foo for S {
216     fn bar(&self) {}
217 $0
218 }"#,
219             r#"
220 trait Foo {
221     fn foo(&self);
222     fn bar(&self) -> bool { true }
223     fn baz(&self) -> u32 { 42 }
224 }
225
226 struct S;
227
228 impl 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#"
243 trait Foo { fn foo(&self); }
244 struct S;
245 impl Foo for S { $0 }"#,
246             r#"
247 trait Foo { fn foo(&self); }
248 struct S;
249 impl 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#"
262 trait Foo { fn foo(&self); }
263 struct S;
264 impl Foo for S$0"#,
265             r#"
266 trait Foo { fn foo(&self); }
267 struct S;
268 impl 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#"
281 trait Foo<T> { fn foo(&self, t: T) -> &T; }
282 struct S;
283 impl Foo<u32> for S { $0 }"#,
284             r#"
285 trait Foo<T> { fn foo(&self, t: T) -> &T; }
286 struct S;
287 impl 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#"
300 trait Foo<T> { fn foo(&self, t: T) -> &T; }
301 struct S;
302 impl<U> Foo<U> for S { $0 }"#,
303             r#"
304 trait Foo<T> { fn foo(&self, t: T) -> &T; }
305 struct S;
306 impl<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#"
319 trait Foo { fn foo(&self); }
320 struct S;
321 impl Foo for S {}$0"#,
322             r#"
323 trait Foo { fn foo(&self); }
324 struct S;
325 impl 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#"
338 mod foo {
339     pub struct Bar;
340     trait Foo { fn foo(&self, bar: Bar); }
341 }
342 struct S;
343 impl foo::Foo for S { $0 }"#,
344             r#"
345 mod foo {
346     pub struct Bar;
347     trait Foo { fn foo(&self, bar: Bar); }
348 }
349 struct S;
350 impl 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#"
363 mod foo {
364     pub mod bar {
365         pub struct Bar;
366         pub trait Foo { fn foo(&self, bar: Bar); }
367     }
368 }
369
370 use foo::bar;
371
372 struct S;
373 impl bar::Foo for S { $0 }"#,
374             r#"
375 mod foo {
376     pub mod bar {
377         pub struct Bar;
378         pub trait Foo { fn foo(&self, bar: Bar); }
379     }
380 }
381
382 use foo::bar;
383
384 struct S;
385 impl 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#"
398 mod foo {
399     pub struct Bar<T>;
400     trait Foo { fn foo(&self, bar: Bar<u32>); }
401 }
402 struct S;
403 impl foo::Foo for S { $0 }"#,
404             r#"
405 mod foo {
406     pub struct Bar<T>;
407     trait Foo { fn foo(&self, bar: Bar<u32>); }
408 }
409 struct S;
410 impl 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#"
423 mod foo {
424     pub struct Bar<T>;
425     trait Foo<T> { fn foo(&self, bar: Bar<T>); }
426 }
427 struct S;
428 impl foo::Foo<u32> for S { $0 }"#,
429             r#"
430 mod foo {
431     pub struct Bar<T>;
432     trait Foo<T> { fn foo(&self, bar: Bar<T>); }
433 }
434 struct S;
435 impl 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#"
449 mod foo {
450     trait Foo<T> { fn foo(&self, bar: T); }
451     pub struct Param;
452 }
453 struct Param;
454 struct S;
455 impl foo::Foo<Param> for S { $0 }"#,
456             r#"
457 mod foo {
458     trait Foo<T> { fn foo(&self, bar: T); }
459     pub struct Param;
460 }
461 struct Param;
462 struct S;
463 impl 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#"
476 mod foo {
477     pub struct Bar<T>;
478     impl Bar<T> { type Assoc = u32; }
479     trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
480 }
481 struct S;
482 impl foo::Foo for S { $0 }"#,
483             r#"
484 mod foo {
485     pub struct Bar<T>;
486     impl Bar<T> { type Assoc = u32; }
487     trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
488 }
489 struct S;
490 impl 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#"
503 mod foo {
504     pub struct Bar<T>;
505     pub struct Baz;
506     trait Foo { fn foo(&self, bar: Bar<Baz>); }
507 }
508 struct S;
509 impl foo::Foo for S { $0 }"#,
510             r#"
511 mod foo {
512     pub struct Bar<T>;
513     pub struct Baz;
514     trait Foo { fn foo(&self, bar: Bar<Baz>); }
515 }
516 struct S;
517 impl 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#"
530 mod foo {
531     pub trait Fn<Args> { type Output; }
532     trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
533 }
534 struct S;
535 impl foo::Foo for S { $0 }"#,
536             r#"
537 mod foo {
538     pub trait Fn<Args> { type Output; }
539     trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
540 }
541 struct S;
542 impl 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#"
555 trait Foo;
556 struct S;
557 impl 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#"
566 trait Foo {
567     fn (arg: u32);
568     fn valid(some: u32) -> bool { false }
569 }
570 struct S;
571 impl 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")]
581 trait Foo {
582     /// doc string
583     type Output;
584
585     #[must_use]
586     fn foo(&self);
587 }
588 struct S;
589 impl Foo for S {}$0"#,
590             r#"
591 #[doc(alias = "test alias")]
592 trait Foo {
593     /// doc string
594     type Output;
595
596     #[must_use]
597     fn foo(&self);
598 }
599 struct S;
600 impl 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#"
615 trait 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 }
623 struct S;
624 impl Foo for S { $0 }"#,
625             r#"
626 trait 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 }
634 struct S;
635 impl 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#"
646 trait Foo<T = Self> {
647     fn bar(&self, other: &T);
648 }
649
650 struct S;
651 impl Foo for S { $0 }"#,
652             r#"
653 trait Foo<T = Self> {
654     fn bar(&self, other: &T);
655 }
656
657 struct S;
658 impl 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#"
671 trait Foo<T1, T2 = Self> {
672     fn bar(&self, this: &T1, that: &T2);
673 }
674
675 struct S<T>;
676 impl Foo<T> for S<T> { $0 }"#,
677             r#"
678 trait Foo<T1, T2 = Self> {
679     fn bar(&self, this: &T1, that: &T2);
680 }
681
682 struct S<T>;
683 impl 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#"
696 trait Tr {
697     type Ty: Copy + 'static;
698 }
699
700 impl Tr for ()$0 {
701 }"#,
702             r#"
703 trait Tr {
704     type Ty: Copy + 'static;
705 }
706
707 impl 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#"
718 trait Tr {
719     fn foo();
720 }
721
722 impl Tr for ()$0 {
723     +++
724 }"#,
725             r#"
726 trait Tr {
727     fn foo();
728 }
729
730 impl 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#"
744 trait Tr {
745     fn foo();
746 }
747
748 impl Tr for ()$0 {
749     // very important
750 }"#,
751             r#"
752 trait Tr {
753     fn foo();
754 }
755
756 impl 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#"
770 trait Test {
771     fn foo(&self, x: crate)
772 }
773 impl Test for () {
774     $0
775 }
776 "#,
777             r#"
778 trait Test {
779     fn foo(&self, x: crate)
780 }
781 impl 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#"
795 trait Foo<BAR> {
796     fn foo(&self, bar: BAR);
797 }
798 impl Foo for () {
799     $0
800 }
801 "#,
802             r#"
803 trait Foo<BAR> {
804     fn foo(&self, bar: BAR);
805 }
806 impl Foo for () {
807     fn foo(&self, bar: BAR) {
808         ${0:todo!()}
809     }
810 }
811 "#,
812         )
813     }
814 }