void visit(Syntax Node) override { if (didReuseNode(Node.getId())) { // Node has been reused, add it to the list auto Start = Node.getAbsolutePositionBeforeLeadingTrivia(); auto End = Node.getAbsoluteEndPositionAfterTrailingTrivia(); ReusedRegions.push_back({Start, End}); } else { SyntaxVisitor::visit(Node); } }
bool SyntaxParsingCache::nodeCanBeReused(const Syntax &Node, size_t NodeStart, size_t Position, SyntaxKind Kind) const { // Computing the value of NodeStart on the fly is faster than determining a // node's absolute position, but make sure the values match in an assertion // build assert(NodeStart == Node.getAbsolutePositionBeforeLeadingTrivia().getOffset()); if (NodeStart != Position) return false; if (Node.getKind() != Kind) return false; // Node can also not be reused if an edit has been made in the next token's // text, e.g. because `private struct Foo {}` parses as a CodeBlockItem with a // StructDecl inside and `private struc Foo {}` parses as two CodeBlockItems // one for `private` and one for `struc Foo {}` size_t NextLeafNodeLength = 0; if (auto NextNode = Node.getData().getNextNode()) { auto NextLeafNode = NextNode->getFirstToken(); auto NextRawNode = NextLeafNode->getRaw(); assert(NextRawNode->isPresent()); NextLeafNodeLength += NextRawNode->getTokenText().size(); for (auto TriviaPiece : NextRawNode->getLeadingTrivia()) { NextLeafNodeLength += TriviaPiece.getTextLength(); } } auto NodeEnd = NodeStart + Node.getTextLength(); for (auto Edit : Edits) { // Check if this node or the trivia of the next node has been edited. If it // has, we cannot reuse it. if (Edit.intersectsOrTouchesRange(NodeStart, NodeEnd + NextLeafNodeLength)) return false; } return true; }