fix(go-parser): key generic-type methods on base type, not "unknown"#126
Open
gadievron wants to merge 2 commits into
Open
fix(go-parser): key generic-type methods on base type, not "unknown"#126gadievron wants to merge 2 commits into
gadievron wants to merge 2 commits into
Conversation
typeToString had no case for *ast.IndexExpr / *ast.IndexListExpr, so methods on generic types (func (s *Stack[T]) Push()) keyed under class "unknown". Distinct generic types' same-named methods then collided onto one unit id and the store silently overwrote one (data loss). Generic call sites (Gen[K,V](), obj.M[T]()) were likewise dropped from the call graph. - extractor.go: add IndexExpr/IndexListExpr cases to typeToString (bare base type) - callgraph.go: unwrap generic instantiation in analyzeCallExpr; reuse the Ident/SelectorExpr classification (fixes all generic call shapes + receiver) - extractor.go: add duplicateIDWarning() - stderr signal on funcID collision so a future class-key collapse fails loudly instead of silently overwriting Tests: 5 new (generic receiver keys, no-collision data-loss regression, generic calls, dup-guard). go test ./... green; independent + judge verified, no regression. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The binary is listed in .gitignore but was tracked since the initial commit, so it drifted stale on every source change (master's committed binary still emits "unknown.Push"). Untrack it so it stays ignored; CI builds it on every run (.github/workflows/test.yaml) and the dev pipeline rebuilds it when absent (parsers/go/test_pipeline.py). Compile on demand — no committed artifact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gadievron
added a commit
that referenced
this pull request
Jun 17, 2026
The binary is in .gitignore but was tracked since the initial commit, drifting stale on every source change. Untrack it so it stays ignored; CI builds it every run and the dev pipeline rebuilds when absent. Keeps the stack consistent with the same cleanup on the go-parser PRs (#109, #126) — compile on demand, no committed artifact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Go parser keys methods on generic types (
func (s *Stack[T]) Push(...),func (p *Pair[K,V]) Key(...)) under a bogus class nameunknowninstead of the real type, because the receiver-type stringifiertypeToStringhas no case for Go's generic-instantiation AST nodes (*ast.IndexExpr/*ast.IndexListExpr) and falls through todefault: return "unknown".Impact (all confirmed on this branch's base):
m.go:unknown.Pushinstead ofm.go:Stack.Push.Stack[T].Len,Queue[T].Len) collapse to one idm.go:unknown.Len; the store (output.Functions[id] = info) overwrites, so one real unit is dropped.Gen[K,V]()(*ast.IndexListExpr) and generic method callsobj.M[T]()were not recovered byanalyzeCallExpr.Generic types are idiomatic Go since 1.18, so this hits modern codebases broadly.
Changes
extractor.gotypeToString: addcase *ast.IndexExprandcase *ast.IndexListExpr, each recursing intot.Xso the class key is the bare base type (Stack,Pair).callgraph.goanalyzeCallExpr: unwrap a leadingIndexExpr/IndexListExprthen reuse the existingIdent/SelectorExprclassification — fixes all four generic call shapes and recovers the receiver for generic method calls.extractor.goduplicateIDWarning: emit anos.Stderrwarning when afuncIDcollides on store, so any future class-key collapse fails loudly instead of silently overwriting. JSON output shape unchanged.Tests
5 new Go tests: generic-receiver class keys (pointer/value/multi-param), the no-collision data-loss regression (
Stack.Len+Queue.Lenstay distinct), generic call recovery, and the dup-guard.go test ./...green;gofmt/go vetclean.Scope & related work (please read before requesting "why not Zig/PHP too?")
This PR is Go-only by design and is self-contained — it touches only
parsers/go/go_parser/and has no cross-parser dependency. The Go parser uses the standard-librarygo/ast, whose node types are stable, so this lands cleanly onmaster.The same class-key-collapse family also affects the Zig and PHP parsers. Those fixes are in a separate PR that depends on the parser-rewrite PRs #110 (Zig) and #111 (PHP) and so targets the
staging/parser-fix-stackintegration branch, notmaster. This Go PR is independent of all of that —go/astnode types are stable — so do not block it on them.Notes
[T]type arguments are intentionally dropped (we wantStack, notStack[T]); the receiver string is a display field, not used for resolution.funcs[i]()reports the container identifier as the call name; a parenthesized receiverfunc ((T)) M()still hitsdefault(now observable via the dup-guard).