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