fix(extraction): skip bodiless C++ forward declarations (#1093)#1095
Merged
Conversation
A `class Foo;` forward declaration parses as a bodiless class_specifier. extractStruct (#831) and extractEnum already skip their bodiless forms, but extractClass did not — so every forward decl across dozens of headers minted a phantom bodiless `class` node that competed with, and could be picked as the blast-radius representative over, the single real definition. Add an opt-in `skipBodilessClass` extractor flag (set only on cppExtractor) and skip a bodiless class node when it's set, mirroring the struct/enum skip. The flag keeps this C/C++-scoped: languages where a bodiless class is a complete definition (Kotlin `class Empty`, Scala `case object`/`trait`) leave it unset and are unaffected. The body is now resolved once at the top of extractClass and reused for the member walk. Regression tests cover the collapse to a single definition, elaborated-type references creating no phantom, and Kotlin/Scala staying indexed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1093.
Problem
In a large C++/Unreal-Engine codebase,
codegraph_explorefor a heavily used class (e.g.APXCharacter) returned mostly forward-declaration sites and even picked one as the blast-radius representative, while the real definition (with members and callers) was crowded out.A
class Foo;forward declaration parses as a bodilessclass_specifier.extractStruct(#831) andextractEnumalready skip their bodiless forms, butextractClassdid not — so every forward decl (repeated across dozens of headers) minted a phantom bodilessclassnode competing with the single real definition. A probe confirmed it: a class forward-declared twice then defined produced 3classnodes instead of 1.Fix
skipBodilessClass?: booleanonLanguageExtractor, set only oncppExtractor.extractClassresolves the body once at the top and returns early when the flag is set and the node is bodiless — mirroring the existing bodiless struct/enum skip — then reuses that resolved body for the member walk.class Empty, Scalacase object/trait) leave it unset and are unaffected — verified they funnel through the sameextractClasspath.Validation
3 → 1(the real definition, with itstakeDamagemethod, survives); bodiless-struct control unchanged; KotlinEmpty/Fulland Scalatrait Marker/case object Red/class Fooall still indexed.#1093inextraction.test.ts(collapse to single definition, elaborated-type reference → no phantom, Kotlin/Scala unaffected).npm run build(tsc) clean.#662daemon test (unrelated; passes on retry).🤖 Generated with Claude Code