Skip to content

Commit 074b931

Browse files
committed
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) ```
1 parent 2b05436 commit 074b931

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,4 +1197,57 @@ fn foo() {
11971197
"#,
11981198
);
11991199
}
1200+
1201+
#[test]
1202+
fn regression_issue_21020() {
1203+
check_assist(
1204+
convert_tuple_struct_to_named_struct,
1205+
r#"
1206+
pub struct S$0(pub ());
1207+
1208+
trait T {
1209+
fn id(&self) -> usize;
1210+
}
1211+
1212+
trait T2 {
1213+
fn foo(&self) -> usize;
1214+
}
1215+
1216+
impl T for S {
1217+
fn id(&self) -> usize {
1218+
self.0.len()
1219+
}
1220+
}
1221+
1222+
impl T2 for S {
1223+
fn foo(&self) -> usize {
1224+
self.0.len()
1225+
}
1226+
}
1227+
"#,
1228+
r#"
1229+
pub struct S { pub field1: () }
1230+
1231+
trait T {
1232+
fn id(&self) -> usize;
1233+
}
1234+
1235+
trait T2 {
1236+
fn foo(&self) -> usize;
1237+
}
1238+
1239+
impl T for S {
1240+
fn id(&self) -> usize {
1241+
self.field1.len()
1242+
}
1243+
}
1244+
1245+
impl T2 for S {
1246+
fn foo(&self) -> usize {
1247+
self.field1.len()
1248+
}
1249+
}
1250+
"#,
1251+
);
1252+
}
12001253
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,4 +653,40 @@ mod tests {
653653
let expect = expect![["fn it() {\n \n}"]];
654654
expect.assert_eq(&edit.new_root.to_string());
655655
}
656+
657+
#[test]
658+
fn test_more_times_replace_node_to_mutable() {
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::expr_literal("3").clone_for_update();
664+
665+
for arg in arg_list.args() {
666+
editor.replace(arg.syntax(), target_expr.syntax());
667+
}
668+
669+
let edit = editor.finish();
670+
671+
let expect = expect![["(3, 3)"]];
672+
expect.assert_eq(&edit.new_root.to_string());
673+
}
674+
675+
#[test]
676+
fn test_more_times_insert_node_to_mutable() {
677+
let arg_list =
678+
make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
679+
680+
let mut editor = SyntaxEditor::new(arg_list.syntax().clone());
681+
let target_expr = make::ext::expr_unit().clone_for_update();
682+
683+
for arg in arg_list.args() {
684+
editor.insert(Position::before(arg.syntax()), target_expr.syntax());
685+
}
686+
687+
let edit = editor.finish();
688+
689+
let expect = expect![["(()1, ()2)"]];
690+
expect.assert_eq(&edit.new_root.to_string());
691+
}
656692
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
150150
// Map change targets to the correct syntax nodes
151151
let tree_mutator = TreeMutator::new(&root);
152152
let mut changed_elements = vec![];
153+
let mut changed_elements_set = rustc_hash::FxHashSet::default();
154+
let mut deduplicate_node = |node_or_token: &mut SyntaxElement| {
155+
let SyntaxElement::Node(node) = node_or_token else { return };
156+
if changed_elements_set.contains(node) {
157+
*node = node.clone_subtree().clone_for_update();
158+
} else {
159+
changed_elements_set.insert(node.clone());
160+
}
161+
};
153162

154163
for index in independent_changes {
155164
match &mut changes[index as usize] {
@@ -180,6 +189,18 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
180189
}
181190
}
182191

192+
match &mut changes[index as usize] {
193+
Change::Insert(_, element) | Change::Replace(_, Some(element)) => {
194+
deduplicate_node(element);
195+
}
196+
Change::InsertAll(_, elements)
197+
| Change::ReplaceWithMany(_, elements)
198+
| Change::ReplaceAll(_, elements) => {
199+
elements.iter_mut().for_each(&mut deduplicate_node);
200+
}
201+
Change::Replace(_, None) => (),
202+
}
203+
183204
// Collect changed elements
184205
match &changes[index as usize] {
185206
Change::Insert(_, element) => changed_elements.push(element.clone()),

0 commit comments

Comments
 (0)