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