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