fix(extraction): correct C++ reference-return and conversion-operator method names (#1096)
* fix(extraction): correct C++ reference-return and conversion-operator method names Two pre-existing C++ name-extraction bugs surfaced while validating the #1093 forward-declaration fix against real Unreal Engine repos (ActionRoguelike, ALS): 1. Inline methods/functions returning a reference were named after the whole declarator. `const int& getRef() const {…}` parses with a reference_declarator wrapping the function_declarator; extractName unwrapped pointer_declarator but not reference_declarator, so the method was named "& getRef() const" instead of "getRef" — polluting search and breaking caller linkage. Ubiquitous in UE headers (`const FGameplayTagContainer& GetActiveTags() const`). Now the reference wrapper is unwrapped alongside the pointer wrapper. 2. User-defined conversion operators were named with their full declarator — `operator EALSMovementState() const` — instead of `operator EALSMovementState`, so they didn't match the symbolic-overload style (`operator+`) and carried `() const` noise. The operator_cast declarator is now named `operator <type>`. Both are additive and C++-scoped (reference_declarator / operator_cast are C++ grammar nodes). Pointer, value, and out-of-line reference returns, and symbolic operator overloads, are unchanged. Six regression tests added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(changelog): note C++ reference-return and conversion-operator name fixes (#1096) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- 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
f856f7ae49
commit
712a406726
@@ -69,13 +69,29 @@ function extractName(node: SyntaxNode, source: string, extractor: LanguageExtrac
|
||||
// Try field name first
|
||||
const nameNode = getChildByField(node, extractor.nameField);
|
||||
if (nameNode) {
|
||||
// Unwrap pointer_declarator(s) for C/C++ pointer return types
|
||||
// Unwrap pointer_declarator / reference_declarator for C/C++ pointer and
|
||||
// reference return types (`int* f()`, `int& f()`, `int&& f()`). Without
|
||||
// unwrapping the reference wrapper an inline reference-returning method is
|
||||
// named "& f() const" instead of "f" — common in Unreal Engine gameplay
|
||||
// headers (`const FGameplayTagContainer& GetActiveTags() const`). Out-of-line
|
||||
// defs (`T& C::f()`) already resolve via the qualified-name hook. A
|
||||
// pointer_declarator exposes its inner through a `declarator` field; a
|
||||
// reference_declarator has none, so it's reached via namedChild(0).
|
||||
let resolved = nameNode;
|
||||
while (resolved.type === 'pointer_declarator') {
|
||||
while (resolved.type === 'pointer_declarator' || resolved.type === 'reference_declarator') {
|
||||
const inner = getChildByField(resolved, 'declarator') || resolved.namedChild(0);
|
||||
if (!inner) break;
|
||||
resolved = inner;
|
||||
}
|
||||
// C++ user-defined conversion operator: the declarator is an `operator_cast`
|
||||
// whose first child is the target type and second is the `() const` tail. Name
|
||||
// it `operator <type>` (the conventional spelling) rather than the whole
|
||||
// `operator EALSMovementState() const` declarator, so it matches symbolic
|
||||
// overloads (`operator+`) and is findable by the type name.
|
||||
if (resolved.type === 'operator_cast') {
|
||||
const typeNode = resolved.namedChild(0);
|
||||
return typeNode ? `operator ${getNodeText(typeNode, source).trim()}` : getNodeText(resolved, source);
|
||||
}
|
||||
// Handle complex declarators (C/C++)
|
||||
if (resolved.type === 'function_declarator' || resolved.type === 'declarator') {
|
||||
const innerName = getChildByField(resolved, 'declarator') || resolved.namedChild(0);
|
||||
|
||||
Reference in New Issue
Block a user