fix(extraction): detect a plain struct Derived : Base base clause in .h headers as C++ (#1592) - #1593
Open
colbymchenry wants to merge 1 commit into
Open
fix(extraction): detect a plain struct Derived : Base base clause in .h headers as C++ (#1592)#1593colbymchenry wants to merge 1 commit into
struct Derived : Base base clause in .h headers as C++ (#1592)#1593colbymchenry wants to merge 1 commit into
Conversation
…n .h headers as C++ (#1592) A `.h` file whose only C++ syntax is a derived type without an export macro (`struct Derived : Base {};`) fell through the C++ heuristic: the #1159 branch only recognizes the macro-annotated form (`struct ENGINE_API Derived : Base`), and the remaining signals (`class`, `namespace`, `template`, access sections, `virtual`) are all absent from such a header. Routed through the C extractor, the derived struct vanished from the index and a phantom `function Base` with `returnType=Derived` was minted from the base clause instead. `looksLikeCpp()` now runs a second pass for a class/struct base clause — keyword + tag + `:` + optional access specifier/`virtual` + a base name (scoped, possibly templated) followed by the body's `{` or a `,` — a shape with no valid C reading (bit-field colons follow a member name inside the body, ternary colons are separated from the tag by `)`/`*`/a declarator, and `struct_end:` has no whitespace after the keyword). The scan covers the whole file with comments stripped, not the 8 KB sample, so a long C-compatible preamble can no longer hide the one signal. The existing sample-based first pass is unchanged. Tests: plain / `public` / scoped / templated / `final` / multi-base / `virtual` forms detect as cpp, a base clause past 8192 chars detects as cpp, and bit-field, ternary, `struct_`-prefixed identifier, doc-comment prose and the two existing C headers all stay c; an end-to-end extraction of the issue's header yields the `Derived` struct and no phantom function. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LxZj6W6Y1SHXwvpT3uwJpK
This was referenced Aug 22, 2026
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.
Fixes #1592.
What was wrong
A
.hheader whose only C++ construct is a plain derived type —— was classified as C. The
.hlanguage check (looksLikeCpp) recognizesclass,namespace,template, access sections,virtual,using, and — since #1159/#1207 — the export-macro formstruct ENGINE_API Derived : Base. The plain form has none of those signals. Routed through the C extractor,Derivedvanished from the index and the base clause was read as a K&R-style declaration, minting a phantomfunction BasewithreturnType=Derived(the exact output in the issue).A second, independent miss the reporter called out: the check only read the first 8192 characters, so a large header with a long C-compatible preamble (include guards,
#defines, plain typedefs) hid the signal even when it was there.What this does
looksLikeCpp()now runs two passes:class/struct+ tag + optionalfinal+:+ optionalpublic/protected/private/virtual+ a base name (scoped, optionally templated) followed by the body's{or a,introducing the next base.That shape has no valid C reading, so widening it to the whole file can't drag a C header over to C++:
:follows a member name inside the body (unsigned a : 3;), not the tag;:is separated from the tag by)/*/ a declarator (sizeof(struct foo) : 0);struct_end:has no whitespace afterstruct;/* struct timeval: seconds, microseconds */) can't match; and the{/,terminator keeps a string literal's prose from matching too.Detection only — the C++ extractor already handles the header correctly once it's routed there (renaming to
.hpp, as the issue notes, already worked).Tests
__tests__/extraction.test.ts:: public Base/: ns::Base/: Base<int, Foo<T>>/final : Base/ multi-base with{on the next line /: virtual Base→cpp;cpp;c: a bit-field struct,sizeof(struct foo) : 0+ a cast ternary, astruct_end:label andstruct_aidentifiers, doc-comment prose shaped like a base clause, and the two pre-existing C controls;extractFromSource('src/min.h', …)on the issue's header: astructnodeDerived(languagecpp), exactly oneBasenode and it is astruct— no phantom function.Issue repro re-run against this build:
codegraph init→query Derivedreturns thecppstruct;query Basereturns only the struct; the files table recordssrc/min.hascpp.Full suite:
npm test→ 174 files passed, 3010 tests passed, 179 skipped.🤖 Generated with Claude Code
https://claude.ai/code/session_01LxZj6W6Y1SHXwvpT3uwJpK