@ctxo/lang-go
v0.8.0
Published
Ctxo Go language plugin (ctxo-go-analyzer + tree-sitter, full tier)
Downloads
548
Maintainers
Readme
@ctxo/lang-go
Go language plugin for Ctxo. Ships two analysis tiers selected at runtime:
| Tier | Engine | Activated when |
|---|---|---|
| Full | ctxo-go-analyzer binary (Go stdlib + x/tools SSA + CHA) | Go ≥ 1.22 on PATH and the bundled analyzer source builds successfully |
| Syntax | tree-sitter-go | Go toolchain absent; binary build fails; or analyzer cannot locate go.mod / go.work |
The composite picks at initialize() and forwards every extractSymbols /
extractEdges call to the active layer. extractComplexity is always served
by tree-sitter — the analyzer intentionally emits empty complexity arrays so
the two layers compose cleanly.
What full-tier adds over tree-sitter
- Cross-package symbol-id resolution.
pkg/acallingpkg/b.Do()produces an edge whose target ispkg/b/file.go::Do::function, not a synthetic placeholder. Everyget_blast_radius,find_importers, andget_logic_slicequery that crosses a package boundary now returns real results. implementsedges. Go's structural typing means interface satisfaction is invisible to a syntactic parser; the analyzer pairs every concrete type against every interface and emits an edge whentypes.Implements(T, I)ortypes.Implements(*T, I)is true.extendsedges for embedding. Anonymous fields (struct embedding) and embedded interface members produce explicit hierarchy edges soget_class_hierarchyworks on Go.- Generics with
typeArgsmetadata.List[int]andList[string]both produce ausesedge to the unconstructedListsymbol; the type arguments are preserved on edge metadata for future query precision. See ADR-013 §4 Q4. - Dead-code detection via CHA reachability. Unreachable functions and
methods are emitted in a single
deadrecord. A reflect-safe pass marks methods of any type touched byreflect.TypeOf/reflect.ValueOf/reflect.Neworjson.Marshal/Unmarshal/NewDecoder/NewEncoderas live to prevent false positives.
How the binary is built
On first use, GoAnalyzerAdapter.initialize() hashes the analyzer source +
go version and runs go build -trimpath -o
~/.cache/ctxo/lang-go-analyzer/<hash-goVersion>/ctxo-go-analyzer[.exe].
Subsequent runs reuse the cached binary. No build happens during npm install
to keep package installs sandbox-safe (ADR-013 §4 Q2).
If go is not on PATH, build fails, or no go.mod/go.work is found, the
plugin transparently falls back to tree-sitter and ctxo doctor surfaces the
missing toolchain.
Limitations (v0.8.0-alpha.0)
- Library mode is approximate. Without a
main.mainto anchor RTA-style reachability, every exported function/method becomes a root. This over-approximates liveness — fewer false dead-code reports, but symbols that nothing actually consumes still look live. - Generic types skipped from
implements/extendsenumeration. Pairing generic named types is unstable in currentgo/types; we revisit when the upstream API stabilizes. - Closures and reflective construction. Functions passed to stdlib
callbacks (
sort.Slice(..., func(i,j) bool {...})) follow a CHA edge so they ARE reachable; constructed-via-reflection types are kept alive only for the explicit reflect/json call sites listed above.
Architecture and rationale
See ADR-013 for the full decision record (alternative options considered, library choices, open question resolutions). Mirrors the C# pattern from ADR-007.
