honnef.co/go/tools@v0.5.0-0.dev.0.20240520180541-dcae280a5e87/lintcmd/runner/runner.go (about)

     1  // Package runner implements a go/analysis runner. It makes heavy use
     2  // of on-disk caching to reduce overall memory usage and to speed up
     3  // repeat runs.
     4  //
     5  // # Public API
     6  //
     7  // A Runner maps a list of analyzers and package patterns to a list of
     8  // results. Results provide access to diagnostics, directives, errors
     9  // encountered, and information about packages. Results explicitly do
    10  // not contain ASTs or type information. All position information is
    11  // returned in the form of token.Position, not token.Pos. All work
    12  // that requires access to the loaded representation of a package has
    13  // to occur inside analyzers.
    14  //
    15  // # Planning and execution
    16  //
    17  // Analyzing packages is split into two phases: planning and
    18  // execution.
    19  //
    20  // During planning, a directed acyclic graph of package dependencies
    21  // is computed. We materialize the full graph so that we can execute
    22  // the graph from the bottom up, without keeping unnecessary data in
    23  // memory during a DFS and with simplified parallel execution.
    24  //
    25  // During execution, leaf nodes (nodes with no outstanding
    26  // dependencies) get executed in parallel, bounded by a semaphore
    27  // sized according to the number of CPUs. Conceptually, this happens
    28  // in a loop, processing new leaf nodes as they appear, until no more
    29  // nodes are left. In the actual implementation, nodes know their
    30  // dependents, and the last dependency of a node to be processed is
    31  // responsible for scheduling its dependent.
    32  //
    33  // The graph is rooted at a synthetic root node. Upon execution of the
    34  // root node, the algorithm terminates.
    35  //
    36  // Analyzing a package repeats the same planning + execution steps,
    37  // but this time on a graph of analyzers for the package. Parallel
    38  // execution of individual analyzers is bounded by the same semaphore
    39  // as executing packages.
    40  //
    41  // # Parallelism
    42  //
    43  // Actions are executed in parallel where the dependency graph allows.
    44  // Overall parallelism is bounded by a semaphore, sized according to
    45  // GOMAXPROCS. Each concurrently processed package takes up a
    46  // token, as does each analyzer – but a package can always execute at
    47  // least one analyzer, using the package's token.
    48  //
    49  // Depending on the overall shape of the graph, there may be GOMAXPROCS
    50  // packages running a single analyzer each, a single package running
    51  // GOMAXPROCS analyzers, or anything in between.
    52  //
    53  // Total memory consumption grows roughly linearly with the number of
    54  // CPUs, while total execution time is inversely proportional to the
    55  // number of CPUs. Overall, parallelism is affected by the shape of
    56  // the dependency graph. A lot of inter-connected packages will see
    57  // less parallelism than a lot of independent packages.
    58  //
    59  // # Caching
    60  //
    61  // The runner caches facts, directives and diagnostics in a
    62  // content-addressable cache that is designed after Go's own cache.
    63  // Additionally, it makes use of Go's export data.
    64  //
    65  // This cache not only speeds up repeat runs, it also reduces peak
    66  // memory usage. When we've analyzed a package, we cache the results
    67  // and drop them from memory. When a dependent needs any of this
    68  // information, or when analysis is complete and we wish to render the
    69  // results, the data gets loaded from disk again.
    70  //
    71  // Data only exists in memory when it is immediately needed, not
    72  // retained for possible future uses. This trades increased CPU usage
    73  // for reduced memory usage. A single dependency may be loaded many
    74  // times over, but it greatly reduces peak memory usage, as an
    75  // arbitrary amount of time may pass between analyzing a dependency
    76  // and its dependent, during which other packages will be processed.
    77  package runner
    78  
    79  // OPT(dh): we could reduce disk storage usage of cached data by
    80  // compressing it, either directly at the cache layer, or by feeding
    81  // compressed data to the cache. Of course doing so may negatively
    82  // affect CPU usage, and there are lower hanging fruit, such as
    83  // needing to cache less data in the first place.
    84  
    85  // OPT(dh): right now, each package is analyzed completely
    86  // independently. Each package loads all of its dependencies from
    87  // export data and cached facts. If we have two packages A and B,
    88  // which both depend on C, and which both get analyzed in parallel,
    89  // then C will be loaded twice. This wastes CPU time and memory. It
    90  // would be nice if we could reuse a single C for the analysis of both
    91  // A and B.
    92  //
    93  // We can't reuse the actual types.Package or facts, because each
    94  // package gets its own token.FileSet. Sharing a global FileSet has
    95  // several drawbacks, including increased memory usage and running the
    96  // risk of running out of FileSet address space.
    97  //
    98  // We could however avoid loading the same raw export data from disk
    99  // twice, as well as deserializing gob data twice. One possible
   100  // solution would be a duplicate-suppressing in-memory cache that
   101  // caches data for a limited amount of time. When the same package
   102  // needs to be loaded twice in close succession, we can reuse work,
   103  // without holding unnecessary data in memory for an extended period
   104  // of time.
   105  //
   106  // We would likely need to do extensive benchmarking to figure out how
   107  // long to keep data around to find a sweet spot where we reduce CPU
   108  // load without increasing memory usage.
   109  //
   110  // We can probably populate the cache after we've analyzed a package,
   111  // on the assumption that it will have to be loaded again in the near
   112  // future.
   113  
   114  import (
   115  	"bytes"
   116  	"encoding/gob"
   117  	"fmt"
   118  	"go/token"
   119  	"go/types"
   120  	"io"
   121  	"os"
   122  	"reflect"
   123  	"runtime"
   124  	"sort"
   125  	"strings"
   126  	"sync/atomic"
   127  	"time"
   128  
   129  	"honnef.co/go/tools/analysis/lint"
   130  	"honnef.co/go/tools/analysis/report"
   131  	"honnef.co/go/tools/config"
   132  	"honnef.co/go/tools/go/loader"
   133  	tsync "honnef.co/go/tools/internal/sync"
   134  	"honnef.co/go/tools/lintcmd/cache"
   135  	"honnef.co/go/tools/unused"
   136  
   137  	"golang.org/x/tools/go/analysis"
   138  	"golang.org/x/tools/go/packages"
   139  	"golang.org/x/tools/go/types/objectpath"
   140  )
   141  
   142  const sanityCheck = false
   143  
   144  // Diagnostic is like go/analysis.Diagnostic, but with all token.Pos resolved to token.Position.
   145  type Diagnostic struct {
   146  	Position token.Position
   147  	End      token.Position
   148  	Category string
   149  	Message  string
   150  
   151  	SuggestedFixes []SuggestedFix
   152  	Related        []RelatedInformation
   153  }
   154  
   155  // RelatedInformation provides additional context for a diagnostic.
   156  type RelatedInformation struct {
   157  	Position token.Position
   158  	End      token.Position
   159  	Message  string
   160  }
   161  
   162  type SuggestedFix struct {
   163  	Message   string
   164  	TextEdits []TextEdit
   165  }
   166  
   167  type TextEdit struct {
   168  	Position token.Position
   169  	End      token.Position
   170  	NewText  []byte
   171  }
   172  
   173  // A Result describes the result of analyzing a single package.
   174  //
   175  // It holds references to cached diagnostics and directives. They can
   176  // be loaded on demand with the Load method.
   177  type Result struct {
   178  	Package *loader.PackageSpec
   179  	Config  config.Config
   180  	Initial bool
   181  	Skipped bool
   182  
   183  	Failed bool
   184  	Errors []error
   185  	// Action results, path to file
   186  	results string
   187  	// Results relevant to testing, only set when test mode is enabled, path to file
   188  	testData string
   189  }
   190  
   191  type SerializedDirective struct {
   192  	Command   string
   193  	Arguments []string
   194  	// The position of the comment
   195  	DirectivePosition token.Position
   196  	// The position of the node that the comment is attached to
   197  	NodePosition token.Position
   198  }
   199  
   200  func serializeDirective(dir lint.Directive, fset *token.FileSet) SerializedDirective {
   201  	return SerializedDirective{
   202  		Command:           dir.Command,
   203  		Arguments:         dir.Arguments,
   204  		DirectivePosition: report.DisplayPosition(fset, dir.Directive.Pos()),
   205  		NodePosition:      report.DisplayPosition(fset, dir.Node.Pos()),
   206  	}
   207  }
   208  
   209  type ResultData struct {
   210  	Directives  []SerializedDirective
   211  	Diagnostics []Diagnostic
   212  	Unused      unused.Result
   213  }
   214  
   215  func (r Result) Load() (ResultData, error) {
   216  	if r.Failed {
   217  		panic("Load called on failed Result")
   218  	}
   219  	if r.results == "" {
   220  		// this package was only a dependency
   221  		return ResultData{}, nil
   222  	}
   223  	f, err := os.Open(r.results)
   224  	if err != nil {
   225  		return ResultData{}, fmt.Errorf("failed loading result: %w", err)
   226  	}
   227  	defer f.Close()
   228  	var out ResultData
   229  	err = gob.NewDecoder(f).Decode(&out)
   230  	return out, err
   231  }
   232  
   233  // TestData contains extra information about analysis runs that is only available in test mode.
   234  type TestData struct {
   235  	// Facts contains facts produced by analyzers for a package.
   236  	// Unlike vetx, this list only contains facts specific to this package,
   237  	// not all facts for the transitive closure of dependencies.
   238  	Facts []TestFact
   239  	// List of files that were part of the package.
   240  	Files []string
   241  }
   242  
   243  // LoadTest returns data relevant to testing.
   244  // It should only be called if Runner.TestMode was set to true.
   245  func (r Result) LoadTest() (TestData, error) {
   246  	if r.Failed {
   247  		panic("Load called on failed Result")
   248  	}
   249  	if r.results == "" {
   250  		// this package was only a dependency
   251  		return TestData{}, nil
   252  	}
   253  	f, err := os.Open(r.testData)
   254  	if err != nil {
   255  		return TestData{}, fmt.Errorf("failed loading test data: %w", err)
   256  	}
   257  	defer f.Close()
   258  	var out TestData
   259  	err = gob.NewDecoder(f).Decode(&out)
   260  	return out, err
   261  }
   262  
   263  type action interface {
   264  	Deps() []action
   265  	Triggers() []action
   266  	DecrementPending() bool
   267  	MarkFailed()
   268  	IsFailed() bool
   269  	AddError(error)
   270  }
   271  
   272  type baseAction struct {
   273  	// Action description
   274  
   275  	deps     []action
   276  	triggers []action
   277  	pending  uint32
   278  
   279  	// Action results
   280  
   281  	// failed is set to true if the action couldn't be processed. This
   282  	// may either be due to an error specific to this action, in
   283  	// which case the errors field will be populated, or due to a
   284  	// dependency being marked as failed, in which case errors will be
   285  	// empty.
   286  	failed bool
   287  	errors []error
   288  }
   289  
   290  func (act *baseAction) Deps() []action     { return act.deps }
   291  func (act *baseAction) Triggers() []action { return act.triggers }
   292  func (act *baseAction) DecrementPending() bool {
   293  	return atomic.AddUint32(&act.pending, ^uint32(0)) == 0
   294  }
   295  func (act *baseAction) MarkFailed()        { act.failed = true }
   296  func (act *baseAction) IsFailed() bool     { return act.failed }
   297  func (act *baseAction) AddError(err error) { act.errors = append(act.errors, err) }
   298  
   299  // packageAction describes the act of loading a package, fully
   300  // analyzing it, and storing the results.
   301  type packageAction struct {
   302  	baseAction
   303  
   304  	// Action description
   305  	Package   *loader.PackageSpec
   306  	factsOnly bool
   307  	hash      cache.ActionID
   308  
   309  	// Action results
   310  	cfg      config.Config
   311  	vetx     string
   312  	results  string
   313  	testData string
   314  	skipped  bool
   315  }
   316  
   317  func (act *packageAction) String() string {
   318  	return fmt.Sprintf("packageAction(%s)", act.Package)
   319  }
   320  
   321  type objectFact struct {
   322  	fact analysis.Fact
   323  	// TODO(dh): why do we store the objectpath when producing the
   324  	// fact? Is it just for the sanity checking, which compares the
   325  	// stored path with a path recomputed from objectFactKey.Obj?
   326  	path objectpath.Path
   327  }
   328  
   329  type objectFactKey struct {
   330  	Obj  types.Object
   331  	Type reflect.Type
   332  }
   333  
   334  type packageFactKey struct {
   335  	Pkg  *types.Package
   336  	Type reflect.Type
   337  }
   338  
   339  type gobFact struct {
   340  	PkgPath string
   341  	ObjPath string
   342  	Fact    analysis.Fact
   343  }
   344  
   345  // TestFact is a serialization of facts that is specific to the test mode.
   346  type TestFact struct {
   347  	ObjectName string
   348  	Position   token.Position
   349  	FactString string
   350  	Analyzer   string
   351  }
   352  
   353  // analyzerAction describes the act of analyzing a package with a
   354  // single analyzer.
   355  type analyzerAction struct {
   356  	baseAction
   357  
   358  	// Action description
   359  
   360  	Analyzer *analysis.Analyzer
   361  
   362  	// Action results
   363  
   364  	// We can store actual results here without worrying about memory
   365  	// consumption because analyzer actions get garbage collected once
   366  	// a package has been fully analyzed.
   367  	Result       interface{}
   368  	Diagnostics  []Diagnostic
   369  	ObjectFacts  map[objectFactKey]objectFact
   370  	PackageFacts map[packageFactKey]analysis.Fact
   371  	Pass         *analysis.Pass
   372  }
   373  
   374  func (act *analyzerAction) String() string {
   375  	return fmt.Sprintf("analyzerAction(%s)", act.Analyzer)
   376  }
   377  
   378  // A Runner executes analyzers on packages.
   379  type Runner struct {
   380  	Stats     Stats
   381  	GoVersion string
   382  	// if GoVersion == "module", and we couldn't determine the
   383  	// module's Go version, use this as the fallback
   384  	FallbackGoVersion string
   385  	// If set to true, Runner will populate results with data relevant to testing analyzers
   386  	TestMode bool
   387  
   388  	// GoVersion might be "module"; actualGoVersion contains the resolved version
   389  	actualGoVersion string
   390  
   391  	// Config that gets merged with per-package configs
   392  	cfg       config.Config
   393  	cache     *cache.Cache
   394  	semaphore tsync.Semaphore
   395  }
   396  
   397  type subrunner struct {
   398  	*Runner
   399  	analyzers     []*analysis.Analyzer
   400  	factAnalyzers []*analysis.Analyzer
   401  	analyzerNames string
   402  	cache         *cache.Cache
   403  }
   404  
   405  // New returns a new Runner.
   406  func New(cfg config.Config, c *cache.Cache) (*Runner, error) {
   407  	return &Runner{
   408  		cfg:       cfg,
   409  		cache:     c,
   410  		semaphore: tsync.NewSemaphore(runtime.GOMAXPROCS(0)),
   411  	}, nil
   412  }
   413  
   414  func newSubrunner(r *Runner, analyzers []*analysis.Analyzer) *subrunner {
   415  	analyzerNames := make([]string, len(analyzers))
   416  	for i, a := range analyzers {
   417  		analyzerNames[i] = a.Name
   418  	}
   419  	sort.Strings(analyzerNames)
   420  
   421  	var factAnalyzers []*analysis.Analyzer
   422  	for _, a := range analyzers {
   423  		if len(a.FactTypes) > 0 {
   424  			factAnalyzers = append(factAnalyzers, a)
   425  		}
   426  	}
   427  	return &subrunner{
   428  		Runner:        r,
   429  		analyzers:     analyzers,
   430  		factAnalyzers: factAnalyzers,
   431  		analyzerNames: strings.Join(analyzerNames, ","),
   432  		cache:         r.cache,
   433  	}
   434  }
   435  
   436  func newPackageActionRoot(pkg *loader.PackageSpec, cache map[*loader.PackageSpec]*packageAction) *packageAction {
   437  	a := newPackageAction(pkg, cache)
   438  	a.factsOnly = false
   439  	return a
   440  }
   441  
   442  func newPackageAction(pkg *loader.PackageSpec, cache map[*loader.PackageSpec]*packageAction) *packageAction {
   443  	if a, ok := cache[pkg]; ok {
   444  		return a
   445  	}
   446  
   447  	a := &packageAction{
   448  		Package:   pkg,
   449  		factsOnly: true, // will be overwritten by any call to Action
   450  	}
   451  	cache[pkg] = a
   452  
   453  	if len(pkg.Errors) > 0 {
   454  		a.errors = make([]error, len(pkg.Errors))
   455  		for i, err := range pkg.Errors {
   456  			a.errors[i] = err
   457  		}
   458  		a.failed = true
   459  
   460  		// We don't need to process our imports if this package is
   461  		// already broken.
   462  		return a
   463  	}
   464  
   465  	a.deps = make([]action, 0, len(pkg.Imports))
   466  	for _, dep := range pkg.Imports {
   467  		depa := newPackageAction(dep, cache)
   468  		depa.triggers = append(depa.triggers, a)
   469  		a.deps = append(a.deps, depa)
   470  
   471  		if depa.failed {
   472  			a.failed = true
   473  		}
   474  	}
   475  	// sort dependencies because the list of dependencies is part of
   476  	// the cache key
   477  	sort.Slice(a.deps, func(i, j int) bool {
   478  		return a.deps[i].(*packageAction).Package.ID < a.deps[j].(*packageAction).Package.ID
   479  	})
   480  
   481  	a.pending = uint32(len(a.deps))
   482  
   483  	return a
   484  }
   485  
   486  func newAnalyzerAction(an *analysis.Analyzer, cache map[*analysis.Analyzer]*analyzerAction) *analyzerAction {
   487  	if a, ok := cache[an]; ok {
   488  		return a
   489  	}
   490  
   491  	a := &analyzerAction{
   492  		Analyzer:     an,
   493  		ObjectFacts:  map[objectFactKey]objectFact{},
   494  		PackageFacts: map[packageFactKey]analysis.Fact{},
   495  	}
   496  	cache[an] = a
   497  	for _, dep := range an.Requires {
   498  		depa := newAnalyzerAction(dep, cache)
   499  		depa.triggers = append(depa.triggers, a)
   500  		a.deps = append(a.deps, depa)
   501  	}
   502  	a.pending = uint32(len(a.deps))
   503  	return a
   504  }
   505  
   506  func getCachedFiles(cache *cache.Cache, ids []cache.ActionID, out []*string) error {
   507  	for i, id := range ids {
   508  		var err error
   509  		*out[i], _, err = cache.GetFile(id)
   510  		if err != nil {
   511  			return err
   512  		}
   513  	}
   514  	return nil
   515  }
   516  
   517  func (r *subrunner) do(act action) error {
   518  	a := act.(*packageAction)
   519  	defer func() {
   520  		r.Stats.finishPackage()
   521  		if !a.factsOnly {
   522  			r.Stats.finishInitialPackage()
   523  		}
   524  	}()
   525  
   526  	// compute hash of action
   527  	a.cfg = a.Package.Config.Merge(r.cfg)
   528  	h := r.cache.NewHash("staticcheck " + a.Package.PkgPath)
   529  
   530  	// Note that we do not filter the list of analyzers by the
   531  	// package's configuration. We don't allow configuration to
   532  	// accidentally break dependencies between analyzers, and it's
   533  	// easier to always run all checks and filter the output. This
   534  	// also makes cached data more reusable.
   535  
   536  	// OPT(dh): not all changes in configuration invalidate cached
   537  	// data. specifically, when a.factsOnly == true, we only care
   538  	// about checks that produce facts, and settings that affect those
   539  	// checks.
   540  
   541  	// Config used for constructing the hash; this config doesn't have
   542  	// Checks populated, because we always run all checks.
   543  	//
   544  	// This even works for users who add custom checks, because we include the binary's hash.
   545  	hashCfg := a.cfg
   546  	hashCfg.Checks = nil
   547  	// note that we don't hash staticcheck's version; it is set as the
   548  	// salt by a package main.
   549  	fmt.Fprintf(h, "cfg %#v\n", hashCfg)
   550  	fmt.Fprintf(h, "pkg %x\n", a.Package.Hash)
   551  	fmt.Fprintf(h, "analyzers %s\n", r.analyzerNames)
   552  	fmt.Fprintf(h, "go %s\n", r.actualGoVersion)
   553  	fmt.Fprintf(h, "env godebug %q\n", os.Getenv("GODEBUG"))
   554  
   555  	// OPT(dh): do we actually need to hash vetx? can we not assume
   556  	// that for identical inputs, staticcheck will produce identical
   557  	// vetx?
   558  	for _, dep := range a.deps {
   559  		dep := dep.(*packageAction)
   560  		vetxHash, err := cache.FileHash(dep.vetx)
   561  		if err != nil {
   562  			return fmt.Errorf("failed computing hash: %w", err)
   563  		}
   564  		fmt.Fprintf(h, "vetout %q %x\n", dep.Package.PkgPath, vetxHash)
   565  	}
   566  	a.hash = cache.ActionID(h.Sum())
   567  
   568  	// try to fetch hashed data
   569  	ids := make([]cache.ActionID, 0, 2)
   570  	ids = append(ids, cache.Subkey(a.hash, "vetx"))
   571  	if !a.factsOnly {
   572  		ids = append(ids, cache.Subkey(a.hash, "results"))
   573  		if r.TestMode {
   574  			ids = append(ids, cache.Subkey(a.hash, "testdata"))
   575  		}
   576  	}
   577  	if err := getCachedFiles(r.cache, ids, []*string{&a.vetx, &a.results, &a.testData}); err != nil {
   578  		result, err := r.doUncached(a)
   579  		if err != nil {
   580  			return err
   581  		}
   582  		if a.failed {
   583  			return nil
   584  		}
   585  
   586  		a.skipped = result.skipped
   587  
   588  		// OPT(dh) instead of collecting all object facts and encoding
   589  		// them after analysis finishes, we could encode them as we
   590  		// go. however, that would require some locking.
   591  		//
   592  		// OPT(dh): We could sort gobFacts for more consistent output,
   593  		// but it doesn't matter. The hash of a package includes all
   594  		// of its files, so whether the vetx hash changes or not, a
   595  		// change to a package requires re-analyzing all dependents,
   596  		// even if the vetx data stayed the same. See also the note at
   597  		// the top of loader/hash.go.
   598  
   599  		tf := &bytes.Buffer{}
   600  		enc := gob.NewEncoder(tf)
   601  		for _, gf := range result.facts {
   602  			if err := enc.Encode(gf); err != nil {
   603  				return fmt.Errorf("failed gob encoding data: %w", err)
   604  			}
   605  		}
   606  
   607  		a.vetx, err = r.writeCacheReader(a, "vetx", bytes.NewReader(tf.Bytes()))
   608  		if err != nil {
   609  			return err
   610  		}
   611  
   612  		if a.factsOnly {
   613  			return nil
   614  		}
   615  
   616  		var out ResultData
   617  		out.Directives = make([]SerializedDirective, len(result.dirs))
   618  		for i, dir := range result.dirs {
   619  			out.Directives[i] = serializeDirective(dir, result.lpkg.Fset)
   620  		}
   621  
   622  		out.Diagnostics = result.diags
   623  		out.Unused = result.unused
   624  		a.results, err = r.writeCacheGob(a, "results", out)
   625  		if err != nil {
   626  			return err
   627  		}
   628  
   629  		if r.TestMode {
   630  			out := TestData{
   631  				Facts: result.testFacts,
   632  				Files: result.lpkg.GoFiles,
   633  			}
   634  			a.testData, err = r.writeCacheGob(a, "testdata", out)
   635  			if err != nil {
   636  				return err
   637  			}
   638  		}
   639  	}
   640  	return nil
   641  }
   642  
   643  // ActiveWorkers returns the number of currently running workers.
   644  func (r *Runner) ActiveWorkers() int {
   645  	return r.semaphore.Len()
   646  }
   647  
   648  // TotalWorkers returns the maximum number of possible workers.
   649  func (r *Runner) TotalWorkers() int {
   650  	return r.semaphore.Cap()
   651  }
   652  
   653  func (r *Runner) writeCacheReader(a *packageAction, kind string, rs io.ReadSeeker) (string, error) {
   654  	h := cache.Subkey(a.hash, kind)
   655  	out, _, err := r.cache.Put(h, rs)
   656  	if err != nil {
   657  		return "", fmt.Errorf("failed caching data: %w", err)
   658  	}
   659  	return r.cache.OutputFile(out), nil
   660  }
   661  
   662  func (r *Runner) writeCacheGob(a *packageAction, kind string, data interface{}) (string, error) {
   663  	f, err := os.CreateTemp("", "staticcheck")
   664  	if err != nil {
   665  		return "", err
   666  	}
   667  	defer f.Close()
   668  	os.Remove(f.Name())
   669  	if err := gob.NewEncoder(f).Encode(data); err != nil {
   670  		return "", fmt.Errorf("failed gob encoding data: %w", err)
   671  	}
   672  	if _, err := f.Seek(0, io.SeekStart); err != nil {
   673  		return "", err
   674  	}
   675  	return r.writeCacheReader(a, kind, f)
   676  }
   677  
   678  type packageActionResult struct {
   679  	facts   []gobFact
   680  	diags   []Diagnostic
   681  	unused  unused.Result
   682  	dirs    []lint.Directive
   683  	lpkg    *loader.Package
   684  	skipped bool
   685  
   686  	// Only set when using test mode
   687  	testFacts []TestFact
   688  }
   689  
   690  func (r *subrunner) doUncached(a *packageAction) (packageActionResult, error) {
   691  	// OPT(dh): for a -> b; c -> b; if both a and b are being
   692  	// processed concurrently, we shouldn't load b's export data
   693  	// twice.
   694  
   695  	pkg, _, err := loader.Load(a.Package)
   696  	if err != nil {
   697  		return packageActionResult{}, err
   698  	}
   699  
   700  	if len(pkg.Errors) > 0 {
   701  		// this handles errors that occurred during type-checking the
   702  		// package in loader.Load
   703  		for _, err := range pkg.Errors {
   704  			a.errors = append(a.errors, err)
   705  		}
   706  		a.failed = true
   707  		return packageActionResult{}, nil
   708  	}
   709  
   710  	if len(pkg.Syntax) == 0 && pkg.PkgPath != "unsafe" {
   711  		return packageActionResult{lpkg: pkg, skipped: true}, nil
   712  	}
   713  
   714  	// OPT(dh): instead of parsing directives twice (twice because
   715  	// U1000 depends on the facts.Directives analyzer), reuse the
   716  	// existing result
   717  	var dirs []lint.Directive
   718  	if !a.factsOnly {
   719  		dirs = lint.ParseDirectives(pkg.Syntax, pkg.Fset)
   720  	}
   721  	res, err := r.runAnalyzers(a, pkg)
   722  
   723  	return packageActionResult{
   724  		facts:     res.facts,
   725  		testFacts: res.testFacts,
   726  		diags:     res.diagnostics,
   727  		unused:    res.unused,
   728  		dirs:      dirs,
   729  		lpkg:      pkg,
   730  	}, err
   731  }
   732  
   733  func pkgPaths(root *types.Package) map[string]*types.Package {
   734  	out := map[string]*types.Package{}
   735  	var dfs func(*types.Package)
   736  	dfs = func(pkg *types.Package) {
   737  		if _, ok := out[pkg.Path()]; ok {
   738  			return
   739  		}
   740  		out[pkg.Path()] = pkg
   741  		for _, imp := range pkg.Imports() {
   742  			dfs(imp)
   743  		}
   744  	}
   745  	dfs(root)
   746  	return out
   747  }
   748  
   749  func (r *Runner) loadFacts(root *types.Package, dep *packageAction, objFacts map[objectFactKey]objectFact, pkgFacts map[packageFactKey]analysis.Fact) error {
   750  	// Load facts of all imported packages
   751  	vetx, err := os.Open(dep.vetx)
   752  	if err != nil {
   753  		return fmt.Errorf("failed loading cached facts: %w", err)
   754  	}
   755  	defer vetx.Close()
   756  
   757  	pathToPkg := pkgPaths(root)
   758  	dec := gob.NewDecoder(vetx)
   759  	for {
   760  		var gf gobFact
   761  		err := dec.Decode(&gf)
   762  		if err != nil {
   763  			if err == io.EOF {
   764  				break
   765  			}
   766  			return fmt.Errorf("failed loading cached facts: %w", err)
   767  		}
   768  
   769  		pkg, ok := pathToPkg[gf.PkgPath]
   770  		if !ok {
   771  			continue
   772  		}
   773  		if gf.ObjPath == "" {
   774  			pkgFacts[packageFactKey{
   775  				Pkg:  pkg,
   776  				Type: reflect.TypeOf(gf.Fact),
   777  			}] = gf.Fact
   778  		} else {
   779  			obj, err := objectpath.Object(pkg, objectpath.Path(gf.ObjPath))
   780  			if err != nil {
   781  				continue
   782  			}
   783  			objFacts[objectFactKey{
   784  				Obj:  obj,
   785  				Type: reflect.TypeOf(gf.Fact),
   786  			}] = objectFact{gf.Fact, objectpath.Path(gf.ObjPath)}
   787  		}
   788  	}
   789  	return nil
   790  }
   791  
   792  func genericHandle(a action, root action, queue chan action, sem *tsync.Semaphore, exec func(a action) error) {
   793  	if a == root {
   794  		close(queue)
   795  		if sem != nil {
   796  			sem.Release()
   797  		}
   798  		return
   799  	}
   800  	if !a.IsFailed() {
   801  		// the action may have already been marked as failed during
   802  		// construction of the action graph, for example because of
   803  		// unresolved imports.
   804  
   805  		for _, dep := range a.Deps() {
   806  			if dep.IsFailed() {
   807  				// One of our dependencies failed, so mark this package as
   808  				// failed and bail. We don't need to record an error for
   809  				// this package, the relevant error will have been
   810  				// reported by the first package in the chain that failed.
   811  				a.MarkFailed()
   812  				break
   813  			}
   814  		}
   815  	}
   816  
   817  	if !a.IsFailed() {
   818  		if err := exec(a); err != nil {
   819  			a.MarkFailed()
   820  			a.AddError(err)
   821  		}
   822  	}
   823  	if sem != nil {
   824  		sem.Release()
   825  	}
   826  
   827  	for _, t := range a.Triggers() {
   828  		if t.DecrementPending() {
   829  			queue <- t
   830  		}
   831  	}
   832  }
   833  
   834  type analyzerRunner struct {
   835  	pkg *loader.Package
   836  	// object facts of our dependencies; may contain facts of
   837  	// analyzers other than the current one
   838  	depObjFacts map[objectFactKey]objectFact
   839  	// package facts of our dependencies; may contain facts of
   840  	// analyzers other than the current one
   841  	depPkgFacts map[packageFactKey]analysis.Fact
   842  	factsOnly   bool
   843  
   844  	stats *Stats
   845  }
   846  
   847  func (ar *analyzerRunner) do(act action) error {
   848  	a := act.(*analyzerAction)
   849  	results := map[*analysis.Analyzer]interface{}{}
   850  	// TODO(dh): does this have to be recursive?
   851  	for _, dep := range a.deps {
   852  		dep := dep.(*analyzerAction)
   853  		results[dep.Analyzer] = dep.Result
   854  	}
   855  	// OPT(dh): cache factTypes, it is the same for all packages for a given analyzer
   856  	//
   857  	// OPT(dh): do we need the factTypes map? most analyzers have 0-1
   858  	// fact types. iterating over the slice is probably faster than
   859  	// indexing a map.
   860  	factTypes := map[reflect.Type]struct{}{}
   861  	for _, typ := range a.Analyzer.FactTypes {
   862  		factTypes[reflect.TypeOf(typ)] = struct{}{}
   863  	}
   864  	filterFactType := func(typ reflect.Type) bool {
   865  		_, ok := factTypes[typ]
   866  		return ok
   867  	}
   868  	a.Pass = &analysis.Pass{
   869  		Analyzer:   a.Analyzer,
   870  		Fset:       ar.pkg.Fset,
   871  		Files:      ar.pkg.Syntax,
   872  		OtherFiles: ar.pkg.OtherFiles,
   873  		Pkg:        ar.pkg.Types,
   874  		TypesInfo:  ar.pkg.TypesInfo,
   875  		TypesSizes: ar.pkg.TypesSizes,
   876  		Report: func(diag analysis.Diagnostic) {
   877  			if !ar.factsOnly {
   878  				if diag.Category == "" {
   879  					diag.Category = a.Analyzer.Name
   880  				}
   881  				d := Diagnostic{
   882  					Position: report.DisplayPosition(ar.pkg.Fset, diag.Pos),
   883  					End:      report.DisplayPosition(ar.pkg.Fset, diag.End),
   884  					Category: diag.Category,
   885  					Message:  diag.Message,
   886  				}
   887  				for _, sugg := range diag.SuggestedFixes {
   888  					s := SuggestedFix{
   889  						Message: sugg.Message,
   890  					}
   891  					for _, edit := range sugg.TextEdits {
   892  						s.TextEdits = append(s.TextEdits, TextEdit{
   893  							Position: report.DisplayPosition(ar.pkg.Fset, edit.Pos),
   894  							End:      report.DisplayPosition(ar.pkg.Fset, edit.End),
   895  							NewText:  edit.NewText,
   896  						})
   897  					}
   898  					d.SuggestedFixes = append(d.SuggestedFixes, s)
   899  				}
   900  				for _, rel := range diag.Related {
   901  					d.Related = append(d.Related, RelatedInformation{
   902  						Position: report.DisplayPosition(ar.pkg.Fset, rel.Pos),
   903  						End:      report.DisplayPosition(ar.pkg.Fset, rel.End),
   904  						Message:  rel.Message,
   905  					})
   906  				}
   907  				a.Diagnostics = append(a.Diagnostics, d)
   908  			}
   909  		},
   910  		ResultOf: results,
   911  		ImportObjectFact: func(obj types.Object, fact analysis.Fact) bool {
   912  			key := objectFactKey{
   913  				Obj:  obj,
   914  				Type: reflect.TypeOf(fact),
   915  			}
   916  			if f, ok := ar.depObjFacts[key]; ok {
   917  				reflect.ValueOf(fact).Elem().Set(reflect.ValueOf(f.fact).Elem())
   918  				return true
   919  			} else if f, ok := a.ObjectFacts[key]; ok {
   920  				reflect.ValueOf(fact).Elem().Set(reflect.ValueOf(f.fact).Elem())
   921  				return true
   922  			}
   923  			return false
   924  		},
   925  		ImportPackageFact: func(pkg *types.Package, fact analysis.Fact) bool {
   926  			key := packageFactKey{
   927  				Pkg:  pkg,
   928  				Type: reflect.TypeOf(fact),
   929  			}
   930  			if f, ok := ar.depPkgFacts[key]; ok {
   931  				reflect.ValueOf(fact).Elem().Set(reflect.ValueOf(f).Elem())
   932  				return true
   933  			} else if f, ok := a.PackageFacts[key]; ok {
   934  				reflect.ValueOf(fact).Elem().Set(reflect.ValueOf(f).Elem())
   935  				return true
   936  			}
   937  			return false
   938  		},
   939  		ExportObjectFact: func(obj types.Object, fact analysis.Fact) {
   940  			key := objectFactKey{
   941  				Obj:  obj,
   942  				Type: reflect.TypeOf(fact),
   943  			}
   944  			path, _ := objectpath.For(obj)
   945  			a.ObjectFacts[key] = objectFact{fact, path}
   946  		},
   947  		ExportPackageFact: func(fact analysis.Fact) {
   948  			key := packageFactKey{
   949  				Pkg:  ar.pkg.Types,
   950  				Type: reflect.TypeOf(fact),
   951  			}
   952  			a.PackageFacts[key] = fact
   953  		},
   954  		AllPackageFacts: func() []analysis.PackageFact {
   955  			out := make([]analysis.PackageFact, 0, len(ar.depPkgFacts)+len(a.PackageFacts))
   956  			for key, fact := range ar.depPkgFacts {
   957  				out = append(out, analysis.PackageFact{
   958  					Package: key.Pkg,
   959  					Fact:    fact,
   960  				})
   961  			}
   962  			for key, fact := range a.PackageFacts {
   963  				out = append(out, analysis.PackageFact{
   964  					Package: key.Pkg,
   965  					Fact:    fact,
   966  				})
   967  			}
   968  			return out
   969  		},
   970  		AllObjectFacts: func() []analysis.ObjectFact {
   971  			out := make([]analysis.ObjectFact, 0, len(ar.depObjFacts)+len(a.ObjectFacts))
   972  			for key, fact := range ar.depObjFacts {
   973  				if filterFactType(key.Type) {
   974  					out = append(out, analysis.ObjectFact{
   975  						Object: key.Obj,
   976  						Fact:   fact.fact,
   977  					})
   978  				}
   979  			}
   980  			for key, fact := range a.ObjectFacts {
   981  				if filterFactType(key.Type) {
   982  					out = append(out, analysis.ObjectFact{
   983  						Object: key.Obj,
   984  						Fact:   fact.fact,
   985  					})
   986  				}
   987  			}
   988  			return out
   989  		},
   990  	}
   991  
   992  	t := time.Now()
   993  	res, err := a.Analyzer.Run(a.Pass)
   994  	ar.stats.measureAnalyzer(a.Analyzer, ar.pkg.PackageSpec, time.Since(t))
   995  	if err != nil {
   996  		return err
   997  	}
   998  	a.Result = res
   999  	return nil
  1000  }
  1001  
  1002  type analysisResult struct {
  1003  	facts       []gobFact
  1004  	diagnostics []Diagnostic
  1005  	unused      unused.Result
  1006  
  1007  	// Only set when using test mode
  1008  	testFacts []TestFact
  1009  }
  1010  
  1011  func (r *subrunner) runAnalyzers(pkgAct *packageAction, pkg *loader.Package) (analysisResult, error) {
  1012  	depObjFacts := map[objectFactKey]objectFact{}
  1013  	depPkgFacts := map[packageFactKey]analysis.Fact{}
  1014  
  1015  	for _, dep := range pkgAct.deps {
  1016  		if err := r.loadFacts(pkg.Types, dep.(*packageAction), depObjFacts, depPkgFacts); err != nil {
  1017  			return analysisResult{}, err
  1018  		}
  1019  	}
  1020  
  1021  	root := &analyzerAction{}
  1022  	var analyzers []*analysis.Analyzer
  1023  	if pkgAct.factsOnly {
  1024  		// When analyzing non-initial packages, we only care about
  1025  		// analyzers that produce facts.
  1026  		analyzers = r.factAnalyzers
  1027  	} else {
  1028  		analyzers = r.analyzers
  1029  	}
  1030  
  1031  	all := map[*analysis.Analyzer]*analyzerAction{}
  1032  	for _, a := range analyzers {
  1033  		a := newAnalyzerAction(a, all)
  1034  		root.deps = append(root.deps, a)
  1035  		a.triggers = append(a.triggers, root)
  1036  	}
  1037  	root.pending = uint32(len(root.deps))
  1038  
  1039  	ar := &analyzerRunner{
  1040  		pkg:         pkg,
  1041  		factsOnly:   pkgAct.factsOnly,
  1042  		depObjFacts: depObjFacts,
  1043  		depPkgFacts: depPkgFacts,
  1044  		stats:       &r.Stats,
  1045  	}
  1046  	queue := make(chan action, len(all))
  1047  	for _, a := range all {
  1048  		if len(a.Deps()) == 0 {
  1049  			queue <- a
  1050  		}
  1051  	}
  1052  
  1053  	// Don't hang if there are no analyzers to run; for example
  1054  	// because we are analyzing a dependency but have no analyzers
  1055  	// that produce facts.
  1056  	if len(all) == 0 {
  1057  		close(queue)
  1058  	}
  1059  	for item := range queue {
  1060  		b := r.semaphore.AcquireMaybe()
  1061  		if b {
  1062  			go genericHandle(item, root, queue, &r.semaphore, ar.do)
  1063  		} else {
  1064  			// the semaphore is exhausted; run the analysis under the
  1065  			// token we've acquired for analyzing the package.
  1066  			genericHandle(item, root, queue, nil, ar.do)
  1067  		}
  1068  	}
  1069  
  1070  	var unusedResult unused.Result
  1071  	for _, a := range all {
  1072  		if a != root && a.Analyzer.Name == "U1000" && !a.failed {
  1073  			// TODO(dh): figure out a clean abstraction, instead of
  1074  			// special-casing U1000.
  1075  			unusedResult = a.Result.(unused.Result)
  1076  		}
  1077  
  1078  		for key, fact := range a.ObjectFacts {
  1079  			depObjFacts[key] = fact
  1080  		}
  1081  		for key, fact := range a.PackageFacts {
  1082  			depPkgFacts[key] = fact
  1083  		}
  1084  	}
  1085  
  1086  	// OPT(dh): cull objects not reachable via the exported closure
  1087  	var testFacts []TestFact
  1088  	gobFacts := make([]gobFact, 0, len(depObjFacts)+len(depPkgFacts))
  1089  	for key, fact := range depObjFacts {
  1090  		if fact.path == "" {
  1091  			continue
  1092  		}
  1093  		if sanityCheck {
  1094  			p, _ := objectpath.For(key.Obj)
  1095  			if p != fact.path {
  1096  				panic(fmt.Sprintf("got different object paths for %v. old: %q new: %q", key.Obj, fact.path, p))
  1097  			}
  1098  		}
  1099  		gf := gobFact{
  1100  			PkgPath: key.Obj.Pkg().Path(),
  1101  			ObjPath: string(fact.path),
  1102  			Fact:    fact.fact,
  1103  		}
  1104  		gobFacts = append(gobFacts, gf)
  1105  	}
  1106  
  1107  	for key, fact := range depPkgFacts {
  1108  		gf := gobFact{
  1109  			PkgPath: key.Pkg.Path(),
  1110  			Fact:    fact,
  1111  		}
  1112  		gobFacts = append(gobFacts, gf)
  1113  	}
  1114  
  1115  	if r.TestMode {
  1116  		for _, a := range all {
  1117  			for key, fact := range a.ObjectFacts {
  1118  				tgf := TestFact{
  1119  					ObjectName: key.Obj.Name(),
  1120  					Position:   pkg.Fset.Position(key.Obj.Pos()),
  1121  					FactString: fmt.Sprint(fact.fact),
  1122  					Analyzer:   a.Analyzer.Name,
  1123  				}
  1124  				testFacts = append(testFacts, tgf)
  1125  			}
  1126  
  1127  			for _, fact := range a.PackageFacts {
  1128  				tgf := TestFact{
  1129  					ObjectName: "",
  1130  					Position:   pkg.Fset.Position(pkg.Syntax[0].Pos()),
  1131  					FactString: fmt.Sprint(fact),
  1132  					Analyzer:   a.Analyzer.Name,
  1133  				}
  1134  				testFacts = append(testFacts, tgf)
  1135  			}
  1136  		}
  1137  	}
  1138  
  1139  	var diags []Diagnostic
  1140  	for _, a := range root.deps {
  1141  		a := a.(*analyzerAction)
  1142  		diags = append(diags, a.Diagnostics...)
  1143  	}
  1144  	return analysisResult{
  1145  		facts:       gobFacts,
  1146  		testFacts:   testFacts,
  1147  		diagnostics: diags,
  1148  		unused:      unusedResult,
  1149  	}, nil
  1150  }
  1151  
  1152  func registerGobTypes(analyzers []*analysis.Analyzer) {
  1153  	for _, a := range analyzers {
  1154  		for _, typ := range a.FactTypes {
  1155  			// FIXME(dh): use RegisterName so we can work around collisions
  1156  			// in names. For pointer-types, gob incorrectly qualifies
  1157  			// type names with the package name, not the import path.
  1158  			gob.Register(typ)
  1159  		}
  1160  	}
  1161  }
  1162  
  1163  func allAnalyzers(analyzers []*analysis.Analyzer) []*analysis.Analyzer {
  1164  	seen := map[*analysis.Analyzer]struct{}{}
  1165  	out := make([]*analysis.Analyzer, 0, len(analyzers))
  1166  	var dfs func(*analysis.Analyzer)
  1167  	dfs = func(a *analysis.Analyzer) {
  1168  		if _, ok := seen[a]; ok {
  1169  			return
  1170  		}
  1171  		seen[a] = struct{}{}
  1172  		out = append(out, a)
  1173  		for _, dep := range a.Requires {
  1174  			dfs(dep)
  1175  		}
  1176  	}
  1177  	for _, a := range analyzers {
  1178  		dfs(a)
  1179  	}
  1180  	return out
  1181  }
  1182  
  1183  // Run loads the packages specified by patterns, runs analyzers on
  1184  // them and returns the results. Each result corresponds to a single
  1185  // package. Results will be returned for all packages, including
  1186  // dependencies. Errors specific to packages will be reported in the
  1187  // respective results.
  1188  //
  1189  // If cfg is nil, a default config will be used. Otherwise, cfg will
  1190  // be used, with the exception of the Mode field.
  1191  func (r *Runner) Run(cfg *packages.Config, analyzers []*analysis.Analyzer, patterns []string) ([]Result, error) {
  1192  	analyzers = allAnalyzers(analyzers)
  1193  	registerGobTypes(analyzers)
  1194  
  1195  	r.Stats.setState(StateLoadPackageGraph)
  1196  	lpkgs, err := loader.Graph(r.cache, cfg, patterns...)
  1197  	if err != nil {
  1198  		return nil, err
  1199  	}
  1200  	r.Stats.setInitialPackages(len(lpkgs))
  1201  
  1202  	if len(lpkgs) == 0 {
  1203  		return nil, nil
  1204  	}
  1205  
  1206  	var goVersion string
  1207  	if r.GoVersion == "module" {
  1208  		for _, lpkg := range lpkgs {
  1209  			if m := lpkg.Module; m != nil {
  1210  				if goVersion == "" {
  1211  					goVersion = m.GoVersion
  1212  				} else if goVersion != m.GoVersion {
  1213  					// Theoretically, we should only ever see a single Go
  1214  					// module. At least that's currently (as of Go 1.15)
  1215  					// true when using 'go list'.
  1216  					fmt.Fprintln(os.Stderr, "warning: encountered multiple modules and could not deduce targeted Go version")
  1217  					goVersion = ""
  1218  					break
  1219  				}
  1220  			}
  1221  		}
  1222  	} else {
  1223  		goVersion = r.GoVersion
  1224  	}
  1225  
  1226  	if goVersion == "" {
  1227  		if r.FallbackGoVersion == "" {
  1228  			panic("could not determine Go version of module, and fallback version hasn't been set")
  1229  		}
  1230  		goVersion = r.FallbackGoVersion
  1231  	}
  1232  	r.actualGoVersion = goVersion
  1233  	for _, a := range analyzers {
  1234  		flag := a.Flags.Lookup("go")
  1235  		if flag == nil {
  1236  			continue
  1237  		}
  1238  		if err := flag.Value.Set(goVersion); err != nil {
  1239  			return nil, err
  1240  		}
  1241  	}
  1242  
  1243  	r.Stats.setState(StateBuildActionGraph)
  1244  	all := map[*loader.PackageSpec]*packageAction{}
  1245  	root := &packageAction{}
  1246  	for _, lpkg := range lpkgs {
  1247  		a := newPackageActionRoot(lpkg, all)
  1248  		root.deps = append(root.deps, a)
  1249  		a.triggers = append(a.triggers, root)
  1250  	}
  1251  	root.pending = uint32(len(root.deps))
  1252  
  1253  	queue := make(chan action)
  1254  	r.Stats.setTotalPackages(len(all) - 1)
  1255  
  1256  	r.Stats.setState(StateProcessing)
  1257  	go func() {
  1258  		for _, a := range all {
  1259  			if len(a.Deps()) == 0 {
  1260  				queue <- a
  1261  			}
  1262  		}
  1263  	}()
  1264  
  1265  	sr := newSubrunner(r, analyzers)
  1266  	for item := range queue {
  1267  		r.semaphore.Acquire()
  1268  		go genericHandle(item, root, queue, &r.semaphore, func(act action) error {
  1269  			return sr.do(act)
  1270  		})
  1271  	}
  1272  
  1273  	r.Stats.setState(StateFinalizing)
  1274  	out := make([]Result, 0, len(all))
  1275  	for _, item := range all {
  1276  		if item.Package == nil {
  1277  			continue
  1278  		}
  1279  		out = append(out, Result{
  1280  			Package:  item.Package,
  1281  			Config:   item.cfg,
  1282  			Initial:  !item.factsOnly,
  1283  			Skipped:  item.skipped,
  1284  			Failed:   item.failed,
  1285  			Errors:   item.errors,
  1286  			results:  item.results,
  1287  			testData: item.testData,
  1288  		})
  1289  	}
  1290  	return out, nil
  1291  }