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