code-gauge 10.0.0 → 10.2.0

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.
Files changed (54) hide show
  1. package/README.md +56 -34
  2. package/THIRD-PARTY-NOTICES.txt +8 -8
  3. package/dist/checkCommand.cjs +2 -2
  4. package/dist/checkCommand.cjs.map +1 -1
  5. package/dist/checkCommand.d.ts +2 -5
  6. package/dist/checkCommand.js +2 -2
  7. package/dist/checkCommand.js.map +1 -1
  8. package/dist/crossFileDuplication.cjs +1 -1
  9. package/dist/crossFileDuplication.cjs.map +1 -1
  10. package/dist/crossFileDuplication.d.ts +14 -2
  11. package/dist/crossFileDuplication.js +1 -1
  12. package/dist/crossFileDuplication.js.map +1 -1
  13. package/dist/crossFileNearMiss.cjs +1 -1
  14. package/dist/crossFileNearMiss.cjs.map +1 -1
  15. package/dist/crossFileNearMiss.d.ts +6 -4
  16. package/dist/crossFileNearMiss.js +1 -1
  17. package/dist/crossFileNearMiss.js.map +1 -1
  18. package/dist/duplication.cjs +1 -1
  19. package/dist/duplication.cjs.map +1 -1
  20. package/dist/duplication.d.ts +22 -7
  21. package/dist/duplication.js +1 -1
  22. package/dist/duplication.js.map +1 -1
  23. package/dist/nativeMetrics.cjs +1 -1
  24. package/dist/nativeMetrics.cjs.map +1 -1
  25. package/dist/nativeMetrics.d.ts +1 -1
  26. package/dist/nativeMetrics.js +1 -1
  27. package/dist/nativeMetrics.js.map +1 -1
  28. package/dist/thresholdCheck.cjs +1 -1
  29. package/dist/thresholdCheck.cjs.map +1 -1
  30. package/dist/thresholdCheck.d.ts +10 -8
  31. package/dist/thresholdCheck.js +1 -1
  32. package/dist/thresholdCheck.js.map +1 -1
  33. package/dist/thresholds.cjs +1 -1
  34. package/dist/thresholds.cjs.map +1 -1
  35. package/dist/thresholds.d.ts +5 -3
  36. package/dist/thresholds.js +1 -1
  37. package/dist/thresholds.js.map +1 -1
  38. package/dist/types.d.ts +29 -7
  39. package/dist/wasmBinding.cjs +1 -1
  40. package/dist/wasmBinding.js +1 -1
  41. package/native/Cargo.lock +16 -16
  42. package/native/Cargo.toml +8 -8
  43. package/native/code-gauge.wasm +0 -0
  44. package/native/src/complexity.rs +10 -1
  45. package/native/src/container.rs +158 -7
  46. package/native/src/dep_degree.rs +13 -14
  47. package/native/src/duplication.rs +213 -85
  48. package/native/src/functions.rs +112 -24
  49. package/native/src/languages.rs +5 -0
  50. package/native/src/lib.rs +1 -1
  51. package/native/src/measure.rs +9 -4
  52. package/native/src/near_miss.rs +303 -52
  53. package/native/src/types.rs +3 -0
  54. package/package.json +8 -8
package/native/Cargo.lock CHANGED
@@ -484,9 +484,9 @@ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
484
484
 
485
485
  [[package]]
486
486
  name = "willbooster-tree-sitter"
487
- version = "1.0.5"
487
+ version = "1.4.3"
488
488
  source = "registry+https://github.com/rust-lang/crates.io-index"
489
- checksum = "7c6ca3007235ade028b793d6090a5ea16618ea3ab9b53427d1f782b15bf64064"
489
+ checksum = "334d00dd58bc471ce142f80bd05c8dde5d6a5961d23527aa4b3ad640793550ef"
490
490
  dependencies = [
491
491
  "cc",
492
492
  "regex",
@@ -497,9 +497,9 @@ dependencies = [
497
497
 
498
498
  [[package]]
499
499
  name = "willbooster-tree-sitter-c"
500
- version = "1.1.0"
500
+ version = "4.0.2"
501
501
  source = "registry+https://github.com/rust-lang/crates.io-index"
502
- checksum = "5cee6f1a4e0f64f337d28aeaed73879d7e8a87d77c287afb989ce29adea54700"
502
+ checksum = "5eb6af34735987dd02518fced2bd8f6a0b81aff19220290020787c1e12c19e7f"
503
503
  dependencies = [
504
504
  "cc",
505
505
  "tree-sitter-language",
@@ -507,9 +507,9 @@ dependencies = [
507
507
 
508
508
  [[package]]
509
509
  name = "willbooster-tree-sitter-c-sharp"
510
- version = "1.0.3"
510
+ version = "3.0.1"
511
511
  source = "registry+https://github.com/rust-lang/crates.io-index"
512
- checksum = "99b224dcd59cda9b24b588557cca3827abaccaf10da72d125c31e7cdb2e6f7fb"
512
+ checksum = "8c5aa3c4b1bfcdad92d0703c77964c8b805800d3ee8087dddae1d336da96e495"
513
513
  dependencies = [
514
514
  "cc",
515
515
  "tree-sitter-language",
@@ -517,9 +517,9 @@ dependencies = [
517
517
 
518
518
  [[package]]
519
519
  name = "willbooster-tree-sitter-cpp"
520
- version = "1.1.1"
520
+ version = "2.0.2"
521
521
  source = "registry+https://github.com/rust-lang/crates.io-index"
522
- checksum = "72b92a9fcb0dc27bd4af18e06fe6c085dd14d91f009f60ecd92c0308b9cbd068"
522
+ checksum = "fff5f9f592d51e52f1701438c8ee8b91376e15f42584e4e01f4ecb1120b1f354"
523
523
  dependencies = [
524
524
  "cc",
525
525
  "tree-sitter-language",
@@ -527,9 +527,9 @@ dependencies = [
527
527
 
528
528
  [[package]]
529
529
  name = "willbooster-tree-sitter-javascript"
530
- version = "1.0.3"
530
+ version = "4.0.2"
531
531
  source = "registry+https://github.com/rust-lang/crates.io-index"
532
- checksum = "e6c40d41b303b525194daa503a71ec94d8269fe8d1648b2d9138fe902623beff"
532
+ checksum = "60a035c947e2036a42ef8060872a213dc76489b3a82f2e4730b6ed54bd10a7bb"
533
533
  dependencies = [
534
534
  "cc",
535
535
  "tree-sitter-language",
@@ -537,9 +537,9 @@ dependencies = [
537
537
 
538
538
  [[package]]
539
539
  name = "willbooster-tree-sitter-kotlin"
540
- version = "1.4.0"
540
+ version = "4.0.2"
541
541
  source = "registry+https://github.com/rust-lang/crates.io-index"
542
- checksum = "529ae914939b559754e6dd8b34d2705f04d6dcb73f09cb52f024b49eda9b5b88"
542
+ checksum = "58fb49a0177bad0032df8ff897e5c6b66f3ed044e3133a81ebc1583303f6c7aa"
543
543
  dependencies = [
544
544
  "cc",
545
545
  "tree-sitter-language",
@@ -547,9 +547,9 @@ dependencies = [
547
547
 
548
548
  [[package]]
549
549
  name = "willbooster-tree-sitter-rust"
550
- version = "1.1.1"
550
+ version = "2.0.2"
551
551
  source = "registry+https://github.com/rust-lang/crates.io-index"
552
- checksum = "324c9f18cfc29e4da7335ad8cb76beb6ac1ae91a8037a44724bc55fce04f26f7"
552
+ checksum = "740d80b0a761326575e52bf678749e1d08430e988b45d18f5db71bc20ad3a128"
553
553
  dependencies = [
554
554
  "cc",
555
555
  "tree-sitter-language",
@@ -557,9 +557,9 @@ dependencies = [
557
557
 
558
558
  [[package]]
559
559
  name = "willbooster-tree-sitter-typescript"
560
- version = "1.1.1"
560
+ version = "7.0.0"
561
561
  source = "registry+https://github.com/rust-lang/crates.io-index"
562
- checksum = "f8c51b6c9e10d6ae34c2f84c4d44fff79a0210890ede63fda558a6a0f042eb28"
562
+ checksum = "289945de1713b7f13625e2d9646e138f37be74d38d8f58de0cfe669d9fe9ba0c"
563
563
  dependencies = [
564
564
  "cc",
565
565
  "tree-sitter-language",
package/native/Cargo.toml CHANGED
@@ -20,18 +20,18 @@ rustc-hash = "2"
20
20
  # `willbooster-*` crates are WillBooster's forks of the runtime and grammars. Every grammar crate
21
21
  # depends only on `tree-sitter-language`, never on upstream's `tree-sitter` crate, whose
22
22
  # `links = "tree-sitter"` would conflict with the forked runtime's.
23
- tree-sitter = { package = "willbooster-tree-sitter", version = "1" }
24
- tree-sitter-c = { package = "willbooster-tree-sitter-c", version = "=1.1.0" }
25
- tree-sitter-c-sharp = { package = "willbooster-tree-sitter-c-sharp", version = "=1.0.3" }
26
- tree-sitter-cpp = { package = "willbooster-tree-sitter-cpp", version = "=1.1.1" }
23
+ tree-sitter = { package = "willbooster-tree-sitter", version = "1.4.3" }
24
+ tree-sitter-c = { package = "willbooster-tree-sitter-c", version = "=4.0.2" }
25
+ tree-sitter-c-sharp = { package = "willbooster-tree-sitter-c-sharp", version = "=3.0.1" }
26
+ tree-sitter-cpp = { package = "willbooster-tree-sitter-cpp", version = "=2.0.2" }
27
27
  tree-sitter-go = "=0.25.0"
28
28
  tree-sitter-java = "=0.23.5"
29
- tree-sitter-javascript = { package = "willbooster-tree-sitter-javascript", version = "=1.0.3" }
30
- tree-sitter-kotlin = { package = "willbooster-tree-sitter-kotlin", version = "=1.4.0" }
29
+ tree-sitter-javascript = { package = "willbooster-tree-sitter-javascript", version = "=4.0.2" }
30
+ tree-sitter-kotlin = { package = "willbooster-tree-sitter-kotlin", version = "=4.0.2" }
31
31
  tree-sitter-python = "=0.25.0"
32
32
  tree-sitter-ruby = "=0.23.1"
33
- tree-sitter-rust = { package = "willbooster-tree-sitter-rust", version = "=1.1.1" }
34
- tree-sitter-typescript = { package = "willbooster-tree-sitter-typescript", version = "=1.1.1" }
33
+ tree-sitter-rust = { package = "willbooster-tree-sitter-rust", version = "=2.0.2" }
34
+ tree-sitter-typescript = { package = "willbooster-tree-sitter-typescript", version = "=7.0.0" }
35
35
 
36
36
  # The WebAssembly build (src/wasm.rs) exports a plain C ABI instead of N-API.
37
37
  [target.'cfg(not(target_family = "wasm"))'.dependencies]
Binary file
@@ -639,7 +639,8 @@ fn find_boolean_operator_text<'a>(binary_node: Node<'_>, code: &Source<'a>) -> O
639
639
  }
640
640
 
641
641
  /// Java `guard`, C# `when_clause`, Ruby `if_guard`, a Python `case` guard (an `if_clause` under a
642
- /// `case_clause`), and Rust guards inside `match_pattern`. A Python comprehension filter shares
642
+ /// `case_clause`), a Kotlin guard (the `guard` field of a `when_entry`), and Rust guards inside
643
+ /// `match_pattern`. A Python comprehension filter shares
643
644
  /// the `if_clause` type but is a per-element predicate of one expression, not an extra execution
644
645
  /// path: Sonar ports differ on it (complexipy charges it), and code-gauge does not, unlike
645
646
  /// ternaries and conditions, which are charged. A C# exception filter (`catch (E e) when (...)`, a `catch_filter_clause`) is
@@ -656,6 +657,14 @@ fn is_pattern_guard(node: Node<'_>, parent: Option<Node<'_>>) -> bool {
656
657
  if kind == "if_clause" {
657
658
  return parent.is_some_and(|parent| parent.kind_name() == "case_clause");
658
659
  }
660
+ if parent.is_some_and(|parent| {
661
+ parent.kind_name() == "when_entry"
662
+ && parent
663
+ .child_by_field_name("guard")
664
+ .is_some_and(|guard| guard.id() == node.id())
665
+ }) {
666
+ return true;
667
+ }
659
668
  kind == "match_pattern"
660
669
  && all_children(node)
661
670
  .iter()
@@ -1,7 +1,11 @@
1
1
  use rustc_hash::FxHashSet;
2
2
  use tree_sitter::Node;
3
3
 
4
- use crate::functions::next_declarator;
4
+ use crate::functions::{
5
+ find_pair_key_name, find_parallel_assignment_target, find_single_assignment_target,
6
+ find_string_literal_content, find_value_binding, is_value_group, next_declarator,
7
+ unwrap_transparent_value_wrappers,
8
+ };
5
9
  use crate::tree_index::NodeExt;
6
10
  use crate::util::{named_children, node_text, Source};
7
11
 
@@ -88,20 +92,57 @@ fn explicit_ruby_owner(object: Option<Node<'_>>, code: &Source<'_>) -> Option<St
88
92
  (text != "self").then(|| text.to_string())
89
93
  }
90
94
 
91
- /// The name of the declaration whose member a declared function is: the nearest class-like
92
- /// declaration enclosing it, or the owner the function names itself (a Go receiver, a C++ qualified
93
- /// declarator, the object of a Ruby singleton method).
95
+ /// The name of the declaration whose member a function is: the nearest class-like declaration
96
+ /// enclosing it or, for a function written as a value, the declaration binding it; the owner the
97
+ /// function names itself (a Go receiver, a C++ qualified declarator, the object of a Ruby singleton
98
+ /// method); or the path a JavaScript object literal holding it is bound to.
94
99
  pub fn find_container_name(
95
100
  node: Node<'_>,
96
101
  function_nodes: &FxHashSet<&'static str>,
97
102
  code: &Source<'_>,
98
103
  inline_namespaces: &InlineNamespaces<'_>,
99
104
  ) -> Option<String> {
100
- // A function written as a value belongs to whatever it is passed or assigned to, which the
101
- // syntax cannot follow reliably; it keeps the name of what it is bound to and has no owner.
102
- if !is_function_declaration(node) {
105
+ let is_declared = is_function_declaration(node);
106
+ // A function expression with a name of its own (`pick = function impl() {}`) is reported
107
+ // under that name, which is no member of what binds the expression.
108
+ if !is_declared && node.child_by_field_name("name").is_some() {
103
109
  return None;
104
110
  }
111
+ let (holder, bound) = find_value_binding(node, code)?;
112
+ let member = if holder.kind_name() == "pair" {
113
+ holder
114
+ } else {
115
+ bound
116
+ };
117
+ if let Some(object) = member
118
+ .parent_node()
119
+ .filter(|parent| parent.kind_name() == "object")
120
+ {
121
+ return object_owner(object, function_nodes, code, inline_namespaces);
122
+ }
123
+ // A function written as a value belongs to whatever it is passed or assigned to, which the
124
+ // syntax can follow only where a declaration binds it (a class field, a constant of a
125
+ // namespace); elsewhere it keeps the name of what it is bound to and has no owner.
126
+ if !is_declared {
127
+ // A parallel assignment binds the value to the target at its position.
128
+ if is_value_group(holder) {
129
+ let (assignment, target) = find_parallel_assignment_target(bound)?;
130
+ return assigns_attribute(assignment, target)
131
+ .then(|| enclosing_owner(assignment, function_nodes, code, inline_namespaces))
132
+ .flatten();
133
+ }
134
+ if !declares_binding(holder, bound) {
135
+ return None;
136
+ }
137
+ // A C++ variable defined outside its class (`int (*Rules::pick)(int) = [] {}`) spells
138
+ // its owner, as a function defined there does.
139
+ return match find_qualified_declarator(holder) {
140
+ Some(qualified) => {
141
+ cpp_spelled_owner(holder, qualified, function_nodes, code, inline_namespaces)
142
+ }
143
+ None => enclosing_owner(holder, function_nodes, code, inline_namespaces),
144
+ };
145
+ }
105
146
  if let Some(receiver) = node.child_by_field_name("receiver") {
106
147
  return go_receiver_type(receiver, code);
107
148
  }
@@ -113,6 +154,116 @@ pub fn find_container_name(
113
154
  .or_else(|| enclosing_owner(node, function_nodes, code, inline_namespaces))
114
155
  }
115
156
 
157
+ /// Whether `holder` declares the name its value `bound` is bound to, as a field, a property, or a
158
+ /// variable does.
159
+ fn declares_binding(holder: Node<'_>, bound: Node<'_>) -> bool {
160
+ let kind = holder.kind_name();
161
+ if kind == "assignment" {
162
+ return find_single_assignment_target(holder)
163
+ .is_some_and(|target| assigns_attribute(holder, target))
164
+ && holder
165
+ .child_by_field_name("right")
166
+ .is_some_and(|value| value.id() == bound.id());
167
+ }
168
+ kind.ends_with("_declarator")
169
+ || kind.ends_with("_declaration")
170
+ || kind.ends_with("_definition")
171
+ || matches!(kind, "const_item" | "static_item")
172
+ }
173
+
174
+ /// Whether an assignment declares `target` as an attribute of the class around it: a Python class
175
+ /// does by assigning to a plain name and a Ruby one a constant, while a plain name assigned in a
176
+ /// Ruby class body is a local variable of that body.
177
+ fn assigns_attribute(assignment: Node<'_>, target: Node<'_>) -> bool {
178
+ match target.kind_name() {
179
+ // Only Python wraps an assignment in an `expression_statement`, a chain (`e = f = ...`)
180
+ // in that of its outermost assignment.
181
+ "identifier" => {
182
+ let mut outermost = assignment;
183
+ while let Some(outer) = outermost
184
+ .parent_node()
185
+ .filter(|outer| outer.kind_name() == "assignment")
186
+ {
187
+ outermost = outer;
188
+ }
189
+ outermost
190
+ .parent_node()
191
+ .is_some_and(|statement| statement.kind_name() == "expression_statement")
192
+ }
193
+ "constant" => true,
194
+ _ => false,
195
+ }
196
+ }
197
+
198
+ /// The path a JavaScript object literal is bound to, which its members are reached through:
199
+ /// `api` for `const api = { ... }`, `Rules.handlers` for a field of a class, `api.admin` for the
200
+ /// value of a property, `module.exports` for an assignment. An object passed or returned is bound
201
+ /// to nothing the syntax names.
202
+ fn object_owner(
203
+ object: Node<'_>,
204
+ function_nodes: &FxHashSet<&'static str>,
205
+ code: &Source<'_>,
206
+ inline_namespaces: &InlineNamespaces<'_>,
207
+ ) -> Option<String> {
208
+ let bound = unwrap_transparent_value_wrappers(object);
209
+ let holder = bound.parent_node()?;
210
+ let is_value = |field: &str| {
211
+ holder
212
+ .child_by_field_name(field)
213
+ .is_some_and(|value| value.id() == bound.id())
214
+ };
215
+ match holder.kind_name() {
216
+ "variable_declarator" | "field_definition" | "public_field_definition"
217
+ if is_value("value") =>
218
+ {
219
+ let name = holder
220
+ .child_by_field_name("name")
221
+ .or_else(|| holder.child_by_field_name("property"))?;
222
+ // A field may be named by a literal (`"handlers" = {}`); a computed name or a
223
+ // destructuring pattern names nothing.
224
+ let name = match name.kind_name() {
225
+ "string" => find_string_literal_content(name, code)?,
226
+ "number" => node_text(name, code).to_string(),
227
+ kind if kind.ends_with("identifier") => node_text(name, code).to_string(),
228
+ _ => return None,
229
+ };
230
+ Some(
231
+ match enclosing_owner(holder, function_nodes, code, inline_namespaces) {
232
+ Some(owner) => format!("{owner}.{name}"),
233
+ None => name,
234
+ },
235
+ )
236
+ }
237
+ "pair" if is_value("value") => {
238
+ let outer = holder
239
+ .parent_node()
240
+ .filter(|outer| outer.kind_name() == "object")?;
241
+ let owner = object_owner(outer, function_nodes, code, inline_namespaces)?;
242
+ Some(format!("{owner}.{}", find_pair_key_name(holder, code)?))
243
+ }
244
+ "assignment_expression" if is_value("right") => holder
245
+ .child_by_field_name("left")
246
+ .and_then(|target| member_path(target, code)),
247
+ _ => None,
248
+ }
249
+ }
250
+
251
+ /// A name or a chain of property accesses on one (`exports`, `Rules.prototype`, `this.handlers`),
252
+ /// spelled without the comments and line breaks its source may hold.
253
+ fn member_path(node: Node<'_>, code: &Source<'_>) -> Option<String> {
254
+ match node.kind_name() {
255
+ "identifier" | "this" => Some(node_text(node, code).to_string()),
256
+ "member_expression" => {
257
+ let object = member_path(node.child_by_field_name("object")?, code)?;
258
+ let property = node
259
+ .child_by_field_name("property")
260
+ .filter(|property| property.kind_name() == "property_identifier")?;
261
+ Some(format!("{object}.{}", node_text(property, code)))
262
+ }
263
+ _ => None,
264
+ }
265
+ }
266
+
116
267
  /// A Go method is declared outside its type and names it as its receiver, `(r *Rules)` or
117
268
  /// `(r Rules[T])`.
118
269
  fn go_receiver_type(receiver: Node<'_>, code: &Source<'_>) -> Option<String> {
@@ -72,7 +72,6 @@ const DECLARATOR_WRAPPER_TYPES: &[&str] = &[
72
72
  "parenthesized_declarator",
73
73
  "function_declarator",
74
74
  "attributed_declarator",
75
- "pointer_type_declarator",
76
75
  "qualified_identifier",
77
76
  ];
78
77
 
@@ -149,16 +148,10 @@ pub fn measure_dep_degree(
149
148
  pairs
150
149
  }
151
150
 
152
- /// A C++ member-pointer variable (`int C::* p`, also `int C::* arr[1]`) is declared as a
153
- /// `type_identifier` under the `pointer_type_declarator` spelling `C::*`, possibly through further
154
- /// declarator wrappers; every other `type_identifier` names a type, not a variable. Kotlin spells
155
- /// type names as identifiers: in a `user_type`, or as a type parameter's fieldless name (C# puts its
156
- /// type parameter in a `name` field).
151
+ /// Kotlin spells type names as identifiers: in a `user_type`, or as a type parameter's fieldless
152
+ /// name (C# puts its type parameter in a `name` field).
157
153
  fn is_variable_leaf(leaf: &DepDegreeLeaf<'_>) -> bool {
158
154
  let node = leaf.node;
159
- if node.kind_name() == "type_identifier" {
160
- return is_member_pointer_name(node);
161
- }
162
155
  VARIABLE_NODE_TYPES.contains(&node.kind_name())
163
156
  && !node.parent_node().is_some_and(|parent| {
164
157
  parent.kind_name() == "user_type"
@@ -166,15 +159,21 @@ fn is_variable_leaf(leaf: &DepDegreeLeaf<'_>) -> bool {
166
159
  })
167
160
  }
168
161
 
162
+ /// Whether the identifier is the name a C++ member pointer declares (`int C::* p`, also
163
+ /// `int C::* arr[1]`): its `pointer_declarator`, possibly around further declarator wrappers, is
164
+ /// the `name` of the `qualified_identifier` spelling the class.
169
165
  fn is_member_pointer_name(node: Node<'_>) -> bool {
170
166
  let mut current = node;
171
167
  while let Some(parent) = current.parent_node() {
172
- if parent.kind_name() == "pointer_type_declarator" {
173
- return true;
168
+ // The kind is tested before the field is looked up: this runs for every variable read,
169
+ // and scanning the children of a high-arity parent (a list of arguments) each time would
170
+ // cost the square of its length.
171
+ if parent.kind_name() == "qualified_identifier" {
172
+ return current.kind_name() == "pointer_declarator"
173
+ && field_name_in_parent(current, parent) == Some("name");
174
174
  }
175
175
  // The climb follows the declared-name position only, exactly like unwrap_declarator_wrappers.
176
176
  if !DECLARATOR_WRAPPER_TYPES.contains(&parent.kind_name())
177
- || parent.kind_name() == "qualified_identifier"
178
177
  || field_name_in_parent(current, parent).is_some_and(|field| field != "declarator")
179
178
  {
180
179
  return false;
@@ -338,7 +337,7 @@ fn is_definition_field(holder: Node<'_>, field_name: Option<&str>) -> bool {
338
337
 
339
338
  /// Climbs from the identifier through the C/C++ declarator wrappers it is the declared name of
340
339
  /// (`reference_declarator` and `parenthesized_declarator` expose no field, so their name is the
341
- /// fieldless child; a member pointer's `pointer_type_declarator` is the `name` of a
340
+ /// fieldless child; a member pointer's `pointer_declarator` is the `name` of a
342
341
  /// `qualified_identifier`; an `array_declarator` size or a nested parameter has another field and
343
342
  /// stops the climb) to the outermost wrapper and its field in the declaration.
344
343
  fn unwrap_declarator_wrappers<'t>(leaf: &DepDegreeLeaf<'t>) -> (Node<'t>, Option<&'t str>) {
@@ -400,7 +399,7 @@ fn is_parameter_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
400
399
  // O(1).
401
400
  let continues_member_pointer = declares_member_pointer
402
401
  && parent.kind_name() == "qualified_identifier"
403
- && (current.kind_name() == "pointer_type_declarator" || in_member_pointer)
402
+ && (current.kind_name() == "pointer_declarator" || in_member_pointer)
404
403
  && field_name_in_parent(current, parent) == Some("name");
405
404
  in_member_pointer = continues_member_pointer;
406
405
  if depth >= 1