From a1ef461f5b660c4a160e602d6706a12bba7ada43 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 12 Oct 2025 09:09:11 +0200 Subject: [PATCH 1/2] ok --- crates/pgt_treesitter/src/context/mod.rs | 45 +++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/crates/pgt_treesitter/src/context/mod.rs b/crates/pgt_treesitter/src/context/mod.rs index 80755324a..408a637de 100644 --- a/crates/pgt_treesitter/src/context/mod.rs +++ b/crates/pgt_treesitter/src/context/mod.rs @@ -470,7 +470,9 @@ impl<'a> TreesitterContext<'a> { } // We have arrived at the leaf node - if current_node.child_count() == 0 { + if current_node.child_count() == 0 + || current_node.first_child_for_byte(self.position).is_none() + { self.node_under_cursor = Some(NodeUnderCursor::from(current_node)); return; } @@ -1214,4 +1216,45 @@ mod tests { _ => unreachable!(), } } + + #[test] + fn does_not_overflow_callstack_on_smaller_treesitter_child() { + // Instead of autocompleting "FROM", we'll assume that the user + // is selecting a certain column name, such as `frozen_account`. + let query = format!( + r#"select * from persons where id = @i{}d;"#, + QueryWithCursorPosition::cursor_marker() + ); + + /* + The query (currently) yields the following treesitter tree for the WHERE clause: + + where [29..43] 'where id = @id' + keyword_where [29..34] 'where' + binary_expression [35..43] 'id = @id' + field [35..37] 'id' + identifier [35..37] 'id' + = [38..39] '=' + field [40..43] '@id' + identifier [40..43] '@id' + @ [40..41] '@' + + You can see that the '@' is a child of the "identifier" but has a range smaller than its parent's. + This would crash our context parsing because, at position 42, we weren't at the leaf node but also couldn't + go to a child on that position. + */ + + let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position(); + + let tree = get_tree(text.as_str()); + + let params = TreeSitterContextParams { + position: (position as u32).into(), + text: &text, + tree: &tree, + }; + + // should simply not panic + let _ = TreesitterContext::new(params); + } } From 9e7429452a07635369f7e926292c197edcb90042 Mon Sep 17 00:00:00 2001 From: Julian Domke <68325451+juleswritescode@users.noreply.github.com> Date: Sun, 12 Oct 2025 09:12:33 +0200 Subject: [PATCH 2/2] Update crates/pgt_treesitter/src/context/mod.rs --- crates/pgt_treesitter/src/context/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/pgt_treesitter/src/context/mod.rs b/crates/pgt_treesitter/src/context/mod.rs index 408a637de..e695351b4 100644 --- a/crates/pgt_treesitter/src/context/mod.rs +++ b/crates/pgt_treesitter/src/context/mod.rs @@ -1219,8 +1219,6 @@ mod tests { #[test] fn does_not_overflow_callstack_on_smaller_treesitter_child() { - // Instead of autocompleting "FROM", we'll assume that the user - // is selecting a certain column name, such as `frozen_account`. let query = format!( r#"select * from persons where id = @i{}d;"#, QueryWithCursorPosition::cursor_marker()