fix(cpp): resolve callers for typed pointer method calls (#445)
Resolves typed member-pointer method calls like `m_cpAlg->Processing()` so `codegraph callers CDetect::Processing` returns the expected callers.
- Extract C/C++ `field_expression` member calls as receiver-qualified references, so `ptr->method()` is preserved as a receiver-aware reference.
- Surface out-of-line C++ method definitions (`int CDetect::Processing() {...}` in `.cpp` with class in `.hpp`) as proper method nodes with the correct qualified identity.
- C++ receiver-type inference: declarator regex requires a terminator after the receiver (rules out matching `return m_cpAlg->...`), handles `Type*x`/`Type *x`/`Type* x` uniformly, and rejects C++ keywords as a final guard.
- `resolveMethodOnType` matches by `Class::method` qualified-name suffix, so out-of-line definitions across files resolve (typical `.hpp`/`.cpp` split).
Validated on bitcoin-core (1306 .cpp files): 38,180 → 40,503 cpp method incoming-call edges (+6.1%), deterministic across re-indexes. Regression test added for the ambiguous-name + `return ptr->m()` / `Type x = ptr->m()` patterns.
Closes #445
Co-authored-by: chenyuxuan <458254969@qq.com>
Co-authored-by: Colby McHenry <me@colbymchenry.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
chenyuxuan
Colby McHenry
Claude Opus 4.7
parent
72c08c2bef
commit
c0cf9c1e7d
@@ -2,6 +2,51 @@ import type { Node as SyntaxNode } from 'web-tree-sitter';
|
||||
import { getChildByField, getNodeText } from '../tree-sitter-helpers';
|
||||
import type { LanguageExtractor } from '../tree-sitter-types';
|
||||
|
||||
function extractCppQualifiedMethodName(node: SyntaxNode, source: string): string | undefined {
|
||||
const declarator = getChildByField(node, 'declarator');
|
||||
if (!declarator) return undefined;
|
||||
|
||||
const queue: SyntaxNode[] = [declarator];
|
||||
while (queue.length > 0) {
|
||||
const current = queue.shift()!;
|
||||
if (current.type === 'qualified_identifier') {
|
||||
const text = getNodeText(current, source).trim();
|
||||
const parts = text.split('::').filter(Boolean);
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
for (let i = 0; i < current.namedChildCount; i++) {
|
||||
const child = current.namedChild(i);
|
||||
if (child) queue.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function extractCppReceiverType(node: SyntaxNode, source: string): string | undefined {
|
||||
const declarator = getChildByField(node, 'declarator');
|
||||
if (!declarator) return undefined;
|
||||
|
||||
const queue: SyntaxNode[] = [declarator];
|
||||
while (queue.length > 0) {
|
||||
const current = queue.shift()!;
|
||||
if (current.type === 'qualified_identifier') {
|
||||
const text = getNodeText(current, source).trim();
|
||||
const parts = text.split('::').filter(Boolean);
|
||||
if (parts.length > 1) {
|
||||
return parts.slice(0, -1).join('::');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
for (let i = 0; i < current.namedChildCount; i++) {
|
||||
const child = current.namedChild(i);
|
||||
if (child) queue.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export const cExtractor: LanguageExtractor = {
|
||||
functionTypes: ['function_definition'],
|
||||
classTypes: [],
|
||||
@@ -62,6 +107,8 @@ export const cppExtractor: LanguageExtractor = {
|
||||
nameField: 'declarator',
|
||||
bodyField: 'body',
|
||||
paramsField: 'parameters',
|
||||
resolveName: extractCppQualifiedMethodName,
|
||||
getReceiverType: extractCppReceiverType,
|
||||
getVisibility: (node) => {
|
||||
// Check for access specifier in parent
|
||||
const parent = node.parent;
|
||||
|
||||
Reference in New Issue
Block a user