code-gauge 4.7.0 → 4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
- use std::collections::HashSet;
1
+ use rustc_hash::FxHashSet;
2
2
  use tree_sitter::Node;
3
3
 
4
+ use crate::tree_index::NodeExt;
4
5
  use crate::util::{all_children, find_children_by_field_name, named_children, node_text, Source};
5
6
 
6
7
  /// Declarations without a body have no control flow, so they are signatures, not functions: C++
@@ -24,31 +25,34 @@ const BODY_REQUIRED_FUNCTION_TYPES: &[&str] = &[
24
25
  ];
25
26
 
26
27
  pub fn is_implemented_function(node: Node<'_>) -> bool {
27
- if !BODY_REQUIRED_FUNCTION_TYPES.contains(&node.kind())
28
+ if !BODY_REQUIRED_FUNCTION_TYPES.contains(&node.kind_name())
28
29
  || node.child_by_field_name("body").is_some()
29
30
  {
30
31
  return true;
31
32
  }
32
33
 
33
- if node.kind() == "property_declaration" || node.kind() == "indexer_declaration" {
34
+ if node.kind_name() == "property_declaration" || node.kind_name() == "indexer_declaration" {
34
35
  return node
35
36
  .child_by_field_name("value")
36
- .is_some_and(|value| value.kind() == "arrow_expression_clause");
37
+ .is_some_and(|value| value.kind_name() == "arrow_expression_clause");
37
38
  }
38
39
 
39
40
  // The Kotlin grammar has no fields; an implemented function or accessor holds a
40
41
  // `function_body` child.
41
- if node.kind() == "getter" || node.kind() == "setter" || node.kind() == "function_declaration" {
42
+ if node.kind_name() == "getter"
43
+ || node.kind_name() == "setter"
44
+ || node.kind_name() == "function_declaration"
45
+ {
42
46
  return named_children(node)
43
47
  .iter()
44
- .any(|child| child.kind() == "function_body");
48
+ .any(|child| child.kind_name() == "function_body");
45
49
  }
46
50
 
47
51
  // C++ constructor/destructor function-try-blocks carry their `try_statement` outside the
48
52
  // `body` field; they are implementations, unlike `= 0`/`= default`/`= delete` members.
49
53
  named_children(node)
50
54
  .iter()
51
- .any(|child| child.kind() == "try_statement")
55
+ .any(|child| child.kind_name() == "try_statement")
52
56
  }
53
57
 
54
58
  /// Counts declared parameters of a function/method, ignoring punctuation and comments.
@@ -64,29 +68,31 @@ pub fn count_parameters(node: Node<'_>, code: &Source<'_>) -> usize {
64
68
 
65
69
  // A Java bare lambda parameter (`x -> x + 1`) puts a lone identifier in the `parameters` field;
66
70
  // a C# one (`x => x + 1`) is an `implicit_parameter` leaf.
67
- if parameters_node.kind() == "identifier" || parameters_node.kind() == "implicit_parameter" {
71
+ if parameters_node.kind_name() == "identifier"
72
+ || parameters_node.kind_name() == "implicit_parameter"
73
+ {
68
74
  return 1;
69
75
  }
70
76
  // Kotlin default values (`x: Int = 0`) are siblings of their `parameter`, not children.
71
- if parameters_node.kind() == "function_value_parameters" {
77
+ if parameters_node.kind_name() == "function_value_parameters" {
72
78
  return named_children(parameters_node)
73
79
  .iter()
74
- .filter(|child| child.kind() == "parameter")
80
+ .filter(|child| child.kind_name() == "parameter")
75
81
  .count();
76
82
  }
77
83
  // A Kotlin setter declares its single parameter directly (`set(value) { ... }`).
78
- if parameters_node.kind() == "setter" {
84
+ if parameters_node.kind_name() == "setter" {
79
85
  return 1;
80
86
  }
81
87
  // A C# `params` array is spelled out as `type`/`name` fields of the parameter list itself.
82
- let csharp_params_array_ids: HashSet<usize> = ["type", "name"]
88
+ let csharp_params_array_ids: FxHashSet<usize> = ["type", "name"]
83
89
  .iter()
84
90
  .flat_map(|field| find_children_by_field_name(parameters_node, field))
85
91
  .map(|child| child.id())
86
92
  .collect();
87
93
 
88
94
  // Ruby block-locals after `;` (`{ |x; memo| ... }`) occupy `locals` fields and receive no arguments.
89
- let block_local_ids: HashSet<usize> = find_children_by_field_name(parameters_node, "locals")
95
+ let block_local_ids: FxHashSet<usize> = find_children_by_field_name(parameters_node, "locals")
90
96
  .iter()
91
97
  .map(|child| child.id())
92
98
  .collect();
@@ -95,22 +101,22 @@ pub fn count_parameters(node: Node<'_>, code: &Source<'_>) -> usize {
95
101
  // C/C++ `f(void)` declares none, and a Ruby block parameter (`&blk`) binds the block, which
96
102
  // call sites pass outside the argument list.
97
103
  for child in named_children(parameters_node) {
98
- if crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind())
99
- || child.kind() == "attribute_list"
104
+ if crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind_name())
105
+ || child.kind_name() == "attribute_list"
100
106
  || csharp_params_array_ids.contains(&child.id())
101
- || child.kind() == "self_parameter"
102
- || child.kind() == "receiver_parameter"
103
- || child.kind() == "block_parameter"
107
+ || child.kind_name() == "self_parameter"
108
+ || child.kind_name() == "receiver_parameter"
109
+ || child.kind_name() == "block_parameter"
104
110
  // Python's PEP 570/3102 markers (`/`, `*`) separate parameter kinds but bind nothing.
105
- || child.kind() == "positional_separator"
106
- || child.kind() == "keyword_separator"
111
+ || child.kind_name() == "positional_separator"
112
+ || child.kind_name() == "keyword_separator"
107
113
  || block_local_ids.contains(&child.id())
108
114
  || is_void_parameter(child, code)
109
115
  {
110
116
  continue;
111
117
  }
112
118
  // Go declares several names per declaration (`a, b int`); each name is a parameter.
113
- count += if child.kind() == "parameter_declaration" {
119
+ count += if child.kind_name() == "parameter_declaration" {
114
120
  find_children_by_field_name(child, "name").len().max(1)
115
121
  } else {
116
122
  1
@@ -126,7 +132,7 @@ pub fn count_parameters(node: Node<'_>, code: &Source<'_>) -> usize {
126
132
 
127
133
  /// C/C++ `int f(void)` has a `parameter_declaration` whose type is a bare `void` with no declarator.
128
134
  fn is_void_parameter(node: Node<'_>, code: &Source<'_>) -> bool {
129
- node.kind() == "parameter_declaration"
135
+ node.kind_name() == "parameter_declaration"
130
136
  && node.child_by_field_name("declarator").is_none()
131
137
  && node
132
138
  .child_by_field_name("type")
@@ -139,20 +145,20 @@ fn find_parameters_node(node: Node<'_>) -> Option<Node<'_>> {
139
145
  }
140
146
 
141
147
  // A C# indexer accessor (`this[int i] { get { ... } }`) takes the indexer's parameters.
142
- if node.kind() == "accessor_declaration" {
148
+ if node.kind_name() == "accessor_declaration" {
143
149
  return node
144
- .parent()
145
- .and_then(|list| list.parent())
146
- .filter(|owner| owner.kind() == "indexer_declaration")
150
+ .parent_node()
151
+ .and_then(|list| list.parent_node())
152
+ .filter(|owner| owner.kind_name() == "indexer_declaration")
147
153
  .and_then(|owner| owner.child_by_field_name("parameters"));
148
154
  }
149
155
 
150
156
  // A Java compact constructor implicitly takes the record's components, declared on the
151
157
  // `record_declaration` two levels up (via `class_body`).
152
- if node.kind() == "compact_constructor_declaration" {
158
+ if node.kind_name() == "compact_constructor_declaration" {
153
159
  return node
154
- .parent()
155
- .and_then(|parent| parent.parent())
160
+ .parent_node()
161
+ .and_then(|parent| parent.parent_node())
156
162
  .and_then(|grandparent| grandparent.child_by_field_name("parameters"));
157
163
  }
158
164
 
@@ -166,17 +172,17 @@ fn find_parameters_node(node: Node<'_>) -> Option<Node<'_>> {
166
172
  }
167
173
 
168
174
  // A Kotlin setter's parameter (`set(value)`) sits directly under the setter node.
169
- if node.kind() == "setter"
175
+ if node.kind_name() == "setter"
170
176
  && named_children(node)
171
177
  .iter()
172
- .any(|child| child.kind() == "parameter_with_optional_type")
178
+ .any(|child| child.kind_name() == "parameter_with_optional_type")
173
179
  {
174
180
  return Some(node);
175
181
  }
176
182
 
177
183
  named_children(node).into_iter().find(|child| {
178
184
  matches!(
179
- child.kind(),
185
+ child.kind_name(),
180
186
  "formal_parameters"
181
187
  | "parameter_list"
182
188
  | "function_value_parameters"
@@ -185,20 +191,20 @@ fn find_parameters_node(node: Node<'_>) -> Option<Node<'_>> {
185
191
  })
186
192
  }
187
193
 
188
- pub fn collect_nodes<'t>(root: Node<'t>, node_types: &HashSet<&'static str>) -> Vec<Node<'t>> {
194
+ pub fn collect_nodes<'t>(root: Node<'t>, matches: impl Fn(&str) -> bool) -> Vec<Node<'t>> {
189
195
  let mut nodes = Vec::new();
190
196
 
191
- fn visit<'t>(node: Node<'t>, node_types: &HashSet<&'static str>, nodes: &mut Vec<Node<'t>>) {
192
- if node_types.contains(node.kind()) {
197
+ fn visit<'t>(node: Node<'t>, matches: &impl Fn(&str) -> bool, nodes: &mut Vec<Node<'t>>) {
198
+ if matches(node.kind_name()) {
193
199
  nodes.push(node);
194
200
  }
195
201
 
196
202
  for child in named_children(node) {
197
- visit(child, node_types, nodes);
203
+ visit(child, matches, nodes);
198
204
  }
199
205
  }
200
206
 
201
- visit(root, node_types, &mut nodes);
207
+ visit(root, &matches, &mut nodes);
202
208
  nodes
203
209
  }
204
210
 
@@ -209,11 +215,11 @@ pub fn collect_nodes<'t>(root: Node<'t>, node_types: &HashSet<&'static str>) ->
209
215
  /// `parenthesized_statements` wraps a lone value only when it holds exactly one statement.
210
216
  fn wrapped_transparent_value(wrapper: Node<'_>) -> Option<Node<'_>> {
211
217
  // A C-style cast (Java, C#, C/C++) names its type first, so its value comes from the field.
212
- if wrapper.kind() == "cast_expression" {
218
+ if wrapper.kind_name() == "cast_expression" {
213
219
  return wrapper.child_by_field_name("value");
214
220
  }
215
221
  if !matches!(
216
- wrapper.kind(),
222
+ wrapper.kind_name(),
217
223
  "type_assertion"
218
224
  | "parenthesized_statements"
219
225
  | "parenthesized_expression"
@@ -230,8 +236,8 @@ fn wrapped_transparent_value(wrapper: Node<'_>) -> Option<Node<'_>> {
230
236
  let children = named_children(wrapper);
231
237
  let mut values = children
232
238
  .into_iter()
233
- .filter(|child| !crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind()));
234
- match wrapper.kind() {
239
+ .filter(|child| !crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind_name()));
240
+ match wrapper.kind_name() {
235
241
  "type_assertion" => values.next_back(),
236
242
  "parenthesized_statements" => {
237
243
  let value = values.next()?;
@@ -246,7 +252,7 @@ fn wrapped_transparent_value(wrapper: Node<'_>) -> Option<Node<'_>> {
246
252
  /// names the value.
247
253
  fn unwrap_transparent_value_wrappers(node: Node<'_>) -> Node<'_> {
248
254
  let mut bound = node;
249
- while let Some(wrapper) = bound.parent().filter(|wrapper| {
255
+ while let Some(wrapper) = bound.parent_node().filter(|wrapper| {
250
256
  wrapped_transparent_value(*wrapper).is_some_and(|value| value.id() == bound.id())
251
257
  }) {
252
258
  bound = wrapper;
@@ -279,13 +285,13 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
279
285
  }
280
286
 
281
287
  let bound = unwrap_transparent_value_wrappers(node);
282
- let parent = bound.parent()?;
288
+ let parent = bound.parent_node()?;
283
289
 
284
290
  // A Rust closure bound to a simple `let` identifier takes that identifier as its name.
285
- if node.kind() == "closure_expression" && parent.kind() == "let_declaration" {
291
+ if node.kind_name() == "closure_expression" && parent.kind_name() == "let_declaration" {
286
292
  let pattern_node = parent.child_by_field_name("pattern");
287
293
  return match pattern_node {
288
- Some(pattern) if pattern.kind() == "identifier" => {
294
+ Some(pattern) if pattern.kind_name() == "identifier" => {
289
295
  Some(node_text(pattern, code).to_string())
290
296
  }
291
297
  _ => None,
@@ -296,17 +302,17 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
296
302
  // as does one that direct-initializes a deduced variable (`auto f{[] {}}`), whose type is the
297
303
  // closure itself. With a written type (`std::thread worker([] {})`) the lambda is a constructor
298
304
  // argument, and the constructor stores whatever it likes, so it names nothing.
299
- if node.kind() == "lambda_expression" {
300
- let declaration = match parent.kind() {
305
+ if node.kind_name() == "lambda_expression" {
306
+ let declaration = match parent.kind_name() {
301
307
  "init_declarator" => Some(parent),
302
308
  "argument_list" | "initializer_list" if binding_children(parent).len() == 1 => parent
303
- .parent()
304
- .filter(|holder| holder.kind() == "init_declarator")
309
+ .parent_node()
310
+ .filter(|holder| holder.kind_name() == "init_declarator")
305
311
  .filter(|holder| declares_deduced_type(*holder))
306
312
  // `auto f = {[] {}}` deduces a list holding the closure, not the closure itself;
307
313
  // only the direct form `auto f{[] {}}` makes the variable the closure.
308
314
  .filter(|holder| {
309
- parent.kind() == "argument_list"
315
+ parent.kind_name() == "argument_list"
310
316
  || !all_children(*holder)
311
317
  .iter()
312
318
  .any(|child| !child.is_named() && node_text(*child, code) == "=")
@@ -320,41 +326,43 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
320
326
 
321
327
  // A Go func literal bound via `add := func...`, `var add = func...`, or `add = func...` takes
322
328
  // the identifier (or selector field) at the same list position.
323
- if node.kind() == "func_literal" && parent.kind() == "expression_list" {
329
+ if node.kind_name() == "func_literal" && parent.kind_name() == "expression_list" {
324
330
  return find_go_func_literal_name(bound, parent, code);
325
331
  }
326
332
 
327
333
  // Ruby and Python lambdas assigned to a name take that name.
328
- if node.kind() == "lambda" && parent.kind() == "assignment" {
334
+ if node.kind_name() == "lambda" && parent.kind_name() == "assignment" {
329
335
  return find_ruby_assignment_name(parent, code);
330
336
  }
331
- if node.kind() == "lambda" && is_value_group(parent) {
337
+ if node.kind_name() == "lambda" && is_value_group(parent) {
332
338
  return find_parallel_assignment_name(bound, code);
333
339
  }
334
340
 
335
341
  // A Kotlin lambda or anonymous function initializing a property (`val f = { ... }`, also through
336
342
  // a label or annotation prefix) takes the property name; one assigned to a variable or member
337
343
  // (`run = { ... }`, `obj.run = { ... }`) takes the assigned name.
338
- if node.kind() == "lambda_literal" || node.kind() == "anonymous_function" {
344
+ if node.kind_name() == "lambda_literal" || node.kind_name() == "anonymous_function" {
339
345
  let mut holder = parent;
340
- while holder.kind() == "prefix_expression" {
341
- holder = holder.parent()?;
346
+ while holder.kind_name() == "prefix_expression" {
347
+ holder = holder.parent_node()?;
342
348
  }
343
- if holder.kind() == "property_declaration" {
349
+ if holder.kind_name() == "property_declaration" {
344
350
  return find_kotlin_property_name(holder, code);
345
351
  }
346
- if holder.kind() == "assignment" {
352
+ if holder.kind_name() == "assignment" {
347
353
  return find_kotlin_assignment_name(holder, code);
348
354
  }
349
355
  }
350
356
  // A `lambda { }` / `proc { }` block is measured, but the call around it is what gets bound.
351
- if (node.kind() == "block" || node.kind() == "do_block") && is_ruby_lambda_call(parent, code) {
357
+ if (node.kind_name() == "block" || node.kind_name() == "do_block")
358
+ && is_ruby_lambda_call(parent, code)
359
+ {
352
360
  let call = unwrap_transparent_value_wrappers(parent);
353
- return match call.parent() {
354
- Some(holder) if holder.kind() == "assignment" => {
361
+ return match call.parent_node() {
362
+ Some(holder) if holder.kind_name() == "assignment" => {
355
363
  find_ruby_assignment_name(holder, code)
356
364
  }
357
- Some(holder) if holder.kind() == "pair" => find_pair_key_name(holder, code),
365
+ Some(holder) if holder.kind_name() == "pair" => find_pair_key_name(holder, code),
358
366
  Some(holder) if is_value_group(holder) => find_parallel_assignment_name(call, code),
359
367
  _ => None,
360
368
  };
@@ -364,36 +372,36 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
364
372
  // after the key; an assignment
365
373
  // (`obj.run = () => {}`, `run = () => {}`, Rust/C++ `self.cb = |x| x`, C++ `N::run = [] {}`,
366
374
  // C# `this.Run = () => 1`) after its target.
367
- if parent.kind() == "pair" {
375
+ if parent.kind_name() == "pair" {
368
376
  return find_pair_key_name(parent, code);
369
377
  }
370
378
  // A Go keyed composite-literal element (`S{run: func() {}}`) names its value after the key.
371
- if parent.kind() == "literal_element" {
379
+ if parent.kind_name() == "literal_element" {
372
380
  return find_go_keyed_element_name(parent, code);
373
381
  }
374
382
  // A Rust struct-literal field (`S { cb: || 1 }`) names its closure after the field.
375
- if parent.kind() == "field_initializer" {
383
+ if parent.kind_name() == "field_initializer" {
376
384
  return parent
377
385
  .child_by_field_name("field")
378
386
  .map(|field| node_text(field, code).to_string());
379
387
  }
380
388
  // A C++20 designated initializer (`S s{.run = []{}}`) likewise names its value after the field;
381
389
  // an array designator (`{[0] = ...}`) names nothing, like a subscript assignment target.
382
- if parent.kind() == "initializer_pair" {
390
+ if parent.kind_name() == "initializer_pair" {
383
391
  return find_children_by_field_name(parent, "designator")
384
392
  .last()
385
- .filter(|designator| designator.kind() == "field_designator")
393
+ .filter(|designator| designator.kind_name() == "field_designator")
386
394
  .and_then(|designator| designator.named_child(0))
387
395
  .map(|field| node_text(field, code).to_string());
388
396
  }
389
- if parent.kind() == "assignment_expression" {
397
+ if parent.kind_name() == "assignment_expression" {
390
398
  return find_assignment_target_name(parent, code);
391
399
  }
392
400
 
393
401
  // A JavaScript class field (`handle = () => {}`) names its property through the `property`
394
402
  // field; TypeScript's `public_field_definition` exposes the same thing as `name`. A computed
395
403
  // key is as unstable here as in an object literal, and a string key is read the same way.
396
- let field_name = if parent.kind() == "field_definition" {
404
+ let field_name = if parent.kind_name() == "field_definition" {
397
405
  "property"
398
406
  } else {
399
407
  "name"
@@ -405,7 +413,7 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
405
413
  if !is_value_of_parent(bound, parent) {
406
414
  return None;
407
415
  }
408
- match name.kind() {
416
+ match name.kind_name() {
409
417
  "computed_property_name" => None,
410
418
  "string" => find_string_literal_content(name, code),
411
419
  _ => Some(node_text(name, code).to_string()),
@@ -416,7 +424,7 @@ pub fn find_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
416
424
  /// computed key (`[k]: ...`), an interpolated string or symbol, or an empty string names nothing.
417
425
  fn find_pair_key_name(pair: Node<'_>, code: &Source<'_>) -> Option<String> {
418
426
  let key = pair.child_by_field_name("key")?;
419
- match key.kind() {
427
+ match key.kind_name() {
420
428
  // A numeric key (`{ 1: () => {} }`) is as stable a property name as an identifier, signed
421
429
  // (`{ -1: ... }`) or not; any other expression is computed and names nothing.
422
430
  "property_identifier" | "hash_key_symbol" => Some(node_text(key, code).to_string()),
@@ -432,7 +440,7 @@ fn find_pair_key_name(pair: Node<'_>, code: &Source<'_>) -> Option<String> {
432
440
  for part in binding_children(key) {
433
441
  if named_children(part)
434
442
  .iter()
435
- .any(|child| child.kind() == "interpolation")
443
+ .any(|child| child.kind_name() == "interpolation")
436
444
  {
437
445
  return None;
438
446
  }
@@ -450,7 +458,7 @@ fn find_pair_key_name(pair: Node<'_>, code: &Source<'_>) -> Option<String> {
450
458
  fn core_constraint_type(constraint: Node<'_>) -> Node<'_> {
451
459
  let mut current = constraint;
452
460
  while matches!(
453
- current.kind(),
461
+ current.kind_name(),
454
462
  "type_constraint" | "negated_type" | "type_elem" | "interface_type"
455
463
  ) {
456
464
  match named_children(current).as_slice() {
@@ -474,7 +482,7 @@ fn signed_number_name(key: Node<'_>, code: &Source<'_>) -> Option<String> {
474
482
  .find(|child| !child.is_named())
475
483
  .map(|child| node_text(child, code))
476
484
  .unwrap_or_default();
477
- let text = match operand.kind() {
485
+ let text = match operand.kind_name() {
478
486
  "rune_literal" => find_string_literal_content(operand, code)?,
479
487
  _ => node_text(operand, code).to_string(),
480
488
  };
@@ -490,7 +498,7 @@ fn is_signed_number(key: Node<'_>, code: &Source<'_>) -> bool {
490
498
  signed
491
499
  && named_children(key).first().is_some_and(|operand| {
492
500
  matches!(
493
- operand.kind(),
501
+ operand.kind_name(),
494
502
  "number"
495
503
  | "integer"
496
504
  | "float"
@@ -506,14 +514,14 @@ fn is_signed_number(key: Node<'_>, code: &Source<'_>) -> bool {
506
514
  /// value the last. An unkeyed element sits under a `literal_value` instead and names nothing.
507
515
  fn find_go_keyed_element_name(value_element: Node<'_>, code: &Source<'_>) -> Option<String> {
508
516
  let keyed = value_element
509
- .parent()
510
- .filter(|parent| parent.kind() == "keyed_element")?;
517
+ .parent_node()
518
+ .filter(|parent| parent.kind_name() == "keyed_element")?;
511
519
  let elements = named_children(keyed);
512
520
  if elements.len() < 2 || elements.last()?.id() != value_element.id() {
513
521
  return None;
514
522
  }
515
523
  let key = named_children(*elements.first()?).into_iter().next()?;
516
- match key.kind() {
524
+ match key.kind_name() {
517
525
  "identifier" | "field_identifier" if !has_value_keys(keyed, code) => {
518
526
  Some(node_text(key, code).to_string())
519
527
  }
@@ -536,7 +544,7 @@ fn find_go_keyed_element_name(value_element: Node<'_>, code: &Source<'_>) -> Opt
536
544
  /// `key` holds, so it names nothing, exactly like a computed property key.
537
545
  fn has_value_keys(keyed: Node<'_>, code: &Source<'_>) -> bool {
538
546
  keyed
539
- .parent()
547
+ .parent_node()
540
548
  .and_then(|body| key_type_of_literal_body(body, code))
541
549
  .is_some_and(|declared| is_value_keyed_type(declared, code))
542
550
  }
@@ -557,7 +565,7 @@ fn value_keyed_type(declared: Node<'_>, code: &Source<'_>, depth: usize) -> bool
557
565
  return false;
558
566
  }
559
567
  let resolved = resolve_named_type(declared, code);
560
- match resolved.kind() {
568
+ match resolved.kind_name() {
561
569
  "map_type" | "slice_type" | "array_type" | "implicit_length_array_type" => true,
562
570
  "type_constraint" | "interface_type" | "type_elem" | "negated_type" => {
563
571
  // Method requirements restrict what a type does, not what it is, so only the type terms
@@ -575,14 +583,14 @@ fn value_keyed_type(declared: Node<'_>, code: &Source<'_>, depth: usize) -> bool
575
583
  /// Whether a constraint element only requires methods, directly or through an embedded interface
576
584
  /// that does; such an element leaves the underlying type free.
577
585
  fn requires_methods_only(declared: Node<'_>, code: &Source<'_>, depth: usize) -> bool {
578
- if matches!(declared.kind(), "method_elem" | "method_spec") {
586
+ if matches!(declared.kind_name(), "method_elem" | "method_spec") {
579
587
  return true;
580
588
  }
581
589
  if depth >= MAX_CONSTRAINT_DEPTH {
582
590
  return false;
583
591
  }
584
592
  let resolved = resolve_named_type(declared, code);
585
- match resolved.kind() {
593
+ match resolved.kind_name() {
586
594
  "interface_type" | "type_constraint" | "type_elem" => {
587
595
  let terms = binding_children(resolved);
588
596
  !terms.is_empty()
@@ -605,7 +613,7 @@ fn resolve_named_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Node<'t> {
605
613
  let mut visited = Vec::new();
606
614
  while !visited.contains(&current.id()) {
607
615
  visited.push(current.id());
608
- let next = match current.kind() {
616
+ let next = match current.kind_name() {
609
617
  "generic_type" => current.child_by_field_name("type"),
610
618
  // Go allows parentheses around a type; they name the type they hold.
611
619
  // Parentheses name the type they hold, and a nested literal of a pointer element type
@@ -623,7 +631,7 @@ fn resolve_named_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Node<'t> {
623
631
 
624
632
  /// The type a name stands for, resolved through the scopes enclosing it, innermost first.
625
633
  fn lookup_declared_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Option<Node<'t>> {
626
- if declared.kind() != "type_identifier" {
634
+ if declared.kind_name() != "type_identifier" {
627
635
  return None;
628
636
  }
629
637
  let name = node_text(declared, code);
@@ -636,7 +644,7 @@ fn lookup_declared_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Option<Nod
636
644
  // what the literal is written against.
637
645
  if let Some(constraint) = named_children(current)
638
646
  .into_iter()
639
- .filter(|child| child.kind() == "type_parameter_list")
647
+ .filter(|child| child.kind_name() == "type_parameter_list")
640
648
  .flat_map(|list| declared_type_parameters(list))
641
649
  .find(|(parameter_name, _)| node_text(*parameter_name, code) == name)
642
650
  .and_then(|(_, constraint)| constraint)
@@ -645,7 +653,7 @@ fn lookup_declared_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Option<Nod
645
653
  }
646
654
  // A method's receiver carries the parameters of the type it is declared on
647
655
  // (`func (r R[T]) ...`), so the name resolves through that type's declaration.
648
- if current.kind() == "method_declaration" {
656
+ if current.kind_name() == "method_declaration" {
649
657
  if let Some(constraint) = receiver_parameter_constraint(current, name, code) {
650
658
  return Some(core_constraint_type(constraint));
651
659
  }
@@ -653,7 +661,7 @@ fn lookup_declared_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Option<Nod
653
661
  if let Some(found) = find_type_spec(current, name, code) {
654
662
  return found.child_by_field_name("type");
655
663
  }
656
- scope = current.parent();
664
+ scope = current.parent_node();
657
665
  }
658
666
  None
659
667
  }
@@ -662,9 +670,9 @@ fn lookup_declared_type<'t>(declared: Node<'t>, code: &Source<'t>) -> Option<Nod
662
670
  fn find_type_spec<'t>(scope: Node<'t>, name: &str, code: &Source<'t>) -> Option<Node<'t>> {
663
671
  named_children(scope)
664
672
  .into_iter()
665
- .filter(|child| child.kind() == "type_declaration")
673
+ .filter(|child| child.kind_name() == "type_declaration")
666
674
  .flat_map(named_children)
667
- .filter(|spec| spec.kind() == "type_spec" || spec.kind() == "type_alias")
675
+ .filter(|spec| spec.kind_name() == "type_spec" || spec.kind_name() == "type_alias")
668
676
  .find(|spec| {
669
677
  spec.child_by_field_name("name")
670
678
  .is_some_and(|declared_name| node_text(declared_name, code) == name)
@@ -685,7 +693,7 @@ fn receiver_parameter_constraint<'t>(
685
693
  // A pointer or parenthesized receiver (`func (r *R[T])`, `func (r (R[T]))`) wraps the
686
694
  // instantiation, in either order.
687
695
  .map(unwrap_receiver_type)
688
- .find(|declared| declared.kind() == "generic_type")?;
696
+ .find(|declared| declared.kind_name() == "generic_type")?;
689
697
  let arguments = binding_children(instantiation.child_by_field_name("type_arguments")?);
690
698
  let position = arguments.iter().position(|argument| {
691
699
  let argument = named_children(*argument)
@@ -704,7 +712,7 @@ fn receiver_parameter_constraint<'t>(
704
712
  /// The type a receiver names, past the pointer and parenthesis wrappers it may carry.
705
713
  fn unwrap_receiver_type(declared: Node<'_>) -> Node<'_> {
706
714
  let mut current = declared;
707
- while matches!(current.kind(), "pointer_type" | "parenthesized_type") {
715
+ while matches!(current.kind_name(), "pointer_type" | "parenthesized_type") {
708
716
  match named_children(current).into_iter().next() {
709
717
  Some(inner) => current = inner,
710
718
  None => break,
@@ -718,7 +726,7 @@ fn unwrap_receiver_type(declared: Node<'_>) -> Node<'_> {
718
726
  fn declared_type_parameters<'t>(list: Node<'t>) -> Vec<(Node<'t>, Option<Node<'t>>)> {
719
727
  binding_children(list)
720
728
  .into_iter()
721
- .filter(|declaration| declaration.kind() == "type_parameter_declaration")
729
+ .filter(|declaration| declaration.kind_name() == "type_parameter_declaration")
722
730
  .flat_map(|declaration| {
723
731
  let constraint = declaration.child_by_field_name("type");
724
732
  find_children_by_field_name(declaration, "name")
@@ -734,24 +742,24 @@ fn declared_type_parameters<'t>(list: Node<'t>) -> Vec<(Node<'t>, Option<Node<'t
734
742
  /// {k: f}}` nests a map, `[]S{{run: f}}` a struct). A literal nested in a struct field keeps the
735
743
  /// struct reading, since the field's type is not written at the literal.
736
744
  fn key_type_of_literal_body<'t>(body: Node<'t>, code: &Source<'t>) -> Option<Node<'t>> {
737
- let parent = body.parent()?;
738
- if parent.kind() == "composite_literal" {
745
+ let parent = body.parent_node()?;
746
+ if parent.kind_name() == "composite_literal" {
739
747
  return parent.child_by_field_name("type");
740
748
  }
741
- if parent.kind() != "literal_element" {
749
+ if parent.kind_name() != "literal_element" {
742
750
  return None;
743
751
  }
744
- let mut container = parent.parent()?;
745
- if container.kind() == "keyed_element" {
746
- container = container.parent()?;
752
+ let mut container = parent.parent_node()?;
753
+ if container.kind_name() == "keyed_element" {
754
+ container = container.parent_node()?;
747
755
  }
748
- if container.kind() != "literal_value" {
756
+ if container.kind_name() != "literal_value" {
749
757
  return None;
750
758
  }
751
759
  // The container's own type may be a name, which the element type is read through.
752
760
  let declared = key_type_of_literal_body(container, code)?;
753
761
  let holder = resolve_named_type(declared, code);
754
- let element = match holder.kind() {
762
+ let element = match holder.kind_name() {
755
763
  "map_type" => holder.child_by_field_name("value"),
756
764
  "slice_type" | "array_type" | "implicit_length_array_type" => {
757
765
  holder.child_by_field_name("element")
@@ -768,7 +776,7 @@ fn instantiated_type_argument<'t>(
768
776
  declared: Node<'t>,
769
777
  code: &Source<'t>,
770
778
  ) -> Option<Node<'t>> {
771
- if element.kind() != "type_identifier" || declared.kind() != "generic_type" {
779
+ if element.kind_name() != "type_identifier" || declared.kind_name() != "generic_type" {
772
780
  return None;
773
781
  }
774
782
  let base = declared.child_by_field_name("type")?;
@@ -793,7 +801,7 @@ fn find_declared_type_spec<'t>(from: Node<'t>, name: &str, code: &Source<'t>) ->
793
801
  if let Some(spec) = find_type_spec(current, name, code) {
794
802
  return Some(spec);
795
803
  }
796
- scope = current.parent();
804
+ scope = current.parent_node();
797
805
  }
798
806
  None
799
807
  }
@@ -804,7 +812,10 @@ fn find_declared_type_spec<'t>(from: Node<'t>, name: &str, code: &Source<'t>) ->
804
812
  /// `string_content` (Python nests escapes inside it). Interpolation makes the key unstable.
805
813
  fn find_string_literal_content(literal: Node<'_>, code: &Source<'_>) -> Option<String> {
806
814
  let children = named_children(literal);
807
- if children.iter().any(|child| child.kind() == "interpolation") {
815
+ if children
816
+ .iter()
817
+ .any(|child| child.kind_name() == "interpolation")
818
+ {
808
819
  return None;
809
820
  }
810
821
  // Go exposes no content node at all: it names only the escapes, so the concatenation is
@@ -812,7 +823,7 @@ fn find_string_literal_content(literal: Node<'_>, code: &Source<'_>) -> Option<S
812
823
  let mut content = String::new();
813
824
  let mut has_content_node = false;
814
825
  for child in &children {
815
- match child.kind() {
826
+ match child.kind_name() {
816
827
  "string_content" | "string_fragment" => {
817
828
  has_content_node = true;
818
829
  content.push_str(node_text(*child, code));
@@ -860,7 +871,7 @@ fn find_assignment_target_name(assignment: Node<'_>, code: &Source<'_>) -> Optio
860
871
  return None;
861
872
  }
862
873
  let target = assignment.child_by_field_name("left")?;
863
- let name = match target.kind() {
874
+ let name = match target.kind_name() {
864
875
  "identifier" => target,
865
876
  "member_expression" => target.child_by_field_name("property")?,
866
877
  "field_expression" => target.child_by_field_name("field")?,
@@ -882,8 +893,8 @@ fn find_kotlin_assignment_name(assignment: Node<'_>, code: &Source<'_>) -> Optio
882
893
  let target = first_named_child_of_kind(assignment, "directly_assignable_expression")?;
883
894
  let children = named_children(target);
884
895
  let holder = match children.last()? {
885
- last if last.kind() == "navigation_suffix" => *last,
886
- last if last.kind() == "simple_identifier" && children.len() == 1 => target,
896
+ last if last.kind_name() == "navigation_suffix" => *last,
897
+ last if last.kind_name() == "simple_identifier" && children.len() == 1 => target,
887
898
  _ => return None,
888
899
  };
889
900
  first_named_child_of_kind(holder, "simple_identifier")
@@ -895,17 +906,17 @@ fn find_kotlin_assignment_name(assignment: Node<'_>, code: &Source<'_>) -> Optio
895
906
  /// Kotlin functions by their identifier child, Kotlin secondary constructors and C# destructors
896
907
  /// after their class, and C# operators like C++ ones.
897
908
  fn find_member_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
898
- match node.kind() {
909
+ match node.kind_name() {
899
910
  "accessor_declaration" => {
900
911
  let keyword = node_text(node.child_by_field_name("name")?, code);
901
- let owner = node.parent()?.parent()?;
912
+ let owner = node.parent_node()?.parent_node()?;
902
913
  Some(format!("{}.{keyword}", csharp_property_name(owner, code)?))
903
914
  }
904
915
  "property_declaration" | "indexer_declaration" => {
905
916
  Some(format!("{}.get", csharp_property_name(node, code)?))
906
917
  }
907
918
  "getter" | "setter" => {
908
- let keyword = if node.kind() == "getter" {
919
+ let keyword = if node.kind_name() == "getter" {
909
920
  "get"
910
921
  } else {
911
922
  "set"
@@ -920,13 +931,15 @@ fn find_member_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String
920
931
  .map(|name| node_text(name, code).to_string())
921
932
  }
922
933
  "secondary_constructor" => {
923
- let mut ancestor = node.parent();
934
+ let mut ancestor = node.parent_node();
924
935
  while let Some(current) = ancestor {
925
- if current.kind() == "class_declaration" || current.kind() == "object_declaration" {
936
+ if current.kind_name() == "class_declaration"
937
+ || current.kind_name() == "object_declaration"
938
+ {
926
939
  return first_named_child_of_kind(current, "type_identifier")
927
940
  .map(|name| node_text(name, code).to_string());
928
941
  }
929
- ancestor = current.parent();
942
+ ancestor = current.parent_node();
930
943
  }
931
944
  None
932
945
  }
@@ -948,7 +961,7 @@ fn find_member_function_name(node: Node<'_>, code: &Source<'_>) -> Option<String
948
961
 
949
962
  /// A C# property or indexer (`this`) name.
950
963
  fn csharp_property_name(owner: Node<'_>, code: &Source<'_>) -> Option<String> {
951
- match owner.kind() {
964
+ match owner.kind_name() {
952
965
  "indexer_declaration" => Some("this".to_string()),
953
966
  _ => Some(node_text(owner.child_by_field_name("name")?, code).to_string()),
954
967
  }
@@ -959,18 +972,18 @@ fn csharp_property_name(owner: Node<'_>, code: &Source<'_>) -> Option<String> {
959
972
  /// sibling after the property, any preceding accessor, and any comments between them.
960
973
  fn find_kotlin_accessor_owner_name(accessor: Node<'_>, code: &Source<'_>) -> Option<String> {
961
974
  if let Some(name) = accessor
962
- .parent()
975
+ .parent_node()
963
976
  .and_then(|parent| find_kotlin_property_name(parent, code))
964
977
  {
965
978
  return Some(name);
966
979
  }
967
980
  let mut sibling = accessor.prev_named_sibling();
968
981
  while let Some(current) = sibling {
969
- if current.kind() == "property_declaration" {
982
+ if current.kind_name() == "property_declaration" {
970
983
  return find_kotlin_property_name(current, code);
971
984
  }
972
- if !matches!(current.kind(), "getter" | "setter")
973
- && !crate::ncss::COMMENT_NODE_TYPES.contains(&current.kind())
985
+ if !matches!(current.kind_name(), "getter" | "setter")
986
+ && !crate::ncss::COMMENT_NODE_TYPES.contains(&current.kind_name())
974
987
  {
975
988
  return None;
976
989
  }
@@ -981,7 +994,7 @@ fn find_kotlin_accessor_owner_name(accessor: Node<'_>, code: &Source<'_>) -> Opt
981
994
 
982
995
  /// The declared name of a Kotlin `property_declaration` (`val name: T`), if it declares one.
983
996
  fn find_kotlin_property_name(property: Node<'_>, code: &Source<'_>) -> Option<String> {
984
- if property.kind() != "property_declaration" {
997
+ if property.kind_name() != "property_declaration" {
985
998
  return None;
986
999
  }
987
1000
  let declaration = first_named_child_of_kind(property, "variable_declaration")?;
@@ -992,7 +1005,7 @@ fn find_kotlin_property_name(property: Node<'_>, code: &Source<'_>) -> Option<St
992
1005
  fn first_named_child_of_kind<'t>(node: Node<'t>, kind: &str) -> Option<Node<'t>> {
993
1006
  named_children(node)
994
1007
  .into_iter()
995
- .find(|child| child.kind() == kind)
1008
+ .find(|child| child.kind_name() == kind)
996
1009
  }
997
1010
 
998
1011
  /// Whether the node occupies its parent's value position: the `value` field, or no field at all
@@ -1017,7 +1030,7 @@ fn is_value_of_parent(node: Node<'_>, parent: Node<'_>) -> bool {
1017
1030
  /// or a mapping is unordered, so it groups nothing positionally.
1018
1031
  fn is_value_group(node: Node<'_>) -> bool {
1019
1032
  matches!(
1020
- node.kind(),
1033
+ node.kind_name(),
1021
1034
  "expression_list" | "right_assignment_list" | "tuple" | "list" | "array"
1022
1035
  )
1023
1036
  }
@@ -1025,7 +1038,7 @@ fn is_value_group(node: Node<'_>) -> bool {
1025
1038
  /// The matching target groups, which a nested value group is aligned against level by level.
1026
1039
  fn is_target_group(node: Node<'_>) -> bool {
1027
1040
  matches!(
1028
- node.kind(),
1041
+ node.kind_name(),
1029
1042
  "pattern_list"
1030
1043
  | "left_assignment_list"
1031
1044
  | "tuple_pattern"
@@ -1041,13 +1054,13 @@ fn find_parallel_assignment_name(value: Node<'_>, code: &Source<'_>) -> Option<S
1041
1054
  let mut positions = Vec::new();
1042
1055
  let mut current = value;
1043
1056
  let assignment = loop {
1044
- let parent = current.parent()?;
1057
+ let parent = current.parent_node()?;
1045
1058
  if is_value_group(parent) {
1046
1059
  positions.push((parent, current));
1047
1060
  current = parent;
1048
1061
  continue;
1049
1062
  }
1050
- if parent.kind() == "assignment"
1063
+ if parent.kind_name() == "assignment"
1051
1064
  && parent.child_by_field_name("right")?.id() == current.id()
1052
1065
  {
1053
1066
  break parent;
@@ -1059,9 +1072,9 @@ fn find_parallel_assignment_name(value: Node<'_>, code: &Source<'_>) -> Option<S
1059
1072
  // Ruby spells a fully parenthesized target list as a `left_assignment_list` holding one
1060
1073
  // destructured group (`(a, b) = f, g`), which aligns against that inner one. A Python
1061
1074
  // singleton tuple is a real destructuring level instead, so it is left alone.
1062
- while target.kind() == "left_assignment_list" {
1075
+ while target.kind_name() == "left_assignment_list" {
1063
1076
  match binding_children(target).as_slice() {
1064
- [only] if only.kind() == "destructured_left_assignment" => target = *only,
1077
+ [only] if only.kind_name() == "destructured_left_assignment" => target = *only,
1065
1078
  _ => break,
1066
1079
  }
1067
1080
  }
@@ -1086,7 +1099,7 @@ fn aligned_target<'t>(values: Node<'_>, value: Node<'_>, targets: Node<'t>) -> O
1086
1099
  let splat_after = value_list[index + 1..].iter().any(is_splat);
1087
1100
  let trailing = value_list.len() - 1 - index;
1088
1101
  let unpacks = matches!(
1089
- targets.kind(),
1102
+ targets.kind_name(),
1090
1103
  "pattern_list" | "tuple_pattern" | "list_pattern"
1091
1104
  );
1092
1105
  let targets = binding_children(targets);
@@ -1123,10 +1136,12 @@ fn aligned_target<'t>(values: Node<'_>, value: Node<'_>, targets: Node<'t>) -> O
1123
1136
  // it, by failing the assignment, while Ruby fills the trailing targets from the left
1124
1137
  // when it underflows.
1125
1138
  let reaches_trailing_targets = written_values + 1 >= targets.len()
1126
- || value_list.iter().any(|child| child.kind() == "list_splat");
1139
+ || value_list
1140
+ .iter()
1141
+ .any(|child| child.kind_name() == "list_splat");
1127
1142
  if reaches_trailing_targets {
1128
1143
  targets.get(targets.len() - 1 - trailing).copied()
1129
- } else if !splat_before && targets[splat].kind() == "rest_assignment" {
1144
+ } else if !splat_before && targets[splat].kind_name() == "rest_assignment" {
1130
1145
  // Ruby empties the star and fills the trailing targets from the left when the
1131
1146
  // values run out, so each one binds the next target (`a, *r, c, d = x, f` binds
1132
1147
  // `f` to `c`); Python fails such an assignment instead.
@@ -1142,7 +1157,7 @@ fn aligned_target<'t>(values: Node<'_>, value: Node<'_>, targets: Node<'t>) -> O
1142
1157
  /// A splat on either side of a parallel assignment (`*xs`, `*rest`).
1143
1158
  fn is_splat(node: &Node<'_>) -> bool {
1144
1159
  matches!(
1145
- node.kind(),
1160
+ node.kind_name(),
1146
1161
  "splat_argument" | "rest_assignment" | "list_splat" | "list_splat_pattern"
1147
1162
  )
1148
1163
  }
@@ -1150,7 +1165,7 @@ fn is_splat(node: &Node<'_>) -> bool {
1150
1165
  fn binding_children<'t>(node: Node<'t>) -> Vec<Node<'t>> {
1151
1166
  named_children(node)
1152
1167
  .into_iter()
1153
- .filter(|child| !crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind()))
1168
+ .filter(|child| !crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind_name()))
1154
1169
  .collect()
1155
1170
  }
1156
1171
 
@@ -1158,7 +1173,7 @@ fn binding_children<'t>(node: Node<'t>) -> Vec<Node<'t>> {
1158
1173
  /// global variable; the method of a Ruby attribute writer (`self.run = ...`); or a Python attribute
1159
1174
  /// (`obj.run = ...`). A subscript or a splat has no stable name and binds none.
1160
1175
  fn find_assignment_target_text(target: Node<'_>, code: &Source<'_>) -> Option<String> {
1161
- match target.kind() {
1176
+ match target.kind_name() {
1162
1177
  "identifier" | "constant" | "instance_variable" | "class_variable" | "global_variable" => {
1163
1178
  Some(node_text(target, code).to_string())
1164
1179
  }
@@ -1179,7 +1194,7 @@ fn find_ruby_assignment_name(assignment: Node<'_>, code: &Source<'_>) -> Option<
1179
1194
  let left = assignment.child_by_field_name("left")?;
1180
1195
  let mut target = left;
1181
1196
  if matches!(
1182
- left.kind(),
1197
+ left.kind_name(),
1183
1198
  "left_assignment_list" | "destructured_left_assignment"
1184
1199
  ) {
1185
1200
  while is_target_group(target) {
@@ -1192,11 +1207,11 @@ fn find_ruby_assignment_name(assignment: Node<'_>, code: &Source<'_>) -> Option<
1192
1207
  }
1193
1208
 
1194
1209
  fn is_ruby_lambda_call(node: Node<'_>, code: &Source<'_>) -> bool {
1195
- if node.kind() != "call" || node.child_by_field_name("receiver").is_some() {
1210
+ if node.kind_name() != "call" || node.child_by_field_name("receiver").is_some() {
1196
1211
  return false;
1197
1212
  }
1198
1213
  node.child_by_field_name("method").is_some_and(|method| {
1199
- method.kind() == "identifier"
1214
+ method.kind_name() == "identifier"
1200
1215
  && (node_text(method, code) == "lambda" || node_text(method, code) == "proc")
1201
1216
  })
1202
1217
  }
@@ -1206,22 +1221,23 @@ fn find_go_func_literal_name(
1206
1221
  expression_list: Node<'_>,
1207
1222
  code: &Source<'_>,
1208
1223
  ) -> Option<String> {
1209
- let holder = expression_list.parent()?;
1224
+ let holder = expression_list.parent_node()?;
1210
1225
  // Comments interleave with expressions in the list but have no matching binding target.
1211
1226
  let values: Vec<Node<'_>> = named_children(expression_list)
1212
1227
  .into_iter()
1213
- .filter(|child| child.kind() != "comment")
1228
+ .filter(|child| child.kind_name() != "comment")
1214
1229
  .collect();
1215
1230
  let value_index = values.iter().position(|child| child.id() == node.id())?;
1216
1231
 
1217
- if holder.kind() == "assignment_statement" && !is_plain_assignment(holder, code) {
1232
+ if holder.kind_name() == "assignment_statement" && !is_plain_assignment(holder, code) {
1218
1233
  return None;
1219
1234
  }
1220
- if holder.kind() == "short_var_declaration" || holder.kind() == "assignment_statement" {
1235
+ if holder.kind_name() == "short_var_declaration" || holder.kind_name() == "assignment_statement"
1236
+ {
1221
1237
  let targets = holder.child_by_field_name("left").map(|left| {
1222
1238
  named_children(left)
1223
1239
  .into_iter()
1224
- .filter(|child| child.kind() != "comment")
1240
+ .filter(|child| child.kind_name() != "comment")
1225
1241
  .collect::<Vec<_>>()
1226
1242
  });
1227
1243
  return as_go_binding_name(
@@ -1233,7 +1249,7 @@ fn find_go_func_literal_name(
1233
1249
  );
1234
1250
  }
1235
1251
 
1236
- if holder.kind() == "var_spec" {
1252
+ if holder.kind_name() == "var_spec" {
1237
1253
  let target = find_children_by_field_name(holder, "name")
1238
1254
  .get(value_index)
1239
1255
  .copied();
@@ -1247,10 +1263,10 @@ fn find_go_func_literal_name(
1247
1263
  /// (`m.run = func...`) names its field.
1248
1264
  fn as_go_binding_name(target: Option<Node<'_>>, code: &Source<'_>) -> Option<String> {
1249
1265
  match target {
1250
- Some(target) if target.kind() == "identifier" && node_text(target, code) != "_" => {
1266
+ Some(target) if target.kind_name() == "identifier" && node_text(target, code) != "_" => {
1251
1267
  Some(node_text(target, code).to_string())
1252
1268
  }
1253
- Some(target) if target.kind() == "selector_expression" => target
1269
+ Some(target) if target.kind_name() == "selector_expression" => target
1254
1270
  .child_by_field_name("field")
1255
1271
  .map(|field| node_text(field, code).to_string()),
1256
1272
  _ => None,
@@ -1260,12 +1276,12 @@ fn as_go_binding_name(target: Option<Node<'_>>, code: &Source<'_>) -> Option<Str
1260
1276
  fn find_wrapped_component_name(node: Node<'_>, code: &Source<'_>) -> Option<String> {
1261
1277
  let mut current = node;
1262
1278
  loop {
1263
- let arguments_node = current.parent();
1264
- let call_node = arguments_node.and_then(|arguments| arguments.parent());
1279
+ let arguments_node = current.parent_node();
1280
+ let call_node = arguments_node.and_then(|arguments| arguments.parent_node());
1265
1281
  let (Some(arguments_node), Some(call_node)) = (arguments_node, call_node) else {
1266
1282
  return None;
1267
1283
  };
1268
- if arguments_node.kind() != "arguments" || call_node.kind() != "call_expression" {
1284
+ if arguments_node.kind_name() != "arguments" || call_node.kind_name() != "call_expression" {
1269
1285
  return None;
1270
1286
  }
1271
1287
 
@@ -1273,8 +1289,8 @@ fn find_wrapped_component_name(node: Node<'_>, code: &Source<'_>) -> Option<Stri
1273
1289
  return None;
1274
1290
  }
1275
1291
 
1276
- if let Some(declarator_node) = call_node.parent() {
1277
- if declarator_node.kind() == "variable_declarator" {
1292
+ if let Some(declarator_node) = call_node.parent_node() {
1293
+ if declarator_node.kind_name() == "variable_declarator" {
1278
1294
  return declarator_node
1279
1295
  .child_by_field_name("name")
1280
1296
  .map(|name| node_text(name, code).to_string());
@@ -1299,16 +1315,16 @@ fn is_react_component_wrapper_call(node: Node<'_>, code: &Source<'_>) -> bool {
1299
1315
  /// variable the closure itself rather than something constructed from it.
1300
1316
  fn declares_deduced_type(declarator: Node<'_>) -> bool {
1301
1317
  declarator
1302
- .parent()
1318
+ .parent_node()
1303
1319
  .and_then(|declaration| declaration.child_by_field_name("type"))
1304
- .is_some_and(|declared| declared.kind() == "placeholder_type_specifier")
1320
+ .is_some_and(|declared| declared.kind_name() == "placeholder_type_specifier")
1305
1321
  }
1306
1322
 
1307
1323
  /// Unwraps a C/C++ declarator chain to the declared name.
1308
1324
  fn unwrap_declarator_name(declarator: Option<Node<'_>>, code: &Source<'_>) -> Option<String> {
1309
1325
  let mut current = declarator;
1310
1326
  while let Some(node) = current {
1311
- match node.kind() {
1327
+ match node.kind_name() {
1312
1328
  "identifier" | "field_identifier" | "type_identifier" | "destructor_name"
1313
1329
  | "operator_name" => {
1314
1330
  return Some(node_text(node, code).to_string());
@@ -1339,7 +1355,8 @@ fn next_declarator(node: Node<'_>) -> Option<Node<'_>> {
1339
1355
  if let Some(direct) = node.child_by_field_name("declarator") {
1340
1356
  return Some(direct);
1341
1357
  }
1342
- if node.kind() == "reference_declarator" || node.kind() == "parenthesized_declarator" {
1358
+ if node.kind_name() == "reference_declarator" || node.kind_name() == "parenthesized_declarator"
1359
+ {
1343
1360
  return node.named_child(0);
1344
1361
  }
1345
1362
  None