Documentation
¶
Overview ¶
Package golang is the Go-language parser for CKG. It uses go/parser + go/types via golang.org/x/tools/go/packages to extract declarations and resolved cross-file references (spec §4.6.1).
Index ¶
- func EmitFieldWriteEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge
- func EmitImplementsEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge
- func EmitInstantiatesEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge
- func EmitPromotedMethods(pkgs []*packages.Package, nodes []types.Node) ([]types.Node, []types.Edge)
- func EmitUsesTypeEdges(pkgs []*packages.Package, nodes []types.Node) ([]types.Edge, []parse.PendingRef)
- func LoadAndResolve(root string) (*parse.ResolvedGraph, error)
- func MakeID(qname, lang string, startByte int) string
- type Parser
- func (p *Parser) Extensions() []string
- func (p *Parser) FuncFieldTouches() map[string]map[string]struct{}
- func (p *Parser) ParseFile(path string, src []byte) (*parse.ParseResult, error)
- func (p *Parser) Pkgs() []*packages.Package
- func (p *Parser) Resolve(results []*parse.ParseResult) (*parse.ResolvedGraph, error)
- func (p *Parser) SetPackages(pkgs []*packages.Package)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EmitFieldWriteEdges ¶
field_access.go (defect E): emits `writes_field` edges from a Function/Method to a struct Field node when the function body assigns to that field — `x.F = v`, `x.F op= v`, or `x.F++` / `x.F--`.
Why a post-Resolve pass (like uses_type / instantiates): the writer and the field declaration frequently live in different files or packages (e.g. core.applyTransaction writes core/types.Receipt.EffectiveGasPrice), so the edge can only be resolved against the union of package scopes + the union of emitted Field nodes. go/types' Selections map classifies each selector as a field access and yields the field's owning type, which we map to the Field node's qname "pkgleaf.Type.Field".
Scope (V0): WRITES only. reads_field is intentionally not emitted — a read edge per `x.F` use would explode the edge count for little marginal value; "who mutates this field" is the high-signal half (it answers the data-flow "which writers feed field X" question). Promoted-field writes resolve to the embedding type's qname (from Selection.Recv()) which has no Field node, so they are skipped rather than mis-attributed.
Returns nil when pkgs is empty.
func EmitImplementsEdges ¶
EmitImplementsEdges scans every loaded package's top-level type names, partitions them into interfaces vs concrete types, and emits implements edges (concrete → interface) for every satisfaction pair, plus extends edges (interface → interface) for every embedded interface relationship.
Receiver shape: types.Implements is checked on BOTH the named type T and the pointer type *T so both value-receiver and pointer-receiver method sets count toward satisfaction (the standard Go semantics).
Self-edges and "every type implements interface{}" noise are excluded. Cross-package satisfaction works naturally because pkg.Types.Scope() exposes the full package public surface; the emitted edge IDs come from a qname → ID map built over the supplied nodes (the union of all per-file Struct/Interface/TypeAlias/Enum nodes), so satisfaction across files in different packages still resolves correctly.
Returns an empty slice (never nil) when pkgs is empty or the loaded packages contain no Types information — callers can append unconditionally.
func EmitInstantiatesEdges ¶
EmitInstantiatesEdges scans every loaded package's function bodies for composite literals and new() calls, emitting instantiates edges from the enclosing Function/Method to the named target type.
func EmitPromotedMethods ¶
promoted.go (defect C): materialises Go *promoted* methods as method nodes.
When a struct T embeds a type E, T's method set includes E's methods (Go method promotion). The per-file parser only emits a node for the method where it is DECLARED (E.M), so a lookup of the promoted qname (T.M) — the form an agent naturally tries for `t.M()` — returns nothing.
EmitPromotedMethods runs as a post-resolve pass (like EmitImplementsEdges): it has the loaded packages (go/types method sets, which already account for promotion, multi-level embedding, and overrides) plus the union of emitted nodes. For every in-module struct it emits a method node under the embedding type's qname pointing at the declaring method's source position, plus a `defines` edge from the embedding type — so find_symbol("T.M") resolves and get_subgraph(T) shows the promoted method.
Bounding: a promoted method is emitted only when the DECLARING method already has a node in the graph (i.e. it is in-module). Methods promoted from stdlib / external embeds (e.g. sync.Mutex.Lock) have no node, so they are skipped — this keeps the graph from ballooning with third-party methods.
Returns empty slices (never nil) so callers can append unconditionally.
func EmitUsesTypeEdges ¶
func EmitUsesTypeEdges(pkgs []*packages.Package, nodes []types.Node) ([]types.Edge, []parse.PendingRef)
EmitUsesTypeEdges scans every loaded package's top-level declarations and emits `uses_type` edges from Function/Method/Struct nodes to the named types they reference (params, results, fields).
Returns:
- edges: the resolved uses_type edges
- pending: cross-package PendingRefs for types not present in the node index (q4=A — pending_refs row so the next partial build replays the same input set).
Idempotent — safe to call multiple times against the same nodes/pkgs.
func LoadAndResolve ¶
func LoadAndResolve(root string) (*parse.ResolvedGraph, error)
LoadAndResolve is a convenience for tests: walks Go files under root, runs Pass 1 on each, then Pass 2 across the union.
Type-aware: registers the loaded packages with the parser via SetPackages so the concurrency pass (B1) gets EXTRACTED-confidence Mutex / lock-edge emission instead of falling back to AST-only INFERRED.
Types ¶
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser implements parse.Parser for Go source.
Two operating modes:
- "AST-only" (default): ParseFile re-parses the file with go/parser. No types.Info is available, so the concurrency pass falls back to name-based heuristics with INFERRED confidence. Maintains backward compatibility for callers that don't have a *packages.Package handy (existing tests, ad-hoc CLI use).
- "Type-aware": SetPackages() registers a pre-loaded []*packages.Package (from detect.GoPackages). ParseFile then locates the file in the loaded syntax trees and uses the matching *types.Info for receiver resolution in the concurrency pass — emitting Mutex / Lock edges with EXTRACTED confidence and zero false positives on user-defined "Mutex" types.
func (*Parser) Extensions ¶
func (*Parser) FuncFieldTouches ¶
FuncFieldTouches returns the parser-wide map of Function/Method node ID → set of struct-Field node IDs touched by the body. Populated during ParseFile when typesInfo is available; empty otherwise.
Consumed by buildpipe's W-A cross-function lock propagation pass.
Returns a deep copy of the internal map so the parser's worker pool can continue mutating its own state without risking a data race with the caller. W-A review (2026-05-11 Important #1) caught that the prior implementation `defer Unlock` then returned the live map reference — safe today because runGoPipeline only calls this after parseConcurrent completes, but a single re-ordering would surface a silent race. The copy here is O(funcs × fields_touched), measured at ≪1 ms on the CKG self-graph (15 lock-holders).
func (*Parser) ParseFile ¶
ParseFile runs Pass 1: structural extraction. It does NOT resolve cross-file references — those become PendingRefs handled in Resolve.
When a *packages.Package was registered for `path` via SetPackages, uses the pre-parsed AST + TypesInfo (concurrency pass becomes EXTRACTED). Otherwise re-parses with go/parser (concurrency pass falls back to name-only heuristics with INFERRED confidence).
func (*Parser) Pkgs ¶
Pkgs returns the loaded packages slice registered by SetPackages, or nil when the parser is in AST-only mode. Consumers (e.g. the implements pass) use this to iterate package scopes after Pass 2 Resolve has run. The slice is the live value — callers must not mutate it.
func (*Parser) Resolve ¶
func (p *Parser) Resolve(results []*parse.ParseResult) (*parse.ResolvedGraph, error)
Resolve unions per-file results and uses go/types to resolve PendingRefs. V0 implementation: resolves call-target qnames to existing function/method nodes by qname suffix match. Unresolved pending refs are dropped (V0 simplification — emitting AMBIGUOUS edges would violate the schema's foreign-key constraint on edges.dst, so full AMBIGUOUS handling is deferred until edge persistence supports nullable dst).
func (*Parser) SetPackages ¶
SetPackages registers pre-loaded packages so subsequent ParseFile calls can use go/types resolution. Must be called BEFORE ParseFile for the type-aware path to take effect; idempotent — subsequent calls overwrite the index. Pass nil/empty to revert to AST-only mode.