Skip to content

Go: weak short-name strategies fabricate CALLS edges for selector calls (stdlib receivers hijack project symbols) #1906

Description

@ilyabrykau-orca

Status: fix open — PR #1907 (extractor is_method flag for Go selector calls + Go-gated cbm_go_suppress_weak_method_match). Full post-fix census inline below.

Version

codebase-memory-mcp 0.10.8 (also reproduced on a source build @ d706c33)

Platform

macOS (Apple Silicon)

Install channel

Built from source

Binary variant

standard

What happened, and what did you expect?

A Go selector call whose receiver the Go LSP cannot type falls through to the generic registry, which binds it by bare short name to an arbitrary same-named project symbol (suffix_match / unique_name). Stdlib/third-party calls are the worst case: the real callee is not in the tree, so every candidate is wrong by construction. Go never sets is_method, so the receiver-aware guard TS/JS got in #592/#606 (and Perl in #476) never fires.

Measured (private Go monorepo, ~19.6k CALLS): suffix_match 3817 @ avg 0.30, unique_name 3162 @ avg 0.53 — 36% of all CALLS from name guesses. One 14-line checksum helper touching only os/io/crypto/sha256 got 3/3 false outbound edges: f.Close() → a project Close (conf 0.11, 15 candidates), sha256.New() → an unrelated New, io.Copy → the sole project Copy (unique_name 0.375). trace_path surfaces all of it unfiltered, so Close/New/Run accumulate dozens of phantom callers.

Expected: no CALLS edge for a call the resolver cannot place; typed, local, and import-qualified calls keep resolving.

Reproduction

Dummy fixture: go.mod (module example.com/myapp) + storage/storage.go (the lone project Close method + a typed same-package Boot caller) + hash/hash.go:

package hash

import (
	"os"

	"example.com/myapp/util"
)

func FileLen(path string) int64 {
	f, err := os.Open(path)
	if err != nil {
		return 0
	}
	defer f.Close() // ← false CALLS edge: hash.FileLen -> storage.Close
	st, err := f.Stat()
	if err != nil {
		return 0
	}
	return st.Size()
}

func UsesUtil() string { return util.Tag() } // import-qualified: must keep resolving

Actual: FileLen | Close | {"strategy":"unique_name","confidence":0.75,…} (with ≥2 candidates: suffix_match @ 0.1–0.4). Expected: no FileLen → Close; Boot → Close, bare local calls, and UsesUtil → Tag all survive.

Two Go-specific constraints (why the TS/JS drop-list can't be reused as-is)

Post-fix strategy census (same tree indexed with v0.10.8 vs Stack A = #1907+#1913+#1915)

strategy v0.10.8 with the fixes Δ
lsp_strategy_cross_file 5273 6468 +23%
lsp_direct 3033 3372 +11%
lsp_type_dispatch 137 687 +401%
lsp_interface_dispatch 17 79 +365%
lsp_embed_dispatch 42 new
import_map 284 88 −69%
field_type_hint 493 1484 +201% — see #1927/#1936
unique_name 3162 (avg 0.53) 1573 (avg 0.68) −50%
suffix_match 3817 (avg 0.30) 113 −97%
same_module 3267 224 −93%
CALLS total 19653 14316 −27%

Weak short-name share (suffix_match+unique_name+callee_suffix): 36.0% → 12.4%, with lsp_* rising 8481 → 10672 in absolute terms — the edges were re-resolved, not merely deleted. The field_type_hint growth is the direct consequence tracked as #1927 (guesses moved from a visibly-weak 0.30 bucket into a 0.85 one); fixed by #1936.

Related: #592/#606 (TS/JS), #476 (Perl), #1893 (Swift), #1276 (Python), #1114; tracked in #1932.

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    parsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions