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
5package imports
6
7import (
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	"golang.org/x/tools/go/ast/astutil"
29	"golang.org/x/tools/internal/gocommand"
30	"golang.org/x/tools/internal/gopathwalk"
31)
32
33// importToGroup is a list of functions which map from an import path to
34// a group number.
35var 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
62func 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
71type ImportFixType int
72
73const (
74	AddImport ImportFixType = iota
75	DeleteImport
76	SetImportName
77)
78
79type 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 float64 // see pkg
87}
88
89// An ImportInfo represents a single import statement.
90type 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.
96type 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.
103func 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.
135func 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).
154func 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.
192func 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.
213func (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.
241type 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.
245type 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.
266func (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.
303func (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.
317func (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.
375func (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.
436func (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.
451func 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.
475func (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.
500func (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.
519var fixImports = fixImportsDefault
520
521func 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.
532func 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// MaxRelevance is the highest relevance, used for the standard library.
596// Chosen arbitrarily to match pre-existing gopls code.
597const MaxRelevance = 7.0
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.
602func 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
611	var mu sync.Mutex // to guard asynchronous access to dupCheck
612	dupCheck := map[string]struct{}{}
613
614	// Start off with the standard library.
615	for importPath, exports := range stdlib {
616		p := &pkg{
617			dir:             filepath.Join(goenv["GOROOT"], "src", importPath),
618			importPathShort: importPath,
619			packageName:     path.Base(importPath),
620			relevance:       MaxRelevance,
621		}
622		dupCheck[importPath] = struct{}{}
623		if notSelf(p) && wrappedCallback.dirFound(p) && wrappedCallback.packageNameLoaded(p) {
624			wrappedCallback.exportsLoaded(p, exports)
625		}
626	}
627
628	scanFilter := &scanCallback{
629		rootFound: func(root gopathwalk.Root) bool {
630			// Exclude goroot results -- getting them is relatively expensive, not cached,
631			// and generally redundant with the in-memory version.
632			return root.Type != gopathwalk.RootGOROOT && wrappedCallback.rootFound(root)
633		},
634		dirFound: wrappedCallback.dirFound,
635		packageNameLoaded: func(pkg *pkg) bool {
636			mu.Lock()
637			defer mu.Unlock()
638			if _, ok := dupCheck[pkg.importPathShort]; ok {
639				return false
640			}
641			dupCheck[pkg.importPathShort] = struct{}{}
642			return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg)
643		},
644		exportsLoaded: func(pkg *pkg, exports []string) {
645			// If we're an x_test, load the package under test's test variant.
646			if strings.HasSuffix(filePkg, "_test") && pkg.dir == filepath.Dir(filename) {
647				var err error
648				_, exports, err = loadExportsFromFiles(ctx, env, pkg.dir, true)
649				if err != nil {
650					return
651				}
652			}
653			wrappedCallback.exportsLoaded(pkg, exports)
654		},
655	}
656	resolver, err := env.GetResolver()
657	if err != nil {
658		return err
659	}
660	return resolver.scan(ctx, scanFilter)
661}
662
663func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) (map[string]float64, error) {
664	result := make(map[string]float64)
665	resolver, err := env.GetResolver()
666	if err != nil {
667		return nil, err
668	}
669	for _, path := range paths {
670		result[path] = resolver.scoreImportPath(ctx, path)
671	}
672	return result, nil
673}
674
675func PrimeCache(ctx context.Context, env *ProcessEnv) error {
676	// Fully scan the disk for directories, but don't actually read any Go files.
677	callback := &scanCallback{
678		rootFound: func(gopathwalk.Root) bool {
679			return true
680		},
681		dirFound: func(pkg *pkg) bool {
682			return false
683		},
684		packageNameLoaded: func(pkg *pkg) bool {
685			return false
686		},
687	}
688	return getCandidatePkgs(ctx, callback, "", "", env)
689}
690
691func candidateImportName(pkg *pkg) string {
692	if ImportPathToAssumedName(pkg.importPathShort) != pkg.packageName {
693		return pkg.packageName
694	}
695	return ""
696}
697
698// GetAllCandidates calls wrapped for each package whose name starts with
699// searchPrefix, and can be imported from filename with the package name filePkg.
700func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
701	callback := &scanCallback{
702		rootFound: func(gopathwalk.Root) bool {
703			return true
704		},
705		dirFound: func(pkg *pkg) bool {
706			if !canUse(filename, pkg.dir) {
707				return false
708			}
709			// Try the assumed package name first, then a simpler path match
710			// in case of packages named vN, which are not uncommon.
711			return strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) ||
712				strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix)
713		},
714		packageNameLoaded: func(pkg *pkg) bool {
715			if !strings.HasPrefix(pkg.packageName, searchPrefix) {
716				return false
717			}
718			wrapped(ImportFix{
719				StmtInfo: ImportInfo{
720					ImportPath: pkg.importPathShort,
721					Name:       candidateImportName(pkg),
722				},
723				IdentName: pkg.packageName,
724				FixType:   AddImport,
725				Relevance: pkg.relevance,
726			})
727			return false
728		},
729	}
730	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
731}
732
733// GetImportPaths calls wrapped for each package whose import path starts with
734// searchPrefix, and can be imported from filename with the package name filePkg.
735func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
736	callback := &scanCallback{
737		rootFound: func(gopathwalk.Root) bool {
738			return true
739		},
740		dirFound: func(pkg *pkg) bool {
741			if !canUse(filename, pkg.dir) {
742				return false
743			}
744			return strings.HasPrefix(pkg.importPathShort, searchPrefix)
745		},
746		packageNameLoaded: func(pkg *pkg) bool {
747			wrapped(ImportFix{
748				StmtInfo: ImportInfo{
749					ImportPath: pkg.importPathShort,
750					Name:       candidateImportName(pkg),
751				},
752				IdentName: pkg.packageName,
753				FixType:   AddImport,
754				Relevance: pkg.relevance,
755			})
756			return false
757		},
758	}
759	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
760}
761
762// A PackageExport is a package and its exports.
763type PackageExport struct {
764	Fix     *ImportFix
765	Exports []string
766}
767
768// GetPackageExports returns all known packages with name pkg and their exports.
769func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchPkg, filename, filePkg string, env *ProcessEnv) error {
770	callback := &scanCallback{
771		rootFound: func(gopathwalk.Root) bool {
772			return true
773		},
774		dirFound: func(pkg *pkg) bool {
775			return pkgIsCandidate(filename, references{searchPkg: nil}, pkg)
776		},
777		packageNameLoaded: func(pkg *pkg) bool {
778			return pkg.packageName == searchPkg
779		},
780		exportsLoaded: func(pkg *pkg, exports []string) {
781			sort.Strings(exports)
782			wrapped(PackageExport{
783				Fix: &ImportFix{
784					StmtInfo: ImportInfo{
785						ImportPath: pkg.importPathShort,
786						Name:       candidateImportName(pkg),
787					},
788					IdentName: pkg.packageName,
789					FixType:   AddImport,
790					Relevance: pkg.relevance,
791				},
792				Exports: exports,
793			})
794		},
795	}
796	return getCandidatePkgs(ctx, callback, filename, filePkg, env)
797}
798
799var RequiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB"}
800
801// ProcessEnv contains environment variables and settings that affect the use of
802// the go command, the go/build package, etc.
803type ProcessEnv struct {
804	GocmdRunner *gocommand.Runner
805
806	BuildFlags []string
807	ModFlag    string
808	ModFile    string
809
810	// Env overrides the OS environment, and can be used to specify
811	// GOPROXY, GO111MODULE, etc. PATH cannot be set here, because
812	// exec.Command will not honor it.
813	// Specifying all of RequiredGoEnvVars avoids a call to `go env`.
814	Env map[string]string
815
816	WorkingDir string
817
818	// If Logf is non-nil, debug logging is enabled through this function.
819	Logf func(format string, args ...interface{})
820
821	initialized bool
822
823	resolver Resolver
824}
825
826func (e *ProcessEnv) goEnv() (map[string]string, error) {
827	if err := e.init(); err != nil {
828		return nil, err
829	}
830	return e.Env, nil
831}
832
833func (e *ProcessEnv) matchFile(dir, name string) (bool, error) {
834	bctx, err := e.buildContext()
835	if err != nil {
836		return false, err
837	}
838	return bctx.MatchFile(dir, name)
839}
840
841// CopyConfig copies the env's configuration into a new env.
842func (e *ProcessEnv) CopyConfig() *ProcessEnv {
843	copy := &ProcessEnv{
844		GocmdRunner: e.GocmdRunner,
845		initialized: e.initialized,
846		BuildFlags:  e.BuildFlags,
847		Logf:        e.Logf,
848		WorkingDir:  e.WorkingDir,
849		resolver:    nil,
850		Env:         map[string]string{},
851	}
852	for k, v := range e.Env {
853		copy.Env[k] = v
854	}
855	return copy
856}
857
858func (e *ProcessEnv) init() error {
859	if e.initialized {
860		return nil
861	}
862
863	foundAllRequired := true
864	for _, k := range RequiredGoEnvVars {
865		if _, ok := e.Env[k]; !ok {
866			foundAllRequired = false
867			break
868		}
869	}
870	if foundAllRequired {
871		e.initialized = true
872		return nil
873	}
874
875	if e.Env == nil {
876		e.Env = map[string]string{}
877	}
878
879	goEnv := map[string]string{}
880	stdout, err := e.invokeGo(context.TODO(), "env", append([]string{"-json"}, RequiredGoEnvVars...)...)
881	if err != nil {
882		return err
883	}
884	if err := json.Unmarshal(stdout.Bytes(), &goEnv); err != nil {
885		return err
886	}
887	for k, v := range goEnv {
888		e.Env[k] = v
889	}
890	e.initialized = true
891	return nil
892}
893
894func (e *ProcessEnv) env() []string {
895	var env []string // the gocommand package will prepend os.Environ.
896	for k, v := range e.Env {
897		env = append(env, k+"="+v)
898	}
899	return env
900}
901
902func (e *ProcessEnv) GetResolver() (Resolver, error) {
903	if e.resolver != nil {
904		return e.resolver, nil
905	}
906	if err := e.init(); err != nil {
907		return nil, err
908	}
909	if len(e.Env["GOMOD"]) == 0 {
910		e.resolver = newGopathResolver(e)
911		return e.resolver, nil
912	}
913	e.resolver = newModuleResolver(e)
914	return e.resolver, nil
915}
916
917func (e *ProcessEnv) buildContext() (*build.Context, error) {
918	ctx := build.Default
919	goenv, err := e.goEnv()
920	if err != nil {
921		return nil, err
922	}
923	ctx.GOROOT = goenv["GOROOT"]
924	ctx.GOPATH = goenv["GOPATH"]
925
926	// As of Go 1.14, build.Context has a Dir field
927	// (see golang.org/issue/34860).
928	// Populate it only if present.
929	rc := reflect.ValueOf(&ctx).Elem()
930	dir := rc.FieldByName("Dir")
931	if dir.IsValid() && dir.Kind() == reflect.String {
932		dir.SetString(e.WorkingDir)
933	}
934
935	// Since Go 1.11, go/build.Context.Import may invoke 'go list' depending on
936	// the value in GO111MODULE in the process's environment. We always want to
937	// run in GOPATH mode when calling Import, so we need to prevent this from
938	// happening. In Go 1.16, GO111MODULE defaults to "on", so this problem comes
939	// up more frequently.
940	//
941	// HACK: setting any of the Context I/O hooks prevents Import from invoking
942	// 'go list', regardless of GO111MODULE. This is undocumented, but it's
943	// unlikely to change before GOPATH support is removed.
944	ctx.ReadDir = ioutil.ReadDir
945
946	return &ctx, nil
947}
948
949func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) (*bytes.Buffer, error) {
950	inv := gocommand.Invocation{
951		Verb:       verb,
952		Args:       args,
953		BuildFlags: e.BuildFlags,
954		Env:        e.env(),
955		Logf:       e.Logf,
956		WorkingDir: e.WorkingDir,
957	}
958	return e.GocmdRunner.Run(ctx, inv)
959}
960
961func addStdlibCandidates(pass *pass, refs references) error {
962	goenv, err := pass.env.goEnv()
963	if err != nil {
964		return err
965	}
966	add := func(pkg string) {
967		// Prevent self-imports.
968		if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir {
969			return
970		}
971		exports := copyExports(stdlib[pkg])
972		pass.addCandidate(
973			&ImportInfo{ImportPath: pkg},
974			&packageInfo{name: path.Base(pkg), exports: exports})
975	}
976	for left := range refs {
977		if left == "rand" {
978			// Make sure we try crypto/rand before math/rand.
979			add("crypto/rand")
980			add("math/rand")
981			continue
982		}
983		for importPath := range stdlib {
984			if path.Base(importPath) == left {
985				add(importPath)
986			}
987		}
988	}
989	return nil
990}
991
992// A Resolver does the build-system-specific parts of goimports.
993type Resolver interface {
994	// loadPackageNames loads the package names in importPaths.
995	loadPackageNames(importPaths []string, srcDir string) (map[string]string, error)
996	// scan works with callback to search for packages. See scanCallback for details.
997	scan(ctx context.Context, callback *scanCallback) error
998	// loadExports returns the set of exported symbols in the package at dir.
999	// loadExports may be called concurrently.
1000	loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error)
1001	// scoreImportPath returns the relevance for an import path.
1002	scoreImportPath(ctx context.Context, path string) float64
1003
1004	ClearForNewScan()
1005}
1006
1007// A scanCallback controls a call to scan and receives its results.
1008// In general, minor errors will be silently discarded; a user should not
1009// expect to receive a full series of calls for everything.
1010type scanCallback struct {
1011	// rootFound is called before scanning a new root dir. If it returns true,
1012	// the root will be scanned. Returning false will not necessarily prevent
1013	// directories from that root making it to dirFound.
1014	rootFound func(gopathwalk.Root) bool
1015	// dirFound is called when a directory is found that is possibly a Go package.
1016	// pkg will be populated with everything except packageName.
1017	// If it returns true, the package's name will be loaded.
1018	dirFound func(pkg *pkg) bool
1019	// packageNameLoaded is called when a package is found and its name is loaded.
1020	// If it returns true, the package's exports will be loaded.
1021	packageNameLoaded func(pkg *pkg) bool
1022	// exportsLoaded is called when a package's exports have been loaded.
1023	exportsLoaded func(pkg *pkg, exports []string)
1024}
1025
1026func addExternalCandidates(pass *pass, refs references, filename string) error {
1027	var mu sync.Mutex
1028	found := make(map[string][]pkgDistance)
1029	callback := &scanCallback{
1030		rootFound: func(gopathwalk.Root) bool {
1031			return true // We want everything.
1032		},
1033		dirFound: func(pkg *pkg) bool {
1034			return pkgIsCandidate(filename, refs, pkg)
1035		},
1036		packageNameLoaded: func(pkg *pkg) bool {
1037			if _, want := refs[pkg.packageName]; !want {
1038				return false
1039			}
1040			if pkg.dir == pass.srcDir && pass.f.Name.Name == pkg.packageName {
1041				// The candidate is in the same directory and has the
1042				// same package name. Don't try to import ourselves.
1043				return false
1044			}
1045			if !canUse(filename, pkg.dir) {
1046				return false
1047			}
1048			mu.Lock()
1049			defer mu.Unlock()
1050			found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(pass.srcDir, pkg.dir)})
1051			return false // We'll do our own loading after we sort.
1052		},
1053	}
1054	resolver, err := pass.env.GetResolver()
1055	if err != nil {
1056		return err
1057	}
1058	if err = resolver.scan(context.Background(), callback); err != nil {
1059		return err
1060	}
1061
1062	// Search for imports matching potential package references.
1063	type result struct {
1064		imp *ImportInfo
1065		pkg *packageInfo
1066	}
1067	results := make(chan result, len(refs))
1068
1069	ctx, cancel := context.WithCancel(context.TODO())
1070	var wg sync.WaitGroup
1071	defer func() {
1072		cancel()
1073		wg.Wait()
1074	}()
1075	var (
1076		firstErr     error
1077		firstErrOnce sync.Once
1078	)
1079	for pkgName, symbols := range refs {
1080		wg.Add(1)
1081		go func(pkgName string, symbols map[string]bool) {
1082			defer wg.Done()
1083
1084			found, err := findImport(ctx, pass, found[pkgName], pkgName, symbols, filename)
1085
1086			if err != nil {
1087				firstErrOnce.Do(func() {
1088					firstErr = err
1089					cancel()
1090				})
1091				return
1092			}
1093
1094			if found == nil {
1095				return // No matching package.
1096			}
1097
1098			imp := &ImportInfo{
1099				ImportPath: found.importPathShort,
1100			}
1101
1102			pkg := &packageInfo{
1103				name:    pkgName,
1104				exports: symbols,
1105			}
1106			results <- result{imp, pkg}
1107		}(pkgName, symbols)
1108	}
1109	go func() {
1110		wg.Wait()
1111		close(results)
1112	}()
1113
1114	for result := range results {
1115		pass.addCandidate(result.imp, result.pkg)
1116	}
1117	return firstErr
1118}
1119
1120// notIdentifier reports whether ch is an invalid identifier character.
1121func notIdentifier(ch rune) bool {
1122	return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
1123		'0' <= ch && ch <= '9' ||
1124		ch == '_' ||
1125		ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch)))
1126}
1127
1128// ImportPathToAssumedName returns the assumed package name of an import path.
1129// It does this using only string parsing of the import path.
1130// It picks the last element of the path that does not look like a major
1131// version, and then picks the valid identifier off the start of that element.
1132// It is used to determine if a local rename should be added to an import for
1133// clarity.
1134// This function could be moved to a standard package and exported if we want
1135// for use in other tools.
1136func ImportPathToAssumedName(importPath string) string {
1137	base := path.Base(importPath)
1138	if strings.HasPrefix(base, "v") {
1139		if _, err := strconv.Atoi(base[1:]); err == nil {
1140			dir := path.Dir(importPath)
1141			if dir != "." {
1142				base = path.Base(dir)
1143			}
1144		}
1145	}
1146	base = strings.TrimPrefix(base, "go-")
1147	if i := strings.IndexFunc(base, notIdentifier); i >= 0 {
1148		base = base[:i]
1149	}
1150	return base
1151}
1152
1153// gopathResolver implements resolver for GOPATH workspaces.
1154type gopathResolver struct {
1155	env      *ProcessEnv
1156	walked   bool
1157	cache    *dirInfoCache
1158	scanSema chan struct{} // scanSema prevents concurrent scans.
1159}
1160
1161func newGopathResolver(env *ProcessEnv) *gopathResolver {
1162	r := &gopathResolver{
1163		env: env,
1164		cache: &dirInfoCache{
1165			dirs:      map[string]*directoryPackageInfo{},
1166			listeners: map[*int]cacheListener{},
1167		},
1168		scanSema: make(chan struct{}, 1),
1169	}
1170	r.scanSema <- struct{}{}
1171	return r
1172}
1173
1174func (r *gopathResolver) ClearForNewScan() {
1175	<-r.scanSema
1176	r.cache = &dirInfoCache{
1177		dirs:      map[string]*directoryPackageInfo{},
1178		listeners: map[*int]cacheListener{},
1179	}
1180	r.walked = false
1181	r.scanSema <- struct{}{}
1182}
1183
1184func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
1185	names := map[string]string{}
1186	bctx, err := r.env.buildContext()
1187	if err != nil {
1188		return nil, err
1189	}
1190	for _, path := range importPaths {
1191		names[path] = importPathToName(bctx, path, srcDir)
1192	}
1193	return names, nil
1194}
1195
1196// importPathToName finds out the actual package name, as declared in its .go files.
1197func importPathToName(bctx *build.Context, importPath, srcDir string) string {
1198	// Fast path for standard library without going to disk.
1199	if _, ok := stdlib[importPath]; ok {
1200		return path.Base(importPath) // stdlib packages always match their paths.
1201	}
1202
1203	buildPkg, err := bctx.Import(importPath, srcDir, build.FindOnly)
1204	if err != nil {
1205		return ""
1206	}
1207	pkgName, err := packageDirToName(buildPkg.Dir)
1208	if err != nil {
1209		return ""
1210	}
1211	return pkgName
1212}
1213
1214// packageDirToName is a faster version of build.Import if
1215// the only thing desired is the package name. Given a directory,
1216// packageDirToName then only parses one file in the package,
1217// trusting that the files in the directory are consistent.
1218func packageDirToName(dir string) (packageName string, err error) {
1219	d, err := os.Open(dir)
1220	if err != nil {
1221		return "", err
1222	}
1223	names, err := d.Readdirnames(-1)
1224	d.Close()
1225	if err != nil {
1226		return "", err
1227	}
1228	sort.Strings(names) // to have predictable behavior
1229	var lastErr error
1230	var nfile int
1231	for _, name := range names {
1232		if !strings.HasSuffix(name, ".go") {
1233			continue
1234		}
1235		if strings.HasSuffix(name, "_test.go") {
1236			continue
1237		}
1238		nfile++
1239		fullFile := filepath.Join(dir, name)
1240
1241		fset := token.NewFileSet()
1242		f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly)
1243		if err != nil {
1244			lastErr = err
1245			continue
1246		}
1247		pkgName := f.Name.Name
1248		if pkgName == "documentation" {
1249			// Special case from go/build.ImportDir, not
1250			// handled by ctx.MatchFile.
1251			continue
1252		}
1253		if pkgName == "main" {
1254			// Also skip package main, assuming it's a +build ignore generator or example.
1255			// Since you can't import a package main anyway, there's no harm here.
1256			continue
1257		}
1258		return pkgName, nil
1259	}
1260	if lastErr != nil {
1261		return "", lastErr
1262	}
1263	return "", fmt.Errorf("no importable package found in %d Go files", nfile)
1264}
1265
1266type pkg struct {
1267	dir             string  // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
1268	importPathShort string  // vendorless import path ("net/http", "a/b")
1269	packageName     string  // package name loaded from source if requested
1270	relevance       float64 // a weakly-defined score of how relevant a package is. 0 is most relevant.
1271}
1272
1273type pkgDistance struct {
1274	pkg      *pkg
1275	distance int // relative distance to target
1276}
1277
1278// byDistanceOrImportPathShortLength sorts by relative distance breaking ties
1279// on the short import path length and then the import string itself.
1280type byDistanceOrImportPathShortLength []pkgDistance
1281
1282func (s byDistanceOrImportPathShortLength) Len() int { return len(s) }
1283func (s byDistanceOrImportPathShortLength) Less(i, j int) bool {
1284	di, dj := s[i].distance, s[j].distance
1285	if di == -1 {
1286		return false
1287	}
1288	if dj == -1 {
1289		return true
1290	}
1291	if di != dj {
1292		return di < dj
1293	}
1294
1295	vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort
1296	if len(vi) != len(vj) {
1297		return len(vi) < len(vj)
1298	}
1299	return vi < vj
1300}
1301func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
1302
1303func distance(basepath, targetpath string) int {
1304	p, err := filepath.Rel(basepath, targetpath)
1305	if err != nil {
1306		return -1
1307	}
1308	if p == "." {
1309		return 0
1310	}
1311	return strings.Count(p, string(filepath.Separator)) + 1
1312}
1313
1314func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error {
1315	add := func(root gopathwalk.Root, dir string) {
1316		// We assume cached directories have not changed. We can skip them and their
1317		// children.
1318		if _, ok := r.cache.Load(dir); ok {
1319			return
1320		}
1321
1322		importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):])
1323		info := directoryPackageInfo{
1324			status:                 directoryScanned,
1325			dir:                    dir,
1326			rootType:               root.Type,
1327			nonCanonicalImportPath: VendorlessPath(importpath),
1328		}
1329		r.cache.Store(dir, info)
1330	}
1331	processDir := func(info directoryPackageInfo) {
1332		// Skip this directory if we were not able to get the package information successfully.
1333		if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil {
1334			return
1335		}
1336
1337		p := &pkg{
1338			importPathShort: info.nonCanonicalImportPath,
1339			dir:             info.dir,
1340			relevance:       MaxRelevance - 1,
1341		}
1342		if info.rootType == gopathwalk.RootGOROOT {
1343			p.relevance = MaxRelevance
1344		}
1345
1346		if !callback.dirFound(p) {
1347			return
1348		}
1349		var err error
1350		p.packageName, err = r.cache.CachePackageName(info)
1351		if err != nil {
1352			return
1353		}
1354
1355		if !callback.packageNameLoaded(p) {
1356			return
1357		}
1358		if _, exports, err := r.loadExports(ctx, p, false); err == nil {
1359			callback.exportsLoaded(p, exports)
1360		}
1361	}
1362	stop := r.cache.ScanAndListen(ctx, processDir)
1363	defer stop()
1364
1365	goenv, err := r.env.goEnv()
1366	if err != nil {
1367		return err
1368	}
1369	var roots []gopathwalk.Root
1370	roots = append(roots, gopathwalk.Root{filepath.Join(goenv["GOROOT"], "src"), gopathwalk.RootGOROOT})
1371	for _, p := range filepath.SplitList(goenv["GOPATH"]) {
1372		roots = append(roots, gopathwalk.Root{filepath.Join(p, "src"), gopathwalk.RootGOPATH})
1373	}
1374	// The callback is not necessarily safe to use in the goroutine below. Process roots eagerly.
1375	roots = filterRoots(roots, callback.rootFound)
1376	// We can't cancel walks, because we need them to finish to have a usable
1377	// cache. Instead, run them in a separate goroutine and detach.
1378	scanDone := make(chan struct{})
1379	go func() {
1380		select {
1381		case <-ctx.Done():
1382			return
1383		case <-r.scanSema:
1384		}
1385		defer func() { r.scanSema <- struct{}{} }()
1386		gopathwalk.Walk(roots, add, gopathwalk.Options{Logf: r.env.Logf, ModulesEnabled: false})
1387		close(scanDone)
1388	}()
1389	select {
1390	case <-ctx.Done():
1391	case <-scanDone:
1392	}
1393	return nil
1394}
1395
1396func (r *gopathResolver) scoreImportPath(ctx context.Context, path string) float64 {
1397	if _, ok := stdlib[path]; ok {
1398		return MaxRelevance
1399	}
1400	return MaxRelevance - 1
1401}
1402
1403func filterRoots(roots []gopathwalk.Root, include func(gopathwalk.Root) bool) []gopathwalk.Root {
1404	var result []gopathwalk.Root
1405	for _, root := range roots {
1406		if !include(root) {
1407			continue
1408		}
1409		result = append(result, root)
1410	}
1411	return result
1412}
1413
1414func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
1415	if info, ok := r.cache.Load(pkg.dir); ok && !includeTest {
1416		return r.cache.CacheExports(ctx, r.env, info)
1417	}
1418	return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest)
1419}
1420
1421// VendorlessPath returns the devendorized version of the import path ipath.
1422// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
1423func VendorlessPath(ipath string) string {
1424	// Devendorize for use in import statement.
1425	if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
1426		return ipath[i+len("/vendor/"):]
1427	}
1428	if strings.HasPrefix(ipath, "vendor/") {
1429		return ipath[len("vendor/"):]
1430	}
1431	return ipath
1432}
1433
1434func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) {
1435	// Look for non-test, buildable .go files which could provide exports.
1436	all, err := ioutil.ReadDir(dir)
1437	if err != nil {
1438		return "", nil, err
1439	}
1440	var files []os.FileInfo
1441	for _, fi := range all {
1442		name := fi.Name()
1443		if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) {
1444			continue
1445		}
1446		match, err := env.matchFile(dir, fi.Name())
1447		if err != nil || !match {
1448			continue
1449		}
1450		files = append(files, fi)
1451	}
1452
1453	if len(files) == 0 {
1454		return "", nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir)
1455	}
1456
1457	var pkgName string
1458	var exports []string
1459	fset := token.NewFileSet()
1460	for _, fi := range files {
1461		select {
1462		case <-ctx.Done():
1463			return "", nil, ctx.Err()
1464		default:
1465		}
1466
1467		fullFile := filepath.Join(dir, fi.Name())
1468		f, err := parser.ParseFile(fset, fullFile, nil, 0)
1469		if err != nil {
1470			if env.Logf != nil {
1471				env.Logf("error parsing %v: %v", fullFile, err)
1472			}
1473			continue
1474		}
1475		if f.Name.Name == "documentation" {
1476			// Special case from go/build.ImportDir, not
1477			// handled by MatchFile above.
1478			continue
1479		}
1480		if includeTest && strings.HasSuffix(f.Name.Name, "_test") {
1481			// x_test package. We want internal test files only.
1482			continue
1483		}
1484		pkgName = f.Name.Name
1485		for name := range f.Scope.Objects {
1486			if ast.IsExported(name) {
1487				exports = append(exports, name)
1488			}
1489		}
1490	}
1491
1492	if env.Logf != nil {
1493		sortedExports := append([]string(nil), exports...)
1494		sort.Strings(sortedExports)
1495		env.Logf("loaded exports in dir %v (package %v): %v", dir, pkgName, strings.Join(sortedExports, ", "))
1496	}
1497	return pkgName, exports, nil
1498}
1499
1500// findImport searches for a package with the given symbols.
1501// If no package is found, findImport returns ("", false, nil)
1502func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool, filename string) (*pkg, error) {
1503	// Sort the candidates by their import package length,
1504	// assuming that shorter package names are better than long
1505	// ones.  Note that this sorts by the de-vendored name, so
1506	// there's no "penalty" for vendoring.
1507	sort.Sort(byDistanceOrImportPathShortLength(candidates))
1508	if pass.env.Logf != nil {
1509		for i, c := range candidates {
1510			pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
1511		}
1512	}
1513	resolver, err := pass.env.GetResolver()
1514	if err != nil {
1515		return nil, err
1516	}
1517
1518	// Collect exports for packages with matching names.
1519	rescv := make([]chan *pkg, len(candidates))
1520	for i := range candidates {
1521		rescv[i] = make(chan *pkg, 1)
1522	}
1523	const maxConcurrentPackageImport = 4
1524	loadExportsSem := make(chan struct{}, maxConcurrentPackageImport)
1525
1526	ctx, cancel := context.WithCancel(ctx)
1527	var wg sync.WaitGroup
1528	defer func() {
1529		cancel()
1530		wg.Wait()
1531	}()
1532
1533	wg.Add(1)
1534	go func() {
1535		defer wg.Done()
1536		for i, c := range candidates {
1537			select {
1538			case loadExportsSem <- struct{}{}:
1539			case <-ctx.Done():
1540				return
1541			}
1542
1543			wg.Add(1)
1544			go func(c pkgDistance, resc chan<- *pkg) {
1545				defer func() {
1546					<-loadExportsSem
1547					wg.Done()
1548				}()
1549
1550				if pass.env.Logf != nil {
1551					pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
1552				}
1553				// If we're an x_test, load the package under test's test variant.
1554				includeTest := strings.HasSuffix(pass.f.Name.Name, "_test") && c.pkg.dir == pass.srcDir
1555				_, exports, err := resolver.loadExports(ctx, c.pkg, includeTest)
1556				if err != nil {
1557					if pass.env.Logf != nil {
1558						pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
1559					}
1560					resc <- nil
1561					return
1562				}
1563
1564				exportsMap := make(map[string]bool, len(exports))
1565				for _, sym := range exports {
1566					exportsMap[sym] = true
1567				}
1568
1569				// If it doesn't have the right
1570				// symbols, send nil to mean no match.
1571				for symbol := range symbols {
1572					if !exportsMap[symbol] {
1573						resc <- nil
1574						return
1575					}
1576				}
1577				resc <- c.pkg
1578			}(c, rescv[i])
1579		}
1580	}()
1581
1582	for _, resc := range rescv {
1583		pkg := <-resc
1584		if pkg == nil {
1585			continue
1586		}
1587		return pkg, nil
1588	}
1589	return nil, nil
1590}
1591
1592// pkgIsCandidate reports whether pkg is a candidate for satisfying the
1593// finding which package pkgIdent in the file named by filename is trying
1594// to refer to.
1595//
1596// This check is purely lexical and is meant to be as fast as possible
1597// because it's run over all $GOPATH directories to filter out poor
1598// candidates in order to limit the CPU and I/O later parsing the
1599// exports in candidate packages.
1600//
1601// filename is the file being formatted.
1602// pkgIdent is the package being searched for, like "client" (if
1603// searching for "client.New")
1604func pkgIsCandidate(filename string, refs references, pkg *pkg) bool {
1605	// Check "internal" and "vendor" visibility:
1606	if !canUse(filename, pkg.dir) {
1607		return false
1608	}
1609
1610	// Speed optimization to minimize disk I/O:
1611	// the last two components on disk must contain the
1612	// package name somewhere.
1613	//
1614	// This permits mismatch naming like directory
1615	// "go-foo" being package "foo", or "pkg.v3" being "pkg",
1616	// or directory "google.golang.org/api/cloudbilling/v1"
1617	// being package "cloudbilling", but doesn't
1618	// permit a directory "foo" to be package
1619	// "bar", which is strongly discouraged
1620	// anyway. There's no reason goimports needs
1621	// to be slow just to accommodate that.
1622	for pkgIdent := range refs {
1623		lastTwo := lastTwoComponents(pkg.importPathShort)
1624		if strings.Contains(lastTwo, pkgIdent) {
1625			return true
1626		}
1627		if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) {
1628			lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
1629			if strings.Contains(lastTwo, pkgIdent) {
1630				return true
1631			}
1632		}
1633	}
1634	return false
1635}
1636
1637func hasHyphenOrUpperASCII(s string) bool {
1638	for i := 0; i < len(s); i++ {
1639		b := s[i]
1640		if b == '-' || ('A' <= b && b <= 'Z') {
1641			return true
1642		}
1643	}
1644	return false
1645}
1646
1647func lowerASCIIAndRemoveHyphen(s string) (ret string) {
1648	buf := make([]byte, 0, len(s))
1649	for i := 0; i < len(s); i++ {
1650		b := s[i]
1651		switch {
1652		case b == '-':
1653			continue
1654		case 'A' <= b && b <= 'Z':
1655			buf = append(buf, b+('a'-'A'))
1656		default:
1657			buf = append(buf, b)
1658		}
1659	}
1660	return string(buf)
1661}
1662
1663// canUse reports whether the package in dir is usable from filename,
1664// respecting the Go "internal" and "vendor" visibility rules.
1665func canUse(filename, dir string) bool {
1666	// Fast path check, before any allocations. If it doesn't contain vendor
1667	// or internal, it's not tricky:
1668	// Note that this can false-negative on directories like "notinternal",
1669	// but we check it correctly below. This is just a fast path.
1670	if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") {
1671		return true
1672	}
1673
1674	dirSlash := filepath.ToSlash(dir)
1675	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
1676		return true
1677	}
1678	// Vendor or internal directory only visible from children of parent.
1679	// That means the path from the current directory to the target directory
1680	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
1681	// or bar/vendor or bar/internal.
1682	// After stripping all the leading ../, the only okay place to see vendor or internal
1683	// is at the very beginning of the path.
1684	absfile, err := filepath.Abs(filename)
1685	if err != nil {
1686		return false
1687	}
1688	absdir, err := filepath.Abs(dir)
1689	if err != nil {
1690		return false
1691	}
1692	rel, err := filepath.Rel(absfile, absdir)
1693	if err != nil {
1694		return false
1695	}
1696	relSlash := filepath.ToSlash(rel)
1697	if i := strings.LastIndex(relSlash, "../"); i >= 0 {
1698		relSlash = relSlash[i+len("../"):]
1699	}
1700	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
1701}
1702
1703// lastTwoComponents returns at most the last two path components
1704// of v, using either / or \ as the path separator.
1705func lastTwoComponents(v string) string {
1706	nslash := 0
1707	for i := len(v) - 1; i >= 0; i-- {
1708		if v[i] == '/' || v[i] == '\\' {
1709			nslash++
1710			if nslash == 2 {
1711				return v[i:]
1712			}
1713		}
1714	}
1715	return v
1716}
1717
1718type visitFn func(node ast.Node) ast.Visitor
1719
1720func (fn visitFn) Visit(node ast.Node) ast.Visitor {
1721	return fn(node)
1722}
1723
1724func copyExports(pkg []string) map[string]bool {
1725	m := make(map[string]bool, len(pkg))
1726	for _, v := range pkg {
1727		m[v] = true
1728	}
1729	return m
1730}
1731