Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions __tests__/extraction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3964,6 +3964,40 @@ class APXCharacter { // the one real definition
});
});

describe('C macro-attribute + typedef return type misparse (#1211)', () => {
const cNames = (code: string) =>
extractFromSource('main.c', code).nodes
.filter((n) => n.kind === 'function')
.map((n) => n.name);

it('recovers the function name when a macro attribute precedes a typedef return type', () => {
const code = `
#define SEC_ATTR __attribute__((section(".init")))
typedef unsigned int UINT32;
#define VOID void

SEC_ATTR VOID GoodName(VOID) { }
SEC_ATTR UINT32 LostName(VOID) { return 0; }
`;
const names = cNames(code);
expect(names).toContain('GoodName');
expect(names).toContain('LostName');
expect(names).not.toContain('(VOID)');
});

it('handles multiple leading macro tokens before a known return type', () => {
const code = `
LITE_OS_SEC_TEXT_INIT UINT32 LOS_KernelInit(void) { return 0; }
`;
expect(cNames(code)).toContain('LOS_KernelInit');
});

it('does not blank a real mixed-case return type', () => {
const code = `int normalFunc(void) { return 0; }`;
expect(cNames(code)).toContain('normalFunc');
});
});

describe('C++ templated base-class inheritance (#1043)', () => {
// Inheriting from a template (`class D : public Base<int>`) recorded the base
// ref as the full instantiation `Base<int>`, which never name-matched the
Expand Down
32 changes: 28 additions & 4 deletions src/extraction/languages/c-cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,11 +701,35 @@ function preParseCppSource(source: string, filePath?: string): string {
return blanked;
}

/** C source pre-processing: C-detected headers in CUDA projects (llm.c keeps
* `__device__` helpers and kernel prototypes in plain `.h`) get the same
* content-gated CUDA blank as C++. */
/**
* Blank isolated ALL_CAPS macro tokens sitting before a known C return type at
* line start. Handles project-specific attribute/section macros (SEC_ATTR,
* LITE_OS_SEC_TEXT_INIT, etc.) that no curated list can cover. tree-sitter-c
* can't reconcile an unknown token before a typedef'd return type — the
* function name is lost and replaced by the parameter list (#1211).
*
* Matched tightly: ALL_CAPS tokens only, at line start only, and must be
* followed by a known primitive or common typedef return type — so real
* declarations like `HRESULT DoIt()` (mixed-case) are never touched.
*/
const C_LEADING_MACRO_RE =
/^(\s*)((?:[A-Z_][A-Z0-9_]*\s+)+)((?:unsigned\s+|signed\s+|long\s+|short\s+)?(?:void|int|char|short|long|float|double|bool|size_t|ssize_t|ptrdiff_t|u?int(?:8|16|32|64|ptr)_t|VOID|BOOL|BOOLEAN|BYTE|WORD|DWORD|UINT8|UINT16|UINT32|UINT64|INT8|INT16|INT32|INT64|UINTPTR|CHAR|UCHAR|WCHAR|ULONG|LONG|USHORT|SHORT|HANDLE|HRESULT|NTSTATUS|PVOID|LPVOID)\s)/gm;
function blankCLeadingMacros(source: string): string {
return source.replace(
C_LEADING_MACRO_RE,
(_match, indent: string, macros: string, retType: string) =>
indent + ' '.repeat(macros.length) + retType,
);
}

/** C source pre-processing: blank macro tokens that tree-sitter-c can't
* reconcile before return types (#1211), plus known inline-specifier macros
* shared with C++ (SQLITE_API, WINAPI, etc.), and CUDA constructs in
* C-detected headers. */
function preParseCSource(source: string): string {
return looksLikeCudaSource(source) ? blankCudaConstructs(source) : source;
let result = blankCLeadingMacros(blankCppInlineMacros(source));
if (looksLikeCudaSource(source)) result = blankCudaConstructs(result);
return result;
}

export const cppExtractor: LanguageExtractor = {
Expand Down