Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/add_missing_impl_members.rs')
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs107
1 files changed, 84 insertions, 23 deletions
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 9f9d21923f..ab183ac708 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -2,6 +2,7 @@ use hir::HasSource;
use syntax::{
Edition,
ast::{self, AstNode, make},
+ syntax_editor::{Position, SyntaxEditor},
};
use crate::{
@@ -147,45 +148,78 @@ fn add_missing_impl_members_inner(
let target = impl_def.syntax().text_range();
acc.add(AssistId::quick_fix(assist_id), label, target, |edit| {
- let new_impl_def = edit.make_mut(impl_def.clone());
- let first_new_item = add_trait_assoc_items_to_impl(
+ let new_item = add_trait_assoc_items_to_impl(
&ctx.sema,
ctx.config,
&missing_items,
trait_,
- &new_impl_def,
+ &impl_def,
&target_scope,
);
+ let Some((first_new_item, other_items)) = new_item.split_first() else {
+ return;
+ };
+
+ let mut first_new_item = if let DefaultMethods::No = mode
+ && let ast::AssocItem::Fn(func) = &first_new_item
+ && let Some(body) = try_gen_trait_body(
+ ctx,
+ func,
+ trait_ref,
+ &impl_def,
+ target_scope.krate().edition(ctx.sema.db),
+ )
+ && let Some(func_body) = func.body()
+ {
+ let mut func_editor = SyntaxEditor::new(first_new_item.syntax().clone_subtree());
+ func_editor.replace(func_body.syntax(), body.syntax());
+ ast::AssocItem::cast(func_editor.finish().new_root().clone())
+ } else {
+ Some(first_new_item.clone())
+ };
+
+ let new_assoc_items = first_new_item
+ .clone()
+ .into_iter()
+ .chain(other_items.iter().cloned())
+ .map(either::Either::Right)
+ .collect::<Vec<_>>();
+
+ let mut editor = edit.make_editor(impl_def.syntax());
+ if let Some(assoc_item_list) = impl_def.assoc_item_list() {
+ let items = new_assoc_items.into_iter().filter_map(either::Either::right).collect();
+ assoc_item_list.add_items(&mut editor, items);
+ } else {
+ let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
+ editor.insert_all(
+ Position::after(impl_def.syntax()),
+ vec![make::tokens::whitespace(" ").into(), assoc_item_list.syntax().clone().into()],
+ );
+ first_new_item = assoc_item_list.assoc_items().next();
+ }
+
if let Some(cap) = ctx.config.snippet_cap {
let mut placeholder = None;
if let DefaultMethods::No = mode {
- if let ast::AssocItem::Fn(func) = &first_new_item {
- if try_gen_trait_body(
- ctx,
- func,
- trait_ref,
- &impl_def,
- target_scope.krate().edition(ctx.sema.db),
- )
- .is_none()
+ if let Some(ast::AssocItem::Fn(func)) = &first_new_item {
+ if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
+ && m.syntax().text() == "todo!()"
{
- if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
- {
- if m.syntax().text() == "todo!()" {
- placeholder = Some(m);
- }
- }
+ placeholder = Some(m);
}
}
}
if let Some(macro_call) = placeholder {
- edit.add_placeholder_snippet(cap, macro_call);
- } else {
- edit.add_tabstop_before(cap, first_new_item);
+ let placeholder = edit.make_placeholder_snippet(cap);
+ editor.add_annotation(macro_call.syntax(), placeholder);
+ } else if let Some(first_new_item) = first_new_item {
+ let tabstop = edit.make_tabstop_before(cap);
+ editor.add_annotation(first_new_item.syntax(), tabstop);
};
};
+ edit.add_file_edits(ctx.vfs_file_id(), editor);
})
}
@@ -195,7 +229,7 @@ fn try_gen_trait_body(
trait_ref: hir::TraitRef<'_>,
impl_def: &ast::Impl,
edition: Edition,
-) -> Option<()> {
+) -> Option<ast::BlockExpr> {
let trait_path = make::ext::ident_path(
&trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
);
@@ -322,7 +356,7 @@ impl Foo for S {
}
#[test]
- fn test_impl_def_without_braces() {
+ fn test_impl_def_without_braces_macro() {
check_assist(
add_missing_impl_members,
r#"
@@ -341,6 +375,33 @@ impl Foo for S {
}
#[test]
+ fn test_impl_def_without_braces_tabstop_first_item() {
+ check_assist(
+ add_missing_impl_members,
+ r#"
+trait Foo {
+ type Output;
+ fn foo(&self);
+}
+struct S;
+impl Foo for S { $0 }"#,
+ r#"
+trait Foo {
+ type Output;
+ fn foo(&self);
+}
+struct S;
+impl Foo for S {
+ $0type Output;
+
+ fn foo(&self) {
+ todo!()
+ }
+}"#,
+ );
+ }
+
+ #[test]
fn fill_in_type_params_1() {
check_assist(
add_missing_impl_members,