...

Source file src/pkg/cmd/vendor/golang.org/x/tools/go/analysis/doc.go

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

View as plain text