github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/loader/loader.go (about)

     1  // Copyright 2013 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  // +build go1.5
     6  
     7  package loader
     8  
     9  // See doc.go for package documentation and implementation notes.
    10  
    11  import (
    12  	"errors"
    13  	"fmt"
    14  	"go/ast"
    15  	"go/build"
    16  	"go/parser"
    17  	"go/token"
    18  	"go/types"
    19  	"os"
    20  	"sort"
    21  	"strings"
    22  	"sync"
    23  	"time"
    24  
    25  	"golang.org/x/tools/go/ast/astutil"
    26  	"golang.org/x/tools/go/buildutil"
    27  )
    28  
    29  const trace = false // show timing info for type-checking
    30  
    31  // Config specifies the configuration for loading a whole program from
    32  // Go source code.
    33  // The zero value for Config is a ready-to-use default configuration.
    34  type Config struct {
    35  	// Fset is the file set for the parser to use when loading the
    36  	// program.  If nil, it may be lazily initialized by any
    37  	// method of Config.
    38  	Fset *token.FileSet
    39  
    40  	// ParserMode specifies the mode to be used by the parser when
    41  	// loading source packages.
    42  	ParserMode parser.Mode
    43  
    44  	// TypeChecker contains options relating to the type checker.
    45  	//
    46  	// The supplied IgnoreFuncBodies is not used; the effective
    47  	// value comes from the TypeCheckFuncBodies func below.
    48  	// The supplied Import function is not used either.
    49  	TypeChecker types.Config
    50  
    51  	// TypeCheckFuncBodies is a predicate over package paths.
    52  	// A package for which the predicate is false will
    53  	// have its package-level declarations type checked, but not
    54  	// its function bodies; this can be used to quickly load
    55  	// dependencies from source.  If nil, all func bodies are type
    56  	// checked.
    57  	TypeCheckFuncBodies func(path string) bool
    58  
    59  	// If Build is non-nil, it is used to locate source packages.
    60  	// Otherwise &build.Default is used.
    61  	//
    62  	// By default, cgo is invoked to preprocess Go files that
    63  	// import the fake package "C".  This behaviour can be
    64  	// disabled by setting CGO_ENABLED=0 in the environment prior
    65  	// to startup, or by setting Build.CgoEnabled=false.
    66  	Build *build.Context
    67  
    68  	// The current directory, used for resolving relative package
    69  	// references such as "./go/loader".  If empty, os.Getwd will be
    70  	// used instead.
    71  	Cwd string
    72  
    73  	// If DisplayPath is non-nil, it is used to transform each
    74  	// file name obtained from Build.Import().  This can be used
    75  	// to prevent a virtualized build.Config's file names from
    76  	// leaking into the user interface.
    77  	DisplayPath func(path string) string
    78  
    79  	// If AllowErrors is true, Load will return a Program even
    80  	// if some of the its packages contained I/O, parser or type
    81  	// errors; such errors are accessible via PackageInfo.Errors.  If
    82  	// false, Load will fail if any package had an error.
    83  	AllowErrors bool
    84  
    85  	// CreatePkgs specifies a list of non-importable initial
    86  	// packages to create.  The resulting packages will appear in
    87  	// the corresponding elements of the Program.Created slice.
    88  	CreatePkgs []PkgSpec
    89  
    90  	// ImportPkgs specifies a set of initial packages to load.
    91  	// The map keys are package paths.
    92  	//
    93  	// The map value indicates whether to load tests.  If true, Load
    94  	// will add and type-check two lists of files to the package:
    95  	// non-test files followed by in-package *_test.go files.  In
    96  	// addition, it will append the external test package (if any)
    97  	// to Program.Created.
    98  	ImportPkgs map[string]bool
    99  
   100  	// FindPackage is called during Load to create the build.Package
   101  	// for a given import path from a given directory.
   102  	// If FindPackage is nil, a default implementation
   103  	// based on ctxt.Import is used.  A client may use this hook to
   104  	// adapt to a proprietary build system that does not follow the
   105  	// "go build" layout conventions, for example.
   106  	//
   107  	// It must be safe to call concurrently from multiple goroutines.
   108  	FindPackage func(ctxt *build.Context, fromDir, importPath string, mode build.ImportMode) (*build.Package, error)
   109  }
   110  
   111  // A PkgSpec specifies a non-importable package to be created by Load.
   112  // Files are processed first, but typically only one of Files and
   113  // Filenames is provided.  The path needn't be globally unique.
   114  //
   115  type PkgSpec struct {
   116  	Path      string      // package path ("" => use package declaration)
   117  	Files     []*ast.File // ASTs of already-parsed files
   118  	Filenames []string    // names of files to be parsed
   119  }
   120  
   121  // A Program is a Go program loaded from source as specified by a Config.
   122  type Program struct {
   123  	Fset *token.FileSet // the file set for this program
   124  
   125  	// Created[i] contains the initial package whose ASTs or
   126  	// filenames were supplied by Config.CreatePkgs[i], followed by
   127  	// the external test package, if any, of each package in
   128  	// Config.ImportPkgs ordered by ImportPath.
   129  	//
   130  	// NOTE: these files must not import "C".  Cgo preprocessing is
   131  	// only performed on imported packages, not ad hoc packages.
   132  	//
   133  	// TODO(adonovan): we need to copy and adapt the logic of
   134  	// goFilesPackage (from $GOROOT/src/cmd/go/build.go) and make
   135  	// Config.Import and Config.Create methods return the same kind
   136  	// of entity, essentially a build.Package.
   137  	// Perhaps we can even reuse that type directly.
   138  	Created []*PackageInfo
   139  
   140  	// Imported contains the initially imported packages,
   141  	// as specified by Config.ImportPkgs.
   142  	Imported map[string]*PackageInfo
   143  
   144  	// AllPackages contains the PackageInfo of every package
   145  	// encountered by Load: all initial packages and all
   146  	// dependencies, including incomplete ones.
   147  	AllPackages map[*types.Package]*PackageInfo
   148  
   149  	// importMap is the canonical mapping of package paths to
   150  	// packages.  It contains all Imported initial packages, but not
   151  	// Created ones, and all imported dependencies.
   152  	importMap map[string]*types.Package
   153  }
   154  
   155  // PackageInfo holds the ASTs and facts derived by the type-checker
   156  // for a single package.
   157  //
   158  // Not mutated once exposed via the API.
   159  //
   160  type PackageInfo struct {
   161  	Pkg                   *types.Package
   162  	Importable            bool        // true if 'import "Pkg.Path()"' would resolve to this
   163  	TransitivelyErrorFree bool        // true if Pkg and all its dependencies are free of errors
   164  	Files                 []*ast.File // syntax trees for the package's files
   165  	Errors                []error     // non-nil if the package had errors
   166  	types.Info                        // type-checker deductions.
   167  	dir                   string      // package directory
   168  
   169  	checker   *types.Checker // transient type-checker state
   170  	errorFunc func(error)
   171  }
   172  
   173  func (info *PackageInfo) String() string { return info.Pkg.Path() }
   174  
   175  func (info *PackageInfo) appendError(err error) {
   176  	if info.errorFunc != nil {
   177  		info.errorFunc(err)
   178  	} else {
   179  		fmt.Fprintln(os.Stderr, err)
   180  	}
   181  	info.Errors = append(info.Errors, err)
   182  }
   183  
   184  func (conf *Config) fset() *token.FileSet {
   185  	if conf.Fset == nil {
   186  		conf.Fset = token.NewFileSet()
   187  	}
   188  	return conf.Fset
   189  }
   190  
   191  // ParseFile is a convenience function (intended for testing) that invokes
   192  // the parser using the Config's FileSet, which is initialized if nil.
   193  //
   194  // src specifies the parser input as a string, []byte, or io.Reader, and
   195  // filename is its apparent name.  If src is nil, the contents of
   196  // filename are read from the file system.
   197  //
   198  func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) {
   199  	// TODO(adonovan): use conf.build() etc like parseFiles does.
   200  	return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode)
   201  }
   202  
   203  // FromArgsUsage is a partial usage message that applications calling
   204  // FromArgs may wish to include in their -help output.
   205  const FromArgsUsage = `
   206  <args> is a list of arguments denoting a set of initial packages.
   207  It may take one of two forms:
   208  
   209  1. A list of *.go source files.
   210  
   211     All of the specified files are loaded, parsed and type-checked
   212     as a single package.  All the files must belong to the same directory.
   213  
   214  2. A list of import paths, each denoting a package.
   215  
   216     The package's directory is found relative to the $GOROOT and
   217     $GOPATH using similar logic to 'go build', and the *.go files in
   218     that directory are loaded, parsed and type-checked as a single
   219     package.
   220  
   221     In addition, all *_test.go files in the directory are then loaded
   222     and parsed.  Those files whose package declaration equals that of
   223     the non-*_test.go files are included in the primary package.  Test
   224     files whose package declaration ends with "_test" are type-checked
   225     as another package, the 'external' test package, so that a single
   226     import path may denote two packages.  (Whether this behaviour is
   227     enabled is tool-specific, and may depend on additional flags.)
   228  
   229  A '--' argument terminates the list of packages.
   230  `
   231  
   232  // FromArgs interprets args as a set of initial packages to load from
   233  // source and updates the configuration.  It returns the list of
   234  // unconsumed arguments.
   235  //
   236  // It is intended for use in command-line interfaces that require a
   237  // set of initial packages to be specified; see FromArgsUsage message
   238  // for details.
   239  //
   240  // Only superficial errors are reported at this stage; errors dependent
   241  // on I/O are detected during Load.
   242  //
   243  func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) {
   244  	var rest []string
   245  	for i, arg := range args {
   246  		if arg == "--" {
   247  			rest = args[i+1:]
   248  			args = args[:i]
   249  			break // consume "--" and return the remaining args
   250  		}
   251  	}
   252  
   253  	if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
   254  		// Assume args is a list of a *.go files
   255  		// denoting a single ad hoc package.
   256  		for _, arg := range args {
   257  			if !strings.HasSuffix(arg, ".go") {
   258  				return nil, fmt.Errorf("named files must be .go files: %s", arg)
   259  			}
   260  		}
   261  		conf.CreateFromFilenames("", args...)
   262  	} else {
   263  		// Assume args are directories each denoting a
   264  		// package and (perhaps) an external test, iff xtest.
   265  		for _, arg := range args {
   266  			if xtest {
   267  				conf.ImportWithTests(arg)
   268  			} else {
   269  				conf.Import(arg)
   270  			}
   271  		}
   272  	}
   273  
   274  	return rest, nil
   275  }
   276  
   277  // CreateFromFilenames is a convenience function that adds
   278  // a conf.CreatePkgs entry to create a package of the specified *.go
   279  // files.
   280  //
   281  func (conf *Config) CreateFromFilenames(path string, filenames ...string) {
   282  	conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames})
   283  }
   284  
   285  // CreateFromFiles is a convenience function that adds a conf.CreatePkgs
   286  // entry to create package of the specified path and parsed files.
   287  //
   288  func (conf *Config) CreateFromFiles(path string, files ...*ast.File) {
   289  	conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files})
   290  }
   291  
   292  // ImportWithTests is a convenience function that adds path to
   293  // ImportPkgs, the set of initial source packages located relative to
   294  // $GOPATH.  The package will be augmented by any *_test.go files in
   295  // its directory that contain a "package x" (not "package x_test")
   296  // declaration.
   297  //
   298  // In addition, if any *_test.go files contain a "package x_test"
   299  // declaration, an additional package comprising just those files will
   300  // be added to CreatePkgs.
   301  //
   302  func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) }
   303  
   304  // Import is a convenience function that adds path to ImportPkgs, the
   305  // set of initial packages that will be imported from source.
   306  //
   307  func (conf *Config) Import(path string) { conf.addImport(path, false) }
   308  
   309  func (conf *Config) addImport(path string, tests bool) {
   310  	if path == "C" || path == "unsafe" {
   311  		return // ignore; not a real package
   312  	}
   313  	if conf.ImportPkgs == nil {
   314  		conf.ImportPkgs = make(map[string]bool)
   315  	}
   316  	conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests
   317  }
   318  
   319  // PathEnclosingInterval returns the PackageInfo and ast.Node that
   320  // contain source interval [start, end), and all the node's ancestors
   321  // up to the AST root.  It searches all ast.Files of all packages in prog.
   322  // exact is defined as for astutil.PathEnclosingInterval.
   323  //
   324  // The zero value is returned if not found.
   325  //
   326  func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
   327  	for _, info := range prog.AllPackages {
   328  		for _, f := range info.Files {
   329  			if f.Pos() == token.NoPos {
   330  				// This can happen if the parser saw
   331  				// too many errors and bailed out.
   332  				// (Use parser.AllErrors to prevent that.)
   333  				continue
   334  			}
   335  			if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) {
   336  				continue
   337  			}
   338  			if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
   339  				return info, path, exact
   340  			}
   341  		}
   342  	}
   343  	return nil, nil, false
   344  }
   345  
   346  // InitialPackages returns a new slice containing the set of initial
   347  // packages (Created + Imported) in unspecified order.
   348  //
   349  func (prog *Program) InitialPackages() []*PackageInfo {
   350  	infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported))
   351  	infos = append(infos, prog.Created...)
   352  	for _, info := range prog.Imported {
   353  		infos = append(infos, info)
   354  	}
   355  	return infos
   356  }
   357  
   358  // Package returns the ASTs and results of type checking for the
   359  // specified package.
   360  func (prog *Program) Package(path string) *PackageInfo {
   361  	if info, ok := prog.AllPackages[prog.importMap[path]]; ok {
   362  		return info
   363  	}
   364  	for _, info := range prog.Created {
   365  		if path == info.Pkg.Path() {
   366  			return info
   367  		}
   368  	}
   369  	return nil
   370  }
   371  
   372  // ---------- Implementation ----------
   373  
   374  // importer holds the working state of the algorithm.
   375  type importer struct {
   376  	conf  *Config   // the client configuration
   377  	start time.Time // for logging
   378  
   379  	progMu sync.Mutex // guards prog
   380  	prog   *Program   // the resulting program
   381  
   382  	// findpkg is a memoization of FindPackage.
   383  	findpkgMu sync.Mutex // guards findpkg
   384  	findpkg   map[findpkgKey]findpkgValue
   385  
   386  	importedMu sync.Mutex             // guards imported
   387  	imported   map[string]*importInfo // all imported packages (incl. failures) by import path
   388  
   389  	// import dependency graph: graph[x][y] => x imports y
   390  	//
   391  	// Since non-importable packages cannot be cyclic, we ignore
   392  	// their imports, thus we only need the subgraph over importable
   393  	// packages.  Nodes are identified by their import paths.
   394  	graphMu sync.Mutex
   395  	graph   map[string]map[string]bool
   396  }
   397  
   398  type findpkgKey struct {
   399  	importPath string
   400  	fromDir    string
   401  	mode       build.ImportMode
   402  }
   403  
   404  type findpkgValue struct {
   405  	bp  *build.Package
   406  	err error
   407  }
   408  
   409  // importInfo tracks the success or failure of a single import.
   410  //
   411  // Upon completion, exactly one of info and err is non-nil:
   412  // info on successful creation of a package, err otherwise.
   413  // A successful package may still contain type errors.
   414  //
   415  type importInfo struct {
   416  	path     string        // import path
   417  	info     *PackageInfo  // results of typechecking (including errors)
   418  	complete chan struct{} // closed to broadcast that info is set.
   419  }
   420  
   421  // awaitCompletion blocks until ii is complete,
   422  // i.e. the info field is safe to inspect.
   423  func (ii *importInfo) awaitCompletion() {
   424  	<-ii.complete // wait for close
   425  }
   426  
   427  // Complete marks ii as complete.
   428  // Its info and err fields will not be subsequently updated.
   429  func (ii *importInfo) Complete(info *PackageInfo) {
   430  	if info == nil {
   431  		panic("info == nil")
   432  	}
   433  	ii.info = info
   434  	close(ii.complete)
   435  }
   436  
   437  type importError struct {
   438  	path string // import path
   439  	err  error  // reason for failure to create a package
   440  }
   441  
   442  // Load creates the initial packages specified by conf.{Create,Import}Pkgs,
   443  // loading their dependencies packages as needed.
   444  //
   445  // On success, Load returns a Program containing a PackageInfo for
   446  // each package.  On failure, it returns an error.
   447  //
   448  // If AllowErrors is true, Load will return a Program even if some
   449  // packages contained I/O, parser or type errors, or if dependencies
   450  // were missing.  (Such errors are accessible via PackageInfo.Errors.  If
   451  // false, Load will fail if any package had an error.
   452  //
   453  // It is an error if no packages were loaded.
   454  //
   455  func (conf *Config) Load() (*Program, error) {
   456  	// Create a simple default error handler for parse/type errors.
   457  	if conf.TypeChecker.Error == nil {
   458  		conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
   459  	}
   460  
   461  	// Set default working directory for relative package references.
   462  	if conf.Cwd == "" {
   463  		var err error
   464  		conf.Cwd, err = os.Getwd()
   465  		if err != nil {
   466  			return nil, err
   467  		}
   468  	}
   469  
   470  	// Install default FindPackage hook using go/build logic.
   471  	if conf.FindPackage == nil {
   472  		conf.FindPackage = func(ctxt *build.Context, path, fromDir string, mode build.ImportMode) (*build.Package, error) {
   473  			ioLimit <- true
   474  			bp, err := ctxt.Import(path, fromDir, mode)
   475  			<-ioLimit
   476  			if _, ok := err.(*build.NoGoError); ok {
   477  				return bp, nil // empty directory is not an error
   478  			}
   479  			return bp, err
   480  		}
   481  	}
   482  
   483  	prog := &Program{
   484  		Fset:        conf.fset(),
   485  		Imported:    make(map[string]*PackageInfo),
   486  		importMap:   make(map[string]*types.Package),
   487  		AllPackages: make(map[*types.Package]*PackageInfo),
   488  	}
   489  
   490  	imp := importer{
   491  		conf:     conf,
   492  		prog:     prog,
   493  		findpkg:  make(map[findpkgKey]findpkgValue),
   494  		imported: make(map[string]*importInfo),
   495  		start:    time.Now(),
   496  		graph:    make(map[string]map[string]bool),
   497  	}
   498  
   499  	// -- loading proper (concurrent phase) --------------------------------
   500  
   501  	var errpkgs []string // packages that contained errors
   502  
   503  	// Load the initially imported packages and their dependencies,
   504  	// in parallel.
   505  	// No vendor check on packages imported from the command line.
   506  	infos, importErrors := imp.importAll("", conf.Cwd, conf.ImportPkgs, 0)
   507  	for _, ie := range importErrors {
   508  		conf.TypeChecker.Error(ie.err) // failed to create package
   509  		errpkgs = append(errpkgs, ie.path)
   510  	}
   511  	for _, info := range infos {
   512  		prog.Imported[info.Pkg.Path()] = info
   513  	}
   514  
   515  	// Augment the designated initial packages by their tests.
   516  	// Dependencies are loaded in parallel.
   517  	var xtestPkgs []*build.Package
   518  	for importPath, augment := range conf.ImportPkgs {
   519  		if !augment {
   520  			continue
   521  		}
   522  
   523  		// No vendor check on packages imported from command line.
   524  		bp, err := imp.findPackage(importPath, conf.Cwd, 0)
   525  		if err != nil {
   526  			// Package not found, or can't even parse package declaration.
   527  			// Already reported by previous loop; ignore it.
   528  			continue
   529  		}
   530  
   531  		// Needs external test package?
   532  		if len(bp.XTestGoFiles) > 0 {
   533  			xtestPkgs = append(xtestPkgs, bp)
   534  		}
   535  
   536  		// Consult the cache using the canonical package path.
   537  		path := bp.ImportPath
   538  		imp.importedMu.Lock() // (unnecessary, we're sequential here)
   539  		ii, ok := imp.imported[path]
   540  		// Paranoid checks added due to issue #11012.
   541  		if !ok {
   542  			// Unreachable.
   543  			// The previous loop called importAll and thus
   544  			// startLoad for each path in ImportPkgs, which
   545  			// populates imp.imported[path] with a non-zero value.
   546  			panic(fmt.Sprintf("imported[%q] not found", path))
   547  		}
   548  		if ii == nil {
   549  			// Unreachable.
   550  			// The ii values in this loop are the same as in
   551  			// the previous loop, which enforced the invariant
   552  			// that at least one of ii.err and ii.info is non-nil.
   553  			panic(fmt.Sprintf("imported[%q] == nil", path))
   554  		}
   555  		if ii.info == nil {
   556  			// Unreachable.
   557  			// awaitCompletion has the postcondition
   558  			// ii.info != nil.
   559  			panic(fmt.Sprintf("imported[%q].info = nil", path))
   560  		}
   561  		info := ii.info
   562  		imp.importedMu.Unlock()
   563  
   564  		// Parse the in-package test files.
   565  		files, errs := imp.conf.parsePackageFiles(bp, 't')
   566  		for _, err := range errs {
   567  			info.appendError(err)
   568  		}
   569  
   570  		// The test files augmenting package P cannot be imported,
   571  		// but may import packages that import P,
   572  		// so we must disable the cycle check.
   573  		imp.addFiles(info, files, false)
   574  	}
   575  
   576  	createPkg := func(path string, files []*ast.File, errs []error) {
   577  		// TODO(adonovan): fix: use dirname of files, not cwd.
   578  		info := imp.newPackageInfo(path, conf.Cwd)
   579  		for _, err := range errs {
   580  			info.appendError(err)
   581  		}
   582  
   583  		// Ad hoc packages are non-importable,
   584  		// so no cycle check is needed.
   585  		// addFiles loads dependencies in parallel.
   586  		imp.addFiles(info, files, false)
   587  		prog.Created = append(prog.Created, info)
   588  	}
   589  
   590  	// Create packages specified by conf.CreatePkgs.
   591  	for _, cp := range conf.CreatePkgs {
   592  		files, errs := parseFiles(conf.fset(), conf.build(), nil, ".", cp.Filenames, conf.ParserMode)
   593  		files = append(files, cp.Files...)
   594  
   595  		path := cp.Path
   596  		if path == "" {
   597  			if len(files) > 0 {
   598  				path = files[0].Name.Name
   599  			} else {
   600  				path = "(unnamed)"
   601  			}
   602  		}
   603  		createPkg(path, files, errs)
   604  	}
   605  
   606  	// Create external test packages.
   607  	sort.Sort(byImportPath(xtestPkgs))
   608  	for _, bp := range xtestPkgs {
   609  		files, errs := imp.conf.parsePackageFiles(bp, 'x')
   610  		createPkg(bp.ImportPath+"_test", files, errs)
   611  	}
   612  
   613  	// -- finishing up (sequential) ----------------------------------------
   614  
   615  	if len(prog.Imported)+len(prog.Created) == 0 {
   616  		return nil, errors.New("no initial packages were loaded")
   617  	}
   618  
   619  	// Create infos for indirectly imported packages.
   620  	// e.g. incomplete packages without syntax, loaded from export data.
   621  	for _, obj := range prog.importMap {
   622  		info := prog.AllPackages[obj]
   623  		if info == nil {
   624  			prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true}
   625  		} else {
   626  			// finished
   627  			info.checker = nil
   628  			info.errorFunc = nil
   629  		}
   630  	}
   631  
   632  	if !conf.AllowErrors {
   633  		// Report errors in indirectly imported packages.
   634  		for _, info := range prog.AllPackages {
   635  			if len(info.Errors) > 0 {
   636  				errpkgs = append(errpkgs, info.Pkg.Path())
   637  			}
   638  		}
   639  		if errpkgs != nil {
   640  			var more string
   641  			if len(errpkgs) > 3 {
   642  				more = fmt.Sprintf(" and %d more", len(errpkgs)-3)
   643  				errpkgs = errpkgs[:3]
   644  			}
   645  			return nil, fmt.Errorf("couldn't load packages due to errors: %s%s",
   646  				strings.Join(errpkgs, ", "), more)
   647  		}
   648  	}
   649  
   650  	markErrorFreePackages(prog.AllPackages)
   651  
   652  	return prog, nil
   653  }
   654  
   655  type byImportPath []*build.Package
   656  
   657  func (b byImportPath) Len() int           { return len(b) }
   658  func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath }
   659  func (b byImportPath) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
   660  
   661  // markErrorFreePackages sets the TransitivelyErrorFree flag on all
   662  // applicable packages.
   663  func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) {
   664  	// Build the transpose of the import graph.
   665  	importedBy := make(map[*types.Package]map[*types.Package]bool)
   666  	for P := range allPackages {
   667  		for _, Q := range P.Imports() {
   668  			clients, ok := importedBy[Q]
   669  			if !ok {
   670  				clients = make(map[*types.Package]bool)
   671  				importedBy[Q] = clients
   672  			}
   673  			clients[P] = true
   674  		}
   675  	}
   676  
   677  	// Find all packages reachable from some error package.
   678  	reachable := make(map[*types.Package]bool)
   679  	var visit func(*types.Package)
   680  	visit = func(p *types.Package) {
   681  		if !reachable[p] {
   682  			reachable[p] = true
   683  			for q := range importedBy[p] {
   684  				visit(q)
   685  			}
   686  		}
   687  	}
   688  	for _, info := range allPackages {
   689  		if len(info.Errors) > 0 {
   690  			visit(info.Pkg)
   691  		}
   692  	}
   693  
   694  	// Mark the others as "transitively error-free".
   695  	for _, info := range allPackages {
   696  		if !reachable[info.Pkg] {
   697  			info.TransitivelyErrorFree = true
   698  		}
   699  	}
   700  }
   701  
   702  // build returns the effective build context.
   703  func (conf *Config) build() *build.Context {
   704  	if conf.Build != nil {
   705  		return conf.Build
   706  	}
   707  	return &build.Default
   708  }
   709  
   710  // parsePackageFiles enumerates the files belonging to package path,
   711  // then loads, parses and returns them, plus a list of I/O or parse
   712  // errors that were encountered.
   713  //
   714  // 'which' indicates which files to include:
   715  //    'g': include non-test *.go source files (GoFiles + processed CgoFiles)
   716  //    't': include in-package *_test.go source files (TestGoFiles)
   717  //    'x': include external *_test.go source files. (XTestGoFiles)
   718  //
   719  func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) {
   720  	var filenames []string
   721  	switch which {
   722  	case 'g':
   723  		filenames = bp.GoFiles
   724  	case 't':
   725  		filenames = bp.TestGoFiles
   726  	case 'x':
   727  		filenames = bp.XTestGoFiles
   728  	default:
   729  		panic(which)
   730  	}
   731  
   732  	files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode)
   733  
   734  	// Preprocess CgoFiles and parse the outputs (sequentially).
   735  	if which == 'g' && bp.CgoFiles != nil {
   736  		cgofiles, err := processCgoFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode)
   737  		if err != nil {
   738  			errs = append(errs, err)
   739  		} else {
   740  			files = append(files, cgofiles...)
   741  		}
   742  	}
   743  
   744  	return files, errs
   745  }
   746  
   747  // doImport imports the package denoted by path.
   748  // It implements the types.Importer signature.
   749  //
   750  // It returns an error if a package could not be created
   751  // (e.g. go/build or parse error), but type errors are reported via
   752  // the types.Config.Error callback (the first of which is also saved
   753  // in the package's PackageInfo).
   754  //
   755  // Idempotent.
   756  //
   757  func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) {
   758  	// Package unsafe is handled specially, and has no PackageInfo.
   759  	// (Let's assume there is no "vendor/unsafe" package.)
   760  	if to == "unsafe" {
   761  		return types.Unsafe, nil
   762  	}
   763  	if to == "C" {
   764  		// This should be unreachable, but ad hoc packages are
   765  		// not currently subject to cgo preprocessing.
   766  		// See https://github.com/golang/go/issues/11627.
   767  		return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`,
   768  			from.Pkg.Path())
   769  	}
   770  
   771  	bp, err := imp.findPackage(to, from.dir, buildutil.AllowVendor)
   772  	if err != nil {
   773  		return nil, err
   774  	}
   775  
   776  	// Look for the package in the cache using its canonical path.
   777  	path := bp.ImportPath
   778  	imp.importedMu.Lock()
   779  	ii := imp.imported[path]
   780  	imp.importedMu.Unlock()
   781  	if ii == nil {
   782  		panic("internal error: unexpected import: " + path)
   783  	}
   784  	if ii.info != nil {
   785  		return ii.info.Pkg, nil
   786  	}
   787  
   788  	// Import of incomplete package: this indicates a cycle.
   789  	fromPath := from.Pkg.Path()
   790  	if cycle := imp.findPath(path, fromPath); cycle != nil {
   791  		cycle = append([]string{fromPath}, cycle...)
   792  		return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> "))
   793  	}
   794  
   795  	panic("internal error: import of incomplete (yet acyclic) package: " + fromPath)
   796  }
   797  
   798  // findPackage locates the package denoted by the importPath in the
   799  // specified directory.
   800  func (imp *importer) findPackage(importPath, fromDir string, mode build.ImportMode) (*build.Package, error) {
   801  	// TODO(adonovan): opt: non-blocking duplicate-suppressing cache.
   802  	// i.e. don't hold the lock around FindPackage.
   803  	key := findpkgKey{importPath, fromDir, mode}
   804  	imp.findpkgMu.Lock()
   805  	defer imp.findpkgMu.Unlock()
   806  	v, ok := imp.findpkg[key]
   807  	if !ok {
   808  		bp, err := imp.conf.FindPackage(imp.conf.build(), importPath, fromDir, mode)
   809  		v = findpkgValue{bp, err}
   810  		imp.findpkg[key] = v
   811  	}
   812  	return v.bp, v.err
   813  }
   814  
   815  // importAll loads, parses, and type-checks the specified packages in
   816  // parallel and returns their completed importInfos in unspecified order.
   817  //
   818  // fromPath is the package path of the importing package, if it is
   819  // importable, "" otherwise.  It is used for cycle detection.
   820  //
   821  // fromDir is the directory containing the import declaration that
   822  // caused these imports.
   823  //
   824  func (imp *importer) importAll(fromPath, fromDir string, imports map[string]bool, mode build.ImportMode) (infos []*PackageInfo, errors []importError) {
   825  	// TODO(adonovan): opt: do the loop in parallel once
   826  	// findPackage is non-blocking.
   827  	var pending []*importInfo
   828  	for importPath := range imports {
   829  		bp, err := imp.findPackage(importPath, fromDir, mode)
   830  		if err != nil {
   831  			errors = append(errors, importError{
   832  				path: importPath,
   833  				err:  err,
   834  			})
   835  			continue
   836  		}
   837  		pending = append(pending, imp.startLoad(bp))
   838  	}
   839  
   840  	if fromPath != "" {
   841  		// We're loading a set of imports.
   842  		//
   843  		// We must record graph edges from the importing package
   844  		// to its dependencies, and check for cycles.
   845  		imp.graphMu.Lock()
   846  		deps, ok := imp.graph[fromPath]
   847  		if !ok {
   848  			deps = make(map[string]bool)
   849  			imp.graph[fromPath] = deps
   850  		}
   851  		for _, ii := range pending {
   852  			deps[ii.path] = true
   853  		}
   854  		imp.graphMu.Unlock()
   855  	}
   856  
   857  	for _, ii := range pending {
   858  		if fromPath != "" {
   859  			if cycle := imp.findPath(ii.path, fromPath); cycle != nil {
   860  				// Cycle-forming import: we must not await its
   861  				// completion since it would deadlock.
   862  				//
   863  				// We don't record the error in ii since
   864  				// the error is really associated with the
   865  				// cycle-forming edge, not the package itself.
   866  				// (Also it would complicate the
   867  				// invariants of importPath completion.)
   868  				if trace {
   869  					fmt.Fprintln(os.Stderr, "import cycle: %q", cycle)
   870  				}
   871  				continue
   872  			}
   873  		}
   874  		ii.awaitCompletion()
   875  		infos = append(infos, ii.info)
   876  	}
   877  
   878  	return infos, errors
   879  }
   880  
   881  // findPath returns an arbitrary path from 'from' to 'to' in the import
   882  // graph, or nil if there was none.
   883  func (imp *importer) findPath(from, to string) []string {
   884  	imp.graphMu.Lock()
   885  	defer imp.graphMu.Unlock()
   886  
   887  	seen := make(map[string]bool)
   888  	var search func(stack []string, importPath string) []string
   889  	search = func(stack []string, importPath string) []string {
   890  		if !seen[importPath] {
   891  			seen[importPath] = true
   892  			stack = append(stack, importPath)
   893  			if importPath == to {
   894  				return stack
   895  			}
   896  			for x := range imp.graph[importPath] {
   897  				if p := search(stack, x); p != nil {
   898  					return p
   899  				}
   900  			}
   901  		}
   902  		return nil
   903  	}
   904  	return search(make([]string, 0, 20), from)
   905  }
   906  
   907  // startLoad initiates the loading, parsing and type-checking of the
   908  // specified package and its dependencies, if it has not already begun.
   909  //
   910  // It returns an importInfo, not necessarily in a completed state.  The
   911  // caller must call awaitCompletion() before accessing its info field.
   912  //
   913  // startLoad is concurrency-safe and idempotent.
   914  //
   915  func (imp *importer) startLoad(bp *build.Package) *importInfo {
   916  	path := bp.ImportPath
   917  	imp.importedMu.Lock()
   918  	ii, ok := imp.imported[path]
   919  	if !ok {
   920  		ii = &importInfo{path: path, complete: make(chan struct{})}
   921  		imp.imported[path] = ii
   922  		go func() {
   923  			info := imp.load(bp)
   924  			ii.Complete(info)
   925  		}()
   926  	}
   927  	imp.importedMu.Unlock()
   928  
   929  	return ii
   930  }
   931  
   932  // load implements package loading by parsing Go source files
   933  // located by go/build.
   934  func (imp *importer) load(bp *build.Package) *PackageInfo {
   935  	info := imp.newPackageInfo(bp.ImportPath, bp.Dir)
   936  	info.Importable = true
   937  	files, errs := imp.conf.parsePackageFiles(bp, 'g')
   938  	for _, err := range errs {
   939  		info.appendError(err)
   940  	}
   941  
   942  	imp.addFiles(info, files, true)
   943  
   944  	imp.progMu.Lock()
   945  	imp.prog.importMap[bp.ImportPath] = info.Pkg
   946  	imp.progMu.Unlock()
   947  
   948  	return info
   949  }
   950  
   951  // addFiles adds and type-checks the specified files to info, loading
   952  // their dependencies if needed.  The order of files determines the
   953  // package initialization order.  It may be called multiple times on the
   954  // same package.  Errors are appended to the info.Errors field.
   955  //
   956  // cycleCheck determines whether the imports within files create
   957  // dependency edges that should be checked for potential cycles.
   958  //
   959  func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
   960  	info.Files = append(info.Files, files...)
   961  
   962  	// Ensure the dependencies are loaded, in parallel.
   963  	var fromPath string
   964  	if cycleCheck {
   965  		fromPath = info.Pkg.Path()
   966  	}
   967  	// TODO(adonovan): opt: make the caller do scanImports.
   968  	// Callers with a build.Package can skip it.
   969  	imp.importAll(fromPath, info.dir, scanImports(files), buildutil.AllowVendor)
   970  
   971  	if trace {
   972  		fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n",
   973  			time.Since(imp.start), info.Pkg.Path(), len(files))
   974  	}
   975  
   976  	// Ignore the returned (first) error since we
   977  	// already collect them all in the PackageInfo.
   978  	info.checker.Files(files)
   979  
   980  	if trace {
   981  		fmt.Fprintf(os.Stderr, "%s: stop %q\n",
   982  			time.Since(imp.start), info.Pkg.Path())
   983  	}
   984  }
   985  
   986  func (imp *importer) newPackageInfo(path, dir string) *PackageInfo {
   987  	pkg := types.NewPackage(path, "")
   988  	info := &PackageInfo{
   989  		Pkg: pkg,
   990  		Info: types.Info{
   991  			Types:      make(map[ast.Expr]types.TypeAndValue),
   992  			Defs:       make(map[*ast.Ident]types.Object),
   993  			Uses:       make(map[*ast.Ident]types.Object),
   994  			Implicits:  make(map[ast.Node]types.Object),
   995  			Scopes:     make(map[ast.Node]*types.Scope),
   996  			Selections: make(map[*ast.SelectorExpr]*types.Selection),
   997  		},
   998  		errorFunc: imp.conf.TypeChecker.Error,
   999  		dir:       dir,
  1000  	}
  1001  
  1002  	// Copy the types.Config so we can vary it across PackageInfos.
  1003  	tc := imp.conf.TypeChecker
  1004  	tc.IgnoreFuncBodies = false
  1005  	if f := imp.conf.TypeCheckFuncBodies; f != nil {
  1006  		tc.IgnoreFuncBodies = !f(path)
  1007  	}
  1008  	tc.Importer = closure{imp, info}
  1009  	tc.Error = info.appendError // appendError wraps the user's Error function
  1010  
  1011  	info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
  1012  	imp.progMu.Lock()
  1013  	imp.prog.AllPackages[pkg] = info
  1014  	imp.progMu.Unlock()
  1015  	return info
  1016  }
  1017  
  1018  type closure struct {
  1019  	imp  *importer
  1020  	info *PackageInfo
  1021  }
  1022  
  1023  func (c closure) Import(to string) (*types.Package, error) { return c.imp.doImport(c.info, to) }