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