Skip to content

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
mainfrom
fix/1592-h-base-clause-cpp-detection
Open

fix(extraction): detect a plain struct Derived : Base base clause in .h headers as C++ (#1592)#1593
colbymchenry wants to merge 1 commit into
mainfrom
fix/1592-h-base-clause-cpp-detection

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Fixes #1592.

What was wrong

A .h header whose only C++ construct is a plain derived type —

struct Base {};
struct Derived : Base {};

— was classified as C. The .h language check (looksLikeCpp) recognizes class, namespace, template, access sections, virtual, using, and — since #1159/#1207 — the export-macro form struct ENGINE_API Derived : Base. The plain form has none of those signals. Routed through the C extractor, Derived vanished from the index and the base clause was read as a K&R-style declaration, minting a phantom function Base with returnType=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:

  1. The existing 8 KB sample regex, unchanged.
  2. A scan of the whole file (comments stripped) for a class/struct base clause: class/struct + tag + optional final + : + optional public/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++:

  • a bit-field's : follows a member name inside the body (unsigned a : 3;), not the tag;
  • a ternary's : is separated from the tag by ) / * / a declarator (sizeof(struct foo) : 0);
  • a label or identifier like struct_end: has no whitespace after struct;
  • comments are removed before the scan, so doc-comment prose (/* 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:

  • plain / : public Base / : ns::Base / : Base<int, Foo<T>> / final : Base / multi-base with { on the next line / : virtual Basecpp;
  • a base clause placed after 8192 characters of C-compatible preamble → cpp;
  • controls that must stay c: a bit-field struct, sizeof(struct foo) : 0 + a cast ternary, a struct_end: label and struct_a identifiers, doc-comment prose shaped like a base clause, and the two pre-existing C controls;
  • end-to-end extractFromSource('src/min.h', …) on the issue's header: a struct node Derived (language cpp), exactly one Base node and it is a struct — no phantom function.

Issue repro re-run against this build: codegraph initquery Derived returns the cpp struct; query Base returns only the struct; the files table records src/min.h as cpp.

Full suite: npm test → 174 files passed, 3010 tests passed, 179 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LxZj6W6Y1SHXwvpT3uwJpK

…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
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.

C++: struct Derived : Base in .h files is misdetected as C (#1159 follow-up)

1 participant