5 edit::{self, IndentLevel},
6 make, AstNode, NameOwner,
12 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
13 utils::{get_missing_assoc_items, resolve_target_trait},
14 Assist, AssistCtx, AssistId,
18 enum AddMissingImplMembersMode {
23 // Assist: add_impl_missing_members
25 // Adds scaffold for required impl members.
30 // fn foo(&self) -> T;
34 // impl Trait<u32> for () {<|>
42 // fn foo(&self) -> T;
46 // impl Trait<u32> for () {
47 // fn foo(&self) -> u32 {
53 pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option<Assist> {
54 add_missing_impl_members_inner(
56 AddMissingImplMembersMode::NoDefaultMethods,
57 "add_impl_missing_members",
58 "Implement missing members",
62 // Assist: add_impl_default_members
64 // Adds scaffold for overriding default impl members.
73 // impl Trait for () {
75 // fn foo(&self) {}<|>
87 // impl Trait for () {
94 pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option<Assist> {
95 add_missing_impl_members_inner(
97 AddMissingImplMembersMode::DefaultMethodsOnly,
98 "add_impl_default_members",
99 "Implement default members",
103 fn add_missing_impl_members_inner(
105 mode: AddMissingImplMembersMode,
106 assist_id: &'static str,
108 ) -> Option<Assist> {
109 let _p = ra_prof::profile("add_missing_impl_members_inner");
110 let impl_node = ctx.find_node_at_offset::<ast::ImplDef>()?;
111 let impl_item_list = impl_node.item_list()?;
113 let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?;
115 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
117 ast::AssocItem::FnDef(def) => def.name(),
118 ast::AssocItem::TypeAliasDef(def) => def.name(),
119 ast::AssocItem::ConstDef(def) => def.name(),
121 .map(|it| it.text().clone())
124 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_node)
127 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value),
128 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db).value),
129 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db).value),
131 .filter(|t| def_name(&t).is_some())
132 .filter(|t| match t {
133 ast::AssocItem::FnDef(def) => match mode {
134 AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(),
135 AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(),
137 _ => mode == AddMissingImplMembersMode::NoDefaultMethods,
139 .collect::<Vec<_>>();
141 if missing_items.is_empty() {
147 ctx.add_assist(AssistId(assist_id), label, |edit| {
148 let n_existing_items = impl_item_list.assoc_items().count();
149 let source_scope = sema.scope_for_def(trait_);
150 let target_scope = sema.scope(impl_item_list.syntax());
151 let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
152 .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node));
153 let items = missing_items
155 .map(|it| ast_transform::apply(&*ast_transform, it))
157 ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)),
160 .map(|it| edit::remove_attrs_and_docs(&it));
161 let new_impl_item_list = impl_item_list.append_items(items);
162 let cursor_position = {
163 let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap();
164 first_new_item.syntax().text_range().start()
167 edit.replace_ast(impl_item_list, new_impl_item_list);
168 edit.set_cursor(cursor_position);
172 fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
173 if fn_def.body().is_none() {
174 let body = make::block_expr(None, Some(make::expr_todo()));
175 let body = IndentLevel(1).increase_indent(body);
176 fn_def.with_body(body)
184 use crate::tests::{check_assist, check_assist_not_applicable};
189 fn test_add_missing_impl_members() {
191 add_missing_impl_members,
196 const CONST: usize = 42;
213 const CONST: usize = 42;
225 const CONST: usize = 42;
238 fn test_copied_overriden_members() {
240 add_missing_impl_members,
244 fn bar(&self) -> bool { true }
245 fn baz(&self) -> u32 { 42 }
257 fn bar(&self) -> bool { true }
258 fn baz(&self) -> u32 { 42 }
274 fn test_empty_impl_def() {
276 add_missing_impl_members,
278 trait Foo { fn foo(&self); }
280 impl Foo for S { <|> }"#,
282 trait Foo { fn foo(&self); }
293 fn fill_in_type_params_1() {
295 add_missing_impl_members,
297 trait Foo<T> { fn foo(&self, t: T) -> &T; }
299 impl Foo<u32> for S { <|> }"#,
301 trait Foo<T> { fn foo(&self, t: T) -> &T; }
303 impl Foo<u32> for S {
304 <|>fn foo(&self, t: u32) -> &u32 {
312 fn fill_in_type_params_2() {
314 add_missing_impl_members,
316 trait Foo<T> { fn foo(&self, t: T) -> &T; }
318 impl<U> Foo<U> for S { <|> }"#,
320 trait Foo<T> { fn foo(&self, t: T) -> &T; }
322 impl<U> Foo<U> for S {
323 <|>fn foo(&self, t: U) -> &U {
331 fn test_cursor_after_empty_impl_def() {
333 add_missing_impl_members,
335 trait Foo { fn foo(&self); }
337 impl Foo for S {}<|>"#,
339 trait Foo { fn foo(&self); }
350 fn test_qualify_path_1() {
352 add_missing_impl_members,
356 trait Foo { fn foo(&self, bar: Bar); }
359 impl foo::Foo for S { <|> }"#,
363 trait Foo { fn foo(&self, bar: Bar); }
366 impl foo::Foo for S {
367 <|>fn foo(&self, bar: foo::Bar) {
375 fn test_qualify_path_generic() {
377 add_missing_impl_members,
381 trait Foo { fn foo(&self, bar: Bar<u32>); }
384 impl foo::Foo for S { <|> }"#,
388 trait Foo { fn foo(&self, bar: Bar<u32>); }
391 impl foo::Foo for S {
392 <|>fn foo(&self, bar: foo::Bar<u32>) {
400 fn test_qualify_path_and_substitute_param() {
402 add_missing_impl_members,
406 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
409 impl foo::Foo<u32> for S { <|> }"#,
413 trait Foo<T> { fn foo(&self, bar: Bar<T>); }
416 impl foo::Foo<u32> for S {
417 <|>fn foo(&self, bar: foo::Bar<u32>) {
425 fn test_substitute_param_no_qualify() {
426 // when substituting params, the substituted param should not be qualified!
428 add_missing_impl_members,
431 trait Foo<T> { fn foo(&self, bar: T); }
436 impl foo::Foo<Param> for S { <|> }"#,
439 trait Foo<T> { fn foo(&self, bar: T); }
444 impl foo::Foo<Param> for S {
445 <|>fn foo(&self, bar: Param) {
453 fn test_qualify_path_associated_item() {
455 add_missing_impl_members,
459 impl Bar<T> { type Assoc = u32; }
460 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
463 impl foo::Foo for S { <|> }"#,
467 impl Bar<T> { type Assoc = u32; }
468 trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
471 impl foo::Foo for S {
472 <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) {
480 fn test_qualify_path_nested() {
482 add_missing_impl_members,
487 trait Foo { fn foo(&self, bar: Bar<Baz>); }
490 impl foo::Foo for S { <|> }"#,
495 trait Foo { fn foo(&self, bar: Bar<Baz>); }
498 impl foo::Foo for S {
499 <|>fn foo(&self, bar: foo::Bar<foo::Baz>) {
507 fn test_qualify_path_fn_trait_notation() {
509 add_missing_impl_members,
512 pub trait Fn<Args> { type Output; }
513 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
516 impl foo::Foo for S { <|> }"#,
519 pub trait Fn<Args> { type Output; }
520 trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
523 impl foo::Foo for S {
524 <|>fn foo(&self, bar: dyn Fn(u32) -> i32) {
532 fn test_empty_trait() {
533 check_assist_not_applicable(
534 add_missing_impl_members,
538 impl Foo for S { <|> }"#,
543 fn test_ignore_unnamed_trait_members_and_default_methods() {
544 check_assist_not_applicable(
545 add_missing_impl_members,
549 fn valid(some: u32) -> bool { false }
552 impl Foo for S { <|> }"#,
557 fn test_with_docstring_and_attrs() {
559 add_missing_impl_members,
561 #[doc(alias = "test alias")]
570 impl Foo for S {}<|>"#,
572 #[doc(alias = "test alias")]
591 fn test_default_methods() {
593 add_missing_default_members,
598 const CONST: usize = 42;
600 fn valid(some: u32) -> bool { false }
601 fn foo(some: u32) -> bool;
604 impl Foo for S { <|> }"#,
609 const CONST: usize = 42;
611 fn valid(some: u32) -> bool { false }
612 fn foo(some: u32) -> bool;
616 <|>fn valid(some: u32) -> bool { false }