Skip to content

fix(extraction): index C functions decorated with a leading export macro (#515)#597

Open
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/515-c-macro-decorated-function
Open

fix(extraction): index C functions decorated with a leading export macro (#515)#597
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/515-c-macro-decorated-function

Conversation

@maxmilian
Copy link
Copy Markdown

Summary

Fixes #515. A C function written as EXPORT_MACRO ReturnType Name(...) — a leading export/visibility macro in front of a project-defined (typedef'd) return type — was indexed under the garbage name (params) instead of its real name, so it couldn't be searched or navigated to. This pattern is ubiquitous in vendor SDKs, e.g. the Axera SoC SDK from the report: AX_VIN_GLB_API AX_S32 AX_VIN_Init(AX_VOID).

Root cause

Both the macro and the typedef'd return type are unknown identifiers in type position, so tree-sitter-c peels MACRO RET off as a separate (broken) declaration and parses the real function with its name absorbed as the type field and the parameter list wrapped in a bare parenthesized_declarator instead of a function_declarator:

function_definition
  type: type_identifier "AX_VIN_Init"      <- the real name
  declarator: parenthesized_declarator     <- the params
    identifier "AX_VOID"
  body: compound_statement

extractName then falls through to getNodeText(parenthesized_declarator)"(AX_VOID)".

Fix

recoverMacroDecoratedFunctionName (wired only into the C extractor's resolveName): when a function_definition's declarator field is directly a parenthesized_declarator, take the name from the type field instead. That shape is one valid C never produces.

Tests

__tests__/extraction.test.ts → new C/C++ Extraction block:

  • recovers AX_VIN_Init from the macro-decorated definition (and is not named (AX_VOID))
  • plain int compute(int a) is unaffected
  • int (foo)(void) (redundant parens — keeps a function_declarator) does not misfire and is not renamed to int

Full suite green locally: npm run build clean, 1097 passed | 2 skipped (+3 new).

Scope

Deliberately narrow — verified against the real grammars with parse dumps before/after:

  • Macro + primitive return (AX_API int F(...)), macro + pointer return (AX_API char* F(...)), and all C++ forms already parse to a function_declarator and extract correctly on main — they don't reach this recovery and aren't touched (no resolveName change for the C++ extractor).
  • Bare prototypes in headers (AX_API AX_S32 AX_VIN_Init(void);) are reparsed by tree-sitter as a top-level call expression. Recovering a symbol from that would risk synthesizing symbols from genuine call sites, so it's left as a follow-up. The definition site (this fix) is where the symbol lives, which makes it searchable.

No node-count change — resolveName only renames; it cannot add or drop nodes.

…cro (colbymchenry#515)

A leading export/visibility macro followed by a typedef'd return type —
`AX_VIN_GLB_API AX_S32 AX_VIN_Init(AX_VOID) { ... }`, common in vendor C
SDKs that gate symbols behind `__attribute__((visibility))` /
`__declspec(dllexport)` macros — makes tree-sitter-c misparse the
function: both the macro and the return type are unknown identifiers in
type position, so the grammar peels `MACRO RET` off as a separate broken
declaration and parses the real function with its name absorbed as the
`type` field and the parameter list wrapped in a bare
`parenthesized_declarator` instead of a `function_declarator`. The
function was then indexed under the garbage name `(params)` and could not
be found.

Recover the true name from the `type` field when a function_definition's
declarator is a parenthesized_declarator — a shape valid C never produces
(redundant parens and function-pointer returns keep a function_declarator,
covered by a no-misfire test), so the recovery never fires on well-formed
code.

Deliberately narrow: macro + primitive or pointer return types
(`AX_API int F(...)`, `AX_API char* F(...)`) and all C++ forms already
parse to a function_declarator and extract correctly via the existing
path, so they don't reach this recovery. Bare prototypes in headers, which
tree-sitter reparses as a top-level call expression, are left as a
follow-up to avoid synthesizing symbols from genuine call sites.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maxmilian maxmilian force-pushed the fix/515-c-macro-decorated-function branch from f6c276e to b02776d Compare June 1, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The interface cannot be indexed; the function is decorated with the macro AX_VIN_GLB_API

1 participant