X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Fide_assists%2Fsrc%2Fhandlers%2Fadd_missing_impl_members.rs;h=a10eca10d11946c1b350b0e1189b56c2d91d2de1;hb=749eeef3e75a3acc993fdd454ebadaa7e319509a;hp=0148635f9eba29eb69a509966976a7132df8362d;hpb=e33959a8889104f6bda06755df9ade933aadcf4f;p=rust.git diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs index 0148635f9eb..a10eca10d11 100644 --- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs @@ -1,10 +1,12 @@ -use ide_db::traits::resolve_target_trait; -use syntax::ast::{self, AstNode}; +use hir::HasSource; +use ide_db::{helpers::insert_whitespace_into_node::insert_ws_into, traits::resolve_target_trait}; +use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, + add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, render_snippet, + Cursor, DefaultMethods, }, AssistId, AssistKind, }; @@ -64,7 +66,6 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - // impl Trait for () { // type X = (); // fn foo(&self) {}$0 -// // } // ``` // -> @@ -104,7 +105,7 @@ fn add_missing_impl_members_inner( let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; let missing_items = filter_assoc_items( - ctx.db(), + &ctx.sema, &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def), mode, ); @@ -116,18 +117,37 @@ fn add_missing_impl_members_inner( let target = impl_def.syntax().text_range(); acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { let target_scope = ctx.sema.scope(impl_def.syntax()); - let (new_impl_def, first_new_item) = - add_trait_assoc_items_to_impl(&ctx.sema, missing_items, trait_, impl_def, target_scope); + let missing_items = missing_items + .into_iter() + .map(|it| { + if ctx.sema.hir_file_for(it.syntax()).is_macro() { + if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) { + return it; + } + } + it.clone_for_update() + }) + .collect(); + let (new_impl_def, first_new_item) = add_trait_assoc_items_to_impl( + &ctx.sema, + missing_items, + trait_, + impl_def.clone(), + target_scope, + ); match ctx.config.snippet_cap { None => builder.replace(target, new_impl_def.to_string()), Some(cap) => { let mut cursor = Cursor::Before(first_new_item.syntax()); let placeholder; if let ast::AssocItem::Fn(func) = &first_new_item { - if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { - if m.syntax().text() == "todo!()" { - placeholder = m; - cursor = Cursor::Replace(placeholder.syntax()); + if try_gen_trait_body(ctx, func, &trait_, &impl_def).is_none() { + if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) + { + if m.syntax().text() == "todo!()" { + placeholder = m; + cursor = Cursor::Replace(placeholder.syntax()); + } } } } @@ -141,6 +161,18 @@ fn add_missing_impl_members_inner( }) } +fn try_gen_trait_body( + ctx: &AssistContext, + func: &ast::Fn, + trait_: &hir::Trait, + impl_def: &ast::Impl, +) -> Option<()> { + let trait_path = make::ext::ident_path(&trait_.name(ctx.db()).to_string()); + let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; + let adt = hir_ty.as_adt()?.source(ctx.db())?; + gen_trait_fn_body(func, &trait_path, &adt.value) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -195,6 +227,7 @@ fn foo(&self) { fn baz(&self) { todo!() } + }"#, ); } @@ -231,6 +264,7 @@ fn bar(&self) {} fn foo(&self) { ${0:todo!()} } + }"#, ); } @@ -808,6 +842,103 @@ fn foo(&self, bar: BAR) { ${0:todo!()} } } +"#, + ) + } + + #[test] + fn does_not_requalify_self_as_crate() { + check_assist( + add_missing_default_members, + r" +struct Wrapper(T); + +trait T { + fn f(self) -> Wrapper { + Wrapper(self) + } +} + +impl T for () { + $0 +} +", + r" +struct Wrapper(T); + +trait T { + fn f(self) -> Wrapper { + Wrapper(self) + } +} + +impl T for () { + $0fn f(self) -> Wrapper { + Wrapper(self) + } +} +", + ); + } + + #[test] + fn test_default_body_generation() { + check_assist( + add_missing_impl_members, + r#" +//- minicore: default +struct Foo(usize); + +impl Default for Foo { + $0 +} +"#, + r#" +struct Foo(usize); + +impl Default for Foo { + $0fn default() -> Self { + Self(Default::default()) + } +} +"#, + ) + } + + #[test] + fn test_from_macro() { + check_assist( + add_missing_default_members, + r#" +macro_rules! foo { + () => { + trait FooB { + fn foo<'lt>(&'lt self) {} + } + } +} +foo!(); +struct Foo(usize); + +impl FooB for Foo { + $0 +} +"#, + r#" +macro_rules! foo { + () => { + trait FooB { + fn foo<'lt>(&'lt self) {} + } + } +} +foo!(); +struct Foo(usize); + +impl FooB for Foo { + $0fn foo< 'lt>(& 'lt self){} + +} "#, ) }