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