fix(go): attribute calls inside top-level closures to the var, not the file (#693) (#744)

A function called only from an anonymous func_literal at package level — a
cobra `RunE: func(){…}` handler, a goroutine literal, a callback closure
stored in a `var` — had its call leak to the FILE node, because the Go
var-initializer walk ran with an empty scope. So `callers`/`impact` showed
the function with a file (or no meaningful) caller, unlike JS/TS where an
arrow-in-const becomes a named node whose calls attribute correctly.

Scope the Go top-level var/const initializer walk to the declared symbol, so
a call nested in any func_literal initializer (struct field, slice/map,
nested closure) attributes to the enclosing var. EXTRACTION_VERSION 3->4
(re-index to pick up the corrected attribution).

Validated on cli/cli (858 Go files): node/edge counts identical, file-level
dependents byte-identical (no regression), and 62 top-level-closure calls
correctly moved from file-attributed to var-attributed.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-06-08 22:05:53 -04:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 35b44e242c
commit 5b3f5e36db
4 changed files with 41 additions and 3 deletions
+28
View File
@@ -6438,6 +6438,34 @@ describe('Go cross-package composite literals (blast-radius recall)', () => {
}
});
it('attributes a call inside a top-level closure (cobra RunE) to the var, not the file (#693)', async () => {
const dir = createTempDir();
try {
fs.writeFileSync(path.join(dir, 'go.mod'), 'module example.com/proj\n\ngo 1.21\n');
// Wire is called ONLY from the anonymous RunE closure inside a top-level
// `var rootCmd = &Cmd{...}` — previously the call leaked to the file node,
// so `callers(Wire)` surfaced a file (or read as "no caller"). It must now
// attribute to the enclosing var.
fs.writeFileSync(path.join(dir, 'factory.go'), `package main\n\nfunc Wire() error { return nil }\n`);
fs.writeFileSync(
path.join(dir, 'root.go'),
`package main\n\ntype Cmd struct{ RunE func() error }\n\nvar rootCmd = &Cmd{\n\tRunE: func() error { return Wire() },\n}\n`
);
const cg = CodeGraph.initSync(dir, { config: { include: ['**/*.go'], exclude: [] } });
await cg.indexAll();
cg.resolveReferences();
const wire = cg.getNodesByName('Wire').find((n) => n.kind === 'function');
expect(wire).toBeDefined();
const callers = cg.getCallers(wire!.id).map((c) => c.node);
expect(callers.some((n) => n.kind === 'variable' && n.name === 'rootCmd')).toBe(true);
expect(callers.some((n) => n.kind === 'file')).toBe(false);
cg.destroy();
} finally {
cleanupTempDir(dir);
}
});
it('links a parenthesized pointer type conversion `(*T)(x)` to the type', async () => {
const dir = createTempDir();
try {