golang

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func EmitFieldWriteEdges

func EmitFieldWriteEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge

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

func EmitImplementsEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge

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

func EmitInstantiatesEdges(pkgs []*packages.Package, nodes []types.Node) []types.Edge

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

func EmitPromotedMethods(pkgs []*packages.Package, nodes []types.Node) ([]types.Node, []types.Edge)

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.

func MakeID

func MakeID(qname, lang string, startByte int) string

MakeID delegates to the shared parse.MakeID so all language parsers compute identical IDs for the same (qname, lang, startByte) tuple.

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 New

func New(srcRoot string) *Parser

New returns a Parser rooted at srcRoot (used for relative file paths).

func (*Parser) Extensions

func (p *Parser) Extensions() []string

func (*Parser) FuncFieldTouches

func (p *Parser) FuncFieldTouches() map[string]map[string]struct{}

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

func (p *Parser) ParseFile(path string, src []byte) (*parse.ParseResult, error)

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

func (p *Parser) Pkgs() []*packages.Package

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

func (p *Parser) SetPackages(pkgs []*packages.Package)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL