swift-syntax
swift-syntax copied to clipboard
Implement tracking of syntax nodes if the syntax tree is edited
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
fromtrackedTree != nil
inreplacingChild
) - 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
- Node modification requires two pointer dereferences plus null check (
@swift-ci Please test
@swift-ci Please test
@swift-ci Please test Windows
@swift-ci Please test
@swift-ci Please test
@swift-ci Please test Windows
@swift-ci Please test
@swift-ci Please test Windows
@swift-ci Please test macOS