github.com/april1989/origin-go-tools@v0.0.32/internal/imports/fix.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  package imports
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"go/ast"
    13  	"go/build"
    14  	"go/parser"
    15  	"go/token"
    16  	"io/ioutil"
    17  	"os"
    18  	"path"
    19  	"path/filepath"
    20  	"reflect"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"unicode"
    26  	"unicode/utf8"
    27  
    28  	"github.com/april1989/origin-go-tools/go/ast/astutil"
    29  	"github.com/april1989/origin-go-tools/internal/gocommand"
    30  	"github.com/april1989/origin-go-tools/internal/gopathwalk"
    31  )
    32  
    33  // importToGroup is a list of functions which map from an import path to
    34  // a group number.
    35  var importToGroup = []func(localPrefix, importPath string) (num int, ok bool){
    36  	func(localPrefix, importPath string) (num int, ok bool) {
    37  		if localPrefix == "" {
    38  			return
    39  		}
    40  		for _, p := range strings.Split(localPrefix, ",") {
    41  			if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath {
    42  				return 3, true
    43  			}
    44  		}
    45  		return
    46  	},
    47  	func(_, importPath string) (num int, ok bool) {
    48  		if strings.HasPrefix(importPath, "appengine") {
    49  			return 2, true
    50  		}
    51  		return
    52  	},
    53  	func(_, importPath string) (num int, ok bool) {
    54  		firstComponent := strings.Split(importPath, "/")[0]
    55  		if strings.Contains(firstComponent, ".") {
    56  			return 1, true
    57  		}
    58  		return
    59  	},
    60  }
    61  
    62  func importGroup(localPrefix, importPath string) int {
    63  	for _, fn := range importToGroup {
    64  		if n, ok := fn(localPrefix, importPath); ok {
    65  			return n
    66  		}
    67  	}
    68  	return 0
    69  }
    70  
    71  type ImportFixType int
    72  
    73  const (
    74  	AddImport ImportFixType = iota
    75  	DeleteImport
    76  	SetImportName
    77  )
    78  
    79  type ImportFix struct {
    80  	// StmtInfo represents the import statement this fix will add, remove, or change.
    81  	StmtInfo ImportInfo
    82  	// IdentName is the identifier that this fix will add or remove.
    83  	IdentName string
    84  	// FixType is the type of fix this is (AddImport, DeleteImport, SetImportName).
    85  	FixType   ImportFixType
    86  	Relevance int // see pkg
    87  }
    88  
    89  // An ImportInfo represents a single import statement.
    90  type ImportInfo struct {
    91  	ImportPath string // import path, e.g. "crypto/rand".
    92  	Name       string // import name, e.g. "crand", or "" if none.
    93  }
    94  
    95  // A packageInfo represents what's known about a package.
    96  type packageInfo struct {
    97  	name    string          // real package name, if known.
    98  	exports map[string]bool // known exports.
    99  }
   100  
   101  // parseOtherFiles parses all the Go files in srcDir except filename, including
   102  // test files if filename looks like a test.
   103  func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File {
   104  	// This could use go/packages but it doesn't buy much, and it fails
   105  	// with https://golang.org/issue/26296 in LoadFiles mode in some cases.
   106  	considerTests := strings.HasSuffix(filename, "_test.go")
   107  
   108  	fileBase := filepath.Base(filename)
   109  	packageFileInfos, err := ioutil.ReadDir(srcDir)
   110  	if err != nil {
   111  		return nil
   112  	}
   113  
   114  	var files []*ast.File
   115  	for _, fi := range packageFileInfos {
   116  		if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") {
   117  			continue
   118  		}
   119  		if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") {
   120  			continue
   121  		}
   122  
   123  		f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, 0)
   124  		if err != nil {
   125  			continue
   126  		}
   127  
   128  		files = append(files, f)
   129  	}
   130  
   131  	return files
   132  }
   133  
   134  // addGlobals puts the names of package vars into the provided map.
   135  func addGlobals(f *ast.File, globals map[string]bool) {
   136  	for _, decl := range f.Decls {
   137  		genDecl, ok := decl.(*ast.GenDecl)
   138  		if !ok {
   139  			continue
   140  		}
   141  
   142  		for _, spec := range genDecl.Specs {
   143  			valueSpec, ok := spec.(*ast.ValueSpec)
   144  			if !ok {
   145  				continue
   146  			}
   147  			globals[valueSpec.Names[0].Name] = true
   148  		}
   149  	}
   150  }
   151  
   152  // collectReferences builds a map of selector expressions, from
   153  // left hand side (X) to a set of right hand sides (Sel).
   154  func collectReferences(f *ast.File) references {
   155  	refs := references{}
   156  
   157  	var visitor visitFn
   158  	visitor = func(node ast.Node) ast.Visitor {
   159  		if node == nil {
   160  			return visitor
   161  		}
   162  		switch v := node.(type) {
   163  		case *ast.SelectorExpr:
   164  			xident, ok := v.X.(*ast.Ident)
   165  			if !ok {
   166  				break
   167  			}
   168  			if xident.Obj != nil {
   169  				// If the parser can resolve it, it's not a package ref.
   170  				break
   171  			}
   172  			if !ast.IsExported(v.Sel.Name) {
   173  				// Whatever this is, it's not exported from a package.
   174  				break
   175  			}
   176  			pkgName := xident.Name
   177  			r := refs[pkgName]
   178  			if r == nil {
   179  				r = make(map[string]bool)
   180  				refs[pkgName] = r
   181  			}
   182  			r[v.Sel.Name] = true
   183  		}
   184  		return visitor
   185  	}
   186  	ast.Walk(visitor, f)
   187  	return refs
   188  }
   189  
   190  // collectImports returns all the imports in f.
   191  // Unnamed imports (., _) and "C" are ignored.
   192  func collectImports(f *ast.File) []*ImportInfo {
   193  	var imports []*ImportInfo
   194  	for _, imp := range f.Imports {
   195  		var name string
   196  		if imp.Name != nil {
   197  			name = imp.Name.Name
   198  		}
   199  		if imp.Path.Value == `"C"` || name == "_" || name == "." {
   200  			continue
   201  		}
   202  		path := strings.Trim(imp.Path.Value, `"`)
   203  		imports = append(imports, &ImportInfo{
   204  			Name:       name,
   205  			ImportPath: path,
   206  		})
   207  	}
   208  	return imports
   209  }
   210  
   211  // findMissingImport searches pass's candidates for an import that provides
   212  // pkg, containing all of syms.
   213  func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo {
   214  	for _, candidate := range p.candidates {
   215  		pkgInfo, ok := p.knownPackages[candidate.ImportPath]
   216  		if !ok {
   217  			continue
   218  		}
   219  		if p.importIdentifier(candidate) != pkg {
   220  			continue
   221  		}
   222  
   223  		allFound := true
   224  		for right := range syms {
   225  			if !pkgInfo.exports[right] {
   226  				allFound = false
   227  				break
   228  			}
   229  		}
   230  
   231  		if allFound {
   232  			return candidate
   233  		}
   234  	}
   235  	return nil
   236  }
   237  
   238  // references is set of references found in a Go file. The first map key is the
   239  // left hand side of a selector expression, the second key is the right hand
   240  // side, and the value should always be true.
   241  type references map[string]map[string]bool
   242  
   243  // A pass contains all the inputs and state necessary to fix a file's imports.
   244  // It can be modified in some ways during use; see comments below.
   245  type pass struct {
   246  	// Inputs. These must be set before a call to load, and not modified after.
   247  	fset                 *token.FileSet // fset used to parse f and its siblings.
   248  	f                    *ast.File      // the file being fixed.
   249  	srcDir               string         // the directory containing f.
   250  	env                  *ProcessEnv    // the environment to use for go commands, etc.
   251  	loadRealPackageNames bool           // if true, load package names from disk rather than guessing them.
   252  	otherFiles           []*ast.File    // sibling files.
   253  
   254  	// Intermediate state, generated by load.
   255  	existingImports map[string]*ImportInfo
   256  	allRefs         references
   257  	missingRefs     references
   258  
   259  	// Inputs to fix. These can be augmented between successive fix calls.
   260  	lastTry       bool                    // indicates that this is the last call and fix should clean up as best it can.
   261  	candidates    []*ImportInfo           // candidate imports in priority order.
   262  	knownPackages map[string]*packageInfo // information about all known packages.
   263  }
   264  
   265  // loadPackageNames saves the package names for everything referenced by imports.
   266  func (p *pass) loadPackageNames(imports []*ImportInfo) error {
   267  	if p.env.Logf != nil {
   268  		p.env.Logf("loading package names for %v packages", len(imports))
   269  		defer func() {
   270  			p.env.Logf("done loading package names for %v packages", len(imports))
   271  		}()
   272  	}
   273  	var unknown []string
   274  	for _, imp := range imports {
   275  		if _, ok := p.knownPackages[imp.ImportPath]; ok {
   276  			continue
   277  		}
   278  		unknown = append(unknown, imp.ImportPath)
   279  	}
   280  
   281  	resolver, err := p.env.GetResolver()
   282  	if err != nil {
   283  		return err
   284  	}
   285  
   286  	names, err := resolver.loadPackageNames(unknown, p.srcDir)
   287  	if err != nil {
   288  		return err
   289  	}
   290  
   291  	for path, name := range names {
   292  		p.knownPackages[path] = &packageInfo{
   293  			name:    name,
   294  			exports: map[string]bool{},
   295  		}
   296  	}
   297  	return nil
   298  }
   299  
   300  // importIdentifier returns the identifier that imp will introduce. It will
   301  // guess if the package name has not been loaded, e.g. because the source
   302  // is not available.
   303  func (p *pass) importIdentifier(imp *ImportInfo) string {
   304  	if imp.Name != "" {
   305  		return imp.Name
   306  	}
   307  	known := p.knownPackages[imp.ImportPath]
   308  	if known != nil && known.name != "" {
   309  		return known.name
   310  	}
   311  	return ImportPathToAssumedName(imp.ImportPath)
   312  }
   313  
   314  // load reads in everything necessary to run a pass, and reports whether the
   315  // file already has all the imports it needs. It fills in p.missingRefs with the
   316  // file's missing symbols, if any, or removes unused imports if not.
   317  func (p *pass) load() ([]*ImportFix, bool) {
   318  	p.knownPackages = map[string]*packageInfo{}
   319  	p.missingRefs = references{}
   320  	p.existingImports = map[string]*ImportInfo{}
   321  
   322  	// Load basic information about the file in question.
   323  	p.allRefs = collectReferences(p.f)
   324  
   325  	// Load stuff from other files in the same package:
   326  	// global variables so we know they don't need resolving, and imports
   327  	// that we might want to mimic.
   328  	globals := map[string]bool{}
   329  	for _, otherFile := range p.otherFiles {
   330  		// Don't load globals from files that are in the same directory
   331  		// but a different package. Using them to suggest imports is OK.
   332  		if p.f.Name.Name == otherFile.Name.Name {
   333  			addGlobals(otherFile, globals)
   334  		}
   335  		p.candidates = append(p.candidates, collectImports(otherFile)...)
   336  	}
   337  
   338  	// Resolve all the import paths we've seen to package names, and store
   339  	// f's imports by the identifier they introduce.
   340  	imports := collectImports(p.f)
   341  	if p.loadRealPackageNames {
   342  		err := p.loadPackageNames(append(imports, p.candidates...))
   343  		if err != nil {
   344  			if p.env.Logf != nil {
   345  				p.env.Logf("loading package names: %v", err)
   346  			}
   347  			return nil, false
   348  		}
   349  	}
   350  	for _, imp := range imports {
   351  		p.existingImports[p.importIdentifier(imp)] = imp
   352  	}
   353  
   354  	// Find missing references.
   355  	for left, rights := range p.allRefs {
   356  		if globals[left] {
   357  			continue
   358  		}
   359  		_, ok := p.existingImports[left]
   360  		if !ok {
   361  			p.missingRefs[left] = rights
   362  			continue
   363  		}
   364  	}
   365  	if len(p.missingRefs) != 0 {
   366  		return nil, false
   367  	}
   368  
   369  	return p.fix()
   370  }
   371  
   372  // fix attempts to satisfy missing imports using p.candidates. If it finds
   373  // everything, or if p.lastTry is true, it updates fixes to add the imports it found,
   374  // delete anything unused, and update import names, and returns true.
   375  func (p *pass) fix() ([]*ImportFix, bool) {
   376  	// Find missing imports.
   377  	var selected []*ImportInfo
   378  	for left, rights := range p.missingRefs {
   379  		if imp := p.findMissingImport(left, rights); imp != nil {
   380  			selected = append(selected, imp)
   381  		}
   382  	}
   383  
   384  	if !p.lastTry && len(selected) != len(p.missingRefs) {
   385  		return nil, false
   386  	}
   387  
   388  	// Found everything, or giving up. Add the new imports and remove any unused.
   389  	var fixes []*ImportFix
   390  	for _, imp := range p.existingImports {
   391  		// We deliberately ignore globals here, because we can't be sure
   392  		// they're in the same package. People do things like put multiple
   393  		// main packages in the same directory, and we don't want to
   394  		// remove imports if they happen to have the same name as a var in
   395  		// a different package.
   396  		if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok {
   397  			fixes = append(fixes, &ImportFix{
   398  				StmtInfo:  *imp,
   399  				IdentName: p.importIdentifier(imp),
   400  				FixType:   DeleteImport,
   401  			})
   402  			continue
   403  		}
   404  
   405  		// An existing import may need to update its import name to be correct.
   406  		if name := p.importSpecName(imp); name != imp.Name {
   407  			fixes = append(fixes, &ImportFix{
   408  				StmtInfo: ImportInfo{
   409  					Name:       name,
   410  					ImportPath: imp.ImportPath,
   411  				},
   412  				IdentName: p.importIdentifier(imp),
   413  				FixType:   SetImportName,
   414  			})
   415  		}
   416  	}
   417  
   418  	for _, imp := range selected {
   419  		fixes = append(fixes, &ImportFix{
   420  			StmtInfo: ImportInfo{
   421  				Name:       p.importSpecName(imp),
   422  				ImportPath: imp.ImportPath,
   423  			},
   424  			IdentName: p.importIdentifier(imp),
   425  			FixType:   AddImport,
   426  		})
   427  	}
   428  
   429  	return fixes, true
   430  }
   431  
   432  // importSpecName gets the import name of imp in the import spec.
   433  //
   434  // When the import identifier matches the assumed import name, the import name does
   435  // not appear in the import spec.
   436  func (p *pass) importSpecName(imp *ImportInfo) string {
   437  	// If we did not load the real package names, or the name is already set,
   438  	// we just return the existing name.
   439  	if !p.loadRealPackageNames || imp.Name != "" {
   440  		return imp.Name
   441  	}
   442  
   443  	ident := p.importIdentifier(imp)
   444  	if ident == ImportPathToAssumedName(imp.ImportPath) {
   445  		return "" // ident not needed since the assumed and real names are the same.
   446  	}
   447  	return ident
   448  }
   449  
   450  // apply will perform the fixes on f in order.
   451  func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) {
   452  	for _, fix := range fixes {
   453  		switch fix.FixType {
   454  		case DeleteImport:
   455  			astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
   456  		case AddImport:
   457  			astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
   458  		case SetImportName:
   459  			// Find the matching import path and change the name.
   460  			for _, spec := range f.Imports {
   461  				path := strings.Trim(spec.Path.Value, `"`)
   462  				if path == fix.StmtInfo.ImportPath {
   463  					spec.Name = &ast.Ident{
   464  						Name:    fix.StmtInfo.Name,
   465  						NamePos: spec.Pos(),
   466  					}
   467  				}
   468  			}
   469  		}
   470  	}
   471  }
   472  
   473  // assumeSiblingImportsValid assumes that siblings' use of packages is valid,
   474  // adding the exports they use.
   475  func (p *pass) assumeSiblingImportsValid() {
   476  	for _, f := range p.otherFiles {
   477  		refs := collectReferences(f)
   478  		imports := collectImports(f)
   479  		importsByName := map[string]*ImportInfo{}
   480  		for _, imp := range imports {
   481  			importsByName[p.importIdentifier(imp)] = imp
   482  		}
   483  		for left, rights := range refs {
   484  			if imp, ok := importsByName[left]; ok {
   485  				if m, ok := stdlib[imp.ImportPath]; ok {
   486  					// We have the stdlib in memory; no need to guess.
   487  					rights = copyExports(m)
   488  				}
   489  				p.addCandidate(imp, &packageInfo{
   490  					// no name; we already know it.
   491  					exports: rights,
   492  				})
   493  			}
   494  		}
   495  	}
   496  }
   497  
   498  // addCandidate adds a candidate import to p, and merges in the information
   499  // in pkg.
   500  func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) {
   501  	p.candidates = append(p.candidates, imp)
   502  	if existing, ok := p.knownPackages[imp.ImportPath]; ok {
   503  		if existing.name == "" {
   504  			existing.name = pkg.name
   505  		}
   506  		for export := range pkg.exports {
   507  			existing.exports[export] = true
   508  		}
   509  	} else {
   510  		p.knownPackages[imp.ImportPath] = pkg
   511  	}
   512  }
   513  
   514  // fixImports adds and removes imports from f so that all its references are
   515  // satisfied and there are no unused imports.
   516  //
   517  // This is declared as a variable rather than a function so goimports can
   518  // easily be extended by adding a file with an init function.
   519  var fixImports = fixImportsDefault
   520  
   521  func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error {
   522  	fixes, err := getFixes(fset, f, filename, env)
   523  	if err != nil {
   524  		return err
   525  	}
   526  	apply(fset, f, fixes)
   527  	return err
   528  }
   529  
   530  // getFixes gets the import fixes that need to be made to f in order to fix the imports.
   531  // It does not modify the ast.
   532  func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) {
   533  	abs, err := filepath.Abs(filename)
   534  	if err != nil {
   535  		return nil, err
   536  	}
   537  	srcDir := filepath.Dir(abs)
   538  	if env.Logf != nil {
   539  		env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
   540  	}
   541  
   542  	// First pass: looking only at f, and using the naive algorithm to
   543  	// derive package names from import paths, see if the file is already
   544  	// complete. We can't add any imports yet, because we don't know
   545  	// if missing references are actually package vars.
   546  	p := &pass{fset: fset, f: f, srcDir: srcDir, env: env}
   547  	if fixes, done := p.load(); done {
   548  		return fixes, nil
   549  	}
   550  
   551  	otherFiles := parseOtherFiles(fset, srcDir, filename)
   552  
   553  	// Second pass: add information from other files in the same package,
   554  	// like their package vars and imports.
   555  	p.otherFiles = otherFiles
   556  	if fixes, done := p.load(); done {
   557  		return fixes, nil
   558  	}
   559  
   560  	// Now we can try adding imports from the stdlib.
   561  	p.assumeSiblingImportsValid()
   562  	addStdlibCandidates(p, p.missingRefs)
   563  	if fixes, done := p.fix(); done {
   564  		return fixes, nil
   565  	}
   566  
   567  	// Third pass: get real package names where we had previously used
   568  	// the naive algorithm.
   569  	p = &pass{fset: fset, f: f, srcDir: srcDir, env: env}
   570  	p.loadRealPackageNames = true
   571  	p.otherFiles = otherFiles
   572  	if fixes, done := p.load(); done {
   573  		return fixes, nil
   574  	}
   575  
   576  	if err := addStdlibCandidates(p, p.missingRefs); err != nil {
   577  		return nil, err
   578  	}
   579  	p.assumeSiblingImportsValid()
   580  	if fixes, done := p.fix(); done {
   581  		return fixes, nil
   582  	}
   583  
   584  	// Go look for candidates in $GOPATH, etc. We don't necessarily load
   585  	// the real exports of sibling imports, so keep assuming their contents.
   586  	if err := addExternalCandidates(p, p.missingRefs, filename); err != nil {
   587  		return nil, err
   588  	}
   589  
   590  	p.lastTry = true
   591  	fixes, _ := p.fix()
   592  	return fixes, nil
   593  }
   594  
   595  // Highest relevance, used for the standard library. Chosen arbitrarily to
   596  // match pre-existing gopls code.
   597  const MaxRelevance = 7
   598  
   599  // getCandidatePkgs works with the passed callback to find all acceptable packages.
   600  // It deduplicates by import path, and uses a cached stdlib rather than reading
   601  // from disk.
   602  func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filename, filePkg string, env *ProcessEnv) error {
   603  	notSelf := func(p *pkg) bool {
   604  		return p.packageName != filePkg || p.dir != filepath.Dir(filename)
   605  	}
   606  	goenv, err := env.goEnv()
   607  	if err != nil {
   608  		return err
   609  	}
   610  	// Start off with the standard library.
   611  	for importPath, exports := range stdlib {
   612  		p := &pkg{
   613  			dir:             filepath.Join(goenv["GOROOT"], "src", importPath),
   614  			importPathShort: importPath,
   615  			packageName:     path.Base(importPath),
   616  			relevance:       MaxRelevance,
   617  		}
   618  		if notSelf(p) && wrappedCallback.dirFound(p) && wrappedCallback.packageNameLoaded(p) {
   619  			wrappedCallback.exportsLoaded(p, exports)
   620  		}
   621  	}
   622  
   623  	var mu sync.Mutex
   624  	dupCheck := map[string]struct{}{}
   625  
   626  	scanFilter := &scanCallback{
   627  		rootFound: func(root gopathwalk.Root) bool {
   628  			// Exclude goroot results -- getting them is relatively expensive, not cached,
   629  			// and generally redundant with the in-memory version.
   630  			return root.Type != gopathwalk.RootGOROOT && wrappedCallback.rootFound(root)
   631  		},
   632  		dirFound: wrappedCallback.dirFound,
   633  		packageNameLoaded: func(pkg *pkg) bool {
   634  			mu.Lock()
   635  			defer mu.Unlock()
   636  			if _, ok := dupCheck[pkg.importPathShort]; ok {
   637  				return false
   638  			}
   639  			dupCheck[pkg.importPathShort] = struct{}{}
   640  			return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg)
   641  		},
   642  		exportsLoaded: func(pkg *pkg, exports []string) {
   643  			// If we're an x_test, load the package under test's test variant.
   644  			if strings.HasSuffix(filePkg, "_test") && pkg.dir == filepath.Dir(filename) {
   645  				var err error
   646  				_, exports, err = loadExportsFromFiles(ctx, env, pkg.dir, true)
   647  				if err != nil {
   648  					return
   649  				}
   650  			}
   651  			wrappedCallback.exportsLoaded(pkg, exports)
   652  		},
   653  	}
   654  	resolver, err := env.GetResolver()
   655  	if err != nil {
   656  		return err
   657  	}
   658  	return resolver.scan(ctx, scanFilter)
   659  }
   660  
   661  func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) (map[string]int, error) {
   662  	result := make(map[string]int)
   663  	resolver, err := env.GetResolver()
   664  	if err != nil {
   665  		return nil, err
   666  	}
   667  	for _, path := range paths {
   668  		result[path] = resolver.scoreImportPath(ctx, path)
   669  	}
   670  	return result, nil
   671  }
   672  
   673  func PrimeCache(ctx context.Context, env *ProcessEnv) error {
   674  	// Fully scan the disk for directories, but don't actually read any Go files.
   675  	callback := &scanCallback{
   676  		rootFound: func(gopathwalk.Root) bool {
   677  			return true
   678  		},
   679  		dirFound: func(pkg *pkg) bool {
   680  			return false
   681  		},
   682  		packageNameLoaded: func(pkg *pkg) bool {
   683  			return false
   684  		},
   685  	}
   686  	return getCandidatePkgs(ctx, callback, "", "", env)
   687  }
   688  
   689  func candidateImportName(pkg *pkg) string {
   690  	if ImportPathToAssumedName(pkg.importPathShort) != pkg.packageName {
   691  		return pkg.packageName
   692  	}
   693  	return ""
   694  }
   695  
   696  // GetAllCandidates calls wrapped for each package whose name starts with
   697  // searchPrefix, and can be imported from filename with the package name filePkg.
   698  func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
   699  	callback := &scanCallback{
   700  		rootFound: func(gopathwalk.Root) bool {
   701  			return true
   702  		},
   703  		dirFound: func(pkg *pkg) bool {
   704  			if !canUse(filename, pkg.dir) {
   705  				return false
   706  			}
   707  			// Try the assumed package name first, then a simpler path match
   708  			// in case of packages named vN, which are not uncommon.
   709  			return strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) ||
   710  				strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix)
   711  		},
   712  		packageNameLoaded: func(pkg *pkg) bool {
   713  			if !strings.HasPrefix(pkg.packageName, searchPrefix) {
   714  				return false
   715  			}
   716  			wrapped(ImportFix{
   717  				StmtInfo: ImportInfo{
   718  					ImportPath: pkg.importPathShort,
   719  					Name:       candidateImportName(pkg),
   720  				},
   721  				IdentName: pkg.packageName,
   722  				FixType:   AddImport,
   723  				Relevance: pkg.relevance,
   724  			})
   725  			return false
   726  		},
   727  	}
   728  	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
   729  }
   730  
   731  // GetImportPaths calls wrapped for each package whose import path starts with
   732  // searchPrefix, and can be imported from filename with the package name filePkg.
   733  func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
   734  	callback := &scanCallback{
   735  		rootFound: func(gopathwalk.Root) bool {
   736  			return true
   737  		},
   738  		dirFound: func(pkg *pkg) bool {
   739  			if !canUse(filename, pkg.dir) {
   740  				return false
   741  			}
   742  			return strings.HasPrefix(pkg.importPathShort, searchPrefix)
   743  		},
   744  		packageNameLoaded: func(pkg *pkg) bool {
   745  			wrapped(ImportFix{
   746  				StmtInfo: ImportInfo{
   747  					ImportPath: pkg.importPathShort,
   748  					Name:       candidateImportName(pkg),
   749  				},
   750  				IdentName: pkg.packageName,
   751  				FixType:   AddImport,
   752  				Relevance: pkg.relevance,
   753  			})
   754  			return false
   755  		},
   756  	}
   757  	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
   758  }
   759  
   760  // A PackageExport is a package and its exports.
   761  type PackageExport struct {
   762  	Fix     *ImportFix
   763  	Exports []string
   764  }
   765  
   766  // GetPackageExports returns all known packages with name pkg and their exports.
   767  func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchPkg, filename, filePkg string, env *ProcessEnv) error {
   768  	callback := &scanCallback{
   769  		rootFound: func(gopathwalk.Root) bool {
   770  			return true
   771  		},
   772  		dirFound: func(pkg *pkg) bool {
   773  			return pkgIsCandidate(filename, references{searchPkg: nil}, pkg)
   774  		},
   775  		packageNameLoaded: func(pkg *pkg) bool {
   776  			return pkg.packageName == searchPkg
   777  		},
   778  		exportsLoaded: func(pkg *pkg, exports []string) {
   779  			sort.Strings(exports)
   780  			wrapped(PackageExport{
   781  				Fix: &ImportFix{
   782  					StmtInfo: ImportInfo{
   783  						ImportPath: pkg.importPathShort,
   784  						Name:       candidateImportName(pkg),
   785  					},
   786  					IdentName: pkg.packageName,
   787  					FixType:   AddImport,
   788  					Relevance: pkg.relevance,
   789  				},
   790  				Exports: exports,
   791  			})
   792  		},
   793  	}
   794  	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
   795  }
   796  
   797  var RequiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB"}
   798  
   799  // ProcessEnv contains environment variables and settings that affect the use of
   800  // the go command, the go/build package, etc.
   801  type ProcessEnv struct {
   802  	GocmdRunner *gocommand.Runner
   803  
   804  	BuildFlags []string
   805  
   806  	// Env overrides the OS environment, and can be used to specify
   807  	// GOPROXY, GO111MODULE, etc. PATH cannot be set here, because
   808  	// exec.Command will not honor it.
   809  	// Specifying all of RequiredGoEnvVars avoids a call to `go env`.
   810  	Env map[string]string
   811  
   812  	WorkingDir string
   813  
   814  	// If Logf is non-nil, debug logging is enabled through this function.
   815  	Logf func(format string, args ...interface{})
   816  
   817  	initialized bool
   818  
   819  	resolver Resolver
   820  }
   821  
   822  func (e *ProcessEnv) goEnv() (map[string]string, error) {
   823  	if err := e.init(); err != nil {
   824  		return nil, err
   825  	}
   826  	return e.Env, nil
   827  }
   828  
   829  func (e *ProcessEnv) matchFile(dir, name string) (bool, error) {
   830  	return build.Default.MatchFile(dir, name)
   831  }
   832  
   833  // CopyConfig copies the env's configuration into a new env.
   834  func (e *ProcessEnv) CopyConfig() *ProcessEnv {
   835  	copy := &ProcessEnv{
   836  		GocmdRunner: e.GocmdRunner,
   837  		initialized: e.initialized,
   838  		BuildFlags:  e.BuildFlags,
   839  		Logf:        e.Logf,
   840  		WorkingDir:  e.WorkingDir,
   841  		resolver:    nil,
   842  		Env:         map[string]string{},
   843  	}
   844  	for k, v := range e.Env {
   845  		copy.Env[k] = v
   846  	}
   847  	return copy
   848  }
   849  
   850  func (e *ProcessEnv) init() error {
   851  	if e.initialized {
   852  		return nil
   853  	}
   854  
   855  	foundAllRequired := true
   856  	for _, k := range RequiredGoEnvVars {
   857  		if _, ok := e.Env[k]; !ok {
   858  			foundAllRequired = false
   859  			break
   860  		}
   861  	}
   862  	if foundAllRequired {
   863  		e.initialized = true
   864  		return nil
   865  	}
   866  
   867  	if e.Env == nil {
   868  		e.Env = map[string]string{}
   869  	}
   870  
   871  	goEnv := map[string]string{}
   872  	stdout, err := e.invokeGo(context.TODO(), "env", append([]string{"-json"}, RequiredGoEnvVars...)...)
   873  	if err != nil {
   874  		return err
   875  	}
   876  	if err := json.Unmarshal(stdout.Bytes(), &goEnv); err != nil {
   877  		return err
   878  	}
   879  	for k, v := range goEnv {
   880  		e.Env[k] = v
   881  	}
   882  	e.initialized = true
   883  	return nil
   884  }
   885  
   886  func (e *ProcessEnv) env() []string {
   887  	var env []string // the gocommand package will prepend os.Environ.
   888  	for k, v := range e.Env {
   889  		env = append(env, k+"="+v)
   890  	}
   891  	return env
   892  }
   893  
   894  func (e *ProcessEnv) GetResolver() (Resolver, error) {
   895  	if e.resolver != nil {
   896  		return e.resolver, nil
   897  	}
   898  	if err := e.init(); err != nil {
   899  		return nil, err
   900  	}
   901  	if len(e.Env["GOMOD"]) == 0 {
   902  		e.resolver = newGopathResolver(e)
   903  		return e.resolver, nil
   904  	}
   905  	e.resolver = newModuleResolver(e)
   906  	return e.resolver, nil
   907  }
   908  
   909  func (e *ProcessEnv) buildContext() (*build.Context, error) {
   910  	ctx := build.Default
   911  	goenv, err := e.goEnv()
   912  	if err != nil {
   913  		return nil, err
   914  	}
   915  	ctx.GOROOT = goenv["GOROOT"]
   916  	ctx.GOPATH = goenv["GOPATH"]
   917  
   918  	// As of Go 1.14, build.Context has a Dir field
   919  	// (see golang.org/issue/34860).
   920  	// Populate it only if present.
   921  	rc := reflect.ValueOf(&ctx).Elem()
   922  	dir := rc.FieldByName("Dir")
   923  	if !dir.IsValid() {
   924  		// Working drafts of Go 1.14 named the field "WorkingDir" instead.
   925  		// TODO(bcmills): Remove this case after the Go 1.14 beta has been released.
   926  		dir = rc.FieldByName("WorkingDir")
   927  	}
   928  	if dir.IsValid() && dir.Kind() == reflect.String {
   929  		dir.SetString(e.WorkingDir)
   930  	}
   931  
   932  	return &ctx, nil
   933  }
   934  
   935  func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) (*bytes.Buffer, error) {
   936  	inv := gocommand.Invocation{
   937  		Verb:       verb,
   938  		Args:       args,
   939  		BuildFlags: e.BuildFlags,
   940  		Env:        e.env(),
   941  		Logf:       e.Logf,
   942  		WorkingDir: e.WorkingDir,
   943  	}
   944  	return e.GocmdRunner.Run(ctx, inv)
   945  }
   946  
   947  func addStdlibCandidates(pass *pass, refs references) error {
   948  	goenv, err := pass.env.goEnv()
   949  	if err != nil {
   950  		return err
   951  	}
   952  	add := func(pkg string) {
   953  		// Prevent self-imports.
   954  		if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir {
   955  			return
   956  		}
   957  		exports := copyExports(stdlib[pkg])
   958  		pass.addCandidate(
   959  			&ImportInfo{ImportPath: pkg},
   960  			&packageInfo{name: path.Base(pkg), exports: exports})
   961  	}
   962  	for left := range refs {
   963  		if left == "rand" {
   964  			// Make sure we try crypto/rand before math/rand.
   965  			add("crypto/rand")
   966  			add("math/rand")
   967  			continue
   968  		}
   969  		for importPath := range stdlib {
   970  			if path.Base(importPath) == left {
   971  				add(importPath)
   972  			}
   973  		}
   974  	}
   975  	return nil
   976  }
   977  
   978  // A Resolver does the build-system-specific parts of goimports.
   979  type Resolver interface {
   980  	// loadPackageNames loads the package names in importPaths.
   981  	loadPackageNames(importPaths []string, srcDir string) (map[string]string, error)
   982  	// scan works with callback to search for packages. See scanCallback for details.
   983  	scan(ctx context.Context, callback *scanCallback) error
   984  	// loadExports returns the set of exported symbols in the package at dir.
   985  	// loadExports may be called concurrently.
   986  	loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error)
   987  	// scoreImportPath returns the relevance for an import path.
   988  	scoreImportPath(ctx context.Context, path string) int
   989  
   990  	ClearForNewScan()
   991  }
   992  
   993  // A scanCallback controls a call to scan and receives its results.
   994  // In general, minor errors will be silently discarded; a user should not
   995  // expect to receive a full series of calls for everything.
   996  type scanCallback struct {
   997  	// rootFound is called before scanning a new root dir. If it returns true,
   998  	// the root will be scanned. Returning false will not necessarily prevent
   999  	// directories from that root making it to dirFound.
  1000  	rootFound func(gopathwalk.Root) bool
  1001  	// dirFound is called when a directory is found that is possibly a Go package.
  1002  	// pkg will be populated with everything except packageName.
  1003  	// If it returns true, the package's name will be loaded.
  1004  	dirFound func(pkg *pkg) bool
  1005  	// packageNameLoaded is called when a package is found and its name is loaded.
  1006  	// If it returns true, the package's exports will be loaded.
  1007  	packageNameLoaded func(pkg *pkg) bool
  1008  	// exportsLoaded is called when a package's exports have been loaded.
  1009  	exportsLoaded func(pkg *pkg, exports []string)
  1010  }
  1011  
  1012  func addExternalCandidates(pass *pass, refs references, filename string) error {
  1013  	var mu sync.Mutex
  1014  	found := make(map[string][]pkgDistance)
  1015  	callback := &scanCallback{
  1016  		rootFound: func(gopathwalk.Root) bool {
  1017  			return true // We want everything.
  1018  		},
  1019  		dirFound: func(pkg *pkg) bool {
  1020  			return pkgIsCandidate(filename, refs, pkg)
  1021  		},
  1022  		packageNameLoaded: func(pkg *pkg) bool {
  1023  			if _, want := refs[pkg.packageName]; !want {
  1024  				return false
  1025  			}
  1026  			if pkg.dir == pass.srcDir && pass.f.Name.Name == pkg.packageName {
  1027  				// The candidate is in the same directory and has the
  1028  				// same package name. Don't try to import ourselves.
  1029  				return false
  1030  			}
  1031  			if !canUse(filename, pkg.dir) {
  1032  				return false
  1033  			}
  1034  			mu.Lock()
  1035  			defer mu.Unlock()
  1036  			found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(pass.srcDir, pkg.dir)})
  1037  			return false // We'll do our own loading after we sort.
  1038  		},
  1039  	}
  1040  	resolver, err := pass.env.GetResolver()
  1041  	if err != nil {
  1042  		return err
  1043  	}
  1044  	if err = resolver.scan(context.Background(), callback); err != nil {
  1045  		return err
  1046  	}
  1047  
  1048  	// Search for imports matching potential package references.
  1049  	type result struct {
  1050  		imp *ImportInfo
  1051  		pkg *packageInfo
  1052  	}
  1053  	results := make(chan result, len(refs))
  1054  
  1055  	ctx, cancel := context.WithCancel(context.TODO())
  1056  	var wg sync.WaitGroup
  1057  	defer func() {
  1058  		cancel()
  1059  		wg.Wait()
  1060  	}()
  1061  	var (
  1062  		firstErr     error
  1063  		firstErrOnce sync.Once
  1064  	)
  1065  	for pkgName, symbols := range refs {
  1066  		wg.Add(1)
  1067  		go func(pkgName string, symbols map[string]bool) {
  1068  			defer wg.Done()
  1069  
  1070  			found, err := findImport(ctx, pass, found[pkgName], pkgName, symbols, filename)
  1071  
  1072  			if err != nil {
  1073  				firstErrOnce.Do(func() {
  1074  					firstErr = err
  1075  					cancel()
  1076  				})
  1077  				return
  1078  			}
  1079  
  1080  			if found == nil {
  1081  				return // No matching package.
  1082  			}
  1083  
  1084  			imp := &ImportInfo{
  1085  				ImportPath: found.importPathShort,
  1086  			}
  1087  
  1088  			pkg := &packageInfo{
  1089  				name:    pkgName,
  1090  				exports: symbols,
  1091  			}
  1092  			results <- result{imp, pkg}
  1093  		}(pkgName, symbols)
  1094  	}
  1095  	go func() {
  1096  		wg.Wait()
  1097  		close(results)
  1098  	}()
  1099  
  1100  	for result := range results {
  1101  		pass.addCandidate(result.imp, result.pkg)
  1102  	}
  1103  	return firstErr
  1104  }
  1105  
  1106  // notIdentifier reports whether ch is an invalid identifier character.
  1107  func notIdentifier(ch rune) bool {
  1108  	return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
  1109  		'0' <= ch && ch <= '9' ||
  1110  		ch == '_' ||
  1111  		ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch)))
  1112  }
  1113  
  1114  // ImportPathToAssumedName returns the assumed package name of an import path.
  1115  // It does this using only string parsing of the import path.
  1116  // It picks the last element of the path that does not look like a major
  1117  // version, and then picks the valid identifier off the start of that element.
  1118  // It is used to determine if a local rename should be added to an import for
  1119  // clarity.
  1120  // This function could be moved to a standard package and exported if we want
  1121  // for use in other tools.
  1122  func ImportPathToAssumedName(importPath string) string {
  1123  	base := path.Base(importPath)
  1124  	if strings.HasPrefix(base, "v") {
  1125  		if _, err := strconv.Atoi(base[1:]); err == nil {
  1126  			dir := path.Dir(importPath)
  1127  			if dir != "." {
  1128  				base = path.Base(dir)
  1129  			}
  1130  		}
  1131  	}
  1132  	base = strings.TrimPrefix(base, "go-")
  1133  	if i := strings.IndexFunc(base, notIdentifier); i >= 0 {
  1134  		base = base[:i]
  1135  	}
  1136  	return base
  1137  }
  1138  
  1139  // gopathResolver implements resolver for GOPATH workspaces.
  1140  type gopathResolver struct {
  1141  	env      *ProcessEnv
  1142  	walked   bool
  1143  	cache    *dirInfoCache
  1144  	scanSema chan struct{} // scanSema prevents concurrent scans.
  1145  }
  1146  
  1147  func newGopathResolver(env *ProcessEnv) *gopathResolver {
  1148  	r := &gopathResolver{
  1149  		env: env,
  1150  		cache: &dirInfoCache{
  1151  			dirs:      map[string]*directoryPackageInfo{},
  1152  			listeners: map[*int]cacheListener{},
  1153  		},
  1154  		scanSema: make(chan struct{}, 1),
  1155  	}
  1156  	r.scanSema <- struct{}{}
  1157  	return r
  1158  }
  1159  
  1160  func (r *gopathResolver) ClearForNewScan() {
  1161  	<-r.scanSema
  1162  	r.cache = &dirInfoCache{
  1163  		dirs:      map[string]*directoryPackageInfo{},
  1164  		listeners: map[*int]cacheListener{},
  1165  	}
  1166  	r.walked = false
  1167  	r.scanSema <- struct{}{}
  1168  }
  1169  
  1170  func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
  1171  	names := map[string]string{}
  1172  	bctx, err := r.env.buildContext()
  1173  	if err != nil {
  1174  		return nil, err
  1175  	}
  1176  	for _, path := range importPaths {
  1177  		names[path] = importPathToName(bctx, path, srcDir)
  1178  	}
  1179  	return names, nil
  1180  }
  1181  
  1182  // importPathToName finds out the actual package name, as declared in its .go files.
  1183  func importPathToName(bctx *build.Context, importPath, srcDir string) string {
  1184  	// Fast path for standard library without going to disk.
  1185  	if _, ok := stdlib[importPath]; ok {
  1186  		return path.Base(importPath) // stdlib packages always match their paths.
  1187  	}
  1188  
  1189  	buildPkg, err := bctx.Import(importPath, srcDir, build.FindOnly)
  1190  	if err != nil {
  1191  		return ""
  1192  	}
  1193  	pkgName, err := packageDirToName(buildPkg.Dir)
  1194  	if err != nil {
  1195  		return ""
  1196  	}
  1197  	return pkgName
  1198  }
  1199  
  1200  // packageDirToName is a faster version of build.Import if
  1201  // the only thing desired is the package name. Given a directory,
  1202  // packageDirToName then only parses one file in the package,
  1203  // trusting that the files in the directory are consistent.
  1204  func packageDirToName(dir string) (packageName string, err error) {
  1205  	d, err := os.Open(dir)
  1206  	if err != nil {
  1207  		return "", err
  1208  	}
  1209  	names, err := d.Readdirnames(-1)
  1210  	d.Close()
  1211  	if err != nil {
  1212  		return "", err
  1213  	}
  1214  	sort.Strings(names) // to have predictable behavior
  1215  	var lastErr error
  1216  	var nfile int
  1217  	for _, name := range names {
  1218  		if !strings.HasSuffix(name, ".go") {
  1219  			continue
  1220  		}
  1221  		if strings.HasSuffix(name, "_test.go") {
  1222  			continue
  1223  		}
  1224  		nfile++
  1225  		fullFile := filepath.Join(dir, name)
  1226  
  1227  		fset := token.NewFileSet()
  1228  		f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly)
  1229  		if err != nil {
  1230  			lastErr = err
  1231  			continue
  1232  		}
  1233  		pkgName := f.Name.Name
  1234  		if pkgName == "documentation" {
  1235  			// Special case from go/build.ImportDir, not
  1236  			// handled by ctx.MatchFile.
  1237  			continue
  1238  		}
  1239  		if pkgName == "main" {
  1240  			// Also skip package main, assuming it's a +build ignore generator or example.
  1241  			// Since you can't import a package main anyway, there's no harm here.
  1242  			continue
  1243  		}
  1244  		return pkgName, nil
  1245  	}
  1246  	if lastErr != nil {
  1247  		return "", lastErr
  1248  	}
  1249  	return "", fmt.Errorf("no importable package found in %d Go files", nfile)
  1250  }
  1251  
  1252  type pkg struct {
  1253  	dir             string // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
  1254  	importPathShort string // vendorless import path ("net/http", "a/b")
  1255  	packageName     string // package name loaded from source if requested
  1256  	relevance       int    // a weakly-defined score of how relevant a package is. 0 is most relevant.
  1257  }
  1258  
  1259  type pkgDistance struct {
  1260  	pkg      *pkg
  1261  	distance int // relative distance to target
  1262  }
  1263  
  1264  // byDistanceOrImportPathShortLength sorts by relative distance breaking ties
  1265  // on the short import path length and then the import string itself.
  1266  type byDistanceOrImportPathShortLength []pkgDistance
  1267  
  1268  func (s byDistanceOrImportPathShortLength) Len() int { return len(s) }
  1269  func (s byDistanceOrImportPathShortLength) Less(i, j int) bool {
  1270  	di, dj := s[i].distance, s[j].distance
  1271  	if di == -1 {
  1272  		return false
  1273  	}
  1274  	if dj == -1 {
  1275  		return true
  1276  	}
  1277  	if di != dj {
  1278  		return di < dj
  1279  	}
  1280  
  1281  	vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort
  1282  	if len(vi) != len(vj) {
  1283  		return len(vi) < len(vj)
  1284  	}
  1285  	return vi < vj
  1286  }
  1287  func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  1288  
  1289  func distance(basepath, targetpath string) int {
  1290  	p, err := filepath.Rel(basepath, targetpath)
  1291  	if err != nil {
  1292  		return -1
  1293  	}
  1294  	if p == "." {
  1295  		return 0
  1296  	}
  1297  	return strings.Count(p, string(filepath.Separator)) + 1
  1298  }
  1299  
  1300  func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error {
  1301  	add := func(root gopathwalk.Root, dir string) {
  1302  		// We assume cached directories have not changed. We can skip them and their
  1303  		// children.
  1304  		if _, ok := r.cache.Load(dir); ok {
  1305  			return
  1306  		}
  1307  
  1308  		importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):])
  1309  		info := directoryPackageInfo{
  1310  			status:                 directoryScanned,
  1311  			dir:                    dir,
  1312  			rootType:               root.Type,
  1313  			nonCanonicalImportPath: VendorlessPath(importpath),
  1314  		}
  1315  		r.cache.Store(dir, info)
  1316  	}
  1317  	processDir := func(info directoryPackageInfo) {
  1318  		// Skip this directory if we were not able to get the package information successfully.
  1319  		if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil {
  1320  			return
  1321  		}
  1322  
  1323  		p := &pkg{
  1324  			importPathShort: info.nonCanonicalImportPath,
  1325  			dir:             info.dir,
  1326  			relevance:       MaxRelevance - 1,
  1327  		}
  1328  		if info.rootType == gopathwalk.RootGOROOT {
  1329  			p.relevance = MaxRelevance
  1330  		}
  1331  
  1332  		if !callback.dirFound(p) {
  1333  			return
  1334  		}
  1335  		var err error
  1336  		p.packageName, err = r.cache.CachePackageName(info)
  1337  		if err != nil {
  1338  			return
  1339  		}
  1340  
  1341  		if !callback.packageNameLoaded(p) {
  1342  			return
  1343  		}
  1344  		if _, exports, err := r.loadExports(ctx, p, false); err == nil {
  1345  			callback.exportsLoaded(p, exports)
  1346  		}
  1347  	}
  1348  	stop := r.cache.ScanAndListen(ctx, processDir)
  1349  	defer stop()
  1350  
  1351  	goenv, err := r.env.goEnv()
  1352  	if err != nil {
  1353  		return err
  1354  	}
  1355  	var roots []gopathwalk.Root
  1356  	roots = append(roots, gopathwalk.Root{filepath.Join(goenv["GOROOT"], "src"), gopathwalk.RootGOROOT})
  1357  	for _, p := range filepath.SplitList(goenv["GOPATH"]) {
  1358  		roots = append(roots, gopathwalk.Root{filepath.Join(p, "src"), gopathwalk.RootGOPATH})
  1359  	}
  1360  	// The callback is not necessarily safe to use in the goroutine below. Process roots eagerly.
  1361  	roots = filterRoots(roots, callback.rootFound)
  1362  	// We can't cancel walks, because we need them to finish to have a usable
  1363  	// cache. Instead, run them in a separate goroutine and detach.
  1364  	scanDone := make(chan struct{})
  1365  	go func() {
  1366  		select {
  1367  		case <-ctx.Done():
  1368  			return
  1369  		case <-r.scanSema:
  1370  		}
  1371  		defer func() { r.scanSema <- struct{}{} }()
  1372  		gopathwalk.Walk(roots, add, gopathwalk.Options{Logf: r.env.Logf, ModulesEnabled: false})
  1373  		close(scanDone)
  1374  	}()
  1375  	select {
  1376  	case <-ctx.Done():
  1377  	case <-scanDone:
  1378  	}
  1379  	return nil
  1380  }
  1381  
  1382  func (r *gopathResolver) scoreImportPath(ctx context.Context, path string) int {
  1383  	if _, ok := stdlib[path]; ok {
  1384  		return MaxRelevance
  1385  	}
  1386  	return MaxRelevance - 1
  1387  }
  1388  
  1389  func filterRoots(roots []gopathwalk.Root, include func(gopathwalk.Root) bool) []gopathwalk.Root {
  1390  	var result []gopathwalk.Root
  1391  	for _, root := range roots {
  1392  		if !include(root) {
  1393  			continue
  1394  		}
  1395  		result = append(result, root)
  1396  	}
  1397  	return result
  1398  }
  1399  
  1400  func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
  1401  	if info, ok := r.cache.Load(pkg.dir); ok && !includeTest {
  1402  		return r.cache.CacheExports(ctx, r.env, info)
  1403  	}
  1404  	return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest)
  1405  }
  1406  
  1407  // VendorlessPath returns the devendorized version of the import path ipath.
  1408  // For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
  1409  func VendorlessPath(ipath string) string {
  1410  	// Devendorize for use in import statement.
  1411  	if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
  1412  		return ipath[i+len("/vendor/"):]
  1413  	}
  1414  	if strings.HasPrefix(ipath, "vendor/") {
  1415  		return ipath[len("vendor/"):]
  1416  	}
  1417  	return ipath
  1418  }
  1419  
  1420  func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) {
  1421  	// Look for non-test, buildable .go files which could provide exports.
  1422  	all, err := ioutil.ReadDir(dir)
  1423  	if err != nil {
  1424  		return "", nil, err
  1425  	}
  1426  	var files []os.FileInfo
  1427  	for _, fi := range all {
  1428  		name := fi.Name()
  1429  		if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) {
  1430  			continue
  1431  		}
  1432  		match, err := env.matchFile(dir, fi.Name())
  1433  		if err != nil || !match {
  1434  			continue
  1435  		}
  1436  		files = append(files, fi)
  1437  	}
  1438  
  1439  	if len(files) == 0 {
  1440  		return "", nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir)
  1441  	}
  1442  
  1443  	var pkgName string
  1444  	var exports []string
  1445  	fset := token.NewFileSet()
  1446  	for _, fi := range files {
  1447  		select {
  1448  		case <-ctx.Done():
  1449  			return "", nil, ctx.Err()
  1450  		default:
  1451  		}
  1452  
  1453  		fullFile := filepath.Join(dir, fi.Name())
  1454  		f, err := parser.ParseFile(fset, fullFile, nil, 0)
  1455  		if err != nil {
  1456  			if env.Logf != nil {
  1457  				env.Logf("error parsing %v: %v", fullFile, err)
  1458  			}
  1459  			continue
  1460  		}
  1461  		if f.Name.Name == "documentation" {
  1462  			// Special case from go/build.ImportDir, not
  1463  			// handled by MatchFile above.
  1464  			continue
  1465  		}
  1466  		if includeTest && strings.HasSuffix(f.Name.Name, "_test") {
  1467  			// x_test package. We want internal test files only.
  1468  			continue
  1469  		}
  1470  		pkgName = f.Name.Name
  1471  		for name := range f.Scope.Objects {
  1472  			if ast.IsExported(name) {
  1473  				exports = append(exports, name)
  1474  			}
  1475  		}
  1476  	}
  1477  
  1478  	if env.Logf != nil {
  1479  		sortedExports := append([]string(nil), exports...)
  1480  		sort.Strings(sortedExports)
  1481  		env.Logf("loaded exports in dir %v (package %v): %v", dir, pkgName, strings.Join(sortedExports, ", "))
  1482  	}
  1483  	return pkgName, exports, nil
  1484  }
  1485  
  1486  // findImport searches for a package with the given symbols.
  1487  // If no package is found, findImport returns ("", false, nil)
  1488  func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool, filename string) (*pkg, error) {
  1489  	// Sort the candidates by their import package length,
  1490  	// assuming that shorter package names are better than long
  1491  	// ones.  Note that this sorts by the de-vendored name, so
  1492  	// there's no "penalty" for vendoring.
  1493  	sort.Sort(byDistanceOrImportPathShortLength(candidates))
  1494  	if pass.env.Logf != nil {
  1495  		for i, c := range candidates {
  1496  			pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
  1497  		}
  1498  	}
  1499  	resolver, err := pass.env.GetResolver()
  1500  	if err != nil {
  1501  		return nil, err
  1502  	}
  1503  
  1504  	// Collect exports for packages with matching names.
  1505  	rescv := make([]chan *pkg, len(candidates))
  1506  	for i := range candidates {
  1507  		rescv[i] = make(chan *pkg, 1)
  1508  	}
  1509  	const maxConcurrentPackageImport = 4
  1510  	loadExportsSem := make(chan struct{}, maxConcurrentPackageImport)
  1511  
  1512  	ctx, cancel := context.WithCancel(ctx)
  1513  	var wg sync.WaitGroup
  1514  	defer func() {
  1515  		cancel()
  1516  		wg.Wait()
  1517  	}()
  1518  
  1519  	wg.Add(1)
  1520  	go func() {
  1521  		defer wg.Done()
  1522  		for i, c := range candidates {
  1523  			select {
  1524  			case loadExportsSem <- struct{}{}:
  1525  			case <-ctx.Done():
  1526  				return
  1527  			}
  1528  
  1529  			wg.Add(1)
  1530  			go func(c pkgDistance, resc chan<- *pkg) {
  1531  				defer func() {
  1532  					<-loadExportsSem
  1533  					wg.Done()
  1534  				}()
  1535  
  1536  				if pass.env.Logf != nil {
  1537  					pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
  1538  				}
  1539  				// If we're an x_test, load the package under test's test variant.
  1540  				includeTest := strings.HasSuffix(pass.f.Name.Name, "_test") && c.pkg.dir == pass.srcDir
  1541  				_, exports, err := resolver.loadExports(ctx, c.pkg, includeTest)
  1542  				if err != nil {
  1543  					if pass.env.Logf != nil {
  1544  						pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
  1545  					}
  1546  					resc <- nil
  1547  					return
  1548  				}
  1549  
  1550  				exportsMap := make(map[string]bool, len(exports))
  1551  				for _, sym := range exports {
  1552  					exportsMap[sym] = true
  1553  				}
  1554  
  1555  				// If it doesn't have the right
  1556  				// symbols, send nil to mean no match.
  1557  				for symbol := range symbols {
  1558  					if !exportsMap[symbol] {
  1559  						resc <- nil
  1560  						return
  1561  					}
  1562  				}
  1563  				resc <- c.pkg
  1564  			}(c, rescv[i])
  1565  		}
  1566  	}()
  1567  
  1568  	for _, resc := range rescv {
  1569  		pkg := <-resc
  1570  		if pkg == nil {
  1571  			continue
  1572  		}
  1573  		return pkg, nil
  1574  	}
  1575  	return nil, nil
  1576  }
  1577  
  1578  // pkgIsCandidate reports whether pkg is a candidate for satisfying the
  1579  // finding which package pkgIdent in the file named by filename is trying
  1580  // to refer to.
  1581  //
  1582  // This check is purely lexical and is meant to be as fast as possible
  1583  // because it's run over all $GOPATH directories to filter out poor
  1584  // candidates in order to limit the CPU and I/O later parsing the
  1585  // exports in candidate packages.
  1586  //
  1587  // filename is the file being formatted.
  1588  // pkgIdent is the package being searched for, like "client" (if
  1589  // searching for "client.New")
  1590  func pkgIsCandidate(filename string, refs references, pkg *pkg) bool {
  1591  	// Check "internal" and "vendor" visibility:
  1592  	if !canUse(filename, pkg.dir) {
  1593  		return false
  1594  	}
  1595  
  1596  	// Speed optimization to minimize disk I/O:
  1597  	// the last two components on disk must contain the
  1598  	// package name somewhere.
  1599  	//
  1600  	// This permits mismatch naming like directory
  1601  	// "go-foo" being package "foo", or "pkg.v3" being "pkg",
  1602  	// or directory "google.golang.org/api/cloudbilling/v1"
  1603  	// being package "cloudbilling", but doesn't
  1604  	// permit a directory "foo" to be package
  1605  	// "bar", which is strongly discouraged
  1606  	// anyway. There's no reason goimports needs
  1607  	// to be slow just to accommodate that.
  1608  	for pkgIdent := range refs {
  1609  		lastTwo := lastTwoComponents(pkg.importPathShort)
  1610  		if strings.Contains(lastTwo, pkgIdent) {
  1611  			return true
  1612  		}
  1613  		if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) {
  1614  			lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
  1615  			if strings.Contains(lastTwo, pkgIdent) {
  1616  				return true
  1617  			}
  1618  		}
  1619  	}
  1620  	return false
  1621  }
  1622  
  1623  func hasHyphenOrUpperASCII(s string) bool {
  1624  	for i := 0; i < len(s); i++ {
  1625  		b := s[i]
  1626  		if b == '-' || ('A' <= b && b <= 'Z') {
  1627  			return true
  1628  		}
  1629  	}
  1630  	return false
  1631  }
  1632  
  1633  func lowerASCIIAndRemoveHyphen(s string) (ret string) {
  1634  	buf := make([]byte, 0, len(s))
  1635  	for i := 0; i < len(s); i++ {
  1636  		b := s[i]
  1637  		switch {
  1638  		case b == '-':
  1639  			continue
  1640  		case 'A' <= b && b <= 'Z':
  1641  			buf = append(buf, b+('a'-'A'))
  1642  		default:
  1643  			buf = append(buf, b)
  1644  		}
  1645  	}
  1646  	return string(buf)
  1647  }
  1648  
  1649  // canUse reports whether the package in dir is usable from filename,
  1650  // respecting the Go "internal" and "vendor" visibility rules.
  1651  func canUse(filename, dir string) bool {
  1652  	// Fast path check, before any allocations. If it doesn't contain vendor
  1653  	// or internal, it's not tricky:
  1654  	// Note that this can false-negative on directories like "notinternal",
  1655  	// but we check it correctly below. This is just a fast path.
  1656  	if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") {
  1657  		return true
  1658  	}
  1659  
  1660  	dirSlash := filepath.ToSlash(dir)
  1661  	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
  1662  		return true
  1663  	}
  1664  	// Vendor or internal directory only visible from children of parent.
  1665  	// That means the path from the current directory to the target directory
  1666  	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
  1667  	// or bar/vendor or bar/internal.
  1668  	// After stripping all the leading ../, the only okay place to see vendor or internal
  1669  	// is at the very beginning of the path.
  1670  	absfile, err := filepath.Abs(filename)
  1671  	if err != nil {
  1672  		return false
  1673  	}
  1674  	absdir, err := filepath.Abs(dir)
  1675  	if err != nil {
  1676  		return false
  1677  	}
  1678  	rel, err := filepath.Rel(absfile, absdir)
  1679  	if err != nil {
  1680  		return false
  1681  	}
  1682  	relSlash := filepath.ToSlash(rel)
  1683  	if i := strings.LastIndex(relSlash, "../"); i >= 0 {
  1684  		relSlash = relSlash[i+len("../"):]
  1685  	}
  1686  	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
  1687  }
  1688  
  1689  // lastTwoComponents returns at most the last two path components
  1690  // of v, using either / or \ as the path separator.
  1691  func lastTwoComponents(v string) string {
  1692  	nslash := 0
  1693  	for i := len(v) - 1; i >= 0; i-- {
  1694  		if v[i] == '/' || v[i] == '\\' {
  1695  			nslash++
  1696  			if nslash == 2 {
  1697  				return v[i:]
  1698  			}
  1699  		}
  1700  	}
  1701  	return v
  1702  }
  1703  
  1704  type visitFn func(node ast.Node) ast.Visitor
  1705  
  1706  func (fn visitFn) Visit(node ast.Node) ast.Visitor {
  1707  	return fn(node)
  1708  }
  1709  
  1710  func copyExports(pkg []string) map[string]bool {
  1711  	m := make(map[string]bool, len(pkg))
  1712  	for _, v := range pkg {
  1713  		m[v] = true
  1714  	}
  1715  	return m
  1716  }