Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
"#,
);
}
}
54 changes: 54 additions & 0 deletions crates/syntax/src/syntax_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,4 +653,58 @@ 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_token() {
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::token(parser::SyntaxKind::UNDERSCORE);

for arg in arg_list.args() {
editor.replace(arg.syntax(), &target_expr);
}

let edit = editor.finish();

let expect = expect![["(_, _)"]];
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());
}
}
41 changes: 41 additions & 0 deletions crates/syntax/src/syntax_editor/edit_algo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,35 @@ 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 node;
let node = match node_or_token {
SyntaxElement::Token(token) => match token.parent() {
None => return,
Some(parent) => {
node = parent;
&node
}
},
SyntaxElement::Node(node) => node,
};
if changed_elements_set.contains(node) {
let new_node = node.clone_subtree().clone_for_update();
match node_or_token {
SyntaxElement::Node(node) => *node = new_node,
SyntaxElement::Token(token) => {
*token = new_node
.children_with_tokens()
.filter_map(SyntaxElement::into_token)
.find(|it| it.kind() == token.kind() && it.text() == token.text())
.unwrap();
}
}
} else {
changed_elements_set.insert(node.clone());
}
};

for index in independent_changes {
match &mut changes[index as usize] {
Expand Down Expand Up @@ -180,6 +209,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()),
Expand Down