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