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
+1 -1
View File
@@ -21,4 +21,4 @@
* turns the re-index hint into noise — keep it honest (see CLAUDE.md, "Honesty
* in the product is load-bearing").
*/
export const EXTRACTION_VERSION = 3;
export const EXTRACTION_VERSION = 4;
+11 -2
View File
@@ -1499,13 +1499,14 @@ export class TreeSitterExtractor {
for (const spec of specs) {
const nameNode = spec.namedChild(0);
let varNode: Node | null = null;
if (nameNode && nameNode.type === 'identifier') {
const name = getNodeText(nameNode, this.source);
const valueNode = spec.namedChildCount > 1 ? spec.namedChild(spec.namedChildCount - 1) : null;
const initValue = valueNode ? getNodeText(valueNode, this.source).slice(0, 100) : undefined;
const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
this.createNode(node.type === 'const_declaration' ? 'constant' : 'variable', name, spec, {
varNode = this.createNode(node.type === 'const_declaration' ? 'constant' : 'variable', name, spec, {
docstring,
signature: initSignature,
});
@@ -1515,8 +1516,16 @@ export class TreeSitterExtractor {
// implementations) or `var c = pkg.New()` are extracted as
// instantiates/calls dependencies — the body walker only covers
// initializers inside functions, not these top-level declarations.
// Scope the walk to the declared symbol so a call inside an anonymous
// func_literal initializer — a cobra `RunE: func(){…}` handler, a
// goroutine or callback closure — attributes to the var instead of
// leaking to the file node (which reads as "no caller"), issue #693.
const valueField = getChildByField(spec, 'value');
if (valueField) this.visitFunctionBody(valueField, '');
if (valueField) {
if (varNode) this.nodeStack.push(varNode.id);
this.visitFunctionBody(valueField, varNode?.id ?? '');
if (varNode) this.nodeStack.pop();
}
}
// Handle short_var_declaration (:=)