mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-27 16:07:46 +00:00
Fix syntax_editor duplicated changed element
Example
---
```rust
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 target_expr = make::expr_literal("3").clone_for_update();
for arg in arg_list.args() {
editor.replace(arg.syntax(), target_expr.syntax());
}
let edit = editor.finish();
let expect = expect![["(3, 3)"]];
expect.assert_eq(&edit.new_root.to_string());
```
**Before this PR**
```text
(, )3
```
**After this PR**
```text
(3, 3)
```
This commit is contained in:
parent
4bf516ee5a
commit
b8bbebf4f0
@ -1197,4 +1197,57 @@ fn foo() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_issue_21020() {
|
||||
check_assist(
|
||||
convert_tuple_struct_to_named_struct,
|
||||
r#"
|
||||
pub struct S$0(pub ());
|
||||
|
||||
trait T {
|
||||
fn id(&self) -> usize;
|
||||
}
|
||||
|
||||
trait T2 {
|
||||
fn foo(&self) -> usize;
|
||||
}
|
||||
|
||||
impl T for S {
|
||||
fn id(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl T2 for S {
|
||||
fn foo(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
pub struct S { pub field1: () }
|
||||
|
||||
trait T {
|
||||
fn id(&self) -> usize;
|
||||
}
|
||||
|
||||
trait T2 {
|
||||
fn foo(&self) -> usize;
|
||||
}
|
||||
|
||||
impl T for S {
|
||||
fn id(&self) -> usize {
|
||||
self.field1.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl T2 for S {
|
||||
fn foo(&self) -> usize {
|
||||
self.field1.len()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -653,4 +653,40 @@ mod tests {
|
||||
let expect = expect![["fn it() {\n \n}"]];
|
||||
expect.assert_eq(&edit.new_root.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_times_replace_node_to_mutable() {
|
||||
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 target_expr = make::expr_literal("3").clone_for_update();
|
||||
|
||||
for arg in arg_list.args() {
|
||||
editor.replace(arg.syntax(), target_expr.syntax());
|
||||
}
|
||||
|
||||
let edit = editor.finish();
|
||||
|
||||
let expect = expect![["(3, 3)"]];
|
||||
expect.assert_eq(&edit.new_root.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_times_insert_node_to_mutable() {
|
||||
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 target_expr = make::ext::expr_unit().clone_for_update();
|
||||
|
||||
for arg in arg_list.args() {
|
||||
editor.insert(Position::before(arg.syntax()), target_expr.syntax());
|
||||
}
|
||||
|
||||
let edit = editor.finish();
|
||||
|
||||
let expect = expect![["(()1, ()2)"]];
|
||||
expect.assert_eq(&edit.new_root.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,6 +150,15 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||
// Map change targets to the correct syntax nodes
|
||||
let tree_mutator = TreeMutator::new(&root);
|
||||
let mut changed_elements = vec![];
|
||||
let mut changed_elements_set = rustc_hash::FxHashSet::default();
|
||||
let mut deduplicate_node = |node_or_token: &mut SyntaxElement| {
|
||||
let SyntaxElement::Node(node) = node_or_token else { return };
|
||||
if changed_elements_set.contains(node) {
|
||||
*node = node.clone_subtree().clone_for_update();
|
||||
} else {
|
||||
changed_elements_set.insert(node.clone());
|
||||
}
|
||||
};
|
||||
|
||||
for index in independent_changes {
|
||||
match &mut changes[index as usize] {
|
||||
@ -180,6 +189,18 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
|
||||
}
|
||||
}
|
||||
|
||||
match &mut changes[index as usize] {
|
||||
Change::Insert(_, element) | Change::Replace(_, Some(element)) => {
|
||||
deduplicate_node(element);
|
||||
}
|
||||
Change::InsertAll(_, elements)
|
||||
| Change::ReplaceWithMany(_, elements)
|
||||
| Change::ReplaceAll(_, elements) => {
|
||||
elements.iter_mut().for_each(&mut deduplicate_node);
|
||||
}
|
||||
Change::Replace(_, None) => (),
|
||||
}
|
||||
|
||||
// Collect changed elements
|
||||
match &changes[index as usize] {
|
||||
Change::Insert(_, element) => changed_elements.push(element.clone()),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user