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