src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

analysis.go (10498B)


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