Skip to main content

ra_ap_syntax/
syntax_editor.rs

1//! Syntax Tree editor
2//!
3//! Inspired by Roslyn's [`SyntaxEditor`].
4//!
5//! [`SyntaxEditor`]: https://github.com/dotnet/roslyn/blob/43b0b05cc4f492fd5de00f6f6717409091df8daa/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs
6
7use std::{
8    cell::RefCell,
9    fmt, iter,
10    num::NonZeroU32,
11    ops::RangeInclusive,
12    sync::atomic::{AtomicU32, Ordering},
13};
14
15use rowan::TextRange;
16use rustc_hash::FxHashMap;
17
18use crate::{
19    AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T,
20    ast::{self, edit::IndentLevel, syntax_factory::SyntaxFactory},
21};
22
23mod edit_algo;
24mod edits;
25mod mapping;
26
27pub use edits::{GetOrCreateWhereClause, Removable};
28pub use mapping::{SyntaxMapping, SyntaxMappingBuilder};
29
30#[derive(Debug)]
31pub struct SyntaxEditor {
32    root: SyntaxNode,
33    changes: RefCell<Vec<Change>>,
34    annotations: RefCell<Vec<(SyntaxElement, SyntaxAnnotation)>>,
35    make: SyntaxFactory,
36}
37
38impl SyntaxEditor {
39    /// Creates a syntax editor from `root`.
40    ///
41    /// The returned `root` is guaranteed to be a detached, immutable node.
42    /// If the provided node is not a root (i.e., has a parent), it is cloned
43    /// into a fresh subtree to satisfy syntax editor invariants.
44    pub fn new(root: SyntaxNode) -> (Self, SyntaxNode) {
45        let mut root = root;
46
47        if root.parent().is_some() {
48            root = root.clone_subtree()
49        };
50
51        let editor = Self {
52            root: root.clone(),
53            changes: RefCell::new(Vec::new()),
54            annotations: RefCell::new(Vec::new()),
55            make: SyntaxFactory::with_mappings(),
56        };
57
58        (editor, root)
59    }
60
61    /// Typed-node variant of [`SyntaxEditor::new`].
62    pub fn with_ast_node<T>(root: &T) -> (Self, T)
63    where
64        T: AstNode,
65    {
66        let (editor, root) = Self::new(root.syntax().clone());
67
68        (editor, T::cast(root).unwrap())
69    }
70
71    pub fn make(&self) -> &SyntaxFactory {
72        &self.make
73    }
74
75    pub fn add_annotation(&self, element: impl Element, annotation: SyntaxAnnotation) {
76        self.annotations.borrow_mut().push((element.syntax_element(), annotation))
77    }
78
79    pub fn add_annotation_all(&self, elements: Vec<impl Element>, annotation: SyntaxAnnotation) {
80        self.annotations
81            .borrow_mut()
82            .extend(elements.into_iter().map(|e| e.syntax_element()).zip(iter::repeat(annotation)));
83    }
84
85    pub fn merge(&self, other: SyntaxEditor) {
86        debug_assert!(
87            self.root == other.root || other.root.ancestors().any(|node| node == self.root),
88            "{:?} is not in the same tree as {:?}",
89            other.root,
90            self.root
91        );
92
93        self.changes.borrow_mut().append(&mut other.changes.into_inner());
94        if let Some(mut m) = self.make.mappings() {
95            m.merge(other.make.take());
96        }
97        self.annotations.borrow_mut().append(&mut other.annotations.into_inner());
98    }
99
100    pub fn insert(&self, position: Position, element: impl Element) {
101        debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
102        self.changes.borrow_mut().push(Change::Insert(position, element.syntax_element()))
103    }
104
105    pub fn insert_all(&self, position: Position, elements: Vec<SyntaxElement>) {
106        debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
107        self.changes.borrow_mut().push(Change::InsertAll(position, elements))
108    }
109
110    pub fn insert_with_whitespace(&self, position: Position, element: impl Element) {
111        self.insert_all_with_whitespace(position, vec![element.syntax_element()])
112    }
113
114    pub fn insert_all_with_whitespace(&self, position: Position, mut elements: Vec<SyntaxElement>) {
115        if let Some(first) = elements.first()
116            && let Some(ws) = ws_before(&position, first, &self.make)
117        {
118            elements.insert(0, ws.into());
119        }
120        if let Some(last) = elements.last()
121            && let Some(ws) = ws_after(&position, last, &self.make)
122        {
123            elements.push(ws.into());
124        }
125        self.insert_all(position, elements)
126    }
127
128    pub fn delete(&self, element: impl Element) {
129        let element = element.syntax_element();
130        debug_assert!(is_ancestor_or_self_of_element(&element, &self.root));
131        debug_assert!(
132            !matches!(&element, SyntaxElement::Node(node) if node == &self.root),
133            "should not delete root node"
134        );
135        let mut changes = self.changes.borrow_mut();
136        for change in changes.iter_mut() {
137            if let Change::Replace(existing, replacement) = change
138                && *existing == element
139            {
140                if replacement.is_none() {
141                    return;
142                }
143                *replacement = None;
144                return;
145            }
146        }
147        changes.push(Change::Replace(element, None));
148    }
149
150    pub fn delete_all(&self, range: RangeInclusive<SyntaxElement>) {
151        if range.start() == range.end() {
152            self.delete(range.start());
153            return;
154        }
155
156        debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root));
157        self.changes.borrow_mut().push(Change::ReplaceAll(range, Vec::new()))
158    }
159
160    pub fn replace(&self, old: impl Element, new: impl Element) {
161        let old = old.syntax_element();
162        debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
163        let new = new.syntax_element();
164        let mut changes = self.changes.borrow_mut();
165        for change in changes.iter_mut() {
166            if let Change::Replace(existing, replacement) = change
167                && *existing == old
168            {
169                match replacement {
170                    None => return,
171                    Some(existing_new) if *existing_new == new => return,
172                    Some(existing_new) => {
173                        *existing_new = new;
174                        return;
175                    }
176                }
177            }
178        }
179        changes.push(Change::Replace(old, Some(new)));
180    }
181
182    pub fn replace_with_many(&self, old: impl Element, new: Vec<SyntaxElement>) {
183        let old = old.syntax_element();
184        debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
185        debug_assert!(
186            !(matches!(&old, SyntaxElement::Node(node) if node == &self.root) && new.len() > 1),
187            "cannot replace root node with many elements"
188        );
189        self.changes.borrow_mut().push(Change::ReplaceWithMany(old.syntax_element(), new));
190    }
191
192    pub fn replace_all(&self, range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
193        if range.start() == range.end() {
194            self.replace_with_many(range.start(), new);
195            return;
196        }
197
198        debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root));
199        self.changes.borrow_mut().push(Change::ReplaceAll(range, new))
200    }
201
202    pub fn finish(self) -> SyntaxEdit {
203        edit_algo::apply_edits(self)
204    }
205
206    pub fn deleted(&self, element: impl Element) -> bool {
207        let element = element.syntax_element();
208        self.changes
209            .borrow()
210            .iter()
211            .any(|change| matches!(change, Change::Replace(existing, None) if *existing == element))
212    }
213}
214
215/// Represents a completed [`SyntaxEditor`] operation.
216pub struct SyntaxEdit {
217    old_root: SyntaxNode,
218    new_root: SyntaxNode,
219    changed_elements: Vec<SyntaxElement>,
220    annotations: FxHashMap<SyntaxAnnotation, Vec<SyntaxElement>>,
221}
222
223impl SyntaxEdit {
224    /// Root of the initial unmodified syntax tree.
225    pub fn old_root(&self) -> &SyntaxNode {
226        &self.old_root
227    }
228
229    /// Root of the modified syntax tree.
230    pub fn new_root(&self) -> &SyntaxNode {
231        &self.new_root
232    }
233
234    /// Which syntax elements in the modified syntax tree were inserted or
235    /// modified as part of the edit.
236    ///
237    /// Note that for syntax nodes, only the upper-most parent of a set of
238    /// changes is included, not any child elements that may have been modified.
239    pub fn changed_elements(&self) -> &[SyntaxElement] {
240        self.changed_elements.as_slice()
241    }
242
243    /// Finds which syntax elements have been annotated with the given
244    /// annotation.
245    ///
246    /// Note that an annotation might not appear in the modified syntax tree if
247    /// the syntax elements that were annotated did not make it into the final
248    /// syntax tree.
249    pub fn find_annotation(&self, annotation: SyntaxAnnotation) -> &[SyntaxElement] {
250        self.annotations.get(&annotation).as_ref().map_or(&[], |it| it.as_slice())
251    }
252
253    pub fn find_element(&self, old_node: &SyntaxNode) -> Option<SyntaxNode> {
254        let old_root_start = self.old_root.text_range().start();
255        let old_start = old_node.text_range().start() - old_root_start;
256        let new_root_start = self.new_root.text_range().start();
257        let kind = old_node.kind();
258
259        self.new_root
260            .descendants()
261            .find(|it| it.kind() == kind && it.text_range().start() - new_root_start == old_start)
262    }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
266#[repr(transparent)]
267pub struct SyntaxAnnotation(NonZeroU32);
268
269impl Default for SyntaxAnnotation {
270    fn default() -> Self {
271        static COUNTER: AtomicU32 = AtomicU32::new(1);
272
273        // Only consistency within a thread matters, as SyntaxElements are !Send
274        let id = COUNTER.fetch_add(1, Ordering::Relaxed);
275
276        Self(NonZeroU32::new(id).expect("syntax annotation id overflow"))
277    }
278}
279
280/// Position describing where to insert elements
281#[derive(Debug)]
282pub struct Position {
283    repr: PositionRepr,
284}
285
286impl Position {
287    pub(crate) fn parent(&self) -> SyntaxNode {
288        self.place().0
289    }
290
291    pub(crate) fn place(&self) -> (SyntaxNode, usize) {
292        match &self.repr {
293            PositionRepr::FirstChild(parent) => (parent.clone(), 0),
294            PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1),
295        }
296    }
297}
298
299#[derive(Debug)]
300enum PositionRepr {
301    FirstChild(SyntaxNode),
302    After(SyntaxElement),
303}
304
305impl Position {
306    pub fn after(elem: impl Element) -> Position {
307        let repr = PositionRepr::After(elem.syntax_element());
308        Position { repr }
309    }
310
311    pub fn before(elem: impl Element) -> Position {
312        let elem = elem.syntax_element();
313        let repr = match elem.prev_sibling_or_token() {
314            Some(it) => PositionRepr::After(it),
315            None => PositionRepr::FirstChild(elem.parent().unwrap()),
316        };
317        Position { repr }
318    }
319
320    pub fn first_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
321        let repr = PositionRepr::FirstChild(node.clone().into());
322        Position { repr }
323    }
324
325    pub fn last_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
326        let node = node.clone().into();
327        let repr = match node.last_child_or_token() {
328            Some(it) => PositionRepr::After(it),
329            None => PositionRepr::FirstChild(node),
330        };
331        Position { repr }
332    }
333}
334
335#[derive(Debug)]
336enum Change {
337    /// Inserts a single element at the specified position.
338    Insert(Position, SyntaxElement),
339    /// Inserts many elements in-order at the specified position.
340    InsertAll(Position, Vec<SyntaxElement>),
341    /// Represents both a replace single element and a delete element operation.
342    Replace(SyntaxElement, Option<SyntaxElement>),
343    /// Replaces a single element with many elements.
344    ReplaceWithMany(SyntaxElement, Vec<SyntaxElement>),
345    /// Replaces a range of elements with another list of elements.
346    /// Range will always have start != end.
347    ReplaceAll(RangeInclusive<SyntaxElement>, Vec<SyntaxElement>),
348}
349
350impl Change {
351    fn target_range(&self) -> TextRange {
352        match self {
353            Change::Insert(target, _) | Change::InsertAll(target, _) => match &target.repr {
354                PositionRepr::FirstChild(parent) => TextRange::at(
355                    parent.first_child_or_token().unwrap().text_range().start(),
356                    0.into(),
357                ),
358                PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
359            },
360            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => target.text_range(),
361            Change::ReplaceAll(range, _) => {
362                range.start().text_range().cover(range.end().text_range())
363            }
364        }
365    }
366
367    fn target_parent(&self) -> SyntaxNode {
368        match self {
369            Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
370            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => match target {
371                SyntaxElement::Node(target) => target.parent().unwrap_or_else(|| target.clone()),
372                SyntaxElement::Token(target) => target.parent().unwrap(),
373            },
374            Change::ReplaceAll(target, _) => target.start().parent().unwrap(),
375        }
376    }
377
378    fn change_kind(&self) -> ChangeKind {
379        match self {
380            Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
381            Change::Replace(_, _) | Change::ReplaceWithMany(_, _) => ChangeKind::Replace,
382            Change::ReplaceAll(_, _) => ChangeKind::ReplaceRange,
383        }
384    }
385}
386
387#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
388enum ChangeKind {
389    Insert,
390    ReplaceRange,
391    Replace,
392}
393
394impl fmt::Display for Change {
395    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396        match self {
397            Change::Insert(position, node_or_token) => {
398                let parent = position.parent();
399                let mut parent_str = parent.to_string();
400                let target_range = self.target_range().start() - parent.text_range().start();
401
402                parent_str.insert_str(
403                    target_range.into(),
404                    &format!("\x1b[42m{node_or_token}\x1b[0m\x1b[K"),
405                );
406                f.write_str(&parent_str)
407            }
408            Change::InsertAll(position, vec) => {
409                let parent = position.parent();
410                let mut parent_str = parent.to_string();
411                let target_range = self.target_range().start() - parent.text_range().start();
412                let insertion: String = vec.iter().map(|it| it.to_string()).collect();
413
414                parent_str
415                    .insert_str(target_range.into(), &format!("\x1b[42m{insertion}\x1b[0m\x1b[K"));
416                f.write_str(&parent_str)
417            }
418            Change::Replace(old, new) => {
419                if let Some(new) = new {
420                    write!(f, "\x1b[41m{old}\x1b[42m{new}\x1b[0m\x1b[K")
421                } else {
422                    write!(f, "\x1b[41m{old}\x1b[0m\x1b[K")
423                }
424            }
425            Change::ReplaceWithMany(old, vec) => {
426                let new: String = vec.iter().map(|it| it.to_string()).collect();
427                write!(f, "\x1b[41m{old}\x1b[42m{new}\x1b[0m\x1b[K")
428            }
429            Change::ReplaceAll(range, vec) => {
430                let parent = range.start().parent().unwrap();
431                let parent_str = parent.to_string();
432                let pre_range =
433                    TextRange::new(parent.text_range().start(), range.start().text_range().start());
434                let old_range = TextRange::new(
435                    range.start().text_range().start(),
436                    range.end().text_range().end(),
437                );
438                let post_range =
439                    TextRange::new(range.end().text_range().end(), parent.text_range().end());
440
441                let pre_str = &parent_str[pre_range - parent.text_range().start()];
442                let old_str = &parent_str[old_range - parent.text_range().start()];
443                let post_str = &parent_str[post_range - parent.text_range().start()];
444                let new: String = vec.iter().map(|it| it.to_string()).collect();
445
446                write!(f, "{pre_str}\x1b[41m{old_str}\x1b[42m{new}\x1b[0m\x1b[K{post_str}")
447            }
448        }
449    }
450}
451
452/// Utility trait to allow calling syntax editor functions with references or owned
453/// nodes. Do not use outside of this module.
454pub trait Element {
455    fn syntax_element(self) -> SyntaxElement;
456}
457
458impl<E: Element + Clone> Element for &'_ E {
459    fn syntax_element(self) -> SyntaxElement {
460        self.clone().syntax_element()
461    }
462}
463
464impl Element for SyntaxElement {
465    fn syntax_element(self) -> SyntaxElement {
466        self
467    }
468}
469
470impl Element for SyntaxNode {
471    fn syntax_element(self) -> SyntaxElement {
472        self.into()
473    }
474}
475
476impl Element for SyntaxToken {
477    fn syntax_element(self) -> SyntaxElement {
478        self.into()
479    }
480}
481
482fn ws_before(
483    position: &Position,
484    new: &SyntaxElement,
485    factory: &SyntaxFactory,
486) -> Option<SyntaxToken> {
487    let prev = match &position.repr {
488        PositionRepr::FirstChild(_) => return None,
489        PositionRepr::After(it) => it,
490    };
491
492    if prev.kind() == T!['{']
493        && new.kind() == SyntaxKind::USE
494        && let Some(item_list) = prev.parent().and_then(ast::ItemList::cast)
495    {
496        let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into());
497        indent.0 += 1;
498        return Some(factory.whitespace(&format!("\n{indent}")));
499    }
500
501    if prev.kind() == T!['{']
502        && ast::Stmt::can_cast(new.kind())
503        && let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast)
504    {
505        let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into());
506        indent.0 += 1;
507        return Some(factory.whitespace(&format!("\n{indent}")));
508    }
509
510    ws_between(prev, new, factory)
511}
512
513fn ws_after(
514    position: &Position,
515    new: &SyntaxElement,
516    factory: &SyntaxFactory,
517) -> Option<SyntaxToken> {
518    let next = match &position.repr {
519        PositionRepr::FirstChild(parent) => parent.first_child_or_token()?,
520        PositionRepr::After(sibling) => sibling.next_sibling_or_token()?,
521    };
522    ws_between(new, &next, factory)
523}
524
525fn ws_between(
526    left: &SyntaxElement,
527    right: &SyntaxElement,
528    factory: &SyntaxFactory,
529) -> Option<SyntaxToken> {
530    if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE {
531        return None;
532    }
533    if right.kind() == T![;] || right.kind() == T![,] {
534        return None;
535    }
536    if left.kind() == T![<] || right.kind() == T![>] {
537        return None;
538    }
539    if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME {
540        return None;
541    }
542    if right.kind() == SyntaxKind::GENERIC_ARG_LIST {
543        return None;
544    }
545    if right.kind() == SyntaxKind::USE {
546        let mut indent = IndentLevel::from_element(left);
547        if left.kind() == SyntaxKind::USE {
548            indent.0 = IndentLevel::from_element(right).0.max(indent.0);
549        }
550        return Some(factory.whitespace(&format!("\n{indent}")));
551    }
552    if left.kind() == SyntaxKind::ATTR {
553        let mut indent = IndentLevel::from_element(right);
554        if right.kind() == SyntaxKind::ATTR {
555            indent.0 = IndentLevel::from_element(left).0.max(indent.0);
556        }
557        return Some(factory.whitespace(&format!("\n{indent}")));
558    }
559    Some(factory.whitespace(" "))
560}
561
562fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool {
563    node == ancestor || node.ancestors().any(|it| &it == ancestor)
564}
565
566fn is_ancestor_or_self_of_element(node: &SyntaxElement, ancestor: &SyntaxNode) -> bool {
567    matches!(node, SyntaxElement::Node(node) if node == ancestor)
568        || node.ancestors().any(|it| &it == ancestor)
569}
570
571#[cfg(test)]
572mod tests {
573    use expect_test::expect;
574
575    use crate::{
576        AstNode,
577        ast::{self, make},
578    };
579
580    use super::*;
581
582    #[test]
583    fn basic_usage() {
584        let root = make::match_arm(
585            make::wildcard_pat().into(),
586            None,
587            make::expr_tuple([
588                make::expr_bin_op(
589                    make::expr_literal("2").into(),
590                    ast::BinaryOp::ArithOp(ast::ArithOp::Add),
591                    make::expr_literal("2").into(),
592                ),
593                make::expr_literal("true").into(),
594            ])
595            .into(),
596        );
597
598        let (editor, root) = SyntaxEditor::with_ast_node(&root);
599        let make = editor.make();
600
601        let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
602        let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
603
604        let name = make::name("var_name");
605        let name_ref = make::name_ref("var_name");
606
607        let placeholder_snippet = SyntaxAnnotation::default();
608        editor.add_annotation(name.syntax(), placeholder_snippet);
609        editor.add_annotation(name_ref.syntax(), placeholder_snippet);
610
611        let new_block = make.block_expr(
612            [editor
613                .make()
614                .let_stmt(
615                    make.ident_pat(false, false, name.clone()).into(),
616                    None,
617                    Some(to_replace.clone().into()),
618                )
619                .into()],
620            Some(to_wrap.clone().into()),
621        );
622
623        editor.replace(to_replace.syntax(), name_ref.syntax());
624        editor.replace(to_wrap.syntax(), new_block.syntax());
625
626        let edit = editor.finish();
627
628        let expect = expect![[r#"
629            _ => {
630                let var_name = 2 + 2;
631                (var_name, true)
632            },"#]];
633        expect.assert_eq(&edit.new_root.to_string());
634
635        assert_eq!(edit.find_annotation(placeholder_snippet).len(), 2);
636        assert!(
637            edit.annotations
638                .values()
639                .flatten()
640                .all(|element| element.ancestors().any(|it| &it == edit.new_root()))
641        )
642    }
643
644    #[test]
645    fn test_insert_independent() {
646        let root = make::block_expr(
647            [make::let_stmt(
648                make::ext::simple_ident_pat(make::name("second")).into(),
649                None,
650                Some(make::expr_literal("2").into()),
651            )
652            .into()],
653            None,
654        );
655
656        let (editor, root) = SyntaxEditor::with_ast_node(&root);
657        let make = editor.make();
658        let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
659
660        editor.insert(
661            Position::first_child_of(root.stmt_list().unwrap().syntax()),
662            make.let_stmt(
663                make::ext::simple_ident_pat(make::name("first")).into(),
664                None,
665                Some(make::expr_literal("1").into()),
666            )
667            .syntax(),
668        );
669
670        editor.insert(
671            Position::after(second_let.syntax()),
672            make.let_stmt(
673                make::ext::simple_ident_pat(make::name("third")).into(),
674                None,
675                Some(make::expr_literal("3").into()),
676            )
677            .syntax(),
678        );
679
680        let edit = editor.finish();
681
682        let expect = expect![[r#"
683            let first = 1;{
684                let second = 2;let third = 3;
685            }"#]];
686        expect.assert_eq(&edit.new_root.to_string());
687    }
688
689    #[test]
690    fn test_insert_dependent() {
691        let root = make::block_expr(
692            [],
693            Some(
694                make::block_expr(
695                    [make::let_stmt(
696                        make::ext::simple_ident_pat(make::name("second")).into(),
697                        None,
698                        Some(make::expr_literal("2").into()),
699                    )
700                    .into()],
701                    None,
702                )
703                .into(),
704            ),
705        );
706
707        let (editor, root) = SyntaxEditor::with_ast_node(&root);
708        let make = editor.make();
709
710        let inner_block =
711            root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
712        let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
713
714        let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
715
716        let first_let = make.let_stmt(
717            make::ext::simple_ident_pat(make::name("first")).into(),
718            None,
719            Some(make::expr_literal("1").into()),
720        );
721
722        let third_let = make.let_stmt(
723            make::ext::simple_ident_pat(make::name("third")).into(),
724            None,
725            Some(make::expr_literal("3").into()),
726        );
727
728        editor.insert(
729            Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
730            first_let.syntax(),
731        );
732        editor.insert(Position::after(second_let.syntax()), third_let.syntax());
733        editor.replace(inner_block.syntax(), new_block_expr.syntax());
734
735        let edit = editor.finish();
736
737        let expect = expect![[r#"
738            {
739                {
740                let first = 1;{
741                let second = 2;let third = 3;
742            }
743            }
744            }"#]];
745        expect.assert_eq(&edit.new_root.to_string());
746    }
747
748    #[test]
749    fn test_dependent_change_prefers_nearest_changed_ancestor() {
750        let root = make::block_expr(
751            [],
752            Some(
753                make::block_expr(
754                    [make::let_stmt(
755                        make::ext::simple_ident_pat(make::name("second")).into(),
756                        None,
757                        Some(make::expr_literal("2").into()),
758                    )
759                    .into()],
760                    None,
761                )
762                .into(),
763            ),
764        );
765
766        let (editor, root) = SyntaxEditor::with_ast_node(&root);
767        let make = editor.make();
768
769        let inner_block =
770            root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
771
772        let outer_replacement = make.block_expr([], Some(ast::Expr::BlockExpr(root.clone())));
773        let inner_replacement =
774            make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
775
776        let first_let = make.let_stmt(
777            make::ext::simple_ident_pat(make::name("first")).into(),
778            None,
779            Some(make::expr_literal("1").into()),
780        );
781
782        editor.insert(
783            Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
784            first_let.syntax(),
785        );
786        editor.replace(inner_block.syntax(), inner_replacement.syntax());
787        editor.replace(root.syntax(), outer_replacement.syntax());
788
789        let edit = editor.finish();
790
791        let expect = expect![[r#"
792            {
793                {
794                {
795                let first = 1;{
796                let second = 2;
797            }
798            }
799            }
800            }"#]];
801        expect.assert_eq(&edit.new_root.to_string());
802    }
803
804    #[test]
805    fn test_replace_root_with_dependent() {
806        let root = make::block_expr(
807            [make::let_stmt(
808                make::ext::simple_ident_pat(make::name("second")).into(),
809                None,
810                Some(make::expr_literal("2").into()),
811            )
812            .into()],
813            None,
814        );
815
816        let (editor, root) = SyntaxEditor::with_ast_node(&root);
817        let make = editor.make();
818
819        let inner_block = root;
820
821        let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
822
823        let first_let = make.let_stmt(
824            make::ext::simple_ident_pat(make::name("first")).into(),
825            None,
826            Some(make::expr_literal("1").into()),
827        );
828
829        editor.insert(
830            Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
831            first_let.syntax(),
832        );
833        editor.replace(inner_block.syntax(), new_block_expr.syntax());
834
835        let edit = editor.finish();
836
837        let expect = expect![[r#"
838            {
839                let first = 1;{
840                let second = 2;
841            }
842            }"#]];
843        expect.assert_eq(&edit.new_root.to_string());
844    }
845
846    #[test]
847    fn test_replace_token_in_parent() {
848        let parent_fn = make::fn_(
849            None,
850            None,
851            make::name("it"),
852            None,
853            None,
854            make::param_list(None, []),
855            make::block_expr([], Some(make::ext::expr_unit())),
856            Some(make::ret_type(make::ty_unit())),
857            false,
858            false,
859            false,
860            false,
861        );
862
863        let (editor, parent_fn) = SyntaxEditor::with_ast_node(&parent_fn);
864
865        if let Some(ret_ty) = parent_fn.ret_type() {
866            editor.delete(ret_ty.syntax().clone());
867
868            if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token()
869                && token.kind().is_trivia()
870            {
871                editor.delete(token);
872            }
873        }
874
875        if let Some(tail) = parent_fn.body().unwrap().tail_expr() {
876            editor.delete(tail.syntax().clone());
877        }
878
879        let edit = editor.finish();
880
881        let expect = expect![["fn it() {\n    \n}"]];
882        expect.assert_eq(&edit.new_root.to_string());
883    }
884
885    #[test]
886    fn test_more_times_replace_node_to_same_token() {
887        let arg_list =
888            make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
889
890        let (editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
891
892        let target_expr = make::token(parser::SyntaxKind::UNDERSCORE);
893
894        for arg in arg_list.args() {
895            editor.replace(arg.syntax(), &target_expr);
896        }
897
898        let edit = editor.finish();
899
900        let expect = expect![["(_, _)"]];
901        expect.assert_eq(&edit.new_root.to_string());
902    }
903
904    #[test]
905    fn test_more_times_replace_node_to_same_node() {
906        let arg_list =
907            make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
908
909        let (editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
910
911        let target_expr = make::expr_literal("3");
912
913        for arg in arg_list.args() {
914            editor.replace(arg.syntax(), target_expr.syntax());
915        }
916
917        let edit = editor.finish();
918
919        let expect = expect![["(3, 3)"]];
920        expect.assert_eq(&edit.new_root.to_string());
921    }
922
923    #[test]
924    fn test_more_times_insert_node_to_same_node() {
925        let arg_list =
926            make::arg_list([make::expr_literal("1").into(), make::expr_literal("2").into()]);
927
928        let (editor, arg_list) = SyntaxEditor::with_ast_node(&arg_list);
929
930        let target_expr = make::ext::expr_unit();
931
932        for arg in arg_list.args() {
933            editor.insert(Position::before(arg.syntax()), target_expr.syntax());
934        }
935
936        let edit = editor.finish();
937
938        let expect = expect![["(()1, ()2)"]];
939        expect.assert_eq(&edit.new_root.to_string());
940    }
941}