From 6dd459b4abad7ceb789926d93a063942145e092d Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Thu, 4 Jul 2024 20:14:52 -0400 Subject: [PATCH] fix(lib): an empty root node should not precede an empty range The problem is, given an empty file, the root node of this file spans 0 bytes. As such, the logic for determining whether or not the node precedes the range fails, and is true when it should be false. --- cli/src/tests/query_test.rs | 14 ++++++++++++++ lib/src/query.c | 22 ++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/cli/src/tests/query_test.rs b/cli/src/tests/query_test.rs index 90d940c8..d188921b 100644 --- a/cli/src/tests/query_test.rs +++ b/cli/src/tests/query_test.rs @@ -5194,3 +5194,17 @@ fn test_query_wildcard_with_immediate_first_child() { ], ); } + +#[test] +fn test_query_on_empty_source_code() { + let language = get_language("javascript"); + let source_code = ""; + let query = r#"(program) @program"#; + let query = Query::new(&language, query).unwrap(); + assert_query_matches( + &language, + &query, + source_code, + &[(0, vec![("program", "")])], + ); +} diff --git a/lib/src/query.c b/lib/src/query.c index f93a688f..c9e8fbd0 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -3541,6 +3541,13 @@ static inline bool ts_query_cursor__advance( // Get the properties of the current node. TSNode node = ts_tree_cursor_current_node(&self->cursor); TSNode parent_node = ts_tree_cursor_parent_node(&self->cursor); + + uint32_t start_byte = ts_node_start_byte(node); + uint32_t end_byte = ts_node_end_byte(node); + TSPoint start_point = ts_node_start_point(node); + TSPoint end_point = ts_node_end_point(node); + bool is_empty = start_byte == end_byte; + bool parent_precedes_range = !ts_node_is_null(parent_node) && ( ts_node_end_byte(parent_node) <= self->start_byte || point_lte(ts_node_end_point(parent_node), self->start_point) @@ -3549,13 +3556,16 @@ static inline bool ts_query_cursor__advance( ts_node_start_byte(parent_node) >= self->end_byte || point_gte(ts_node_start_point(parent_node), self->end_point) ); - bool node_precedes_range = parent_precedes_range || ( - ts_node_end_byte(node) <= self->start_byte || - point_lte(ts_node_end_point(node), self->start_point) - ); + bool node_precedes_range = + parent_precedes_range || + end_byte < self->start_byte || + point_lt(end_point, self->start_point) || + (!is_empty && end_byte == self->start_byte) || + (!is_empty && point_eq(end_point, self->start_point)); + bool node_follows_range = parent_follows_range || ( - ts_node_start_byte(node) >= self->end_byte || - point_gte(ts_node_start_point(node), self->end_point) + start_byte >= self->end_byte || + point_gte(start_point, self->end_point) ); bool parent_intersects_range = !parent_precedes_range && !parent_follows_range; bool node_intersects_range = !node_precedes_range && !node_follows_range;