Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3892e7d
chore: gitignore napi-generated artifacts in crates/codegraph-core
carlos-alm Jun 13, 2026
ef8ea4f
chore(tests): remove unused biome suppression in visitor.test.ts
carlos-alm Jun 13, 2026
a372b82
fix(titan-run): sync --start-from enum and phase-timestamp list with …
carlos-alm Jun 13, 2026
9a52c7c
fix(hooks): track Bash file modifications via before/after git status…
carlos-alm Jun 13, 2026
85a26df
chore(native): remove dead code (unused var, method, variant, fields)
carlos-alm Jun 13, 2026
184d221
refactor(native): extract emit_pts_alias_edges params into PtsAliasCt…
carlos-alm Jun 13, 2026
909e1df
fix(wasm): sort call targets by confidence before emit to match nativ…
carlos-alm Jun 13, 2026
66fc899
fix(bench): add 2 warmup runs and raise INCREMENTAL_RUNS to 5 for inc…
carlos-alm Jun 13, 2026
84e1a5f
ci(bench): add per-PR perf canary for extractor/graph/native changes
carlos-alm Jun 13, 2026
d07b358
fix(perf): plumb symbolsOnly through parseFilesWasmInline to skip ana…
carlos-alm Jun 13, 2026
3db5d8c
fix(perf): scope runPostNativeCha to changed files on incremental builds
carlos-alm Jun 13, 2026
8b3aa3d
fix(native): add post-pass phase timings to result.phases
carlos-alm Jun 13, 2026
fd4ffd1
fix(perf): correct INLINE_BACKFILL_THRESHOLD docstring; raise thresho…
carlos-alm Jun 13, 2026
498ee21
fix(perf): guard post-native passes against unnecessary work on 1-fil…
carlos-alm Jun 13, 2026
61a9839
chore(types): remove dead protoMethodsMs field and stale comment
carlos-alm Jun 13, 2026
5f5d4d2
fix: class-scope field annotation typeMap keys to prevent cross-class…
carlos-alm Jun 13, 2026
29dd101
fix(bench): update elixir/julia/objc expected-edges to module-qualifi…
carlos-alm Jun 13, 2026
9320ed2
fix(wasm): emit receiver edges for declaration-typed locals in C++/CUDA
carlos-alm Jun 13, 2026
2986c81
fix(lint): remove unused TypeMapEntry imports; expand primitive-type …
carlos-alm Jun 13, 2026
d3d83ef
docs(cpp,cuda): document pointer/reference declarator scope in handle…
carlos-alm Jun 13, 2026
ba7f506
fix(lint): expand inline toEqual objects to multi-line format for Biome
carlos-alm Jun 13, 2026
050d071
fix: resolve merge conflicts with main
carlos-alm Jun 14, 2026
2304344
fix: remove duplicate PostPassTimings interfaces from auto-merge trip…
carlos-alm Jun 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/domain/graph/builder/stages/native-orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,14 +959,6 @@ interface PostPassTimings {
techniqueBackfillMs: number;
}

interface PostPassTimings {
gapDetectMs: number;
chaMs: number;
thisDispatchMs: number;
reclassifyMs: number;
techniqueBackfillMs: number;
}

/** Format timing result from native orchestrator phases + JS post-processing. */
function formatNativeTimingResult(
p: Record<string, number>,
Expand Down
74 changes: 74 additions & 0 deletions src/extractors/cpp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ function walkCppNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
case 'call_expression':
handleCppCallExpression(node, ctx);
break;
case 'declaration':
handleCppDeclaration(node, ctx);
break;
}

for (let i = 0; i < node.childCount; i++) {
Expand Down Expand Up @@ -204,6 +207,40 @@ function handleCppInclude(node: TreeSitterNode, ctx: ExtractorOutput): void {
});
}

/**
* Seed typeMap for declaration-typed locals: `UserService svc;` and
* `UserService svc = makeService();` both yield typeMap["svc"] = "UserService"
* at confidence 0.9. Mirrors `match_c_family_type_map` ("declaration" branch)
* in the native Rust C++ extractor.
*/
function handleCppDeclaration(node: TreeSitterNode, ctx: ExtractorOutput): void {
const typeNode = node.childForFieldName('type');
if (!typeNode) return;
const typeName = typeNode.text;
// Skip primitive types — they are never class/struct receivers
if (isPrimitiveCppType(typeName)) return;
for (let i = 0; i < node.childCount; i++) {
const child = node.child(i);
if (!child) continue;
const kind = child.type;
let nameNode: TreeSitterNode | null = null;
if (kind === 'init_declarator') {
nameNode = child.childForFieldName('declarator') ?? null;
} else if (kind === 'identifier') {
nameNode = child;
}
Comment on lines +227 to +231

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Pointer/reference declarators silently skipped

The handler only seeds typeMap for direct identifier children and init_declarator children. For UserService *svc; or UserService &svc = ...;, the declarator field of the declaration node is a pointer_declarator / reference_declarator, not a bare identifier — so those variables never get a typeMap entry and svc->method() calls won't generate receiver edges. This may intentionally mirror the Rust match_c_family_type_map limitation; if so, a comment noting the gap would be helpful. The same applies in src/extractors/cuda.ts.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added a clarifying comment in both handleCppDeclaration and handleCudaDeclaration (commit d3d83ef) documenting that this is intentional: the native Rust match_c_family_type_map helper in crates/codegraph-core/src/extractors/helpers.rs also only iterates init_declarator and identifier children of a declaration node — pointer_declarator/reference_declarator children are skipped on both sides. Both engines have identical scope here, so this is not a parity gap.

// Note: pointer_declarator / reference_declarator children (e.g. `UserService *svc;`)
// are intentionally skipped here — they are also skipped by the native Rust
// match_c_family_type_map helper, which only handles 'init_declarator' and
// 'identifier' children. Both engines have the same scope for this case.
if (!nameNode) continue;
const varName = unwrapCppDeclaratorName(nameNode);
if (varName) {
ctx.typeMap.set(varName, { type: typeName, confidence: 0.9 });
}
}
}

function handleCppCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
const funcNode = node.childForFieldName('function');
if (!funcNode) return;
Expand Down Expand Up @@ -324,6 +361,43 @@ function extractCppClassFields(classNode: TreeSitterNode): SubDeclaration[] {
return fields;
}

/**
* Primitive C/C++ types that are never class/struct receivers. Seeding these
* into typeMap would cause spurious receiver edges (e.g. `int x` → `int`).
*/
const CPP_PRIMITIVE_TYPES = new Set([
'int',
'long',
'short',
'unsigned',
'signed',
'float',
'double',
'char',
'bool',
'void',
'wchar_t',
'auto',
'size_t',
'uint8_t',
'uint16_t',
'uint32_t',
'uint64_t',
'int8_t',
'int16_t',
'int32_t',
'int64_t',
'ptrdiff_t',
'intptr_t',
'uintptr_t',
]);

function isPrimitiveCppType(typeName: string): boolean {
// Strip qualifiers like `const`, `volatile`, `unsigned` etc.
const base = typeName.split(/\s+/).pop() ?? typeName;
return CPP_PRIMITIVE_TYPES.has(base) || CPP_PRIMITIVE_TYPES.has(typeName);
}

function extractCppEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
const entries: SubDeclaration[] = [];
const body = findChild(enumNode, 'enumerator_list');
Expand Down
73 changes: 73 additions & 0 deletions src/extractors/cuda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ function walkCudaNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
case 'call_expression':
handleCudaCallExpression(node, ctx);
break;
case 'declaration':
handleCudaDeclaration(node, ctx);
break;
}

for (let i = 0; i < node.childCount; i++) {
Expand Down Expand Up @@ -204,6 +207,40 @@ function handleCudaInclude(node: TreeSitterNode, ctx: ExtractorOutput): void {
});
}

/**
* Seed typeMap for declaration-typed locals: `UserService svc;` and
* `UserService svc = make();` both yield typeMap["svc"] = "UserService"
* at confidence 0.9. Mirrors `match_c_family_type_map` ("declaration" branch)
* in the native Rust CUDA extractor.
*/
function handleCudaDeclaration(node: TreeSitterNode, ctx: ExtractorOutput): void {
const typeNode = node.childForFieldName('type');
if (!typeNode) return;
const typeName = typeNode.text;
// Skip primitive types — they are never class/struct receivers
if (isCudaPrimitiveType(typeName)) return;
for (let i = 0; i < node.childCount; i++) {
const child = node.child(i);
if (!child) continue;
const kind = child.type;
let nameNode: TreeSitterNode | null = null;
if (kind === 'init_declarator') {
nameNode = child.childForFieldName('declarator') ?? null;
} else if (kind === 'identifier') {
nameNode = child;
}
// Note: pointer_declarator / reference_declarator children (e.g. `UserService *svc;`)
// are intentionally skipped here — they are also skipped by the native Rust
// match_c_family_type_map helper, which only handles 'init_declarator' and
// 'identifier' children. Both engines have the same scope for this case.
if (!nameNode) continue;
const varName = extractCudaFieldName(nameNode);
if (varName) {
ctx.typeMap.set(varName, { type: typeName, confidence: 0.9 });
}
}
}

function handleCudaCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
const funcNode = node.childForFieldName('function');
if (!funcNode) return;
Expand Down Expand Up @@ -374,6 +411,42 @@ function innerCudaDeclarator(node: TreeSitterNode): TreeSitterNode | null {
return null;
}

/**
* Primitive C/C++/CUDA types that are never class/struct receivers. Seeding
* these into typeMap would produce spurious receiver edges (e.g. `int x` → `int`).
*/
const CUDA_PRIMITIVE_TYPES = new Set([
'int',
'long',
'short',
'unsigned',
'signed',
'float',
'double',
'char',
'bool',
'void',
'wchar_t',
'auto',
'size_t',
'uint8_t',
'uint16_t',
'uint32_t',
'uint64_t',
'int8_t',
'int16_t',
'int32_t',
'int64_t',
'ptrdiff_t',
'intptr_t',
'uintptr_t',
]);

function isCudaPrimitiveType(typeName: string): boolean {
const base = typeName.split(/\s+/).pop() ?? typeName;
return CUDA_PRIMITIVE_TYPES.has(base) || CUDA_PRIMITIVE_TYPES.has(typeName);
}

function extractCudaEnumEntries(enumNode: TreeSitterNode): SubDeclaration[] {
const entries: SubDeclaration[] = [];
const body = findChild(enumNode, 'enumerator_list');
Expand Down
Loading