1 use ide_db::traits::resolve_target_trait;
2 use syntax::ast::{self, AstNode};
5 assist_context::{AssistContext, Assists},
7 add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods,
12 // Assist: add_impl_missing_members
14 // Adds scaffold for required impl members.
19 // fn foo(&self) -> T;
23 // impl Trait<u32> for () {$0
31 // fn foo(&self) -> T;
35 // impl Trait<u32> for () {
38 // fn foo(&self) -> u32 {
43 pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
44 add_missing_impl_members_inner(
48 "add_impl_missing_members",
49 "Implement missing members",
53 // Assist: add_impl_default_members
55 // Adds scaffold for overriding default impl members.
64 // impl Trait for () {
78 // impl Trait for () {
85 pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
86 add_missing_impl_members_inner(
90 "add_impl_default_members",
91 "Implement default members",
95 fn add_missing_impl_members_inner(
99 assist_id: &'static str,
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)?;
106 let missing_items = filter_assoc_items(
108 &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def),
112 if missing_items.is_empty() {
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()),
124 let mut cursor = Cursor::Before(first_new_item.syntax());
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!()" {
130 cursor = Cursor::Replace(placeholder.syntax());
134 builder.replace_snippet(
137 render_snippet(cap, new_impl_def.syntax(), cursor),
146 use crate::tests::{check_assist, check_assist_not_applicable};
151 fn test_add_missing_impl_members() {
153 add_missing_impl_members,
158 const CONST: usize = 42;
175 const CONST: usize = 42;
189 const CONST: usize = 42;
203 fn test_copied_overriden_members() {
205 add_missing_impl_members,
209 fn bar(&self) -> bool { true }
210 fn baz(&self) -> u32 { 42 }
222 fn bar(&self) -> bool { true }
223 fn baz(&self) -> u32 { 42 }
239 fn test_empty_impl_def() {
241 add_missing_impl_members,
243 trait Foo { fn foo(&self); }
245 impl Foo for S { $0 }"#,
247 trait Foo { fn foo(&self); }
258 fn test_impl_def_without_braces() {
260 add_missing_impl_members,
262 trait Foo { fn foo(&self); }
266 trait Foo { fn foo(&self); }
277 fn fill_in_type_params_1() {
279 add_missing_impl_members,
281 trait Foo<T> { fn foo(&self, t: T) -> &T; }
283 impl Foo<u32> for S { $0 }"#,
285 trait Foo<T> { fn foo(&self, t: T) -> &T; }
287 impl Foo<u32> for S {
288 fn foo(&self, t: u32) -> &u32 {
296 fn fill_in_type_params_2() {
298 add_missing_impl_members,
300 trait Foo<T> { fn foo(&self, t: T) -> &T; }
302 impl<U> Foo<U> for S { $0 }"#,
304 trait Foo<T> { fn foo(&self, t: T) -> &T; }
306 impl<U> Foo<U> for S {
307 fn foo(&self, t: U) -> &U {
315 fn test_cursor_after_empty_impl_def() {
317 add_missing_impl_members,
319 trait Foo { fn foo(&self); }
321 impl Foo for S {}$0"#,
323 trait Foo { fn foo(&self); }
334 fn test_qualify_path_1() {
336 add_missing_impl_members,
340 trait Foo { fn foo(&self, bar: Bar); }
343 impl foo::Foo for S { $0 }"#,
347 trait Foo { fn foo(&self, bar: Bar); }
350 impl foo::Foo for S {
351 fn foo(&self, bar: foo::Bar) {
359 fn test_qualify_path_2() {
361 add_missing_impl_members,
366 pub trait Foo { fn foo(&self, bar: Bar); }
373 impl bar::Foo for S { $0 }"#,
378 pub trait Foo { fn foo(&self, bar: Bar); }
385 impl bar::Foo for S {
386 fn foo(&self, bar: bar::Bar) {
394 fn test_qualify_path_generic() {
396 add_missing_impl_members,
400 trait Foo { fn foo(&self, bar: Bar<u32>); }
403 impl foo::Foo for S { $0 }"#,
407 trait Foo { fn foo(&self, bar: Bar<u32>); }
410 impl foo::Foo for S {
411 fn foo(&self, bar: foo::Bar<u32>) {
419 fn test_qualify_path_and_substitute_param() {
421 add_missing_impl_members,
425 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
428 impl foo::Foo<u32> for S { $0 }"#,
432 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
435 impl foo::Foo<u32> for S {
436 fn foo(&self, bar: foo::Bar<u32>) {
444 fn test_substitute_param_no_qualify() {
445 // when substituting params, the substituted param should not be qualified!
447 add_missing_impl_members,
450 trait Foo<T> { fn foo(&self, bar: T); }
455 impl foo::Foo<Param> for S { $0 }"#,
458 trait Foo<T> { fn foo(&self, bar: T); }
463 impl foo::Foo<Param> for S {
464 fn foo(&self, bar: Param) {
472 fn test_qualify_path_associated_item() {
474 add_missing_impl_members,
478 impl Bar<T> { type Assoc = u32; }
479 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
482 impl foo::Foo for S { $0 }"#,
486 impl Bar<T> { type Assoc = u32; }
487 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
490 impl foo::Foo for S {
491 fn foo(&self, bar: foo::Bar<u32>::Assoc) {
499 fn test_qualify_path_nested() {
501 add_missing_impl_members,
506 trait Foo { fn foo(&self, bar: Bar<Baz>); }
509 impl foo::Foo for S { $0 }"#,
514 trait Foo { fn foo(&self, bar: Bar<Baz>); }
517 impl foo::Foo for S {
518 fn foo(&self, bar: foo::Bar<foo::Baz>) {
526 fn test_qualify_path_fn_trait_notation() {
528 add_missing_impl_members,
531 pub trait Fn<Args> { type Output; }
532 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
535 impl foo::Foo for S { $0 }"#,
538 pub trait Fn<Args> { type Output; }
539 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
542 impl foo::Foo for S {
543 fn foo(&self, bar: dyn Fn(u32) -> i32) {
551 fn test_empty_trait() {
552 check_assist_not_applicable(
553 add_missing_impl_members,
557 impl Foo for S { $0 }"#,
562 fn test_ignore_unnamed_trait_members_and_default_methods() {
563 check_assist_not_applicable(
564 add_missing_impl_members,
568 fn valid(some: u32) -> bool { false }
571 impl Foo for S { $0 }"#,
576 fn test_with_docstring_and_attrs() {
578 add_missing_impl_members,
580 #[doc(alias = "test alias")]
589 impl Foo for S {}$0"#,
591 #[doc(alias = "test alias")]
611 fn test_default_methods() {
613 add_missing_default_members,
618 const CONST: usize = 42;
620 fn valid(some: u32) -> bool { false }
621 fn foo(some: u32) -> bool;
624 impl Foo for S { $0 }"#,
629 const CONST: usize = 42;
631 fn valid(some: u32) -> bool { false }
632 fn foo(some: u32) -> bool;
636 $0fn valid(some: u32) -> bool { false }
642 fn test_generic_single_default_parameter() {
644 add_missing_impl_members,
646 trait Foo<T = Self> {
647 fn bar(&self, other: &T);
651 impl Foo for S { $0 }"#,
653 trait Foo<T = Self> {
654 fn bar(&self, other: &T);
659 fn bar(&self, other: &Self) {
667 fn test_generic_default_parameter_is_second() {
669 add_missing_impl_members,
671 trait Foo<T1, T2 = Self> {
672 fn bar(&self, this: &T1, that: &T2);
676 impl Foo<T> for S<T> { $0 }"#,
678 trait Foo<T1, T2 = Self> {
679 fn bar(&self, this: &T1, that: &T2);
683 impl Foo<T> for S<T> {
684 fn bar(&self, this: &T, that: &Self) {
692 fn test_assoc_type_bounds_are_removed() {
694 add_missing_impl_members,
697 type Ty: Copy + 'static;
704 type Ty: Copy + 'static;
714 fn test_whitespace_fixup_preserves_bad_tokens() {
716 add_missing_impl_members,
740 fn test_whitespace_fixup_preserves_comments() {
742 add_missing_impl_members,
768 add_missing_impl_members,
771 fn foo(&self, x: crate)
779 fn foo(&self, x: crate)
782 fn foo(&self, x: crate) {
791 fn missing_generic_type() {
793 add_missing_impl_members,
796 fn foo(&self, bar: BAR);
804 fn foo(&self, bar: BAR);
807 fn foo(&self, bar: BAR) {