A C++ class deriving from a template — `class Derived : public Base<int>`, a CRTP base `class App : public CRTPBase<App>`, a struct inheriting a template, or a templated base mixed into a multi-base clause — recorded its base as the full instantiation text (`Base<int>`). That never name-matched the template, which is indexed as the bare node `Base`, so the `extends` edge never resolved and the derived class looked like it inherited from nothing — callers/impact analysis stopped at the boundary. Strip the template arguments from the base-type reference name in the `base_class_clause` handler via a new `stripCppTemplateArgs` helper: it removes every balanced `<…>` group (any nesting/position), so `Base<int>` → `Base` and `ns::Tpl<int>` → `ns::Tpl`. The remaining qualified head is exactly what the non-templated base case already produces, so resolution treats templated and non-templated bases identically; a name with no template args passes through unchanged. Covers same-file and same-namespace bases (the dominant real-world patterns). A base in a different namespace referenced with its qualifier (`other_ns::Tpl<int>`) still doesn't resolve, but that's a pre-existing, orthogonal namespace-resolution gap — the non-templated `other_ns::Plain` fails identically — not a template issue. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4c0c87ff6e
commit
f4e03e9cdc
@@ -84,6 +84,33 @@ export function normalizeCppReturnType(raw: string): string | undefined {
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip C++ template arguments from a base-type reference name so it matches the
|
||||
* bare class/struct the template was DEFINED as. `template<typename T> class
|
||||
* Base { … }` is indexed as a node named `Base`, but a derived class
|
||||
* `class D : public Base<int>` records its base as the full `Base<int>` (and
|
||||
* `class Q : public ns::Tpl<int>` as `ns::Tpl<int>`) — neither name-matches
|
||||
* `Base` / `ns::Tpl`, so the `extends` edge never resolves and the derived class
|
||||
* looks like it inherits from nothing (#1043).
|
||||
*
|
||||
* Removes every balanced `<…>` group regardless of nesting or position, so
|
||||
* `Base<int>` → `Base`, `ns::Tpl<Foo<int>>` → `ns::Tpl`, and the rare
|
||||
* `Outer<int>::Inner` → `Outer::Inner`. The remaining qualified head is exactly
|
||||
* what the non-templated base case already produces, so resolution treats them
|
||||
* identically. A name with no template args passes through unchanged.
|
||||
*/
|
||||
export function stripCppTemplateArgs(name: string): string {
|
||||
if (!name.includes('<')) return name;
|
||||
let out = '';
|
||||
let depth = 0;
|
||||
for (const ch of name) {
|
||||
if (ch === '<') depth++;
|
||||
else if (ch === '>') { if (depth > 0) depth--; }
|
||||
else if (depth === 0) out += ch;
|
||||
}
|
||||
return out.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* A function/method's return type lives in the `function_definition`'s `type`
|
||||
* field (`Metrics& Metrics::instance()` → `Metrics`). Constructors, destructors,
|
||||
|
||||
Reference in New Issue
Block a user