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 5 package analysis
6 7 import (
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.
17 type 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) (any, 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 79 func (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.
90 type 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 Module *Module // the package's enclosing module (possibly nil in some drivers)
104 105 // Report reports a Diagnostic, a finding about a specific location
106 // in the analyzed source code such as a potential mistake.
107 // It may be called by the Run function.
108 Report func(Diagnostic)
109 110 // ResultOf provides the inputs to this analysis pass, which are
111 // the corresponding results of its prerequisite analyzers.
112 // The map keys are the elements of Analysis.Required,
113 // and the type of each corresponding value is the required
114 // analysis's ResultType.
115 ResultOf map[*Analyzer]any
116 117 // ReadFile returns the contents of the named file.
118 //
119 // The only valid file names are the elements of OtherFiles
120 // and IgnoredFiles, and names returned by
121 // Fset.File(f.FileStart).Name() for each f in Files.
122 //
123 // Analyzers must use this function (if provided) instead of
124 // accessing the file system directly. This allows a driver to
125 // provide a virtualized file tree (including, for example,
126 // unsaved editor buffers) and to track dependencies precisely
127 // to avoid unnecessary recomputation.
128 ReadFile func(filename string) ([]byte, error)
129 130 // -- facts --
131 132 // ImportObjectFact retrieves a fact associated with obj.
133 // Given a value ptr of type *T, where *T satisfies Fact,
134 // ImportObjectFact copies the value to *ptr.
135 //
136 // ImportObjectFact panics if called after the pass is complete.
137 // ImportObjectFact is not concurrency-safe.
138 ImportObjectFact func(obj types.Object, fact Fact) bool
139 140 // ImportPackageFact retrieves a fact associated with package pkg,
141 // which must be this package or one of its dependencies.
142 // See comments for ImportObjectFact.
143 ImportPackageFact func(pkg *types.Package, fact Fact) bool
144 145 // ExportObjectFact associates a fact of type *T with the obj,
146 // replacing any previous fact of that type.
147 //
148 // ExportObjectFact panics if it is called after the pass is
149 // complete, or if obj does not belong to the package being analyzed.
150 // ExportObjectFact is not concurrency-safe.
151 ExportObjectFact func(obj types.Object, fact Fact)
152 153 // ExportPackageFact associates a fact with the current package.
154 // See comments for ExportObjectFact.
155 ExportPackageFact func(fact Fact)
156 157 // AllPackageFacts returns a new slice containing all package
158 // facts of the analysis's FactTypes in unspecified order.
159 // See comments for AllObjectFacts.
160 AllPackageFacts func() []PackageFact
161 162 // AllObjectFacts returns a new slice containing all object
163 // facts of the analysis's FactTypes in unspecified order.
164 //
165 // The result includes all facts exported by packages
166 // whose symbols are referenced by the current package
167 // (by qualified identifiers or field/method selections).
168 // And it includes all facts exported from the current
169 // package by the current analysis pass.
170 AllObjectFacts func() []ObjectFact
171 172 /* Further fields may be added in future. */
173 }
174 175 // PackageFact is a package together with an associated fact.
176 type PackageFact struct {
177 Package *types.Package
178 Fact Fact
179 }
180 181 // ObjectFact is an object together with an associated fact.
182 type ObjectFact struct {
183 Object types.Object
184 Fact Fact
185 }
186 187 // Reportf is a helper function that reports a Diagnostic using the
188 // specified position and formatted error message.
189 func (pass *Pass) Reportf(pos token.Pos, format string, args ...any) {
190 msg := fmt.Sprintf(format, args...)
191 pass.Report(Diagnostic{Pos: pos, Message: msg})
192 }
193 194 // The Range interface provides a range. It's equivalent to and satisfied by
195 // ast.Node.
196 type Range interface {
197 Pos() token.Pos // position of first character belonging to the node
198 End() token.Pos // position of first character immediately after the node
199 }
200 201 // ReportRangef is a helper function that reports a Diagnostic using the
202 // range provided. ast.Node values can be passed in as the range because
203 // they satisfy the Range interface.
204 func (pass *Pass) ReportRangef(rng Range, format string, args ...any) {
205 msg := fmt.Sprintf(format, args...)
206 pass.Report(Diagnostic{Pos: rng.Pos(), End: rng.End(), Message: msg})
207 }
208 209 func (pass *Pass) String() string {
210 return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
211 }
212 213 // A Fact is an intermediate fact produced during analysis.
214 //
215 // Each fact is associated with a named declaration (a types.Object) or
216 // with a package as a whole. A single object or package may have
217 // multiple associated facts, but only one of any particular fact type.
218 //
219 // A Fact represents a predicate such as "never returns", but does not
220 // represent the subject of the predicate such as "function F" or "package P".
221 //
222 // Facts may be produced in one analysis pass and consumed by another
223 // analysis pass even if these are in different address spaces.
224 // If package P imports Q, all facts about Q produced during
225 // analysis of that package will be available during later analysis of P.
226 // Facts are analogous to type export data in a build system:
227 // just as export data enables separate compilation of several passes,
228 // facts enable "separate analysis".
229 //
230 // Each pass (a, p) starts with the set of facts produced by the
231 // same analyzer a applied to the packages directly imported by p.
232 // The analysis may add facts to the set, and they may be exported in turn.
233 // An analysis's Run function may retrieve facts by calling
234 // Pass.Import{Object,Package}Fact and update them using
235 // Pass.Export{Object,Package}Fact.
236 //
237 // A fact is logically private to its Analysis. To pass values
238 // between different analyzers, use the results mechanism;
239 // see Analyzer.Requires, Analyzer.ResultType, and Pass.ResultOf.
240 //
241 // A Fact type must be a pointer.
242 // Facts are encoded and decoded using encoding/gob.
243 // A Fact may implement the GobEncoder/GobDecoder interfaces
244 // to customize its encoding. Fact encoding should not fail.
245 //
246 // A Fact should not be modified once exported.
247 type Fact interface {
248 AFact() // dummy method to avoid type errors
249 }
250 251 // A Module describes the module to which a package belongs.
252 type Module struct {
253 Path string // module path
254 Version string // module version ("" if unknown, such as for workspace modules)
255 GoVersion string // go version used in module (e.g. "go1.22.0")
256 }
257