Skip to content

Commit f03f95f

Browse files
committed
support replacing root node
1 parent f74ef3a commit f03f95f

File tree

3 files changed

+200
-14
lines changed

3 files changed

+200
-14
lines changed

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

Lines changed: 192 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,28 @@ impl SyntaxEditor {
5151
}
5252

5353
pub fn insert(&mut self, position: Position, element: impl Element) {
54+
debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
5455
self.changes.push(Change::Insert(position, element.syntax_element()))
5556
}
5657

5758
pub fn insert_all(&mut self, position: Position, elements: Vec<SyntaxElement>) {
59+
debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
5860
self.changes.push(Change::InsertAll(position, elements))
5961
}
6062

6163
pub fn delete(&mut self, element: impl Element) {
64+
let element = element.syntax_element();
65+
debug_assert!(is_ancestor_or_self_of_element(&element, &self.root));
66+
debug_assert!(
67+
!matches!(&element, SyntaxElement::Node(node) if node == &self.root),
68+
"should not delete root node"
69+
);
6270
self.changes.push(Change::Replace(element.syntax_element(), None));
6371
}
6472

6573
pub fn replace(&mut self, old: impl Element, new: impl Element) {
74+
let old = old.syntax_element();
75+
debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
6676
self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element())));
6777
}
6878

@@ -199,7 +209,10 @@ impl Change {
199209
fn target_parent(&self) -> SyntaxNode {
200210
match self {
201211
Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
202-
Change::Replace(target, _) => target.parent().unwrap(),
212+
Change::Replace(SyntaxElement::Node(target), _) => {
213+
target.parent().unwrap_or_else(|| target.clone())
214+
}
215+
Change::Replace(SyntaxElement::Token(target), _) => target.parent().unwrap(),
203216
}
204217
}
205218

@@ -248,6 +261,15 @@ impl Element for SyntaxToken {
248261
}
249262
}
250263

264+
fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool {
265+
node == ancestor || node.ancestors().any(|it| &it == ancestor)
266+
}
267+
268+
fn is_ancestor_or_self_of_element(node: &SyntaxElement, ancestor: &SyntaxNode) -> bool {
269+
matches!(node, SyntaxElement::Node(node) if node == ancestor)
270+
|| node.ancestors().any(|it| &it == ancestor)
271+
}
272+
251273
#[cfg(test)]
252274
mod tests {
253275
use expect_test::expect;
@@ -370,15 +392,11 @@ mod tests {
370392
Some(to_wrap.clone().into()),
371393
);
372394

373-
// should die:
374395
editor.replace(to_replace.syntax(), name_ref.syntax());
375396
editor.replace(to_wrap.syntax(), new_block.syntax());
376-
// editor.replace(to_replace.syntax(), name_ref.syntax());
377397

378398
let edit = editor.finish();
379399

380-
dbg!(&edit.annotations);
381-
382400
let expect = expect![[r#"
383401
_ => {
384402
let var_name = 2 + 2;
@@ -393,4 +411,173 @@ mod tests {
393411
.flat_map(|(_, elements)| elements)
394412
.all(|element| element.ancestors().any(|it| &it == edit.root())))
395413
}
414+
415+
#[test]
416+
#[should_panic = "some replace change ranges intersect: [Replace(Node([email protected]), Some(Node([email protected]))), Replace(Node([email protected]), Some(Node([email protected])))]"]
417+
fn fail_on_non_disjoint_single_replace() {
418+
let root = make::match_arm([make::wildcard_pat().into()], None, make::expr_tuple([]));
419+
420+
let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
421+
422+
let mut editor = SyntaxEditor::new(root.syntax().clone());
423+
424+
let name_ref = make::name_ref("var_name").clone_for_update();
425+
426+
// should die, ranges are not disjoint
427+
editor.replace(to_wrap.syntax(), name_ref.syntax());
428+
editor.replace(to_wrap.syntax(), name_ref.syntax());
429+
430+
let _ = editor.finish();
431+
}
432+
433+
#[test]
434+
fn test_insert_independent() {
435+
let root = make::block_expr(
436+
[make::let_stmt(
437+
make::ext::simple_ident_pat(make::name("second")).into(),
438+
None,
439+
Some(make::expr_literal("2").into()),
440+
)
441+
.into()],
442+
None,
443+
);
444+
445+
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
446+
447+
let mut editor = SyntaxEditor::new(root.syntax().clone());
448+
449+
editor.insert(
450+
Position::first_child_of(root.stmt_list().unwrap().syntax()),
451+
make_let_stmt(
452+
None,
453+
make::ext::simple_ident_pat(make::name("first")).into(),
454+
None,
455+
Some(make::expr_literal("1").into()),
456+
)
457+
.syntax(),
458+
);
459+
460+
editor.insert(
461+
Position::after(second_let.syntax()),
462+
make_let_stmt(
463+
None,
464+
make::ext::simple_ident_pat(make::name("third")).into(),
465+
None,
466+
Some(make::expr_literal("3").into()),
467+
)
468+
.syntax(),
469+
);
470+
471+
let edit = editor.finish();
472+
473+
let expect = expect![[r#"
474+
let first = 1;{
475+
let second = 2;let third = 3;
476+
}"#]];
477+
expect.assert_eq(&edit.root.to_string());
478+
}
479+
480+
#[test]
481+
fn test_insert_dependent() {
482+
let root = make::block_expr(
483+
[],
484+
Some(
485+
make::block_expr(
486+
[make::let_stmt(
487+
make::ext::simple_ident_pat(make::name("second")).into(),
488+
None,
489+
Some(make::expr_literal("2").into()),
490+
)
491+
.into()],
492+
None,
493+
)
494+
.into(),
495+
),
496+
);
497+
498+
let inner_block =
499+
root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
500+
let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
501+
502+
let mut editor = SyntaxEditor::new(root.syntax().clone());
503+
504+
let new_block_expr =
505+
make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone())));
506+
507+
let first_let = make_let_stmt(
508+
Some(&mut editor),
509+
make::ext::simple_ident_pat(make::name("first")).into(),
510+
None,
511+
Some(make::expr_literal("1").into()),
512+
);
513+
514+
let third_let = make_let_stmt(
515+
Some(&mut editor),
516+
make::ext::simple_ident_pat(make::name("third")).into(),
517+
None,
518+
Some(make::expr_literal("3").into()),
519+
);
520+
521+
editor.insert(
522+
Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
523+
first_let.syntax(),
524+
);
525+
editor.insert(Position::after(second_let.syntax()), third_let.syntax());
526+
editor.replace(inner_block.syntax(), new_block_expr.syntax());
527+
528+
let edit = editor.finish();
529+
530+
let expect = expect![[r#"
531+
{
532+
{
533+
let first = 1;{
534+
let second = 2;let third = 3;
535+
}
536+
}
537+
}"#]];
538+
expect.assert_eq(&edit.root.to_string());
539+
}
540+
541+
#[test]
542+
fn test_replace_root_with_dependent() {
543+
let root = make::block_expr(
544+
[make::let_stmt(
545+
make::ext::simple_ident_pat(make::name("second")).into(),
546+
None,
547+
Some(make::expr_literal("2").into()),
548+
)
549+
.into()],
550+
None,
551+
);
552+
553+
let inner_block = root.clone();
554+
555+
let mut editor = SyntaxEditor::new(root.syntax().clone());
556+
557+
let new_block_expr =
558+
make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone())));
559+
560+
let first_let = make_let_stmt(
561+
Some(&mut editor),
562+
make::ext::simple_ident_pat(make::name("first")).into(),
563+
None,
564+
Some(make::expr_literal("1").into()),
565+
);
566+
567+
editor.insert(
568+
Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
569+
first_let.syntax(),
570+
);
571+
editor.replace(inner_block.syntax(), new_block_expr.syntax());
572+
573+
let edit = editor.finish();
574+
575+
let expect = expect![[r#"
576+
{
577+
let first = 1;{
578+
let second = 2;
579+
}
580+
}"#]];
581+
expect.assert_eq(&edit.root.to_string());
582+
}
396583
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
192192
}
193193

194194
// Apply changes
195+
let mut root = tree_mutator.mutable_clone;
196+
195197
for change in changes {
196198
match change {
197199
Change::Insert(position, element) => {
@@ -205,6 +207,9 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
205207
Change::Replace(target, None) => {
206208
target.detach();
207209
}
210+
Change::Replace(SyntaxElement::Node(target), Some(new_target)) if &target == &root => {
211+
root = new_target.into_node().expect("root node replacement should be a node");
212+
}
208213
Change::Replace(target, Some(new_target)) => {
209214
let parent = target.parent().unwrap();
210215
parent.splice_children(target.index()..target.index() + 1, vec![new_target]);
@@ -214,7 +219,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
214219

215220
// Propagate annotations
216221
let annotations = annotations.into_iter().filter_map(|(element, annotation)| {
217-
match mappings.upmap_element(&element, &tree_mutator.mutable_clone) {
222+
match mappings.upmap_element(&element, &root) {
218223
// Needed to follow the new tree to find the resulting element
219224
Some(Ok(mapped)) => Some((mapped, annotation)),
220225
// Element did not need to be mapped
@@ -230,11 +235,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
230235
annotation_groups.entry(annotation).or_insert(vec![]).push(element);
231236
}
232237

233-
SyntaxEdit {
234-
root: tree_mutator.mutable_clone,
235-
changed_elements,
236-
annotations: annotation_groups,
237-
}
238+
SyntaxEdit { root, changed_elements, annotations: annotation_groups }
238239
}
239240

240241
fn to_owning_node(element: &SyntaxElement) -> SyntaxNode {
@@ -278,15 +279,14 @@ impl ChangedAncestor {
278279
}
279280

280281
struct TreeMutator {
281-
immutable: SyntaxNode,
282282
mutable_clone: SyntaxNode,
283283
}
284284

285285
impl TreeMutator {
286286
fn new(immutable: &SyntaxNode) -> TreeMutator {
287287
let immutable = immutable.clone();
288288
let mutable_clone = immutable.clone_for_update();
289-
TreeMutator { immutable, mutable_clone }
289+
TreeMutator { mutable_clone }
290290
}
291291

292292
fn make_element_mut(&self, element: &SyntaxElement) -> SyntaxElement {

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ impl SyntaxMapping {
108108
input_ancestor: &SyntaxNode,
109109
output_ancestor: &SyntaxNode,
110110
) -> Result<Vec<usize>, MissingMapping> {
111-
eprintln!("mapping ancestor {input_ancestor:#?} to {output_ancestor:#?}");
112111
let mut current =
113112
self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone());
114113
let mut upmap_chain = vec![current.index()];

0 commit comments

Comments
 (0)