Understanding the codebase
gohawk separates its public analyzer catalog from the command that runs it and from the individual analyzer implementations. Most contributions touch one analyzer group, its fixtures, and its documentation rather than every layer.
Request flow
main.go → internal/cli → analyzers → internal/analyzers/<group> → analysisutil and analysisutil/ssamain.gois a thin executable entry point.internal/cliparses selection flags, resolves an execution plan, and hands the selected analyzers to Go’s analysis driver.analyzersis the public catalog. It defines groups, opt-in status, stable execution order, and the metadata used by the CLI and documentation.internal/analyzerscontains the analyzer implementations, grouped by contracts, ownership, reliability, and testing.internal/analyzerbasecontains the internal catalog model, stable check identities, diagnostic helpers, and shared flag value types.analysisutilcontains syntax and type helpers.analysisutil/ssacontains control-flow, call, value, and ownership helpers for SSA-backed analyzers.
The dependency direction is deliberate: implementations depend on shared analysis helpers, and the public catalog depends on implementations. Shared helpers never import the catalog or an analyzer group.
Analyzer declaration
Each analyzer has three connected pieces:
- Its implementation file defines an
analysis.Analyzerand run function. - Its group’s
analyzers.godeclares ananalyzerbase.AnalyzerSpecwith the analyzer activation, checks, check activation, and suggested-fix support. analyzers/analyzers.goplaces the analyzer in the stable execution order.
analyzerbase.NewCatalog validates these declarations at construction time.
It rejects missing checks, duplicate identities, and incomplete execution
order rather than allowing catalog drift.
Tests and documentation
analyzers/analyzers_test.go runs analyzers against packages under
testdata/src. A // want "message" comment marks a diagnostic that must be
reported; unmarked code is an accepted form that must remain quiet.
Documentation examples live in the same fixture packages between
//gohawk:example markers. go generate ./... runs the documentation
generator, which executes the real analyzers and writes their actual
diagnostics and source ranges into the Markdown examples and website manifest.
The examples are therefore test-backed rather than separately maintained
pseudocode.
Where to start
For a syntax-based analyzer, begin with
internal/analyzers/ownership/deferinloop.go. For a small SSA-backed analyzer, begin with
internal/analyzers/ownership/exitpolicy.go. The goroutine, resource-lifetime,
closed-domain, and lock-order analyzers model substantially more control and
data flow and are better approached after reading the shared SSA helpers.
Continue with How to contribute for the complete sequence for adding or changing an analyzer.