mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-24 19:30:10 +08:00
fix(cpp): an alias naming a class through a derived class leads to the class it inherits (#2549)
protobuf's `using ConformanceRequestSetting = BinaryAndJsonConformanceSuite::ConformanceRequestSetting;` names a class the suite inherits from `ConformanceTestSuite`. An alias was followed only to a class declared under exactly the name it spells, so constructions through it stopped at the alias. Its target is now looked up a segment at a time through each class's bases, as C++ does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
6df4827625
commit
754cc45ad7
@@ -438,6 +438,22 @@ function baseClassesOf(cls: string, context: ResolutionContext): string[] {
|
||||
return bases;
|
||||
}
|
||||
|
||||
/**
|
||||
* The qualified name of the class `names` spells, looked up from `scope`:
|
||||
* spelled out in a scope around it (classNamed), else a segment at a time as
|
||||
* a declared type is, so a class one of the named class's bases declares is
|
||||
* found. protobuf's conformance suites alias `using ConformanceRequestSetting =
|
||||
* BinaryAndJsonConformanceSuite::ConformanceRequestSetting;`, a class their
|
||||
* base `ConformanceTestSuite` declares.
|
||||
*/
|
||||
function classReached(names: readonly string[], scope: string, ref: UnresolvedRef, context: ResolutionContext): string | undefined {
|
||||
const spelled = classNamed(names, scopesWithin(scope), context);
|
||||
if (spelled) return spelled;
|
||||
// (The walk stops on a class only once every segment is taken.)
|
||||
const { found } = lookupSegments({ names: [...names], templated: names.map(() => false) }, scopesWithin(scope), ref, context);
|
||||
return found && typeof found === 'object' && 'cls' in found ? found.cls : undefined;
|
||||
}
|
||||
|
||||
/** The qualified name of the class `names` spells, looked up from `scopes`. */
|
||||
function classNamed(names: readonly string[], scopes: readonly string[], context: ResolutionContext): string | undefined {
|
||||
const spelled = names.join('::');
|
||||
@@ -521,9 +537,14 @@ export function cppAliasedTypeName(resolved: CppAliasedType): string {
|
||||
return [resolved.target[resolved.target.length - 1]!, ...resolved.rest].join('::');
|
||||
}
|
||||
|
||||
/** The qualified name of the project class a type resolved through aliases is, if it is one: `leveldb::SkipList::Iterator`. */
|
||||
export function cppAliasedClass(resolved: CppAliasedType, context: ResolutionContext): string | undefined {
|
||||
return classNamed([...resolved.target, ...resolved.rest], scopesWithin(resolved.scope), context);
|
||||
/**
|
||||
* The qualified name of the project class a type resolved through aliases is,
|
||||
* if it is one: `leveldb::SkipList::Iterator`. With the ref it is resolved
|
||||
* for, a class a base of the named class declares counts (classReached).
|
||||
*/
|
||||
export function cppAliasedClass(resolved: CppAliasedType, context: ResolutionContext, ref?: UnresolvedRef): string | undefined {
|
||||
const names = [...resolved.target, ...resolved.rest];
|
||||
return ref ? classReached(names, resolved.scope, ref, context) : classNamed(names, scopesWithin(resolved.scope), context);
|
||||
}
|
||||
|
||||
/** What a C++ type name names when it is looked up for a class (see cppClassNamed). */
|
||||
@@ -573,7 +594,7 @@ export function cppClassNamed(
|
||||
// The aliased type is written in the alias's own scope.
|
||||
const aliased = expand(text ? aliasedTypeIn(text, alias.name) : null, name.names.slice(next), name.templated.slice(next),
|
||||
parentScope(alias.qualifiedName), ref, context, 1, templateParametersAround(alias, context));
|
||||
const cls = aliased && !aliased.pointer && classNamed([...aliased.target, ...aliased.rest], scopesWithin(aliased.scope), context);
|
||||
const cls = aliased && !aliased.pointer && classReached([...aliased.target, ...aliased.rest], aliased.scope, ref, context);
|
||||
if (cls) return { cls };
|
||||
// A member of a type outside the project (`Alias::Inner`) is not the alias.
|
||||
return next === name.names.length ? { alias } : null;
|
||||
|
||||
@@ -11405,7 +11405,7 @@ function matchCppConstruction(ref: UnresolvedRef, context: ResolutionContext): R
|
||||
: { original: ref, targetNodeId: node.id, confidence: 0.7, resolvedBy: 'exact-match' };
|
||||
if (cppDeclaresLocalAlias(written, ref, context)) {
|
||||
const aliased = resolveCppAliasedType(written, ref, context);
|
||||
const named = aliased && !aliased.pointer ? cppAliasedClass(aliased, context) : undefined;
|
||||
const named = aliased && !aliased.pointer ? cppAliasedClass(aliased, context, ref) : undefined;
|
||||
const cls = named ? context.getNodesByQualifiedName(named).find((n) => CPP_CLASS_KINDS.has(n.kind)) : undefined;
|
||||
return cls ? made(cls) : null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user