Skip to content

fix(extraction/cpp): keep export-macro-annotated classes and their extends edge (#946)#1062

Open
luoyxy wants to merge 1 commit into
colbymchenry:mainfrom
luoyxy:fix/cpp-export-macro-class
Open

fix(extraction/cpp): keep export-macro-annotated classes and their extends edge (#946)#1062
luoyxy wants to merge 1 commit into
colbymchenry:mainfrom
luoyxy:fix/cpp-export-macro-class

Conversation

@luoyxy

@luoyxy luoyxy commented Jun 29, 2026

Copy link
Copy Markdown

Summary

UE-style classes annotated with an ALL-CAPS *_API export macro
(class MYMODULE_API Name : public Base { ... }) are dropped entirely today.
tree-sitter has no preprocessor, so it reads class MYMODULE_API as an
elaborated type specifier and the whole declaration as a function_definition;
isMacroMisparsedTypeDecl then drops that phantom as unrecoverable. The result:
the class node AND its extends edge are lost, so subclass / type-hierarchy /
inheritance-impact queries return nothing for effectively every gameplay class
in an Unreal Engine project.

Fix

Add a preParse hook (blankCppExportMacros) to cppExtractor that blanks the
export macro with equal-length spaces before parsing — the same offset-preserving
technique blankCsharpPreprocessorDirectives uses (#237). The header then parses
as an ordinary class_specifier with a base_class_clause, so the class is
indexed and the existing base-clause extraction emits the extends edge, with
every symbol's line/column unchanged.

Scope is deliberately tight to avoid touching valid code: ALL-CAPS (>=2 char)
macro token, only between class/struct and the type name (two identifiers in
a row — a genuine definition never has that), and only when the type name is
followed by final, a base clause (:) or the body ({). class Foo {,
template<class T>, enum class E {, and an ALL-CAPS class name with no macro
(class FOO : public Bar) are all untouched. The existing
isMacroMisparsedTypeDecl drop path is kept as a fallback for forms this doesn't
cover (function-like macros, macros with lowercase letters).

Tests

…tends edge (colbymchenry#946)

UE-style classes annotated with an ALL-CAPS `*_API` export macro
(`class MYMODULE_API Name : public Base { ... }`) were dropped entirely:
tree-sitter has no preprocessor, so it reads `class MYMODULE_API` as an
elaborated type specifier and the whole declaration as a function_definition
named after the class. `isMacroMisparsedTypeDecl` then drops that phantom
function as unrecoverable, so the class node AND its base/`extends` edge are
lost. As a result, subclass / type-hierarchy / inheritance-impact queries
return nothing for what is effectively every gameplay class in a UE project.

Add a `preParse` hook (`blankCppExportMacros`) to `cppExtractor` that blanks
the export macro with equal-length spaces before parsing -- the same
offset-preserving technique `blankCsharpPreprocessorDirectives` uses (colbymchenry#237).
The header then parses as an ordinary `class_specifier` with a
`base_class_clause`, so the class is indexed and the existing base-clause
extraction emits the `extends` edge, with every symbol's line/column unchanged.

Scope is deliberately tight to avoid touching valid code: an ALL-CAPS (>=2
char) macro token, only between `class`/`struct` and the type name (two
identifiers in a row -- a genuine definition never has that), and only when the
type name is followed by `final`, a base clause (`:`) or the body (`{`).
`class Foo {`, `template<class T>`, `enum class E {`, and an ALL-CAPS class
name with no macro (`class FOO : public Bar`) are all left untouched. The
existing `isMacroMisparsedTypeDecl` drop path is kept as a fallback for forms
this doesn't cover (function-like macros, macros with lowercase letters).

The existing colbymchenry#946 tests are upgraded from "phantom function is absent" to the
stronger "class node + extends edge are present", plus unit tests for
`blankCppExportMacros` covering offset preservation and non-matching cases.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant