Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/generate_trait_from_impl.rs')
-rw-r--r--crates/ide-assists/src/handlers/generate_trait_from_impl.rs87
1 files changed, 44 insertions, 43 deletions
diff --git a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 92a4bd35b3..56500cf068 100644
--- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -2,12 +2,8 @@ use crate::assist_context::{AssistContext, Assists};
use ide_db::assists::AssistId;
use syntax::{
AstNode, SyntaxKind, T,
- ast::{
- self, HasGenericParams, HasName, HasVisibility,
- edit_in_place::{HasVisibilityEdit, Indent},
- make,
- },
- ted::{self, Position},
+ ast::{self, HasGenericParams, HasName, HasVisibility, edit_in_place::Indent, make},
+ syntax_editor::{Position, SyntaxEditor},
};
// NOTES :
@@ -88,8 +84,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
return None;
}
- let assoc_items = impl_ast.assoc_item_list()?;
- let first_element = assoc_items.assoc_items().next();
+ let impl_assoc_items = impl_ast.assoc_item_list()?;
+ let first_element = impl_assoc_items.assoc_items().next();
first_element.as_ref()?;
let impl_name = impl_ast.self_ty()?;
@@ -99,20 +95,16 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
"Generate trait from impl",
impl_ast.syntax().text_range(),
|builder| {
- let impl_ast = builder.make_mut(impl_ast);
- let trait_items = assoc_items.clone_for_update();
- let impl_items = builder.make_mut(assoc_items);
- let impl_name = builder.make_mut(impl_name);
-
- trait_items.assoc_items().for_each(|item| {
- strip_body(&item);
- remove_items_visibility(&item);
- });
-
- impl_items.assoc_items().for_each(|item| {
- remove_items_visibility(&item);
- });
-
+ let trait_items: ast::AssocItemList = {
+ let trait_items = impl_assoc_items.clone_subtree();
+ let mut trait_items_editor = SyntaxEditor::new(trait_items.syntax().clone());
+
+ trait_items.assoc_items().for_each(|item| {
+ strip_body(&mut trait_items_editor, &item);
+ remove_items_visibility(&mut trait_items_editor, &item);
+ });
+ ast::AssocItemList::cast(trait_items_editor.finish().new_root().clone()).unwrap()
+ };
let trait_ast = make::trait_(
false,
"NewTrait",
@@ -130,6 +122,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
trait_name_ref.syntax().clone().into(),
make::tokens::single_space().into(),
make::token(T![for]).into(),
+ make::tokens::single_space().into(),
];
if let Some(params) = impl_ast.generic_param_list() {
@@ -137,10 +130,15 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
elements.insert(1, gen_args.syntax().clone().into());
}
- ted::insert_all(Position::before(impl_name.syntax()), elements);
+ let mut editor = builder.make_editor(impl_ast.syntax());
+ impl_assoc_items.assoc_items().for_each(|item| {
+ remove_items_visibility(&mut editor, &item);
+ });
+
+ editor.insert_all(Position::before(impl_name.syntax()), elements);
// Insert trait before TraitImpl
- ted::insert_all_raw(
+ editor.insert_all(
Position::before(impl_ast.syntax()),
vec![
trait_ast.syntax().clone().into(),
@@ -150,11 +148,12 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
// Link the trait name & trait ref names together as a placeholder snippet group
if let Some(cap) = ctx.config.snippet_cap {
- builder.add_placeholder_snippet_group(
- cap,
- vec![trait_name.syntax().clone(), trait_name_ref.syntax().clone()],
- );
+ let placeholder = builder.make_placeholder_snippet(cap);
+ editor.add_annotation(trait_name.syntax(), placeholder);
+ editor.add_annotation(trait_name_ref.syntax(), placeholder);
}
+
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
},
);
@@ -162,31 +161,33 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
}
/// `E0449` Trait items always share the visibility of their trait
-fn remove_items_visibility(item: &ast::AssocItem) {
+fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) {
if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) {
if let Some(vis) = has_vis.visibility()
&& let Some(token) = vis.syntax().next_sibling_or_token()
&& token.kind() == SyntaxKind::WHITESPACE
{
- ted::remove(token);
+ editor.delete(token);
+ }
+ if let Some(vis) = has_vis.visibility() {
+ editor.delete(vis.syntax());
}
- has_vis.set_visibility(None);
}
}
-fn strip_body(item: &ast::AssocItem) {
- if let ast::AssocItem::Fn(f) = item {
- if let Some(body) = f.body() {
- // In contrast to function bodies, we want to see no ws before a semicolon.
- // So let's remove them if we see any.
- if let Some(prev) = body.syntax().prev_sibling_or_token() {
- if prev.kind() == SyntaxKind::WHITESPACE {
- ted::remove(prev);
- }
- }
-
- ted::replace(body.syntax(), make::tokens::semicolon());
+fn strip_body(editor: &mut SyntaxEditor, item: &ast::AssocItem) {
+ if let ast::AssocItem::Fn(f) = item
+ && let Some(body) = f.body()
+ {
+ // In contrast to function bodies, we want to see no ws before a semicolon.
+ // So let's remove them if we see any.
+ if let Some(prev) = body.syntax().prev_sibling_or_token()
+ && prev.kind() == SyntaxKind::WHITESPACE
+ {
+ editor.delete(prev);
}
+
+ editor.replace(body.syntax(), make::tokens::semicolon());
};
}