From 0c43988a5e17eb5feecac103f88cdae49dc5973d Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Thu, 26 Sep 2024 23:15:26 -0400 Subject: [PATCH] fix(lib): correct descendant-for-range behavior with zero-width tokens --- cli/src/tests/node_test.rs | 20 ++++++++++++++++++++ lib/src/node.c | 18 ++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cli/src/tests/node_test.rs b/cli/src/tests/node_test.rs index 4b987a53..20ae9c3b 100644 --- a/cli/src/tests/node_test.rs +++ b/cli/src/tests/node_test.rs @@ -658,6 +658,26 @@ fn test_node_descendant_for_range() { assert_eq!(pair_node.end_byte(), string_index + 9); assert_eq!(pair_node.start_position(), Point::new(6, 4)); assert_eq!(pair_node.end_position(), Point::new(6, 13)); + + // Zero-width token + { + let code = ""; + let mut parser = Parser::new(); + parser.set_language(&get_language("html")).unwrap(); + + let tree = parser.parse(code, None).unwrap(); + let root = tree.root_node(); + + let child = root + .named_descendant_for_point_range(Point::new(0, 8), Point::new(0, 8)) + .unwrap(); + assert_eq!(child.kind(), "raw_text"); + + let child2 = root.named_descendant_for_byte_range(8, 8).unwrap(); + assert_eq!(child2.kind(), "raw_text"); + + assert_eq!(child, child2); + } } #[test] diff --git a/lib/src/node.c b/lib/src/node.c index 83d48cb8..3d68c765 100644 --- a/lib/src/node.c +++ b/lib/src/node.c @@ -375,9 +375,13 @@ static inline TSNode ts_node__descendant_for_byte_range( uint32_t node_end = iterator.position.bytes; // The end of this node must extend far enough forward to touch - // the end of the range and exceed the start of the range. + // the end of the range if (node_end < range_end) continue; - if (node_end <= range_start) continue; + + // ...and exceed the start of the range, unless the node itself is + // empty, in which case it must at least be equal to the start of the range. + bool is_empty = ts_node_start_byte(child) == node_end; + if (is_empty ? node_end < range_start : node_end <= range_start) continue; // The start of this node must extend far enough backward to // touch the start of the range. @@ -414,9 +418,15 @@ static inline TSNode ts_node__descendant_for_point_range( TSPoint node_end = iterator.position.extent; // The end of this node must extend far enough forward to touch - // the end of the range and exceed the start of the range. + // the end of the range if (point_lt(node_end, range_end)) continue; - if (point_lte(node_end, range_start)) continue; + + // ...and exceed the start of the range, unless the node itself is + // empty, in which case it must at least be equal to the start of the range. + bool is_empty = point_eq(ts_node_start_point(child), node_end); + if (is_empty ? point_lt(node_end, range_start) : point_lte(node_end, range_start)) { + continue; + } // The start of this node must extend far enough backward to // touch the start of the range.