Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-assists/src/utils.rs8
-rw-r--r--crates/ide-completion/src/completions/item_list/trait_impl.rs70
-rw-r--r--crates/syntax/src/ast/edit.rs24
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs28
4 files changed, 62 insertions, 68 deletions
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 7cd2f4c3fd..35f28aed53 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -21,8 +21,7 @@ use syntax::{
SyntaxNode, SyntaxToken, T, TextRange, TextSize, WalkEvent,
ast::{
self, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
- edit::{AstNodeEdit, IndentLevel},
- edit_in_place::AttrsOwnerEdit,
+ edit::{AstNodeEdit, AttrsOwnerEdit, IndentLevel},
make,
prec::ExprPrecedence,
syntax_factory::SyntaxFactory,
@@ -246,8 +245,9 @@ pub fn add_trait_assoc_items_to_impl(
PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone());
cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap();
}
- cloned_item.remove_attrs_and_docs();
- cloned_item
+ let (editor, cloned_item) = SyntaxEditor::with_ast_node(&cloned_item);
+ cloned_item.remove_attrs_and_docs(&editor);
+ ast::AssocItem::cast(editor.finish().new_root().clone()).unwrap()
})
.filter_map(|item| match item {
ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 3020fb3956..02e14d8c8e 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -38,12 +38,14 @@ use ide_db::{
syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items,
};
use syntax::ast::HasGenericParams;
+use syntax::syntax_editor::{Position, SyntaxEditor};
use syntax::{
AstNode, SmolStr, SyntaxElement, SyntaxKind, T, TextRange, ToSmolStr,
ast::{
- self, HasGenericArgs, HasTypeBounds, edit::AstNodeEdit, edit_in_place::AttrsOwnerEdit, make,
+ self, HasGenericArgs, HasTypeBounds,
+ edit::{AstNodeEdit, AttrsOwnerEdit},
},
- format_smolstr, ted,
+ format_smolstr,
};
use crate::{
@@ -266,20 +268,17 @@ fn get_transformed_assoc_item(
) -> Option<ast::AssocItem> {
let trait_ = impl_def.trait_(ctx.db)?;
let source_scope = &ctx.sema.scope(assoc_item.syntax())?;
- let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?;
- let transform = PathTransform::trait_impl(
- target_scope,
- source_scope,
- trait_,
- ctx.sema.source(impl_def)?.value,
- );
+ let impl_source = ctx.sema.source(impl_def)?;
+ let target_scope = &ctx.sema.scope(impl_source.syntax().value)?;
+ let transform =
+ PathTransform::trait_impl(target_scope, source_scope, trait_, impl_source.value);
- let assoc_item = assoc_item.clone_for_update();
// FIXME: Paths in nested macros are not handled well. See
// `macro_generated_assoc_item2` test.
let assoc_item = ast::AssocItem::cast(transform.apply(assoc_item.syntax()))?;
- assoc_item.remove_attrs_and_docs();
- Some(assoc_item)
+ let (editor, assoc_item) = SyntaxEditor::with_ast_node(&assoc_item);
+ assoc_item.remove_attrs_and_docs(&editor);
+ ast::AssocItem::cast(editor.finish().new_root().clone())
}
/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
@@ -291,39 +290,37 @@ fn get_transformed_fn(
) -> Option<ast::Fn> {
let trait_ = impl_def.trait_(ctx.db)?;
let source_scope = &ctx.sema.scope(fn_.syntax())?;
- let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?;
- let transform = PathTransform::trait_impl(
- target_scope,
- source_scope,
- trait_,
- ctx.sema.source(impl_def)?.value,
- );
+ let impl_source = ctx.sema.source(impl_def)?;
+ let target_scope = &ctx.sema.scope(impl_source.syntax().value)?;
+ let transform =
+ PathTransform::trait_impl(target_scope, source_scope, trait_, impl_source.value);
let fn_ = fn_.reset_indent();
// FIXME: Paths in nested macros are not handled well. See
// `macro_generated_assoc_item2` test.
let fn_ = ast::Fn::cast(transform.apply(fn_.syntax()))?;
- fn_.remove_attrs_and_docs();
+ let (editor, fn_) = SyntaxEditor::with_ast_node(&fn_);
+ let factory = editor.make();
+ fn_.remove_attrs_and_docs(&editor);
match async_ {
AsyncSugaring::Desugar => {
match fn_.ret_type() {
Some(ret_ty) => {
let ty = ret_ty.ty()?;
- ted::replace(
+ editor.replace(
ty.syntax(),
- make::ty(&format!("impl Future<Output = {ty}>"))
- .syntax()
- .clone_for_update(),
+ factory.ty(&format!("impl Future<Output = {ty}>")).syntax(),
+ );
+ }
+ None => {
+ let ret_type = factory.ret_type(factory.ty("impl Future<Output = ()>"));
+ editor.insert_with_whitespace(
+ Position::after(fn_.param_list()?.syntax()),
+ ret_type.syntax(),
);
}
- None => ted::append_child(
- fn_.param_list()?.syntax(),
- make::ret_type(make::ty("impl Future<Output = ()>"))
- .syntax()
- .clone_for_update(),
- ),
}
- fn_.async_token().unwrap().detach();
+ editor.delete(fn_.async_token()?);
}
AsyncSugaring::Resugar => {
let ty = fn_.ret_type()?.ty()?;
@@ -350,18 +347,21 @@ fn get_transformed_fn(
if let ast::Type::TupleType(ty) = &output
&& ty.fields().next().is_none()
{
- ted::remove(fn_.ret_type()?.syntax());
+ editor.delete(fn_.ret_type()?.syntax());
} else {
- ted::replace(ty.syntax(), output.syntax());
+ editor.replace(ty.syntax(), output.syntax());
}
}
_ => (),
}
- ted::prepend_child(fn_.syntax(), make::token(T![async]));
+ editor.insert_with_whitespace(
+ Position::first_child_of(fn_.syntax()),
+ factory.token(T![async]),
+ );
}
AsyncSugaring::Async | AsyncSugaring::Plain => (),
}
- Some(fn_)
+ ast::Fn::cast(editor.finish().new_root().clone())
}
fn add_type_alias_impl(
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 20f1aaf22d..1e898844ae 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -10,7 +10,7 @@ use std::{
use crate::{
AstToken, NodeOrToken, SyntaxElement,
- SyntaxKind::WHITESPACE,
+ SyntaxKind::{ATTR, COMMENT, WHITESPACE},
SyntaxNode, SyntaxToken,
ast::{self, AstNode, HasName, make},
syntax_editor::{Position, SyntaxEditor, SyntaxMappingBuilder},
@@ -201,6 +201,28 @@ pub trait AstNodeEdit: AstNode + Clone + Sized {
impl<N: AstNode + Clone> AstNodeEdit for N {}
+pub trait AttrsOwnerEdit: ast::HasAttrs {
+ fn remove_attrs_and_docs(&self, editor: &SyntaxEditor) {
+ let mut remove_next_ws = false;
+ for child in self.syntax().children_with_tokens() {
+ match child.kind() {
+ ATTR | COMMENT => {
+ remove_next_ws = true;
+ editor.delete(child);
+ continue;
+ }
+ WHITESPACE if remove_next_ws => {
+ editor.delete(child);
+ }
+ _ => (),
+ }
+ remove_next_ws = false;
+ }
+ }
+}
+
+impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
+
impl ast::IdentPat {
pub fn set_pat(&self, pat: Option<ast::Pat>, editor: &SyntaxEditor) -> ast::IdentPat {
let make = editor.make();
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 2b947f2d0f..68e4f956c2 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -6,8 +6,6 @@ use parser::T;
use crate::{
AstNode, AstToken, Direction,
- SyntaxKind::{ATTR, COMMENT, WHITESPACE},
- SyntaxNode,
algo::{self, neighbor},
ast::{self, edit::IndentLevel, make, syntax_factory::SyntaxFactory},
syntax_editor::SyntaxEditor,
@@ -16,32 +14,6 @@ use crate::{
use super::HasName;
-pub trait AttrsOwnerEdit: ast::HasAttrs {
- fn remove_attrs_and_docs(&self) {
- remove_attrs_and_docs(self.syntax());
-
- fn remove_attrs_and_docs(node: &SyntaxNode) {
- let mut remove_next_ws = false;
- for child in node.children_with_tokens() {
- match child.kind() {
- ATTR | COMMENT => {
- remove_next_ws = true;
- child.detach();
- continue;
- }
- WHITESPACE if remove_next_ws => {
- child.detach();
- }
- _ => (),
- }
- remove_next_ws = false;
- }
- }
- }
-}
-
-impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
-
impl ast::GenericParamList {
/// Constructs a matching [`ast::GenericArgList`]
pub fn to_generic_args(&self, make: &SyntaxFactory) -> ast::GenericArgList {