perf(treesitter): use child_containing_descendant() in has-ancestor? (#28512)

Problem: `has-ancestor?` is O(n²) for the depth of the tree since it iterates over each of the node's ancestors (bottom-up), and each ancestor takes O(n) time.
This happens because tree-sitter's nodes don't store their parent nodes, and the tree is searched (top-down) each time a new parent is requested.

Solution: Make use of new `ts_node_child_containing_descendant()` in tree-sitter v0.22.6 (which is now the minimum required version) to rewrite the `has-ancestor?` predicate in C to become O(n).

For a sample file, decreases the time taken by `has-ancestor?` from 360ms to 6ms.
This commit is contained in:
vanaigr
2024-05-16 09:57:58 -05:00
committed by GitHub
parent 31dc627969
commit 4b02916334
7 changed files with 129 additions and 27 deletions

View File

@@ -457,17 +457,8 @@ local predicate_handlers = {
end
for _, node in ipairs(nodes) do
local ancestor_types = {} --- @type table<string, boolean>
for _, type in ipairs({ unpack(predicate, 3) }) do
ancestor_types[type] = true
end
local cur = node:parent()
while cur do
if ancestor_types[cur:type()] then
return true
end
cur = cur:parent()
if node:__has_ancestor(predicate) then
return true
end
end
return false