From 2f5df7add78e254f672e23a6e13621817663fb6c Mon Sep 17 00:00:00 2001 From: Volodymyr Chernetskyi <19735328+chernetskyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:20:15 +0200 Subject: [PATCH] fix(treesitter): #has-parent? errors on a node with no parent Problem: The #has-parent? predicate indexes the result of node:parent() without checking it, so a capture that matches a tree's root node raises query.lua:600: attempt to index a nil value instead of simply not matching. In a highlights query that breaks highlighting for the whole buffer. The sibling #has-ancestor? predicate handles the same situation. Solution: Treat a missing parent as "does not match". AI-assisted --- runtime/lua/vim/treesitter/query.lua | 3 ++- test/functional/treesitter/query_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 3e18b8973a..a612870475 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -597,7 +597,8 @@ local predicate_handlers = { end for _, node in ipairs(nodes) do - if vim.list_contains({ unpack(predicate, 3) }, node:parent():type()) then + local parent = node:parent() + if parent and vim.list_contains({ unpack(predicate, 3) }, parent:type()) then return true end end diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index 04f2f519e9..f5de261d17 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -452,6 +452,26 @@ void ui_refresh(void) eq({}, result) end) + it('supports builtin predicate has-parent?', function() + insert([[ + int x = 123; + enum C { y = 124 };]]) + + local result = exec_lua( + get_query_result, + [[((number_literal) @literal (#has-parent? @literal "init_declarator"))]] + ) + eq({ { 'literal', 'number_literal', { 0, 8, 0, 11 }, '123' } }, result) + + -- The root node has no parent: the predicate does not match, rather than + -- erroring on the nil parent. + result = exec_lua( + get_query_result, + [[((translation_unit) @root (#has-parent? @root "translation_unit"))]] + ) + eq({}, result) + end) + it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() insert('char* astring = "Hello World!";')