From 22fa144016eb43e63f0da570a64e5644d06c6f4d Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Thu, 28 Aug 2025 14:47:20 -0400 Subject: [PATCH] fix(lib): check if an `ERROR` node is named before assuming it's the builtin error node (cherry picked from commit b7f36a13bad7c9b672022d21d741e034096dda4d) --- cli/src/tests/query_test.rs | 32 ++++++++++++++++++- lib/src/language.c | 2 +- .../test_grammars/anonymous_error/corpus.txt | 9 ++++++ .../test_grammars/anonymous_error/grammar.js | 6 ++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/test_grammars/anonymous_error/corpus.txt create mode 100644 test/fixtures/test_grammars/anonymous_error/grammar.js diff --git a/cli/src/tests/query_test.rs b/cli/src/tests/query_test.rs index 09aac8a7..e769cf89 100644 --- a/cli/src/tests/query_test.rs +++ b/cli/src/tests/query_test.rs @@ -17,7 +17,10 @@ use super::helpers::{ }; use crate::tests::{ generate_parser, - helpers::query_helpers::{collect_captures, collect_matches}, + helpers::{ + fixtures::get_test_fixture_language, + query_helpers::{collect_captures, collect_matches}, + }, ITERATION_COUNT, }; @@ -5697,3 +5700,30 @@ fn test_query_with_predicate_causing_oob_access() { (#set! injection.language \"regex\"))"; Query::new(&language, query).unwrap(); } + +#[test] +fn test_query_with_anonymous_error_node() { + let language = get_test_fixture_language("anonymous_error"); + let mut parser = Parser::new(); + parser.set_language(&language).unwrap(); + + let source = "ERROR"; + + let tree = parser.parse(source, None).unwrap(); + let query = Query::new( + &language, + r#" + "ERROR" @error + (document "ERROR" @error) + "#, + ) + .unwrap(); + let mut cursor = QueryCursor::new(); + let matches = cursor.matches(&query, tree.root_node(), source.as_bytes()); + let matches = collect_matches(matches, &query, source); + + assert_eq!( + matches, + vec![(1, vec![("error", "ERROR")]), (0, vec![("error", "ERROR")])] + ); +} diff --git a/lib/src/language.c b/lib/src/language.c index b341a670..2dce6998 100644 --- a/lib/src/language.c +++ b/lib/src/language.c @@ -186,7 +186,7 @@ TSSymbol ts_language_symbol_for_name( uint32_t length, bool is_named ) { - if (!strncmp(string, "ERROR", length)) return ts_builtin_sym_error; + if (is_named && !strncmp(string, "ERROR", length)) return ts_builtin_sym_error; uint16_t count = (uint16_t)ts_language_symbol_count(self); for (TSSymbol i = 0; i < count; i++) { TSSymbolMetadata metadata = ts_language_symbol_metadata(self, i); diff --git a/test/fixtures/test_grammars/anonymous_error/corpus.txt b/test/fixtures/test_grammars/anonymous_error/corpus.txt new file mode 100644 index 00000000..f1dd3d34 --- /dev/null +++ b/test/fixtures/test_grammars/anonymous_error/corpus.txt @@ -0,0 +1,9 @@ +====================== +A simple error literal +====================== + +ERROR + +--- + +(document) diff --git a/test/fixtures/test_grammars/anonymous_error/grammar.js b/test/fixtures/test_grammars/anonymous_error/grammar.js new file mode 100644 index 00000000..c06d1bd2 --- /dev/null +++ b/test/fixtures/test_grammars/anonymous_error/grammar.js @@ -0,0 +1,6 @@ +module.exports = grammar({ + name: 'anonymous_error', + rules: { + document: $ => repeat(choice('ok', 'ERROR')), + } +});