1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package analysis
6
7import (
8	"flag"
9	"fmt"
10	"go/ast"
11	"go/token"
12	"go/types"
13	"reflect"
14)
15
16// An Analyzer describes an analysis function and its options.
17type Analyzer struct {
18	// The Name of the analyzer must be a valid Go identifier
19	// as it may appear in command-line flags, URLs, and so on.
20	Name string
21
22	// Doc is the documentation for the analyzer.
23	// The part before the first "\n\n" is the title
24	// (no capital or period, max ~60 letters).
25	Doc string
26
27	// URL holds an optional link to a web page with additional
28	// documentation for this analyzer.
29	URL string
30
31	// Flags defines any flags accepted by the analyzer.
32	// The manner in which these flags are exposed to the user
33	// depends on the driver which runs the analyzer.
34	Flags flag.FlagSet
35
36	// Run applies the analyzer to a package.
37	// It returns an error if the analyzer failed.
38	//
39	// On success, the Run function may return a result
40	// computed by the Analyzer; its type must match ResultType.
41	// The driver makes this result available as an input to
42	// another Analyzer that depends directly on this one (see
43	// Requires) when it analyzes the same package.
44	//
45	// To pass analysis results between packages (and thus
46	// potentially between address spaces), use Facts, which are
47	// serializable.
48	Run func(*Pass) (interface{}, error)
49
50	// RunDespiteErrors allows the driver to invoke
51	// the Run method of this analyzer even on a
52	// package that contains parse or type errors.
53	// The Pass.TypeErrors field may consequently be non-empty.
54	RunDespiteErrors bool
55
56	// Requires is a set of analyzers that must run successfully
57	// before this one on a given package. This analyzer may inspect
58	// the outputs produced by each analyzer in Requires.
59	// The graph over analyzers implied by Requires edges must be acyclic.
60	//
61	// Requires establishes a "horizontal" dependency between
62	// analysis passes (different analyzers, same package).
63	Requires []*Analyzer
64
65	// ResultType is the type of the optional result of the Run function.
66	ResultType reflect.Type
67
68	// FactTypes indicates that this analyzer imports and exports
69	// Facts of the specified concrete types.
70	// An analyzer that uses facts may assume that its import
71	// dependencies have been similarly analyzed before it runs.
72	// Facts must be pointers.
73	//
74	// FactTypes establishes a "vertical" dependency between
75	// analysis passes (same analyzer, different packages).
76	FactTypes []Fact
77}
78
79func (a *Analyzer) String() string { return a.Name }
80
81// A Pass provides information to the Run function that
82// applies a specific analyzer to a single Go package.
83//
84// It forms the interface between the analysis logic and the driver
85// program, and has both input and an output components.
86//
87// As in a compiler, one pass may depend on the result computed by another.
88//
89// The Run function should not call any of the Pass functions concurrently.
90type Pass struct {
91	Analyzer *Analyzer // the identity of the current analyzer
92
93	// syntax and type information
94	Fset         *token.FileSet // file position information; Run may add new files
95	Files        []*ast.File    // the abstract syntax tree of each file
96	OtherFiles   []string       // names of non-Go files of this package
97	IgnoredFiles []string       // names of ignored source files in this package
98	Pkg          *types.Package // type information about the package
99	TypesInfo    *types.Info    // type information about the syntax trees
100	TypesSizes   types.Sizes    // function for computing sizes of types
101	TypeErrors   []types.Error  // type errors (only if Analyzer.RunDespiteErrors)
102
103	// Report reports a Diagnostic, a finding about a specific location
104	// in the analyzed source code such as a potential mistake.
105	// It may be called by the Run function.
106	Report func(Diagnostic)
107
108	// ResultOf provides the inputs to this analysis pass, which are
109	// the corresponding results of its prerequisite analyzers.
110	// The map keys are the elements of Analysis.Required,
111	// and the type of each corresponding value is the required
112	// analysis's ResultType.
113	ResultOf map[*Analyzer]interface{}
114
115	// ReadFile returns the contents of the named file.
116	//
117	// The only valid file names are the elements of OtherFiles
118	// and IgnoredFiles, and names returned by
119	// Fset.File(f.FileStart).Name() for each f in Files.
120	//
121	// Analyzers must use this function (if provided) instead of
122	// accessing the file system directly. This allows a driver to
123	// provide a virtualized file tree (including, for example,
124	// unsaved editor buffers) and to track dependencies precisely
125	// to avoid unnecessary recomputation.
126	ReadFile func(filename string) ([]byte, error)
127
128	// -- facts --
129
130	// ImportObjectFact retrieves a fact associated with obj.
131	// Given a value ptr of type *T, where *T satisfies Fact,
132	// ImportObjectFact copies the value to *ptr.
133	//
134	// ImportObjectFact panics if called after the pass is complete.
135	// ImportObjectFact is not concurrency-safe.
136	ImportObjectFact func(obj types.Object, fact Fact) bool
137
138	// ImportPackageFact retrieves a fact associated with package pkg,
139	// which must be this package or one of its dependencies.
140	// See comments for ImportObjectFact.
141	ImportPackageFact func(pkg *types.Package, fact Fact) bool
142
143	// ExportObjectFact associates a fact of type *T with the obj,
144	// replacing any previous fact of that type.
145	//
146	// ExportObjectFact panics if it is called after the pass is
147	// complete, or if obj does not belong to the package being analyzed.
148	// ExportObjectFact is not concurrency-safe.
149	ExportObjectFact func(obj types.Object, fact Fact)
150
151	// ExportPackageFact associates a fact with the current package.
152	// See comments for ExportObjectFact.
153	ExportPackageFact func(fact Fact)
154
155	// AllPackageFacts returns a new slice containing all package
156	// facts of the analysis's FactTypes in unspecified order.
157	AllPackageFacts func() []PackageFact
158
159	// AllObjectFacts returns a new slice containing all object
160	// facts of the analysis's FactTypes in unspecified order.
161	AllObjectFacts func() []ObjectFact
162
163	/* Further fields may be added in future. */
164}
165
166// PackageFact is a package together with an associated fact.
167type PackageFact struct {
168	Package *types.Package
169	Fact    Fact
170}
171
172// ObjectFact is an object together with an associated fact.
173type ObjectFact struct {
174	Object types.Object
175	Fact   Fact
176}
177
178// Reportf is a helper function that reports a Diagnostic using the
179// specified position and formatted error message.
180func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
181	msg := fmt.Sprintf(format, args...)
182	pass.Report(Diagnostic{Pos: pos, Message: msg})
183}
184
185// The Range interface provides a range. It's equivalent to and satisfied by
186// ast.Node.
187type Range interface {
188	Pos() token.Pos // position of first character belonging to the node
189	End() token.Pos // position of first character immediately after the node
190}
191
192// ReportRangef is a helper function that reports a Diagnostic using the
193// range provided. ast.Node values can be passed in as the range because
194// they satisfy the Range interface.
195func (pass *Pass) ReportRangef(rng Range, format string, args ...interface{}) {
196	msg := fmt.Sprintf(format, args...)
197	pass.Report(Diagnostic{Pos: rng.Pos(), End: rng.End(), Message: msg})
198}
199
200func (pass *Pass) String() string {
201	return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
202}
203
204// A Fact is an intermediate fact produced during analysis.
205//
206// Each fact is associated with a named declaration (a types.Object) or
207// with a package as a whole. A single object or package may have
208// multiple associated facts, but only one of any particular fact type.
209//
210// A Fact represents a predicate such as "never returns", but does not
211// represent the subject of the predicate such as "function F" or "package P".
212//
213// Facts may be produced in one analysis pass and consumed by another
214// analysis pass even if these are in different address spaces.
215// If package P imports Q, all facts about Q produced during
216// analysis of that package will be available during later analysis of P.
217// Facts are analogous to type export data in a build system:
218// just as export data enables separate compilation of several passes,
219// facts enable "separate analysis".
220//
221// Each pass (a, p) starts with the set of facts produced by the
222// same analyzer a applied to the packages directly imported by p.
223// The analysis may add facts to the set, and they may be exported in turn.
224// An analysis's Run function may retrieve facts by calling
225// Pass.Import{Object,Package}Fact and update them using
226// Pass.Export{Object,Package}Fact.
227//
228// A fact is logically private to its Analysis. To pass values
229// between different analyzers, use the results mechanism;
230// see Analyzer.Requires, Analyzer.ResultType, and Pass.ResultOf.
231//
232// A Fact type must be a pointer.
233// Facts are encoded and decoded using encoding/gob.
234// A Fact may implement the GobEncoder/GobDecoder interfaces
235// to customize its encoding. Fact encoding should not fail.
236//
237// A Fact should not be modified once exported.
238type Fact interface {
239	AFact() // dummy method to avoid type errors
240}
241