doc.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. The analysis package defines the interface between a modular static
  3. analysis and an analysis driver program.
  4. Background
  5. A static analysis is a function that inspects a package of Go code and
  6. reports a set of diagnostics (typically mistakes in the code), and
  7. perhaps produces other results as well, such as suggested refactorings
  8. or other facts. An analysis that reports mistakes is informally called a
  9. "checker". For example, the printf checker reports mistakes in
  10. fmt.Printf format strings.
  11. A "modular" analysis is one that inspects one package at a time but can
  12. save information from a lower-level package and use it when inspecting a
  13. higher-level package, analogous to separate compilation in a toolchain.
  14. The printf checker is modular: when it discovers that a function such as
  15. log.Fatalf delegates to fmt.Printf, it records this fact, and checks
  16. calls to that function too, including calls made from another package.
  17. By implementing a common interface, checkers from a variety of sources
  18. can be easily selected, incorporated, and reused in a wide range of
  19. driver programs including command-line tools (such as vet), text editors and
  20. IDEs, build and test systems (such as go build, Bazel, or Buck), test
  21. frameworks, code review tools, code-base indexers (such as SourceGraph),
  22. documentation viewers (such as godoc), batch pipelines for large code
  23. bases, and so on.
  24. Analyzer
  25. The primary type in the API is Analyzer. An Analyzer statically
  26. describes an analysis function: its name, documentation, flags,
  27. relationship to other analyzers, and of course, its logic.
  28. To define an analysis, a user declares a (logically constant) variable
  29. of type Analyzer. Here is a typical example from one of the analyzers in
  30. the go/analysis/passes/ subdirectory:
  31. package unusedresult
  32. var Analyzer = &analysis.Analyzer{
  33. Name: "unusedresult",
  34. Doc: "check for unused results of calls to some functions",
  35. Run: run,
  36. ...
  37. }
  38. func run(pass *analysis.Pass) (interface{}, error) {
  39. ...
  40. }
  41. An analysis driver is a program such as vet that runs a set of
  42. analyses and prints the diagnostics that they report.
  43. The driver program must import the list of Analyzers it needs.
  44. Typically each Analyzer resides in a separate package.
  45. To add a new Analyzer to an existing driver, add another item to the list:
  46. import ( "unusedresult"; "nilness"; "printf" )
  47. var analyses = []*analysis.Analyzer{
  48. unusedresult.Analyzer,
  49. nilness.Analyzer,
  50. printf.Analyzer,
  51. }
  52. A driver may use the name, flags, and documentation to provide on-line
  53. help that describes the analyses its performs.
  54. The doc comment contains a brief one-line summary,
  55. optionally followed by paragraphs of explanation.
  56. The vet command, shown below, is an example of a driver that runs
  57. multiple analyzers. It is based on the multichecker package
  58. (see the "Standalone commands" section for details).
  59. $ go build golang.org/x/tools/go/analysis/cmd/vet
  60. $ ./vet help
  61. vet is a tool for static analysis of Go programs.
  62. Usage: vet [-flag] [package]
  63. Registered analyzers:
  64. asmdecl report mismatches between assembly files and Go declarations
  65. assign check for useless assignments
  66. atomic check for common mistakes using the sync/atomic package
  67. ...
  68. unusedresult check for unused results of calls to some functions
  69. $ ./vet help unusedresult
  70. unusedresult: check for unused results of calls to some functions
  71. Analyzer flags:
  72. -unusedresult.funcs value
  73. comma-separated list of functions whose results must be used (default Error,String)
  74. -unusedresult.stringmethods value
  75. comma-separated list of names of methods of type func() string whose results must be used
  76. Some functions like fmt.Errorf return a result and have no side effects,
  77. so it is always a mistake to discard the result. This analyzer reports
  78. calls to certain functions in which the result of the call is ignored.
  79. The set of functions may be controlled using flags.
  80. The Analyzer type has more fields besides those shown above:
  81. type Analyzer struct {
  82. Name string
  83. Doc string
  84. Flags flag.FlagSet
  85. Run func(*Pass) (interface{}, error)
  86. RunDespiteErrors bool
  87. ResultType reflect.Type
  88. Requires []*Analyzer
  89. FactTypes []Fact
  90. }
  91. The Flags field declares a set of named (global) flag variables that
  92. control analysis behavior. Unlike vet, analysis flags are not declared
  93. directly in the command line FlagSet; it is up to the driver to set the
  94. flag variables. A driver for a single analysis, a, might expose its flag
  95. f directly on the command line as -f, whereas a driver for multiple
  96. analyses might prefix the flag name by the analysis name (-a.f) to avoid
  97. ambiguity. An IDE might expose the flags through a graphical interface,
  98. and a batch pipeline might configure them from a config file.
  99. See the "findcall" analyzer for an example of flags in action.
  100. The RunDespiteErrors flag indicates whether the analysis is equipped to
  101. handle ill-typed code. If not, the driver will skip the analysis if
  102. there were parse or type errors.
  103. The optional ResultType field specifies the type of the result value
  104. computed by this analysis and made available to other analyses.
  105. The Requires field specifies a list of analyses upon which
  106. this one depends and whose results it may access, and it constrains the
  107. order in which a driver may run analyses.
  108. The FactTypes field is discussed in the section on Modularity.
  109. The analysis package provides a Validate function to perform basic
  110. sanity checks on an Analyzer, such as that its Requires graph is
  111. acyclic, its fact and result types are unique, and so on.
  112. Finally, the Run field contains a function to be called by the driver to
  113. execute the analysis on a single package. The driver passes it an
  114. instance of the Pass type.
  115. Pass
  116. A Pass describes a single unit of work: the application of a particular
  117. Analyzer to a particular package of Go code.
  118. The Pass provides information to the Analyzer's Run function about the
  119. package being analyzed, and provides operations to the Run function for
  120. reporting diagnostics and other information back to the driver.
  121. type Pass struct {
  122. Fset *token.FileSet
  123. Files []*ast.File
  124. OtherFiles []string
  125. Pkg *types.Package
  126. TypesInfo *types.Info
  127. ResultOf map[*Analyzer]interface{}
  128. Report func(Diagnostic)
  129. ...
  130. }
  131. The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
  132. type information, and source positions for a single package of Go code.
  133. The OtherFiles field provides the names, but not the contents, of non-Go
  134. files such as assembly that are part of this package. See the "asmdecl"
  135. or "buildtags" analyzers for examples of loading non-Go files and report
  136. diagnostics against them.
  137. The ResultOf field provides the results computed by the analyzers
  138. required by this one, as expressed in its Analyzer.Requires field. The
  139. driver runs the required analyzers first and makes their results
  140. available in this map. Each Analyzer must return a value of the type
  141. described in its Analyzer.ResultType field.
  142. For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
  143. provides a control-flow graph for each function in the package (see
  144. golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
  145. enables other Analyzers to traverse the syntax trees of the package more
  146. efficiently; and the "buildssa" analyzer constructs an SSA-form
  147. intermediate representation.
  148. Each of these Analyzers extends the capabilities of later Analyzers
  149. without adding a dependency to the core API, so an analysis tool pays
  150. only for the extensions it needs.
  151. The Report function emits a diagnostic, a message associated with a
  152. source position. For most analyses, diagnostics are their primary
  153. result.
  154. For convenience, Pass provides a helper method, Reportf, to report a new
  155. diagnostic by formatting a string.
  156. Diagnostic is defined as:
  157. type Diagnostic struct {
  158. Pos token.Pos
  159. Category string // optional
  160. Message string
  161. }
  162. The optional Category field is a short identifier that classifies the
  163. kind of message when an analysis produces several kinds of diagnostic.
  164. Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
  165. and buildtag, inspect the raw text of Go source files or even non-Go
  166. files such as assembly. To report a diagnostic against a line of a
  167. raw text file, use the following sequence:
  168. content, err := ioutil.ReadFile(filename)
  169. if err != nil { ... }
  170. tf := fset.AddFile(filename, -1, len(content))
  171. tf.SetLinesForContent(content)
  172. ...
  173. pass.Reportf(tf.LineStart(line), "oops")
  174. Modular analysis with Facts
  175. To improve efficiency and scalability, large programs are routinely
  176. built using separate compilation: units of the program are compiled
  177. separately, and recompiled only when one of their dependencies changes;
  178. independent modules may be compiled in parallel. The same technique may
  179. be applied to static analyses, for the same benefits. Such analyses are
  180. described as "modular".
  181. A compiler’s type checker is an example of a modular static analysis.
  182. Many other checkers we would like to apply to Go programs can be
  183. understood as alternative or non-standard type systems. For example,
  184. vet's printf checker infers whether a function has the "printf wrapper"
  185. type, and it applies stricter checks to calls of such functions. In
  186. addition, it records which functions are printf wrappers for use by
  187. later analysis units to identify other printf wrappers by induction.
  188. A result such as “f is a printf wrapper” that is not interesting by
  189. itself but serves as a stepping stone to an interesting result (such as
  190. a diagnostic) is called a "fact".
  191. The analysis API allows an analysis to define new types of facts, to
  192. associate facts of these types with objects (named entities) declared
  193. within the current package, or with the package as a whole, and to query
  194. for an existing fact of a given type associated with an object or
  195. package.
  196. An Analyzer that uses facts must declare their types:
  197. var Analyzer = &analysis.Analyzer{
  198. Name: "printf",
  199. FactTypes: []analysis.Fact{new(isWrapper)},
  200. ...
  201. }
  202. type isWrapper struct{} // => *types.Func f “is a printf wrapper”
  203. A driver program ensures that facts for a pass’s dependencies are
  204. generated before analyzing the pass and are responsible for propagating
  205. facts between from one pass to another, possibly across address spaces.
  206. Consequently, Facts must be serializable. The API requires that drivers
  207. use the gob encoding, an efficient, robust, self-describing binary
  208. protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
  209. if the default encoding is unsuitable. Facts should be stateless.
  210. The Pass type has functions to import and export facts,
  211. associated either with an object or with a package:
  212. type Pass struct {
  213. ...
  214. ExportObjectFact func(types.Object, Fact)
  215. ImportObjectFact func(types.Object, Fact) bool
  216. ExportPackageFact func(fact Fact)
  217. ImportPackageFact func(*types.Package, Fact) bool
  218. }
  219. An Analyzer may only export facts associated with the current package or
  220. its objects, though it may import facts from any package or object that
  221. is an import dependency of the current package.
  222. Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
  223. the pair (obj, TypeOf(fact)), and the ImportObjectFact function
  224. retrieves the entry from this map and copies its value into the variable
  225. pointed to by fact. This scheme assumes that the concrete type of fact
  226. is a pointer; this assumption is checked by the Validate function.
  227. See the "printf" analyzer for an example of object facts in action.
  228. Some driver implementations (such as those based on Bazel and Blaze) do
  229. not currently apply analyzers to packages of the standard library.
  230. Therefore, for best results, analyzer authors should not rely on
  231. analysis facts being available for standard packages.
  232. For example, although the printf checker is capable of deducing during
  233. analysis of the log package that log.Printf is a printf-wrapper,
  234. this fact is built in to the analyzer so that it correctly checks
  235. calls to log.Printf even when run in a driver that does not apply
  236. it to standard packages. We plan to remove this limitation in future.
  237. Testing an Analyzer
  238. The analysistest subpackage provides utilities for testing an Analyzer.
  239. In a few lines of code, it is possible to run an analyzer on a package
  240. of testdata files and check that it reported all the expected
  241. diagnostics and facts (and no more). Expectations are expressed using
  242. "// want ..." comments in the input code.
  243. Standalone commands
  244. Analyzers are provided in the form of packages that a driver program is
  245. expected to import. The vet command imports a set of several analyzers,
  246. but users may wish to define their own analysis commands that perform
  247. additional checks. To simplify the task of creating an analysis command,
  248. either for a single analyzer or for a whole suite, we provide the
  249. singlechecker and multichecker subpackages.
  250. The singlechecker package provides the main function for a command that
  251. runs one analyzer. By convention, each analyzer such as
  252. go/passes/findcall should be accompanied by a singlechecker-based
  253. command such as go/analysis/passes/findcall/cmd/findcall, defined in its
  254. entirety as:
  255. package main
  256. import (
  257. "golang.org/x/tools/go/analysis/passes/findcall"
  258. "golang.org/x/tools/go/analysis/singlechecker"
  259. )
  260. func main() { singlechecker.Main(findcall.Analyzer) }
  261. A tool that provides multiple analyzers can use multichecker in a
  262. similar way, giving it the list of Analyzers.
  263. */
  264. package analysis