You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Go: a call to a local function parameter is bound to a same-named method in a package the file does not import (false caller edge) #1857
Go: a call to a local function parameter is bound to a same-named method in a package the file does not import
Version: 1.6.0 (npm @colbymchenry/codegraph), Linux x64, node 24.18.0. Go repo, 239 files / 5,936 nodes / 20,845 edges.
Checked against main at 2026-09-14: the local-binding guards added for #1735/#1759/#1760 are JS/TS-only (isLocallyBoundJsName), and #1496 / #1545 are receiver-based collisions in TS/PHP, so this Go shape appears unfiled.
$ codegraph callers relogin
Callers of "relogin" (2):
function RunReloginScheduler internal/synapse/scheduler.go:36
method run internal/impulse/socketloop.go:297
The second edge is real. The first cannot exist. relogin is a method on *socketLoop in package impulse (internal/impulse/relogin.go:24); internal/synapse/scheduler.go imports only context, log/slog, time, calendar, clock, push — not impulse. Its relogin is a function parameter:
A call to a local parameter was bound to a same-named method in a package not in scope. Two independent agents reported the edge as real before it was checked by hand — a false edge reads as confirmation, so it is more damaging than a missing one.
Positive controls (unique names, same repo): callers parseIndexEntry → 2/2 matching grep; callers releaseRenewInFlight → 1/1, correctly attributed to the enclosing method.
Suggested fix: for Go, do not resolve a callee name that is bound by a parameter or local declaration in the enclosing function, and require an import path or same-package scope before binding a call site across packages.
Thanks for the detailed report. I checked this against current main.
The exact shape in this issue is already fixed on main, but not released yet.#1745 (2c251e2, merged 09-08) added Go's first-letter visibility rule to candidate matching. So an unexported method like impulse.(*socketLoop).relogin can no longer be matched by a call in package synapse. With a minimal repro (a func(context.Context) error parameter named like an unexported method in a package that isn't imported), v1.6.0 reports the false caller and a main build doesn't. It should ship in the next release after v1.6.0.
Two similar shapes still reproduce on main, and both come down to the same root cause: a Go bare call name(...) can still be bound to a method.
Same package: the parameter or local shares its name with a method declared in the same package, so the visibility rule doesn't filter it out.
Exported name across packages: the parameter is named like an exported method (Relogin) in a package the file doesn't import.
In both cases the callee has no receiver, so it can't be that method. This is the Go version of what #1714 handled for JS. The fix needs care, though: Go chains like pkg.Factory().Method() can reach the resolver as a bare Method ref (see #1640). So the check has to confirm from the source that there's no receiver, not just go by the ref's shape.
Thanks for the detailed report, @PCeltide, and thanks for using CodeGraph! This is fixed on main by #1999, which builds on @maxmilian's #1893 (thank you!): a receiver-less Go call such as relogin(ctx) (a function parameter or local func value) no longer links to a same-named method, in the same package or an unimported one; real method calls and pkg.Factory().Method() chains keep their edges. The fix will be in the next release.
Activity
maxmilian commentedon Sep 17, 2026
Thanks for the detailed report. I checked this against current
main.The exact shape in this issue is already fixed on
main, but not released yet. #1745 (2c251e2, merged 09-08) added Go's first-letter visibility rule to candidate matching. So an unexported method likeimpulse.(*socketLoop).relogincan no longer be matched by a call in packagesynapse. With a minimal repro (afunc(context.Context) errorparameter named like an unexported method in a package that isn't imported), v1.6.0 reports the false caller and amainbuild doesn't. It should ship in the next release after v1.6.0.Two similar shapes still reproduce on
main, and both come down to the same root cause: a Go bare callname(...)can still be bound to a method.Relogin) in a package the file doesn't import.In both cases the callee has no receiver, so it can't be that method. This is the Go version of what #1714 handled for JS. The fix needs care, though: Go chains like
pkg.Factory().Method()can reach the resolver as a bareMethodref (see #1640). So the check has to confirm from the source that there's no receiver, not just go by the ref's shape.Fix for both shapes: #1893.
fix(resolution): a receiver-less Go call never binds to a method (#1857…
colbymchenry commentedon Sep 27, 2026
Thanks for the detailed report, @PCeltide, and thanks for using CodeGraph! This is fixed on
mainby #1999, which builds on @maxmilian's #1893 (thank you!): a receiver-less Go call such asrelogin(ctx)(a function parameter or local func value) no longer links to a same-named method, in the same package or an unimported one; real method calls andpkg.Factory().Method()chains keep their edges. The fix will be in the next release.Merge upstream/main (71 commits, through e63fe2e) into fork/consolidated
fix(kernel): a receiver-less Go call never binds to a method (colbymc…
perf(resolution): cheaper sealed-module and receiver-less call checks
perf(resolution): remove the indexing regressions since v1.6.0 (vscod…
fix(resolution): JS/TS calls never pick a class member by name alone …