Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Go: factory calls and GORM-style chains resolve to unrelated symbols

Open
#2,543 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
22/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
go, typescript
Domain
tooling

Research direction

Start by running the synthetic Go reproduction in the issue against a fresh index, then inspect codegraph callees Find output. The bare Query() call is resolved through the Go model-name heuristic in src/resolution/frameworks/go.ts, and the chained Where/First calls go through src/resolution/name-matcher.ts. Done means Find no longer gets edges to CardDo, and the Query() call points to mysql/conn.go.

Written by the indexing model from the issue text.

Description

On CodeGraph 1.6.2, a Go factory → field → fluent-method chain can produce incorrect graph edges after a fresh index. A same-package factory call resolves to an unrelated struct, and chained methods resolve to another query type's same-named methods.

The reproduction below is entirely synthetic. It models the shape of GORM-generated query code and requires no GORM dependency, database, credentials, or application code.

Environment: CodeGraph 1.6.2, release commit 6560052a6f856855d3f71eee838fd66ccfa4285d; Linux x86_64; bundled Node.js 24.16.0.

Run this with an unmodified CodeGraph 1.6.2 installation:

repro_dir="$(mktemp -d)"
mkdir -p "$repro_dir/query" "$repro_dir/mysql"

cat > "$repro_dir/go.mod" <<'EOF'
module example.com/app

go 1.22
EOF

cat > "$repro_dir/query/query.go" <<'EOF'
package query

type Query struct { Session Session }
EOF

cat > "$repro_dir/query/card.go" <<'EOF'
package query

type CardDo struct{}
func (c CardDo) Where(value int) CardDo { return c }
func (c CardDo) First() int { return 1 }
EOF

cat > "$repro_dir/query/session.go" <<'EOF'
package query

type Session struct{}
type SessionDo struct{}
func (s Session) WithContext(ctx int) SessionDo { return SessionDo{} }
func (s SessionDo) Where(value int) SessionDo { return s }
func (s SessionDo) First() int { return 2 }
EOF

cat > "$repro_dir/mysql/conn.go" <<'EOF'
package mysql

import "example.com/app/query"

func Query() *query.Query { return &query.Query{} }
EOF

cat > "$repro_dir/mysql/session.go" <<'EOF'
package mysql

func Find() int {
    model := Query().Session
    return model.WithContext(0).
        Where(1).
        First()
}
EOF

codegraph init --yes "$repro_dir"
codegraph callees Find --file mysql/session.go --json --path "$repro_dir"

The relevant outgoing edges for Find, normalized from the resulting graph, are:

calls         CardDo::First       query/card.go
calls         CardDo::Where       query/card.go
instantiates  Query               query/query.go
calls         Session::WithContext query/session.go

Find calls the function mysql.Query() from mysql/conn.go, then operates on Query().Session. It never uses CardDo. The factory call should point to mysql/conn.go; Where and First should point to SessionDo if their receiver can be resolved. When the receiver cannot be established, leaving those method references unresolved is preferable to creating edges to CardDo.

These false edges affect callers, callees, impact analysis, and the relationships shown by codegraph_explore.

I traced the reproduction to two resolution paths in v1.6.2:

  1. The Go model-name heuristic in src/resolution/frameworks/go.ts can nominate an out-of-package struct for a bare call such as Query(). That heuristic can win against the real same-package function, after which the edge becomes instantiates. The Service/Store/Repository naming patterns have the same failure mode.
  2. Later links in the Go fluent chain reach name matching without their receiver type. src/resolution/name-matcher.ts then picks one of several same-named methods using proximity, producing the unrelated CardDo edges.

A conservative local candidate fix addresses these paths:

  • Restrict the type candidates offered by the Go framework heuristic for bare calls to the caller's package, preserving legitimate same-package type conversions.
  • Require receiver evidence from the current call expression before treating a bare extracted name as a collapsed fluent call, and decline ambiguous method-name matches. The check must handle long multiline arguments, comments, and Go raw strings without borrowing a receiver from a later expression.

Validation of the local candidate: 438 tests passed across 11 related suites, including 13 regression cases. The dedicated cases also passed with both the native kernel and WASM fallback. They cover the factory/type collision, single-line and long multiline chains, known typed receivers, same-package conversions (including parentheses, pointers, and comments), later same-name expressions, and raw-string arguments. The candidate removes the false method edges and restores the factory edge; it does not implement complete GORM receiver-type inference.

Related reports: #1276 and #750. This reproduction covers the factory → struct field → fluent chain shape on v1.6.2.

Dominant language
C
Stars
73.2k
Forks
4.7k
Avg merge
2h 16m
Merged PRs (30d)
423

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from colbymchenry/codegraph

All issues in colbymchenry/codegraph

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.