Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs2
-rw-r--r--crates/ide-assists/src/handlers/apply_demorgan.rs3
-rw-r--r--crates/ide-assists/src/handlers/convert_bool_then.rs6
-rw-r--r--crates/ide-assists/src/handlers/convert_for_to_while_let.rs4
-rw-r--r--crates/ide-assists/src/handlers/convert_let_else_to_match.rs2
-rw-r--r--crates/ide-assists/src/handlers/convert_match_to_let_else.rs12
-rw-r--r--crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs9
-rw-r--r--crates/ide-assists/src/handlers/convert_range_for_to_while.rs6
-rw-r--r--crates/ide-assists/src/handlers/convert_to_guarded_return.rs6
-rw-r--r--crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs8
-rw-r--r--crates/ide-assists/src/handlers/flip_binexpr.rs4
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_trait.rs6
-rw-r--r--crates/ide-assists/src/handlers/generate_getter_or_setter.rs2
-rw-r--r--crates/ide-assists/src/handlers/generate_mut_trait_impl.rs3
-rw-r--r--crates/ide-assists/src/handlers/generate_trait_from_impl.rs4
-rw-r--r--crates/ide-assists/src/handlers/inline_type_alias.rs3
-rw-r--r--crates/ide-assists/src/handlers/introduce_named_lifetime.rs6
-rw-r--r--crates/ide-assists/src/handlers/pull_assignment_up.rs4
-rw-r--r--crates/ide-assists/src/handlers/remove_dbg.rs7
-rw-r--r--crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs2
-rw-r--r--crates/ide-assists/src/handlers/replace_if_let_with_match.rs3
-rw-r--r--crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs3
-rw-r--r--crates/ide-assists/src/handlers/unwrap_block.rs2
-rw-r--r--crates/ide-assists/src/utils.rs14
-rw-r--r--crates/ide-db/src/imports/insert_use.rs6
-rw-r--r--crates/ide-db/src/path_transform.rs52
-rw-r--r--crates/ide-db/src/source_change.rs2
-rw-r--r--crates/syntax/src/ast/edit.rs6
-rw-r--r--crates/syntax/src/syntax_editor.rs60
-rw-r--r--crates/syntax/src/syntax_editor/edits.rs3
30 files changed, 126 insertions, 124 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 e43adefe67..44b367059e 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -175,7 +175,7 @@ fn add_missing_impl_members_inner(
)
&& let Some(func_body) = func.body()
{
- let mut func_editor = SyntaxEditor::new(first_new_item.syntax().clone_subtree());
+ let (mut func_editor, _) = SyntaxEditor::new(first_new_item.syntax().clone());
func_editor.replace(func_body.syntax(), body.syntax());
ast::AssocItem::cast(func_editor.finish().new_root().clone())
} else {
diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs
index 4ee4970248..2ea0d76b01 100644
--- a/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -82,8 +82,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
let make = SyntaxFactory::with_mappings();
- let demorganed = bin_expr.clone_subtree();
- let mut editor = SyntaxEditor::new(demorganed.syntax().clone());
+ let (mut editor, demorganed) = SyntaxEditor::with_ast_node(&bin_expr);
editor.replace(demorganed.op_token()?, make.token(inv_token));
let mut exprs = VecDeque::from([
diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs
index b3bfe5b8c4..c36c79ee99 100644
--- a/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -77,8 +77,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
"Convert `if` expression to `bool::then` call",
target,
|builder| {
- let closure_body = closure_body.clone_subtree();
- let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+ let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
// Rewrite all `Some(e)` in tail position to `e`
for_each_tail_expr(&closure_body, &mut |e| {
let e = match e {
@@ -188,8 +187,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
e => mapless_make.block_expr(None, Some(e)),
};
- let closure_body = closure_body.clone_subtree();
- let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
+ let (mut editor, closure_body) = SyntaxEditor::with_ast_node(&closure_body);
// Wrap all tails in `Some(...)`
let none_path = mapless_make.expr_path(mapless_make.ident_path("None"));
let some_path = mapless_make.expr_path(mapless_make.ident_path("Some"));
diff --git a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
index 15f324eff3..a5c29a45a5 100644
--- a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
+++ b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -81,14 +81,14 @@ pub(crate) fn convert_for_loop_to_while_let(
let indent = IndentLevel::from_node(for_loop.syntax());
if let Some(label) = for_loop.label() {
- let label = label.syntax().clone_for_update();
+ let label = label.syntax();
editor.insert(Position::before(for_loop.syntax()), make.whitespace(" "));
editor.insert(Position::before(for_loop.syntax()), label);
}
crate::utils::insert_attributes(
for_loop.syntax(),
&mut editor,
- for_loop.attrs().map(|it| it.clone_for_update()),
+ for_loop.attrs(),
&make,
);
diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
index fcb4edf12e..9a9808e270 100644
--- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
+++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
@@ -192,7 +192,7 @@ fn remove_mut_and_collect_idents(
let inner = p.pat()?;
if let ast::Pat::IdentPat(ident) = inner {
acc.push(ident);
- p.clone_for_update().into()
+ p.clone().into()
} else {
make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into()
}
diff --git a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
index 1a6d176c90..4b132d68ee 100644
--- a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
+++ b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs
@@ -121,8 +121,7 @@ fn find_extracted_variable(ctx: &AssistContext<'_>, arm: &ast::MatchArm) -> Opti
// Rename `extracted` with `binding` in `pat`.
fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> SyntaxNode {
- let syntax = pat.syntax().clone_subtree();
- let mut editor = SyntaxEditor::new(syntax.clone());
+ let (mut editor, syntax) = SyntaxEditor::new(pat.syntax().clone());
let make = SyntaxFactory::with_mappings();
let extracted = extracted
.iter()
@@ -138,15 +137,12 @@ fn rename_variable(pat: &ast::Pat, extracted: &[Name], binding: ast::Pat) -> Syn
if let Some(name_ref) = record_pat_field.field_name() {
editor.replace(
record_pat_field.syntax(),
- make.record_pat_field(
- make.name_ref(&name_ref.text()),
- binding.clone_for_update(),
- )
- .syntax(),
+ make.record_pat_field(make.name_ref(&name_ref.text()), binding.clone())
+ .syntax(),
);
}
} else {
- editor.replace(extracted_syntax, binding.syntax().clone_for_update());
+ editor.replace(extracted_syntax, binding.syntax());
}
}
editor.add_mappings(make.finish_with_mappings());
diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index aaf727058c..4ea56e3e61 100644
--- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -102,11 +102,11 @@ fn edit_struct_def(
// Note that we don't need to consider macro files in this function because this is
// currently not triggered for struct definitions inside macro calls.
let tuple_fields = record_fields.fields().filter_map(|f| {
- let field = ast::make::tuple_field(f.visibility(), f.ty()?);
- let mut editor = SyntaxEditor::new(field.syntax().clone());
+ let (mut editor, field) =
+ SyntaxEditor::with_ast_node(&ast::make::tuple_field(f.visibility(), f.ty()?));
editor.insert_all(
Position::first_child_of(field.syntax()),
- f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+ f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
);
let field_syntax = editor.finish().new_root().clone();
let field = ast::TupleField::cast(field_syntax)?;
@@ -328,8 +328,7 @@ fn delete_whitespace(edit: &mut SyntaxEditor, whitespace: Option<impl Element>)
}
fn remove_trailing_comma(w: ast::WhereClause) -> SyntaxNode {
- let w = w.syntax().clone_subtree();
- let mut editor = SyntaxEditor::new(w.clone());
+ let (mut editor, w) = SyntaxEditor::new(w.syntax().clone());
if let Some(last) = w.last_child_or_token()
&& last.kind() == T![,]
{
diff --git a/crates/ide-assists/src/handlers/convert_range_for_to_while.rs b/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
index 2e649f14be..09435eeaec 100644
--- a/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
+++ b/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
@@ -155,15 +155,15 @@ fn process_loop_body(
let block_content = first.clone()..=children.last().unwrap_or(first);
let continue_label = make::lifetime("'cont");
- let break_expr = make::expr_break(Some(continue_label.clone()), None).clone_for_update();
- let mut new_edit = SyntaxEditor::new(new_body.syntax().clone());
+ let break_expr = make::expr_break(Some(continue_label.clone()), None);
+ let (mut new_edit, _) = SyntaxEditor::new(new_body.syntax().clone());
for continue_expr in &continues {
new_edit.replace(continue_expr.syntax(), break_expr.syntax());
}
let new_body = new_edit.finish().new_root().clone();
let elements = itertools::chain(
[
- continue_label.syntax().clone_for_update().syntax_element(),
+ continue_label.syntax().syntax_element(),
make::token(T![:]).syntax_element(),
make::tokens::single_space().syntax_element(),
new_body.syntax_element(),
diff --git a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index f8c4fcc5fe..004d09acac 100644
--- a/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -268,7 +268,8 @@ impl<'db> ElseBlock<'db> {
return block_expr.reset_indent();
}
- let block_expr = block_expr.reset_indent().clone_subtree();
+ let (mut edit, block_expr) = SyntaxEditor::with_ast_node(&block_expr.reset_indent());
+
let last_stmt = block_expr.statements().last().map(|it| it.syntax().clone());
let tail_expr = block_expr.tail_expr().map(|it| it.syntax().clone());
let Some(last_element) = tail_expr.clone().or(last_stmt.clone()) else {
@@ -277,7 +278,6 @@ impl<'db> ElseBlock<'db> {
let whitespace = last_element.prev_sibling_or_token().filter(|it| it.kind() == WHITESPACE);
let make = SyntaxFactory::without_mappings();
- let mut edit = SyntaxEditor::new(block_expr.syntax().clone());
if let Some(tail_expr) = block_expr.tail_expr()
&& !self.kind.is_unit()
@@ -287,7 +287,7 @@ impl<'db> ElseBlock<'db> {
} else {
let last_stmt = match block_expr.tail_expr() {
Some(expr) => make.expr_stmt(expr).syntax().clone(),
- None => last_element.clone_for_update(),
+ None => last_element.clone(),
};
let whitespace =
make.whitespace(&whitespace.map_or(String::new(), |it| it.to_string()));
diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index ae41e6c015..4ce7a9d866 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -103,11 +103,11 @@ fn edit_struct_def(
names: Vec<ast::Name>,
) {
let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| {
- let field = ast::make::record_field(f.visibility(), name, f.ty()?);
- let mut field_editor = SyntaxEditor::new(field.syntax().clone());
+ let (mut field_editor, field) =
+ SyntaxEditor::with_ast_node(&ast::make::record_field(f.visibility(), name, f.ty()?));
field_editor.insert_all(
Position::first_child_of(field.syntax()),
- f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(),
+ f.attrs().map(|attr| attr.syntax().clone().into()).collect(),
);
ast::RecordField::cast(field_editor.finish().new_root().clone())
});
@@ -120,7 +120,7 @@ fn edit_struct_def(
editor.delete(w.syntax());
let mut insert_element = Vec::new();
insert_element.push(ast::make::tokens::single_newline().syntax_element());
- insert_element.push(w.syntax().clone_for_update().syntax_element());
+ insert_element.push(w.syntax().syntax_element());
if w.syntax().last_token().is_none_or(|t| t.kind() != SyntaxKind::COMMA) {
insert_element.push(ast::make::token(T![,]).into());
}
diff --git a/crates/ide-assists/src/handlers/flip_binexpr.rs b/crates/ide-assists/src/handlers/flip_binexpr.rs
index 8f2306e903..922a61bf3a 100644
--- a/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -142,11 +142,11 @@ pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
}
(Some(start), None) => {
edit.delete(start.syntax());
- edit.insert(Position::after(&op), start.syntax().clone_for_update());
+ edit.insert(Position::after(&op), start.syntax());
}
(None, Some(end)) => {
edit.delete(end.syntax());
- edit.insert(Position::before(&op), end.syntax().clone_for_update());
+ edit.insert(Position::before(&op), end.syntax());
}
(None, None) => (),
}
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index f703e4dc4a..a9730994a5 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -563,7 +563,7 @@ fn finalize_delegate(
return Some(delegate.clone());
}
- let mut editor = SyntaxEditor::new(delegate.syntax().clone_subtree());
+ let (mut editor, delegate) = SyntaxEditor::with_ast_node(delegate);
// 1. Replace assoc_item_list if we have new items
if let Some(items) = assoc_items
@@ -577,7 +577,7 @@ fn finalize_delegate(
// 2. Remove useless where clauses
if remove_where_clauses {
- remove_useless_where_clauses(&mut editor, delegate);
+ remove_useless_where_clauses(&mut editor, &delegate);
}
ast::Impl::cast(editor.finish().new_root().clone())
@@ -703,7 +703,7 @@ fn resolve_name_conflicts(
}
}
p @ ast::GenericParam::LifetimeParam(_) => {
- new_params.push(p.clone_for_update());
+ new_params.push(p);
}
ast::GenericParam::TypeParam(t) => {
let type_bounds = t.type_bound_list();
diff --git a/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 62ffd3d965..4cd018d02d 100644
--- a/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -429,7 +429,7 @@ fn build_source_change(
generate_getter_from_info(ctx, &assist_info, record_field_info, &syntax_factory)
}
};
- let new_fn = method.clone_for_update();
+ let new_fn = method;
let new_fn = new_fn.indent(1.into());
new_fn.into()
})
diff --git a/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 3a62a8853e..31e49c8ce4 100644
--- a/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -67,8 +67,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
format!("Generate `{trait_new}` impl from this `{trait_name}` trait"),
target,
|edit| {
- let impl_clone = impl_def.reset_indent().clone_subtree();
- let mut editor = SyntaxEditor::new(impl_clone.syntax().clone());
+ let (mut editor, impl_clone) = SyntaxEditor::with_ast_node(&impl_def.reset_indent());
let factory = SyntaxFactory::without_mappings();
apply_generate_mut_impl(&mut editor, &factory, &impl_clone, trait_new);
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 1286abe356..2255560900 100644
--- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -98,8 +98,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
impl_ast.syntax().text_range(),
|builder| {
let trait_items: ast::AssocItemList = {
- let trait_items = impl_assoc_items.clone_subtree();
- let mut trait_items_editor = SyntaxEditor::new(trait_items.syntax().clone());
+ let (mut trait_items_editor, trait_items) =
+ SyntaxEditor::with_ast_node(&impl_assoc_items);
trait_items.assoc_items().for_each(|item| {
strip_body(&mut trait_items_editor, &item);
diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs
index f5b5b228f3..4b60f0ac1e 100644
--- a/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -312,8 +312,7 @@ fn create_replacement(
const_and_type_map: &ConstAndTypeMap,
concrete_type: &ast::Type,
) -> SyntaxNode {
- let updated_concrete_type = concrete_type.syntax().clone_subtree();
- let mut editor = SyntaxEditor::new(updated_concrete_type.clone());
+ let (mut editor, updated_concrete_type) = SyntaxEditor::new(concrete_type.syntax().clone());
let mut replacements: Vec<(SyntaxNode, SyntaxNode)> = Vec::new();
let mut removals: Vec<NodeOrToken<SyntaxNode, _>> = Vec::new();
diff --git a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index 854e9561d2..5e8ea7daff 100644
--- a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -97,8 +97,7 @@ fn generate_fn_def_assist(
};
acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
- let root = fn_def.syntax().ancestors().last().unwrap().clone();
- let mut editor = SyntaxEditor::new(root);
+ let mut editor = edit.make_editor(fn_def.syntax());
let factory = SyntaxFactory::with_mappings();
if let Some(generic_list) = fn_def.generic_param_list() {
@@ -167,8 +166,7 @@ fn generate_impl_def_assist(
let new_lifetime_name = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
acc.add(AssistId::refactor(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |edit| {
- let root = impl_def.syntax().ancestors().last().unwrap().clone();
- let mut editor = SyntaxEditor::new(root);
+ let mut editor = edit.make_editor(impl_def.syntax());
let factory = SyntaxFactory::without_mappings();
if let Some(generic_list) = impl_def.generic_param_list() {
diff --git a/crates/ide-assists/src/handlers/pull_assignment_up.rs b/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 812ebf6c6e..74ed2e14fa 100644
--- a/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -75,7 +75,8 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
}
let target = tgt.syntax().text_range();
- let edit_tgt = tgt.syntax().clone_subtree();
+ let (mut editor, edit_tgt) = SyntaxEditor::new(tgt.syntax().clone());
+
let assignments: Vec<_> = collector
.assignments
.into_iter()
@@ -93,7 +94,6 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
})
.collect();
- let mut editor = SyntaxEditor::new(edit_tgt);
for (stmt, rhs) in assignments {
let mut stmt = stmt.syntax().clone();
if let Some(parent) = stmt.parent()
diff --git a/crates/ide-assists/src/handlers/remove_dbg.rs b/crates/ide-assists/src/handlers/remove_dbg.rs
index 08779a3ed1..180c12f2ec 100644
--- a/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -50,7 +50,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
let mut editor = builder.make_editor(ctx.source_file().syntax());
for (range, expr) in replacements {
if let Some(expr) = expr {
- editor.insert(Position::before(range[0].clone()), expr.syntax().clone_for_update());
+ editor.insert(Position::before(range[0].clone()), expr.syntax());
}
for node_or_token in range {
editor.delete(node_or_token);
@@ -209,8 +209,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
return replaced;
}
- let expanded = expanded.clone_subtree();
- let mut editor = SyntaxEditor::new(expanded.syntax().clone());
+ let (mut editor, expanded) = SyntaxEditor::with_ast_node(&expanded);
// We need to collect to avoid mutation during traversal.
let macro_exprs: Vec<_> =
expanded.syntax().descendants().filter_map(ast::MacroExpr::cast).collect();
@@ -222,7 +221,7 @@ fn replace_nested_dbgs(expanded: ast::Expr) -> ast::Expr {
};
if let Some(expr) = expr_opt {
- editor.replace(mac.syntax(), expr.syntax().clone_for_update());
+ editor.replace(mac.syntax(), expr.syntax());
} else {
editor.delete(mac.syntax());
}
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 01299729bc..62b4e04950 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -227,7 +227,7 @@ fn impl_def_from_trait(
&& let Some(body) = gen_trait_fn_body(&make, func, trait_path, adt, None)
&& let Some(func_body) = func.body()
{
- let mut editor = SyntaxEditor::new(first.syntax().clone());
+ let (mut editor, _) = SyntaxEditor::new(first.syntax().clone());
editor.replace(func_body.syntax(), body.syntax());
ast::AssocItem::cast(editor.finish().new_root().clone())
} else {
diff --git a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index 2bbce2b2c0..ada2fd9b21 100644
--- a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -402,8 +402,7 @@ fn let_and_guard(cond: &ast::Expr) -> (Option<ast::LetExpr>, Option<ast::Expr>)
} else if let ast::Expr::BinExpr(bin_expr) = cond
&& let Some(ast::Expr::LetExpr(let_expr)) = and_bin_expr_left(bin_expr).lhs()
{
- let new_expr = bin_expr.clone_subtree();
- let mut edit = SyntaxEditor::new(new_expr.syntax().clone());
+ let (mut edit, new_expr) = SyntaxEditor::with_ast_node(bin_expr);
let left_bin = and_bin_expr_left(&new_expr);
if let Some(rhs) = left_bin.rhs() {
diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index cdf20586ef..fd090cc081 100644
--- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -111,8 +111,7 @@ fn target_path(ctx: &AssistContext<'_>, mut original_path: ast::Path) -> Option<
}
fn drop_generic_args(path: &ast::Path) -> ast::Path {
- let path = path.clone_subtree();
- let mut editor = SyntaxEditor::new(path.syntax().clone());
+ let (mut editor, path) = SyntaxEditor::with_ast_node(path);
if let Some(segment) = path.segment()
&& let Some(generic_args) = segment.generic_arg_list()
{
diff --git a/crates/ide-assists/src/handlers/unwrap_block.rs b/crates/ide-assists/src/handlers/unwrap_block.rs
index e029d7884f..87e61b35d8 100644
--- a/crates/ide-assists/src/handlers/unwrap_block.rs
+++ b/crates/ide-assists/src/handlers/unwrap_block.rs
@@ -115,7 +115,7 @@ fn wrap_let(assign: &ast::LetStmt, replacement: ast::BlockExpr) -> ast::BlockExp
.skip(1)
.collect();
- let mut edit = SyntaxEditor::new(replacement.syntax().clone());
+ let (mut edit, _) = SyntaxEditor::new(replacement.syntax().clone());
edit.insert_all(Position::before(tail_expr.syntax()), before);
edit.insert_all(Position::after(tail_expr.syntax()), after);
ast::BlockExpr::cast(edit.finish().new_root().clone())
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index c77321ebd1..01bd46406e 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -248,27 +248,23 @@ pub fn add_trait_assoc_items_to_impl(
})
.filter_map(|item| match item {
ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
- let fn_ = fn_.clone_subtree();
+ let (mut fn_editor, fn_) = SyntaxEditor::with_ast_node(&fn_);
let fill_expr: ast::Expr = match config.expr_fill_default {
ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(),
ExprFillDefaultMode::Underscore => make.expr_underscore().into(),
};
let new_body = make.block_expr(None::<ast::Stmt>, Some(fill_expr));
- let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone());
fn_.replace_or_insert_body(&mut fn_editor, new_body);
let new_fn_ = fn_editor.finish().new_root().clone();
ast::AssocItem::cast(new_fn_)
}
ast::AssocItem::TypeAlias(type_alias) => {
- let type_alias = type_alias.clone_subtree();
+ let (mut type_alias_editor, type_alias) = SyntaxEditor::with_ast_node(&type_alias);
if let Some(type_bound_list) = type_alias.type_bound_list() {
- let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone());
type_bound_list.remove(&mut type_alias_editor);
- let type_alias = type_alias_editor.finish().new_root().clone();
- ast::AssocItem::cast(type_alias)
- } else {
- Some(ast::AssocItem::TypeAlias(type_alias))
- }
+ };
+ let type_alias = type_alias_editor.finish().new_root().clone();
+ ast::AssocItem::cast(type_alias)
}
item => Some(item),
})
diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs
index da8525d1fb..3a109a48e4 100644
--- a/crates/ide-db/src/imports/insert_use.rs
+++ b/crates/ide-db/src/imports/insert_use.rs
@@ -305,10 +305,8 @@ fn insert_use_with_alias_option_with_editor(
if mb == Some(MergeBehavior::One) && use_tree.path().is_some() {
use_tree.wrap_in_tree_list();
}
- let use_item = make::use_(None, None, use_tree).clone_for_update();
- for attr in
- scope.required_cfgs.iter().map(|attr| attr.syntax().clone_subtree().clone_for_update())
- {
+ let use_item = make::use_(None, None, use_tree);
+ for attr in scope.required_cfgs.iter().map(|attr| attr.syntax().clone()) {
syntax_editor.insert(Position::first_child_of(use_item.syntax()), attr);
}
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index 508f841340..ab960a1839 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -197,7 +197,7 @@ impl<'a> PathTransform<'a> {
&& let Some(default) =
&default.display_source_code(db, source_module.into(), false).ok()
{
- type_substs.insert(k, make::ty(default).clone_for_update());
+ type_substs.insert(k, make::ty(default));
defaulted_params.push(Either::Left(k));
}
}
@@ -222,7 +222,7 @@ impl<'a> PathTransform<'a> {
k.default(db, target_module.krate(db).to_display_target(db))
&& let Some(default) = default.expr()
{
- const_substs.insert(k, default.syntax().clone_for_update());
+ const_substs.insert(k, default.syntax().clone());
defaulted_params.push(Either::Right(k));
}
}
@@ -278,12 +278,10 @@ impl Ctx<'_> {
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
- let item = self.transform_path(item).clone_subtree();
- let mut editor = SyntaxEditor::new(item.clone());
+ let (mut editor, item) = SyntaxEditor::new(self.transform_path(item));
preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
- editor
- .replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
+ editor.replace(lifetime.syntax(), subst.clone().syntax());
}
});
@@ -331,18 +329,14 @@ impl Ctx<'_> {
result
}
- let root_path = path.clone_subtree();
-
+ let (mut editor, root_path) = SyntaxEditor::new(path.clone());
let result = find_child_paths_and_ident_pats(&root_path);
- let mut editor = SyntaxEditor::new(root_path.clone());
for sub_path in result {
let new = self.transform_path(sub_path.syntax());
editor.replace(sub_path.syntax(), new);
}
-
- let update_sub_item = editor.finish().new_root().clone().clone_subtree();
+ let (mut editor, update_sub_item) = SyntaxEditor::new(editor.finish().new_root().clone());
let item = find_child_paths_and_ident_pats(&update_sub_item);
- let mut editor = SyntaxEditor::new(update_sub_item);
for sub_path in item {
self.transform_path_or_ident_pat(&mut editor, &sub_path);
}
@@ -411,12 +405,12 @@ impl Ctx<'_> {
let segment = make::path_segment_ty(subst.clone(), trait_ref);
let qualified = make::path_from_segments(std::iter::once(segment), false);
- editor.replace(path.syntax(), qualified.clone_for_update().syntax());
+ editor.replace(path.syntax(), qualified.clone().syntax());
} else if let Some(path_ty) = ast::PathType::cast(parent) {
let old = path_ty.syntax();
if old.parent().is_some() {
- editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
+ editor.replace(old, subst.clone().syntax());
} else {
// Some `path_ty` has no parent, especially ones made for default value
// of type parameters.
@@ -434,10 +428,7 @@ impl Ctx<'_> {
);
}
} else {
- editor.replace(
- path.syntax(),
- subst.clone_subtree().clone_for_update().syntax(),
- );
+ editor.replace(path.syntax(), subst.clone().syntax());
}
}
}
@@ -459,18 +450,17 @@ impl Ctx<'_> {
allow_unstable: true,
};
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
- let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
- let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
+ let res = mod_path_to_ast(&found_path, self.target_edition);
+ let (mut res_editor, res) = SyntaxEditor::with_ast_node(&res);
if let Some(args) = path.segment().and_then(|it| it.generic_arg_list())
&& let Some(segment) = res.segment()
{
if let Some(old) = segment.generic_arg_list() {
- res_editor
- .replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
+ res_editor.replace(old.syntax(), args.syntax().clone())
} else {
res_editor.insert(
syntax_editor::Position::last_child_of(segment.syntax()),
- args.clone_subtree().syntax().clone_for_update(),
+ args.syntax().clone(),
);
}
}
@@ -479,7 +469,7 @@ impl Ctx<'_> {
}
hir::PathResolution::ConstParam(cp) => {
if let Some(subst) = self.const_substs.get(&cp) {
- editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
+ editor.replace(path.syntax(), subst.clone());
}
}
hir::PathResolution::SelfType(imp) => {
@@ -496,7 +486,7 @@ impl Ctx<'_> {
true,
)
.ok()?;
- let ast_ty = make::ty(ty_str).clone_for_update();
+ let ast_ty = make::ty(ty_str);
if let Some(adt) = ty.as_adt()
&& let ast::Type::PathType(path_ty) = &ast_ty
@@ -516,8 +506,10 @@ impl Ctx<'_> {
if let Some(qual) =
mod_path_to_ast(&found_path, self.target_edition).qualifier()
{
- let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
- editor.replace(path.syntax(), res.syntax());
+ editor.replace(
+ path.syntax(),
+ make::path_concat(qual, path_ty.path()?).syntax(),
+ );
return Some(());
}
}
@@ -593,8 +585,10 @@ impl Ctx<'_> {
allow_unstable: true,
};
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
- let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
- editor.replace(ident_pat.syntax(), res.syntax());
+ editor.replace(
+ ident_pat.syntax(),
+ mod_path_to_ast(&found_path, self.target_edition).syntax(),
+ );
Some(())
}
_ => None,
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs
index 57072bb5ba..4a83f707fc 100644
--- a/crates/ide-db/src/source_change.rs
+++ b/crates/ide-db/src/source_change.rs
@@ -282,7 +282,7 @@ impl SourceChangeBuilder {
}
pub fn make_editor(&self, node: &SyntaxNode) -> SyntaxEditor {
- SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone()))
+ SyntaxEditor::new(node.ancestors().last().unwrap_or_else(|| node.clone())).0
}
pub fn add_file_edits(&mut self, file_id: impl Into<FileId>, edit: SyntaxEditor) {
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index b706d7f722..23a0411ead 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -105,8 +105,7 @@ impl IndentLevel {
}
pub(super) fn clone_increase_indent(self, node: &SyntaxNode) -> SyntaxNode {
- let node = node.clone_subtree();
- let mut editor = SyntaxEditor::new(node.clone());
+ let (mut editor, node) = SyntaxEditor::new(node.clone());
let tokens = node
.preorder_with_tokens()
.filter_map(|event| match event {
@@ -140,8 +139,7 @@ impl IndentLevel {
}
pub(super) fn clone_decrease_indent(self, node: &SyntaxNode) -> SyntaxNode {
- let node = node.clone_subtree();
- let mut editor = SyntaxEditor::new(node.clone());
+ let (mut editor, node) = SyntaxEditor::new(node.clone());
let tokens = node
.preorder_with_tokens()
.filter_map(|event| match event {
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index e6937e4d0f..dbb9f15e17 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -14,7 +14,7 @@ use std::{
use rowan::TextRange;
use rustc_hash::FxHashMap;
-use crate::{SyntaxElement, SyntaxNode, SyntaxToken};
+use crate::{AstNode, SyntaxElement, SyntaxNode, SyntaxToken};
mod edit_algo;
mod edits;
@@ -32,9 +32,37 @@ pub struct SyntaxEditor {
}
impl SyntaxEditor {
- /// Creates a syntax editor to start editing from `root`
- pub fn new(root: SyntaxNode) -> Self {
- Self { root, changes: vec![], mappings: SyntaxMapping::default(), annotations: vec![] }
+ /// Creates a syntax editor from `root`.
+ ///
+ /// The returned `root` is guaranteed to be a detached, immutable node.
+ /// If the provided node is not a root (i.e., has a parent) or is already
+ /// mutable, it is cloned into a fresh subtree to satisfy syntax editor
+ /// invariants.
+ pub fn new(root: SyntaxNode) -> (Self, SyntaxNode) {
+ let mut root = root;
+
+ if root.parent().is_some() || root.is_mutable() {
+ root = root.clone_subtree()
+ };
+
+ let editor = Self {
+ root: root.clone(),
+ changes: Vec::new(),
+ mappings: SyntaxMapping::default(),
+ annotations: Vec::new(),
+ };
+
+ (editor, root)
+ }
+
+ /// Typed-node variant of [`SyntaxEditor::new`].
+ pub fn with_ast_node<T>(root: &T) -> (Self, T)
+ where
+ T: AstNode,
+ {
+ let (editor, root) = Self::new(root.syntax().clone());
+
+ (editor, T::cast(root).unwrap())
}
pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) {
@@ -420,10 +448,11 @@ mod tests {
.into(),
);
+ let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
- let mut editor = SyntaxEditor::new(root.syntax().clone());
let make = SyntaxFactory::with_mappings();
let name = make::name("var_name");
@@ -478,9 +507,8 @@ mod tests {
None,
);
+ let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
-
- let mut editor = SyntaxEditor::new(root.syntax().clone());
let make = SyntaxFactory::without_mappings();
editor.insert(
@@ -530,11 +558,12 @@ mod tests {
),
);
+ let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
+
let inner_block =
root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
- let mut editor = SyntaxEditor::new(root.syntax().clone());
let make = SyntaxFactory::with_mappings();
let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -584,9 +613,9 @@ mod tests {
None,
);
- let inner_block = root.clone();
+ let (mut editor, root) = SyntaxEditor::with_ast_node(&root);
- let mut editor = SyntaxEditor::new(root.syntax().clone());
+ let inner_block = root;
let make = SyntaxFactory::with_mappings();
let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
@@ -632,7 +661,7 @@ mod tests {
false,
);
- let mut editor = SyntaxEditor::new(parent_fn.syntax().clone());
+ let (mut editor, parent_fn) = SyntaxEditor::with_ast_node(&parent_fn);
if let Some(ret_ty) = parent_fn.ret_type() {
editor.delete(ret_ty.syntax().clone());
@@ -659,7 +688,8 @@ mod tests {
let arg_list =
make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
- let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+ let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
let target_expr = make::token(parser::SyntaxKind::UNDERSCORE);
for arg in arg_list.args() {
@@ -677,7 +707,8 @@ mod tests {
let arg_list =
make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
- let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+ let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
let target_expr = make::expr_literal("3").clone_for_update();
for arg in arg_list.args() {
@@ -695,7 +726,8 @@ mod tests {
let arg_list =
make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
- let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
+ let (mut editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
+
let target_expr = make::ext::expr_unit().clone_for_update();
for arg in arg_list.args() {
diff --git a/crates/syntax/src/syntax_editor/edits.rs b/crates/syntax/src/syntax_editor/edits.rs
index 44f0a8038e..8c842be49d 100644
--- a/crates/syntax/src/syntax_editor/edits.rs
+++ b/crates/syntax/src/syntax_editor/edits.rs
@@ -473,8 +473,7 @@ enum Foo {
}
fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
- let enum_ = ast_from_text::<ast::Enum>(before);
- let mut editor = SyntaxEditor::new(enum_.syntax().clone());
+ let (mut editor, enum_) = SyntaxEditor::with_ast_node(&ast_from_text::<ast::Enum>(before));
if let Some(it) = enum_.variant_list() {
it.add_variant(&mut editor, &variant)
}