Files
codegraph/__tests__
Colby MchenryandClaude Opus 5.5 5a6917b437 fix(c): a function whose return type is a macro call is indexed (#2773)
In C, a function declared with its return type written as a macro call,
like cJSON's `CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)` or
libgit2's `GIT_EXTERN(int) git_blob_dup(...);`, had no node.
blankCppAnnotationMacroCalls blanks a line-leading ALL-CAPS macro call
that a declaration follows, the markup shape of Unreal's `UPROPERTY(...)`.
Since the C/C++ kernel port, C's pre-parse runs it as well, to set aside
redis's `REDIS_NO_SANITIZE("bounds")` and similar. In C the same shape is
often the return type. Blanked together with its argument, it left
`cJSON_Print(...)` and a block, which parse as a call statement. The
function was lost, the calls in its body went to the file, its locals
and parameters became file-level variables, and a header's prototype
read as a call from the header.

C now passes keepCReturnTypes. With it, a macro is kept, and tree-sitter
reads it as a macro_type_specifier, when all of these hold:
- it is in column 0;
- its one argument reads as a type;
- only a function declarator follows: a name, its parameter list,
  `__attribute__` or ALL-CAPS attributes, then `{` or `;`;
- the line right above leaves no declaration open. jemalloc writes
  `size_t JEMALLOC_NOTHROW` there, above `JEMALLOC_ATTR(pure)`.
C++ is unchanged.

Validation:
- New __tests__/c-macro-return-types.test.ts (3 tests: the issue's
  reproduction plus GNU-style, prototype-with-attribute, ATTR_FORMAT,
  REDIS_NO_SANITIZE and jemalloc shapes; a libgit2-style header; the
  blank itself). All 3 fail with main's c-cpp.ts and pass on the kernel
  and with CODEGRAPH_KERNEL=0.
- Pre-parse output compared file by file on 12 repos. The only changes
  are macro text kept where main blanked it; no file's parse-error count
  got worse. Better: cJSON 4 files (cJSON.c 131 -> 6 errors), expat 1,
  APR 69, libgit2 82. Byte-identical pre-parse, and so graphs, on jq,
  redis (with jemalloc), sqlite and curl, and on the C++ controls fmt,
  glm, json and abseil-cpp.
- A/B on main 6bd217a2, graph dumps:
  - cJSON: +92 functions; 7 functions named `(void)` and 100 phantom
    variables and constants gone; edges 2,882 -> 3,750.
  - libgit2: +403 functions; 3 `(void)` functions and 293 phantoms
    gone; 37 calls that went to a phantom parameter gone; edges 81,984
    -> 85,834.
  - APR: +1,551 functions; 7 bogus ones and 1,723 phantoms gone; edges
    16,163 -> 23,278. 39 calls now reach the real APR_DECLARE definition
    instead of its EBCDIC stub. 283 portable calls now see the
    OS/2 and Windows copies beside the Unix one: 278 go to OS/2 at 0.4
    (was Unix at 0.9), and 5 from win32 code go to win32.
  - expat: 22 phantom parameters gone.
- kernel-parity: 0 diffs on both arms; deferred files fall from 33 to
  31 (cJSON), 218 to 161 (APR) and 208 to 128 (libgit2).
- Cost: medians of 3 interleaved init runs: cJSON -1.6%, expat -4.3%,
  libgit2 -6.9%, APR +18.4%. APR's graph is 44% larger. The pre-parse
  itself is unchanged (APR 262 vs 257 ms, libgit2 598 vs 599 ms).

Fixes #2470

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 02:16:31 +00:00
..