big_code_analysis_ast/c_declarator.rs
1//! The C-family declarator-chain walk, shared by the two surfaces that
2//! need it.
3//!
4//! C declarator syntax nests outward from the declared name, so neither
5//! a function's parameter list nor its name is reliably a child of the
6//! function node itself. Both are found from the one node
7//! [`innermost_declarator`] returns — the innermost link on the chain
8//! that is the function's own declarator rather than its return type's:
9//!
10//! - `big_code_analysis::metrics::nargs` reads its `parameters` field (#1200).
11//! - The `Getter::get_func_space_name` impls for C, C++, mozcpp and
12//! Objective-C read its name side through [`declarator_name`] (#1208).
13//!
14//! Keeping one walk keeps the two answers about the same function from
15//! disagreeing, which is how #1208 arose: the arity came from this
16//! chain and the name came from a leftmost pre-order search that stopped
17//! one level too early. The invariant is one *function*, one walk —
18//! not one node: an unexpanded function-like macro puts the arity and
19//! the name on two links of the chain, which each function's own doc
20//! below explains (#1213).
21
22use crate::checker::Checker;
23use crate::node::Node;
24
25/// The innermost declarator along a C-family function's declarator
26/// chain: the node whose `parameters` field holds the function's *own*
27/// formal arguments. [`declarator_name`] takes the name from the same
28/// node's `declarator` field.
29///
30/// C declarator syntax nests outward from the declared name, so a
31/// function node's `declarator` field is only the function's parameter
32/// list when the return type is plain. Anything the return type
33/// contributes — a `*`, a `&`, a parenthesised group — wraps the
34/// `function_declarator` that owns the real list, and the outermost
35/// `parameters` a chain carries can belong to the *return type* rather
36/// than to the function (`int (*f(int a))(int b)` returns a pointer to a
37/// one-argument function and itself takes one argument). Taking the
38/// innermost is what makes both of those come out right (#1200), and
39/// the same node carries the name `f` that a leftmost search misses
40/// (#1208).
41///
42/// "Innermost" has one exception, and it is the one shape where the
43/// grammar's reading and the preprocessor's disagree. An unexpanded
44/// function-like macro — `RUN_STATS_METHOD(allocate)(JNIEnv *env,
45/// jclass clazz)`, which is what every JNI shim looks like — parses as
46/// a `function_declarator` sitting in another one's `declarator` field,
47/// so the innermost list is the macro's `(allocate)` and the function's
48/// own arguments are discarded. Neither language permits that chain: a
49/// function may not return a function type (C11 6.7.6.3p1, C++
50/// `[dcl.fct]`), so a legitimate function returning a function pointer
51/// always interposes a `parenthesized_declarator`, and the direct
52/// nesting can only be a macro (or an `ERROR`, below). The walk stops
53/// at the outer link there and reports the function's arity (#1213).
54///
55/// The walk is by field name, per `.claude/rules/grammar-dispatch.md`
56/// §3, which also sidesteps §1: `PointerDeclarator2`,
57/// `FunctionDeclarator2`/`3` and `ReferenceDeclarator2`/`3`/`4` are
58/// numeric-suffix aliases that a `kind_id` match would have to
59/// enumerate and would silently regress on the next grammar bump.
60///
61/// Three of the rules on the chain expose no field at all, which is why
62/// the field alone is not enough. Every entry below is from the pinned
63/// grammars' `node-types.json` (`tree-sitter-cpp` 0.23.4,
64/// `tree-sitter-c` 0.24.2, `tree-sitter-objc` 3.0.2, vendored
65/// `tree-sitter-mozcpp`), and the fieldless list is the complete set of
66/// `*_declarator` rules with no fields that a *function definition's*
67/// name side can reach — the rest (`variadic_declarator`,
68/// `structured_binding_declarator`, Objective-C's `keyword_declarator`
69/// and `struct_declarator`, and the `abstract_*` family) sit in
70/// parameter, binding or type position, never here.
71///
72/// | rule | `declarator` field |
73/// | --- | --- |
74/// | `pointer_declarator` | required |
75/// | `function_declarator` | required |
76/// | `abstract_function_declarator` | **optional** |
77/// | `reference_declarator` | **absent — no fields** |
78/// | `parenthesized_declarator` | **absent — no fields** |
79/// | `attributed_declarator` | **absent — no fields** |
80///
81/// In all three fieldless rules the inner declarator is the last
82/// *named* child once attributes are set aside, so that is the
83/// fallback:
84///
85/// - `reference_declarator` is `seq(choice('&', '&&'), _declarator)`.
86/// - `parenthesized_declarator` is `seq('(',
87/// optional(ms_call_modifier), _declarator, ')')` — last rather than
88/// sole, so `int (__cdecl *f(int a))(int b)` does not defeat it.
89/// - `attributed_declarator` is `seq(_declarator,
90/// repeat1(attribute_declaration))`, the one rule that puts the
91/// declarator **first**. Excluding `attribute_declaration` — its only
92/// non-declarator child type in all four grammars — restores "last"
93/// as the right answer, and without that exclusion
94/// `int f(int a, int b) [[deprecated]]` reports 0.
95///
96/// `template_argument_list` is excluded for the same reason as
97/// `attribute_declaration`, and it is the one exclusion the fallback
98/// needs beyond the three rules above. The fallback also runs on the
99/// *name* forms, which have no `declarator` field either, and two of
100/// them — `template_function` and `template_method` — put their argument
101/// list last: `void f<int (*)(int x, int y)>(int a)`. A type argument
102/// spelling a function type carries a `parameters` field of its own, so
103/// descending into it made that function read as taking two arguments
104/// and made its name resolve to nothing at all, the abstract declarator
105/// the chain landed on spelling no identifier. Excluding the argument
106/// list leaves the name itself as the last named child, which terminates
107/// the chain where it should.
108///
109/// Comments are excluded for the same reason, tree-sitter admitting one
110/// anywhere.
111///
112/// The fallback stops at a node that already carries `parameters`,
113/// which is the C++ lambda: `abstract_function_declarator`'s
114/// `declarator` field is optional, so `[](int a, int (*cb)(int x))`
115/// would otherwise descend into the `parameter_list` and return `cb`'s
116/// `(int x)` — one argument instead of two.
117///
118/// Every step strictly descends a finite tree, so the walk terminates
119/// without a depth cap.
120///
121/// # ERROR-recovery trees are outside this contract
122///
123/// Every rule above is the grammar's, and none of them holds once
124/// tree-sitter starts recovering. An unexpanded macro in declarator
125/// position — `T *f() TF_ATTRIBUTE_NOINLINE { … }` — puts the real
126/// `function_declarator` inside an `ERROR` node and leaves the macro's
127/// `field_identifier` as the `pointer_declarator`'s last named child,
128/// so the fallback follows the macro and the walk answers `None`.
129///
130/// Give that macro an argument — `T *f() TF_LOCKS_EXCLUDED(mu_) { … }`,
131/// which is the spelling the TensorFlow / Abseil annotations actually
132/// take — and it is a `function_declarator` carrying `parameters`, so
133/// the walk answers with the *macro's* name rather than with nothing.
134/// That is the one shape this change made worse: the leftmost pre-order
135/// search it replaced descended into the `ERROR` and got `f` right.
136/// `a_parenthesised_macro_takes_the_name_of_the_function_it_annotates`
137/// pins it.
138///
139/// Recovery also manufactures the direct `function_declarator` nesting
140/// the macro rule keys on, from source containing no macro-obscured
141/// declarator at all. A *statement* macro followed by an `if` —
142/// TensorFlow's `TF_ASSIGN_OR_RETURN(bool ok, Try(x)); if (ok) { … }` —
143/// recovers into a `function_declarator` whose `declarator` field is the
144/// macro call and whose `parameters` field is the `if` **condition**. So
145/// the rule changes the answer for 19 of the 46 corpus spaces it
146/// touches, from the macro's argument count to the condition's, neither
147/// of which is an arity. There is no fixture for it: whether the
148/// grammar recovers this way depends on where the line breaks fall,
149/// tree-sitter costing a recovery by the extent it skips, so any pinned
150/// spelling would be a claim about whitespace (#1213).
151///
152/// Whatever any strategy returns there is arbitrary, and the walk does
153/// not try to be clever about it. Measured over `DeepSpeech` and
154/// `pdf.js` (14,269 files), moving the four getters onto this walk
155/// named 46 previously-nameless function spaces, un-named 2 and renamed
156/// 4 — 354 nameless spaces down to 310, a net 44. All six of the latter
157/// sit inside recovery subtrees: one of the un-named had been reporting
158/// an `if` statement's callee as a function name, and one of the renamed
159/// is the `TF_LOCKS_EXCLUDED` case above (#1208).
160#[must_use]
161pub fn innermost_declarator<'tree, T: Checker>(node: &Node<'tree>) -> Option<Node<'tree>> {
162 // The chain starts at the `declarator` field rather than at `node`
163 // so the last-named-child fallback can never fire on the function
164 // node itself and walk into its body. The walk runs outside-in, so
165 // the innermost qualifying link is the last one it yields.
166 std::iter::successors(
167 node.child_by_field_name("declarator"),
168 |current| match current.child_by_field_name("declarator") {
169 // An unexpanded function-like macro standing in for the
170 // declarator, which is the shape JNI shims take. Neither C
171 // nor C++ lets a function return a function type (C11
172 // 6.7.6.3p1, C++ `[dcl.fct]`), so a `function_declarator`
173 // directly inside another one's `declarator` field is not a
174 // declarator chain at all: the outer list is the function's
175 // own and the inner one holds the macro's arguments. Both
176 // links have to be tested — a pointer return puts a
177 // `function_declarator` in a `pointer_declarator`'s
178 // `declarator` field, and stopping *there* would end the
179 // chain on a node carrying no `parameters` and report 0
180 // (#1213).
181 Some(inner)
182 if current.kind() == FUNCTION_DECLARATOR && inner.kind() == FUNCTION_DECLARATOR =>
183 {
184 None
185 }
186 Some(declarator) => Some(declarator),
187 None if current.child_by_field_name("parameters").is_some() => None,
188 None => current
189 .children()
190 .filter(|child| {
191 child.is_named()
192 && !T::is_comment(child)
193 && !matches!(child.kind(), ATTRIBUTE | TEMPLATE_ARGUMENTS)
194 })
195 .last(),
196 },
197 )
198 // A conversion operator's `declarator` field is the type it converts
199 // *to*, not its name side: `operator int (*)(int x)` takes no
200 // arguments, and everything from here inward describes that
201 // function-pointer type. Cutting the chain restores the 0 the
202 // pre-#1200 code reported by never finding `parameters` at all.
203 .take_while(|link| link.kind() != CONVERSION_OPERATOR)
204 .filter(|link| link.child_by_field_name("parameters").is_some())
205 .last()
206}
207
208/// The node spelling a C-family function's name.
209///
210/// It is the `declarator` field of [`innermost_declarator`], and it is a
211/// separate function only so the four `get_func_space_name` impls state
212/// that pairing once instead of four times. Each caller still gates the
213/// result on its own grammar's identifier kinds: what counts as a name
214/// is where C, C++ and Objective-C differ (`destructor_name`,
215/// `qualified_identifier`, `operator_name`, `template_function`), and a
216/// kind this module accepted on their behalf would be a claim about
217/// four grammars made in a module that reads none of them.
218///
219/// The macro shape [`innermost_declarator`] stops at is the one place
220/// the name and the arity come off different nodes. There that
221/// `declarator` field is the macro *invocation* — itself a
222/// `function_declarator`, which no getter's identifier gate accepts — so
223/// the walk descends through it to the identifier the macro spells.
224/// `RUN_STATS_METHOD` is the only name in the source: the real
225/// `Java_…_allocate` exists only after `##` pasting, and it is the token
226/// a reader greps for. This is why the module doc states the invariant
227/// per *function* rather than per node (#1213).
228#[must_use]
229pub fn declarator_name<'tree, T: Checker>(node: &Node<'tree>) -> Option<Node<'tree>> {
230 // A run of them rather than one: `A(b)(c)(int x)` is two nested
231 // invocations and the name is still `A`. Each step descends a finite
232 // tree, so this terminates for the same reason the walk above does.
233 //
234 // Written as a chain rather than a `while` with `?` inside it
235 // deliberately. The loop form needs an early return for "this
236 // `function_declarator` has no `declarator` field", which the
237 // grammars declare required and only an `ERROR` could violate — two
238 // arms no test can reach, and coverage counts them.
239 //
240 // The two forms are not identical on that unreachable input, which is
241 // worth stating rather than leaving for the next reader to rediscover
242 // (#1220). On an `ERROR` tree where a `function_declarator` lacks its
243 // `declarator` field, the loop returned `None` and this chain yields
244 // that `function_declarator` itself — the whole declarator span in
245 // place of a name.
246 //
247 // Nothing observes the difference, and the reason is external to this
248 // module: every caller gates the result on its own grammar's
249 // identifier kinds (`TypeIdentifier | Identifier | FieldIdentifier`,
250 // plus the C++ name forms in `getter/cpp.rs` and `getter/mozcpp.rs`),
251 // and `function_declarator` is in none of those lists. The `matches!`
252 // falls through and `get_func_space_name` returns `None` — the same
253 // answer the loop gave. That dependency is the thing to preserve: a
254 // getter that widened its gate to accept `function_declarator` would
255 // start naming functions after their whole declarator span on
256 // malformed input, and this comment is the only place that says so.
257 std::iter::successors(
258 innermost_declarator::<T>(node)?.child_by_field_name("declarator"),
259 |link| {
260 if link.kind() == FUNCTION_DECLARATOR {
261 link.child_by_field_name("declarator")
262 } else {
263 None
264 }
265 },
266 )
267 .last()
268}
269
270/// Compared by `kind()` string rather than `kind_id`, per
271/// `.claude/rules/grammar-dispatch.md` §1: every rule below carries
272/// numeric-suffix aliases across the four C-family grammars, and a
273/// `kind_id` match would have to enumerate every one of them and would
274/// regress silently on the next grammar bump. C and Objective-C simply
275/// never emit `operator_cast`.
276const CONVERSION_OPERATOR: &str = "operator_cast";
277const ATTRIBUTE: &str = "attribute_declaration";
278const TEMPLATE_ARGUMENTS: &str = "template_argument_list";
279/// Carries the most aliases of the four — `FunctionDeclarator2` through
280/// `FunctionDeclarator5` in `tree-sitter-c` alone — so it is the one the
281/// `kind()`-string rule above most needs to cover.
282const FUNCTION_DECLARATOR: &str = "function_declarator";