| 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