go/analysis Framework
- title
- go/analysis Framework
- type
- concept
- summary
- Standard Go framework for building static analyzers that integrate with go vet and golangci-lint
- tags
- golang, static-analysis, tooling
- created
- 2026-04-15
- updated
- 2026-04-15
The golang.org/x/tools/go/analysis package is Go's standard framework for writing static analyzers. Every analyzer built with it can run standalone, integrate with go vet, or plug into golangci-lint.
Structure
An analyzer is a struct with:
var Analyzer = &analysis.Analyzer{
Name: "mycheck",
Doc: "checks for X",
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
The Requires field declares dependencies on other analyzers. The inspect.Analyzer is almost always required โ it provides optimized AST traversal.
The Run function receives an analysis.Pass containing:
Fsetโ file set for position informationFilesโ parsed AST of the packageTypesInfoโ type checker resultsResultOfโ results from required analyzersReportโ function to emit diagnostics
AST walking
Rather than walking every node, use the inspector from inspect.Analyzer:
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{(*ast.CallExpr)(nil)}
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
// analyze the call
})
The filter makes traversal efficient โ you only visit node types you care about.
Type information
The pass.TypesInfo field gives access to Go's type checker results:
TypesInfo.Types[expr]โ type of any expressionTypesInfo.Uses[ident]โ what a name refers toTypesInfo.Defs[ident]โ what a name definesTypesInfo.ObjectOf(ident)โ thetypes.Objectfor an identifier
The types.Object is key for tracking variables. Two identifiers pointing to the same variable share the same object, so pointer equality works even across shadowing.
Testing
The analysistest package makes testing straightforward:
func TestMyCheck(t *testing.T) {
testdata := analysistest.TestData()
analysistest.Run(t, testdata, mycheck.Analyzer, "mypackage")
}
Test files use // want comments for expected diagnostics:
x := badThing() // want "badThing is deprecated"
Running
Standalone:
func main() {
singlechecker.Main(mycheck.Analyzer)
}
With go vet (requires registration in the Go toolchain).
With golangci-lint: add to .golangci.yml under linters-settings.
Examples
- transactioncheck โ detects database operations leaking outside transactions
errcheckโ detects unchecked errorsstaticcheckโ comprehensive static analysis suitenilnessโ detects redundant nil checks and guaranteed nil dereferences