fix(go): a package-level var or const named in uppercase is exported (#3043)

Both extractors created a Go var/const node from its var_spec or
const_spec without exportedness: the TS Go branch passed no isExported
(the declaration-level value is read off the var_declaration, which has
no name), and the kernel's extract_variable set none. Every such node was
unexported, so findGoPackageMember, which looks up pkg.Name among the
package's exported declarations, skipped it: a call through
`var Hook = func...` from another package linked to nothing, though the
same call inside the package linked to the variable.

Both engines now mark the node exported by its own name's case, read
from the spec through goExtractor.isExported / is_exported, as
functions, methods and types already were.

Validation:
- __tests__/go-package-value-exported.test.ts, 16 tests (extraction on
  the kernel and wasm, LF and CRLF; cross-package calls on both paths):
  12 fail on the base main, 6 with only the TS half (the kernel
  checks), all pass with the fix.
- A/B, main vs fix, kernel path: gin 108 var/const flags, 0 edges;
  prometheus 625 flags, 0 edges; etcd 806 flags and 12 new calls,
  all right (e2e.GetVersionFromBinary x11 and
  model.NonDeterministicModel, both `var X = func(...)`); flask and
  express byte-identical. The fix's kernel and wasm graphs are
  byte-identical on all three Go repos, and the wasm A/B matches.
- kernel-parity --lang go: gin 99/99, prometheus 755/755, etcd
  1065/1105 with 40 deferred on main too; 0 diffs.
- etcd index time, median of 3 interleaved: 13.4 s main, 12.6 s fix.

Reimplements PR #1521 by ericquan8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-30 06:01:18 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent c12a7b6a74
commit 37052b1825
5 changed files with 227 additions and 4 deletions
+6 -2
View File
@@ -341,7 +341,8 @@ impl<'t> Walker<'t> {
Some(sig)
}
/// goExtractor.isExported: uppercase first letter of the name field.
/// goExtractor.isExported: uppercase first letter of the name field (a
/// var_spec / const_spec's first name included).
fn is_exported(&self, node: Node) -> bool {
if let Some(name_node) = node.child_by_field_name("name") {
let text = self.text(name_node);
@@ -722,11 +723,14 @@ impl<'t> Walker<'t> {
// own doc comment beside it in the parentheses; one without
// keeps the group's.
let doc = self.docstring_of(spec).or_else(|| docstring.clone());
// Exported by its own name's case, read from the spec (the
// declaration around it has no name).
let is_exported = Some(self.is_exported(spec));
var_row = self.create_node(
if is_const_decl { "constant" } else { "variable" },
&name,
spec,
Extra { docstring: doc, signature, ..Extra::default() },
Extra { docstring: doc, signature, is_exported, ..Extra::default() },
);
}
}