swift-syntax icon indicating copy to clipboard operation
swift-syntax copied to clipboard

Implement tracking of syntax nodes if the syntax tree is edited

Open ahoppen opened this issue 1 year ago • 11 comments

On any syntax tree, you can call .tracked. Any tree that is derived from that tracked tree is able to find the original syntax node in the tracked tree. Use cases of this could be to find the original source ranges of syntax nodes that have been re-written in macros or to allow a syntax rewriter to modify a syntax tree while still being able to get the original source locations for any node that was kept.

The basic idea is as follows: Every syntax node within the tree already contains an indexInTree, which is its index in a depth-first traversal. The node of each tree stores the ranges of indexInTree that have been re-used from the original tree and the offset my which their indexInTree has been shifted compared to the original tree.

For example, if you have the following tree (index in tree in parentheses)

      a (0)
     / \
(1) b   c (2)

And you construct a new tree a follows

       x (0)
     /   \
(1) y     a (2)
         / \
    (3) b   c (4)

Then the new tree would have a single syntax tracking range of 2...4: -2. This defines that nodes with indexInTree 2 to 4 occur in the tracked tree and that to receive the indexInTree within the tracked tree, 2 needs to be subtracted from the node in the derived tree.


I still need to investigate the performance implications of this change. My assumption is that

  • I need to get rid of the array that is now being created in the syntax node initializers because arrays usually result in a costly memory allocation
  • After that, the performance impact should be minimal when tracking is disabled.
    • Node modification requires two pointer dereferences plus null check (rootInfo.syntaxTracking?.trackedTree != nil from trackedTree != nil in replacingChild)
    • Node creation requires #-of-nodes pointer dereferences and null checks to check if any of them have a trackedTree. The cache should be able to serve these fairly quickly if you assume that many of these nodes have been recently created or are from the same original tree and thus share the same node

ahoppen avatar Aug 30 '23 01:08 ahoppen

@swift-ci Please test

ahoppen avatar Aug 31 '23 21:08 ahoppen

@swift-ci Please test

ahoppen avatar Sep 01 '23 20:09 ahoppen

@swift-ci Please test Windows

ahoppen avatar Sep 01 '23 20:09 ahoppen

@swift-ci Please test

ahoppen avatar Sep 06 '23 00:09 ahoppen

@swift-ci Please test

ahoppen avatar Sep 06 '23 01:09 ahoppen

@swift-ci Please test Windows

ahoppen avatar Sep 06 '23 02:09 ahoppen

@swift-ci Please test

ahoppen avatar Sep 08 '23 16:09 ahoppen

@swift-ci Please test Windows

ahoppen avatar Sep 08 '23 16:09 ahoppen

@swift-ci Please test macOS

ahoppen avatar Sep 11 '23 21:09 ahoppen