Docs / design / go-language-coverage · Edit on GitHub

Go language feature coverage (ecommerce-go)

Purpose: Canonical checklist of Go language surfaces that rgctl must index and analyze correctly. Fixture code lives under rgctl-tests/ecommerce-go/internal/langfeatures/. Expected graph facts live in ecommerce-go/correctness/expected-facts.json (ids prefixed lf_).

Tracking: sshaaf/rgctl#46 · plan: go-tier1-completion-plan.md

Honesty limits (not “optional gaps”): no full points-to across reflection/any casts; ambiguous multi-impl interface edges may be multi-target or annotated dynamic — but must not be silently dropped.


Feature matrix

IDLanguage featureFixture fileProbe symbols (names)Expected graph / analysisSeverity
LF-01Package function callcalls_basic.goLfPkgCallerLfPkgCalleeCALLS edgerequired
LF-02Method call same typemethods.go(*LfCart).Checkout(*LfCart).validateCALLS; receiver FQN LfCart.Checkoutrequired
LF-03Method call cross-type same namemethods.go(*LfOrchestrator).Run(*LfBetaStore).ListItems (not LfAlphaStore.ListItems)Correct resolution under name collisionrequired
LF-04Interface method callinterfaces.go(*LfRuntimeClient).StartRunSandbox via LfRuntimeCALLS to impl(s); interface method symbol existsrequired
LF-05Multiple interface implementationsinterfaces.goLfRemoteRuntime.RunSandbox, LfFakeRuntime.RunSandboxBoth method symbols; implements / satisfaction link to LfRuntimerequired
LF-06Struct embedding (anonymous field)embedding.goLfDerived embeds LfBaseEmbedded field in fields[]; embed/EXTENDS-like or CONTAINS relationrequired
LF-07Promoted method via embedembedding.go(*LfDerived).UseBase(*LfBase).BaseMethodCALLS to promoted / base methodrequired
LF-08var declaration def-usevars.goLfVarFlowPDG/def-use sees var x int / var s string defsrequired
LF-09Short var :=vars.goLfShortVarFlowdef-use for := (already partially covered by harness)required
LF-10Const + typed iota / aliasvars.goLfStatus, LfStatusPending, type alias LfUserIDTypeAlias / const or Variable symbolsrequired
LF-11Expression switchcontrol.goLfExprSwitchComplexity counts cases; CFG lowers case statement_list (Return edges from case bodies)required
LF-12Type switchcontrol.goLfTypeSwitchCFG/complexity include type_case; case bodies loweredrequired
LF-13select + channelcontrol.goLfSelectLoopCFG select arms via same case lowering; complexity counts communication_caserequired
LF-14defercontrol.goLfWithDeferCFG records defer; return/panic route through defer chain LIFOrequired
LF-15go statementcontrol.goLfSpawnCFG records go stmt; call edge to spawned func namerequired
LF-16Generics (func + type)generics.goLfIdentity[T], LfBox[T]Symbols retained; calls to LfIdentity resolverequired
LF-17Importsimports_probe.goimport of fmt / internal pkgImport symbols or IMPORTS edgesrequired
LF-18Constructor NewTmethods.goNewLfCartLfCart.<init>, is_constructorrequired
LF-19Receiver field write (CPG)fieldwrite.go(*LfOrderDTO).MarkProcessed writes Statuscpg mutations / field-write index hit with --exclude-ctorsrequired
LF-20Multi-value returnmethods.go(*LfCart).TotalsStructured or preserved return signature stringbest_effort
LF-21Struct tagsfieldwrite.goLfOrderDTO.Status json:"status"Tag in field metadatabest_effort

How to re-verify

# From rgctl repo root
cargo build --release
./target/release/rgctl discover rgctl-tests/ecommerce-go -l go -e vendor \
  --with-cfg --with-taint -v

# Correctness suite (includes lf_* facts once present)
cargo test --test graph_correctness go -- --nocapture

# Spot-check call edges
./target/release/rgctl -r rgctl-tests/ecommerce-go -f json \
  gql "MATCH (a:Function)-[:CALLS]->(b:Function) WHERE a.name = 'Run' RETURN a,b"

When adding a new Go surface, add a row here, a fixture symbol, and an lf_* expected-fact before claiming support.


Go CFG lowering (Tree-sitter)

Shared builder: crates/rgctl-analysis/src/cfg_builder.rs. Unit tests: cfg_builder::tests::test_go_*.

ConstructLoweringStatus
Straight-line (var / := / assign / call / i++ / send)Basic-block statementsdone
if + else / else ifCondition Branch + IfTrue/IfFalsedone
if init; condInit statement before condition blockdone
for three-part (for_clause)Init → cond header → body → update → cond; continue → updatedone
for while-style / infinite / rangeHeader + body cycle (range text on header)done (coarse range)
Expr / type switch + selectFan-out; case statement_list lowered (returns emit Return)done
switch init; …Init before branchdone
Unlabeled break / continueExit / continue-target (innermost for/switch/select)done
Labeled break / continueJump to labeled loop/switch exit or continue-targetdone
goExpression in BB; no parallel CFG forkapprox (LF-15)
deferRegister on stack; return/panic unwind LIFO as FunctionCall blocksdone
fallthroughJump from case body into next case bodydone
goto / labeled_statementEager label blocks; forward/back goto → Jumpdone
&& / || short-circuitCondition lowered into chained IfTrue/IfFalsedone
panicCall + unwind through active defers (Exception terminal)done

Honesty: go does not fork a parallel CFG; defer is a static stack (loop-deferred multiplicity not modeled).