Skip to content

Commit 59fca5a

Browse files
committed
Fix syntax_editor duplicated changed tokens
1 parent 074b931 commit 59fca5a

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,24 @@ mod tests {
654654
expect.assert_eq(&edit.new_root.to_string());
655655
}
656656

657+
#[test]
658+
fn test_more_times_replace_node_to_mutable_token() {
659+
let arg_list =
660+
make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
661+
662+
let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
663+
let target_expr = make::token(parser::SyntaxKind::UNDERSCORE);
664+
665+
for arg in arg_list.args() {
666+
editor.replace(arg.syntax(), &target_expr);
667+
}
668+
669+
let edit = editor.finish();
670+
671+
let expect = expect![["(_, _)"]];
672+
expect.assert_eq(&edit.new_root.to_string());
673+
}
674+
657675
#[test]
658676
fn test_more_times_replace_node_to_mutable() {
659677
let arg_list =

src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,29 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
152152
let mut changed_elements = vec![];
153153
let mut changed_elements_set = rustc_hash::FxHashSet::default();
154154
let mut deduplicate_node = |node_or_token: &mut SyntaxElement| {
155-
let SyntaxElement::Node(node) = node_or_token else { return };
155+
let node;
156+
let node = match node_or_token {
157+
SyntaxElement::Token(token) => match token.parent() {
158+
None => return,
159+
Some(parent) => {
160+
node = parent;
161+
&node
162+
}
163+
},
164+
SyntaxElement::Node(node) => node,
165+
};
156166
if changed_elements_set.contains(node) {
157-
*node = node.clone_subtree().clone_for_update();
167+
let new_node = node.clone_subtree().clone_for_update();
168+
match node_or_token {
169+
SyntaxElement::Node(node) => *node = new_node,
170+
SyntaxElement::Token(token) => {
171+
*token = new_node
172+
.children_with_tokens()
173+
.filter_map(SyntaxElement::into_token)
174+
.find(|it| it.kind() == token.kind() && it.text() == token.text())
175+
.unwrap();
176+
}
177+
}
158178
} else {
159179
changed_elements_set.insert(node.clone());
160180
}

0 commit comments

Comments
 (0)