big_code_analysis/
node.rs1#![allow(
8 clippy::cast_precision_loss,
9 clippy::cast_possible_truncation,
10 clippy::cast_sign_loss
11)]
12
13use tree_sitter::Node as OtherNode;
14use tree_sitter::Tree as OtherTree;
15use tree_sitter::{Parser, TreeCursor};
16
17use crate::checker::Checker;
18use crate::traits::{LanguageInfo, Search};
19
20#[derive(Clone, Debug)]
28pub(crate) struct Tree(OtherTree);
29
30impl Tree {
31 pub(crate) fn new<T: LanguageInfo>(code: &[u8]) -> Self {
32 let mut parser = Parser::new();
33 let language = T::get_lang().get_ts_language().expect(
40 "invariant: dispatcher cfg-gates this call behind the per-language Cargo feature",
41 );
42 parser
43 .set_language(&language)
44 .expect("invariant: grammar version is pinned and compatible with bundled tree-sitter");
45
46 Self(
47 parser
48 .parse(code, None)
49 .expect("invariant: parser has a language set and no cancellation flag"),
50 )
51 }
52
53 pub(crate) fn from_ts_tree(tree: OtherTree) -> Self {
54 Self(tree)
55 }
56
57 pub(crate) fn get_root(&self) -> Node<'_> {
58 Node(self.0.root_node())
59 }
60
61 pub(crate) fn as_ts_tree(&self) -> &OtherTree {
62 &self.0
63 }
64}
65
66#[derive(Clone, Copy, Debug)]
71pub struct Node<'a>(pub OtherNode<'a>);
72
73impl<'a> Node<'a> {
74 #[must_use]
77 pub fn has_error(&self) -> bool {
78 self.0.has_error()
79 }
80
81 pub(crate) fn id(&self) -> usize {
82 self.0.id()
83 }
84
85 pub(crate) fn kind(&self) -> &'static str {
86 self.0.kind()
87 }
88
89 pub(crate) fn kind_id(&self) -> u16 {
90 self.0.kind_id()
91 }
92
93 pub(crate) fn utf8_text(&self, data: &'a [u8]) -> Option<&'a str> {
94 self.0.utf8_text(data).ok()
95 }
96
97 pub(crate) fn start_byte(&self) -> usize {
98 self.0.start_byte()
99 }
100
101 pub(crate) fn end_byte(&self) -> usize {
102 self.0.end_byte()
103 }
104
105 pub(crate) fn start_position(&self) -> (usize, usize) {
106 let temp = self.0.start_position();
107 (temp.row, temp.column)
108 }
109
110 pub(crate) fn end_position(&self) -> (usize, usize) {
111 let temp = self.0.end_position();
112 (temp.row, temp.column)
113 }
114
115 pub(crate) fn start_row(&self) -> usize {
116 self.0.start_position().row
117 }
118
119 pub(crate) fn end_row(&self) -> usize {
120 self.0.end_position().row
121 }
122
123 pub(crate) fn parent(&self) -> Option<Node<'a>> {
124 self.0.parent().map(Node)
125 }
126
127 #[inline]
128 pub(crate) fn has_sibling(&self, id: u16) -> bool {
129 self.0.parent().is_some_and(|parent| {
130 parent
131 .children(&mut parent.walk())
132 .any(|child| child.kind_id() == id)
133 })
134 }
135
136 pub(crate) fn previous_sibling(&self) -> Option<Node<'a>> {
137 self.0.prev_sibling().map(Node)
138 }
139
140 #[inline]
149 pub(crate) fn is_child(&self, id: u16) -> bool {
150 let mut cur = self.0.child(0);
151 while let Some(c) = cur {
152 if c.kind_id() == id {
153 return true;
154 }
155 cur = c.next_sibling();
156 }
157 false
158 }
159
160 pub(crate) fn child_count(&self) -> usize {
161 self.0.child_count()
162 }
163
164 pub(crate) fn is_named(&self) -> bool {
169 self.0.is_named()
170 }
171
172 pub(crate) fn child_by_field_name(&self, name: &str) -> Option<Node<'_>> {
173 self.0.child_by_field_name(name).map(Node)
174 }
175
176 pub(crate) fn child(&self, pos: usize) -> Option<Node<'a>> {
177 self.0.child(pos as u32).map(Node)
178 }
179
180 pub(crate) fn field_name_for_child(&self, child_index: u32) -> Option<&'static str> {
185 self.0.field_name_for_child(child_index)
186 }
187
188 pub(crate) fn children(&self) -> impl ExactSizeIterator<Item = Node<'a>> + use<'a> {
189 let mut cursor = self.cursor();
190 cursor.goto_first_child();
191 (0..self.child_count()).map(move |_| {
192 let result = cursor.node();
193 cursor.goto_next_sibling();
194 result
195 })
196 }
197
198 pub(crate) fn cursor(&self) -> Cursor<'a> {
199 Cursor(self.0.walk())
200 }
201
202 #[allow(dead_code)]
203 pub(crate) fn get_parent(&self, level: usize) -> Option<Node<'a>> {
204 let mut level = level;
205 let mut node = *self;
206 while level != 0 {
207 if let Some(parent) = node.parent() {
208 node = parent;
209 } else {
210 return None;
211 }
212 level -= 1;
213 }
214
215 Some(node)
216 }
217
218 pub(crate) fn count_specific_ancestors<T: crate::ParserTrait>(
219 &self,
220 check: fn(&Node) -> bool,
221 stop: fn(&Node) -> bool,
222 ) -> usize {
223 let mut count = 0;
224 let mut node = *self;
225 while let Some(parent) = node.parent() {
226 if stop(&parent) {
227 break;
228 }
229 if check(&parent) && !T::Checker::is_else_if(&parent) {
230 count += 1;
231 }
232 node = parent;
233 }
234 count
235 }
236
237 pub(crate) fn parent_grandparent_match(
243 &self,
244 parent_pred: fn(&Node) -> bool,
245 grand_pred: fn(&Node) -> bool,
246 ) -> bool {
247 let Some(parent) = self.parent() else {
248 return false;
249 };
250 if !parent_pred(&parent) {
251 return false;
252 }
253 let Some(grand) = parent.parent() else {
254 return false;
255 };
256 grand_pred(&grand)
257 }
258}
259
260#[derive(Clone)]
262pub struct Cursor<'a>(TreeCursor<'a>);
263
264impl<'a> Cursor<'a> {
265 pub(crate) fn reset(&mut self, node: &Node<'a>) {
266 self.0.reset(node.0);
267 }
268
269 pub(crate) fn goto_next_sibling(&mut self) -> bool {
270 self.0.goto_next_sibling()
271 }
272
273 pub(crate) fn goto_first_child(&mut self) -> bool {
274 self.0.goto_first_child()
275 }
276
277 pub(crate) fn node(&self) -> Node<'a> {
278 Node(self.0.node())
279 }
280}
281
282impl<'a> Search<'a> for Node<'a> {
283 fn first_occurrence(&self, pred: fn(u16) -> bool) -> Option<Node<'a>> {
284 let mut cursor = self.cursor();
285 let mut stack = Vec::new();
286 let mut children = Vec::new();
287
288 stack.push(*self);
289
290 while let Some(node) = stack.pop() {
291 if pred(node.kind_id()) {
292 return Some(node);
293 }
294 cursor.reset(&node);
295 if cursor.goto_first_child() {
296 loop {
297 children.push(cursor.node());
298 if !cursor.goto_next_sibling() {
299 break;
300 }
301 }
302 for child in children.drain(..).rev() {
303 stack.push(child);
304 }
305 }
306 }
307
308 None
309 }
310
311 fn act_on_node(&self, action: &mut dyn FnMut(&Node<'a>)) {
312 let mut cursor = self.cursor();
313 let mut stack = Vec::new();
314 let mut children = Vec::new();
315
316 stack.push(*self);
317
318 while let Some(node) = stack.pop() {
319 action(&node);
320 cursor.reset(&node);
321 if cursor.goto_first_child() {
322 loop {
323 children.push(cursor.node());
324 if !cursor.goto_next_sibling() {
325 break;
326 }
327 }
328 for child in children.drain(..).rev() {
329 stack.push(child);
330 }
331 }
332 }
333 }
334
335 fn first_child(&self, pred: fn(u16) -> bool) -> Option<Node<'a>> {
336 self.children().find(|&child| pred(child.kind_id()))
337 }
338
339 fn act_on_child(&self, action: &mut dyn FnMut(&Node<'a>)) {
340 for child in self.children() {
341 action(&child);
342 }
343 }
344}