Go Analysis Framework: modular static analysis by go team Documentation ¶ Overview ¶ Background Analyzer Pass Modular analysis with Facts Testing an Analyzer Standalone commands Package analysis defi
By Coderz Club · 2026-07-26 · Tags: go
Go Analysis Framework: modular static analysis by go team
Documentation ¶ Overview ¶ Background Analyzer Pass Modular analysis with Facts Testing an Analyzer Standalone commands Package analysis defines the interface between a modular static analysis and an analysis driver program. Background ¶A static analysis is a function that inspects a package of Go code and reports a set of diagnostics (typically mistakes in the code), and perhaps produces other results as well, such as suggested refactorings or other facts. An analysis that reports mistakes is informally called a checker . For example, the printf checker reports mistakes in fmt.Printf format strings. A modular analysis is one that inspects one package at a time but can save information from a lower-level package and use it when inspecting a higher-level package, analogous to separate compilation in a toolchain. The printf checker is modular: when it discovers that a function such as log.Fatalf delegates to fmt.Printf, it records this fact, and checks calls to that function too, including calls made from another package. By implementing a common interface, checkers from a variety of sources can be easily selected, incorporated, and reused in a wide range of driver programs including command-line tools (such as vet), text editors and IDEs, build and test systems (such as go build, Bazel, or Buck), test frameworks, code review tools, code-base indexers (such as SourceGraph), documentation viewers (such as godoc), batch pipelines for large code bases, and so on. Analyzer ¶The primary type in the API is Analyzer. An Analyzer statically describes an analysis function: its name, documentation, flags, relationship to other analyzers, and of course, its logic. To define an analysis, a user declares a (logically constant) variable of type Analyzer. Here is a typical example from one of the analyzers in the go/analysis/passes/ subdirectory: package unusedresult var Analyzer = &analysis.Analyzer{ Name: unusedresult , Doc: check for unused results of calls to some functions , Run: run, ... } func run(pass *analysis.Pass) (interface{}, error) { ... } An analysis driver is a program such as vet that runs a set of analyses and prints the diagnostics that they report. The driver program must import the list of Analyzers it needs. Typically each Analyzer resides in a separate package. To add a new Analyzer to an existing driver, add another item to the list: import ( unusedresult ; nilness ; printf ) var analyses = []*analysis.Analyzer{ unusedresult.Analyzer, nilness.Analyzer, printf.Analyzer, } A driver may use the name, flags, and documentation to provide on-line help that describes the analyses it performs. The doc comment contains a brief one-line summary, optionally followed by paragraphs of explanation. The Analyzer type has more fields besides those shown above: type Analyzer struct { Name string Doc string Flags flag.FlagSet Run func(*Pass) (interface{}, error) RunDespiteErrors bool ResultType reflect.Type Requires []*Analyzer FactTypes []Fact } The Flags field declares a set of named (global) flag variables that control analysis behavior. Unlike vet, analysis flags are not declared directly in the command line FlagSet; it is up to the driver to set the flag variables. A driver for a single analysis, a, might expose its flag f directly on the command line as -f, whereas a driver for multiple analyses might prefix the flag name by the analysis name (-a.f) to avoid ambiguity. An IDE might expose the flags through a graphical interface, and a batch pipeline might configure them from a config file. See the findcall analyzer for an example of flags in action. The RunDespiteErrors flag indicates whether the analysis is equipped to handle ill-typed code. If not, the driver will skip the analysis if there were parse or type errors. The optional ResultType field specifies the type of the result value computed by this analysis and made available to other analyses. The Requires field specifies a list of analyses upon which this one depends and whose results it may access, and it constrains the order in which a driver may run analyses. The FactTypes field is discussed in the section on Modularity. The analysis package provides a Validate function to perform basic sanity checks on an Analyzer, such as that its Requires graph is acyclic, its fact and result types are unique, and so on. Finally, the Run field contains a function to be called by the driver to execute the analysis on a single package. The driver passes it an instance of the Pass type. Pass ¶A Pass describes a single unit of work: the application of a particular Analyzer to a particular package of Go code. The Pass provides information to the Analyzer s Run function about the package being analyzed, and provides operations to the Run function for reporting diagnostics and other information back to the driver. type Pass struct { Fset *token.FileSet Files []*ast.File OtherFiles []string IgnoredFiles []string Pkg
Documentation ¶ Overview ¶ Background Analyzer Pass Modular analysis with Facts Testing an Analyzer Standalone commands Package analysis defines the interface between a modular static analysis and an analysis driver program. Background ¶A static analysis is a function that inspects a package of Go code and reports a set of diagnostics (typically mistakes in the code), and perhaps produces other results as well, such as suggested refactorings or other facts. An analysis that reports mistakes is informally called a checker . For example, the printf checker reports mistakes in fmt.Printf format strings. A modular analysis is one that inspects one package at a time but can save information from a lower-level package and use it when inspecting a higher-level package, analogous to separate compilation in a toolchain. The printf checker is modular: when it discovers that a function such as log.Fatalf delegates to fmt.Printf, it records this fact, and checks calls to that function too, including calls made from another package. By implementing a common interface, checkers from a variety of sources can be easily selected, incorporated, and reused in a wide range of driver programs including command-line tools (such as vet), text editors and IDEs, build and test systems (such as go build, Bazel, or Buck), test frameworks, code review tools, code-base indexers (such as SourceGraph), documentation viewers (such as godoc), batch pipelines for large code bases, and so on. Analyzer ¶The primary type in the API is Analyzer. An Analyzer statically describes an analysis function: its name, documentation, flags, relationship to other analyzers, and of course, its logic. To define an analysis, a user declares a (logically constant) variable of type Analyzer. Here is a typical example from one of the analyzers in the go/analysis/passes/ subdirectory: package unusedresult var Analyzer = &analysis.Analyzer{ Name: unusedresult , Doc: check for unused results of calls to some functions , Run: run, ... } func run(pass *analysis.Pass) (interface{}, error) { ... } An analysis driver is a program such as vet that runs a set of analyses and prints the diagnostics that they report. The driver program must import the list of Analyzers it needs. Typically each Analyzer resides in a separate package. To add a new Analyzer to an existing driver, add another item to the list: import ( unusedresult ; nilness ; printf ) var analyses = []*analysis.Analyzer{ unusedresult.Analyzer, nilness.Analyzer, printf.Analyzer, } A driver may use the name, flags, and documentation to provide on-line help that describes the analyses it performs. The doc comment contains a brief one-line summary, optionally followed by paragraphs of explanation. The Analyzer type has more fields besides those shown above: type Analyzer struct { Name string Doc string Flags flag.FlagSet Run func(*Pass) (interface{}, error) RunDespiteErrors bool ResultType reflect.Type Requires []*Analyzer FactTypes []Fact } The Flags field declares a set of named (global) flag variables that control analysis behavior. Unlike vet, analysis flags are not declared directly in the command line FlagSet; it is up to the driver to set the flag variables. A driver for a single analysis, a, might expose its flag f directly on the command line as -f, whereas a driver for multiple analyses might prefix the flag name by the analysis name (-a.f) to avoid ambiguity. An IDE might expose the flags through a graphical interface, and a batch pipeline might configure them from a config file. See the findcall analyzer for an example of flags in action. The RunDespiteErrors flag indicates whether the analysis is equipped to handle ill-typed code. If not, the driver will skip the analysis if there were parse or type errors. The optional ResultType field specifies the type of the result value computed by this analysis and made available to other analyses. The Requires field specifies a list of analyses upon which this one depends and whose results it may access, and it constrains the order in which a driver may run analyses. The FactTypes field is discussed in the section on Modularity. The analysis package provides a Validate function to perform basic sanity checks on an Analyzer, such as that its Requires graph is acyclic, its fact and result types are unique, and so on. Finally, the Run field contains a function to be called by the driver to execute the analysis on a single package. The driver passes it an instance of the Pass type. Pass ¶A Pass describes a single unit of work: the application of a particular Analyzer to a particular package of Go code. The Pass provides information to the Analyzer s Run function about the package being analyzed, and provides operations to the Run function for reporting diagnostics and other information back to the driver. type Pass struct { Fset *token.FileSet Files []*ast.File OtherFiles []string IgnoredFiles []string Pkg