Skip to main content

ra_ap_syntax/
syntax_editor.rs

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