Go Team's Analysis Framework Standardizes Modular Static Checks
The Go team’s golang.org/x/tools/go/analysis package defines a common interface between static analysis checkers and the driver programs that run them. Each analysis is expressed as an Analyzer value that declares its name, documentation, flags, dependencies, and a Run function. Because every checker conforms to the same contract, the same analysis logic can be reused across command-line tools like vet, editors and IDEs, build systems such as Bazel and Buck, code review tools, and code indexers like Sourcegraph—without rewriting it for each host.
The framework is built around “modular” analysis: a checker inspects one package at a time but can persist facts about lower-level packages and reuse them when analyzing higher-level ones, much like separate compilation. The canonical example is the printf checker, which learns that a wrapper like log.Fatalf delegates to fmt.Printf and then validates format strings in calls to that wrapper, even across package boundaries. Analyzers can also declare dependencies via a Requires graph, so results from passes like control-flow graphs (ctrlflow), SSA construction (buildssa), or efficient AST traversal (inspect) are computed once and shared, letting a tool pay only for the capabilities it uses.
At runtime, the driver hands each Analyzer a Pass carrying the package’s syntax trees, type information, source positions, and non-Go files, plus a Report function for emitting diagnostics tied to source locations. Notably, diagnostics carry no severity field—the design leaves prioritization and filtering to the driver and the user’s preferences rather than baking opinions into individual checkers. The result is a composable ecosystem where checkers from different authors can be selected, ordered, and combined with minimal glue.
Read the full article
Continue reading at Hacker News →This is an AI-generated summary. Read the original for the full story.