GoPLS Viewer

Home|gopls/internal/imports/fix.go
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(localPrefiximportPath string) (num intok bool){
36    func(localPrefiximportPath string) (num intok bool) {
37        if localPrefix == "" {
38            return
39        }
40        for _p := range strings.Split(localPrefix",") {
41            if strings.HasPrefix(importPathp) || strings.TrimSuffix(p"/") == importPath {
42                return 3true
43            }
44        }
45        return
46    },
47    func(_importPath string) (num intok bool) {
48        if strings.HasPrefix(importPath"appengine") {
49            return 2true
50        }
51        return
52    },
53    func(_importPath string) (num intok bool) {
54        firstComponent := strings.Split(importPath"/")[0]
55        if strings.Contains(firstComponent".") {
56            return 1true
57        }
58        return
59    },
60}
61
62func importGroup(localPrefiximportPath stringint {
63    for _fn := range importToGroup {
64        if nok := fn(localPrefiximportPath); 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.FileSetsrcDirfilename 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    packageFileInfoserr := 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        ferr := parser.ParseFile(fsetfilepath.Join(srcDirfi.Name()), nil0)
124        if err != nil {
125            continue
126        }
127
128        files = append(filesf)
129    }
130
131    return files
132}
133
134// addGlobals puts the names of package vars into the provided map.
135func addGlobals(f *ast.Fileglobals map[string]bool) {
136    for _decl := range f.Decls {
137        genDeclok := decl.(*ast.GenDecl)
138        if !ok {
139            continue
140        }
141
142        for _spec := range genDecl.Specs {
143            valueSpecok := 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.Filereferences {
155    refs := references{}
156
157    var visitor visitFn
158    visitor = func(node ast.Nodeast.Visitor {
159        if node == nil {
160            return visitor
161        }
162        switch v := node.(type) {
163        case *ast.SelectorExpr:
164            xidentok := 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(visitorf)
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            ImportPathpath,
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 *passfindMissingImport(pkg stringsyms map[string]bool) *ImportInfo {
214    for _candidate := range p.candidates {
215        pkgInfook := 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 *passloadPackageNames(imports []*ImportInfoerror {
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(unknownimp.ImportPath)
279    }
280
281    resolvererr := p.env.GetResolver()
282    if err != nil {
283        return err
284    }
285
286    nameserr := resolver.loadPackageNames(unknownp.srcDir)
287    if err != nil {
288        return err
289    }
290
291    for pathname := 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 *passimportIdentifier(imp *ImportInfostring {
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 *passload() ([]*ImportFixbool) {
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(otherFileglobals)
334        }
335        p.candidates = append(p.candidatescollectImports(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(importsp.candidates...))
343        if err != nil {
344            if p.env.Logf != nil {
345                p.env.Logf("loading package names: %v"err)
346            }
347            return nilfalse
348        }
349    }
350    for _imp := range imports {
351        p.existingImports[p.importIdentifier(imp)] = imp
352    }
353
354    // Find missing references.
355    for leftrights := 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 nilfalse
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 *passfix() ([]*ImportFixbool) {
376    // Find missing imports.
377    var selected []*ImportInfo
378    for leftrights := range p.missingRefs {
379        if imp := p.findMissingImport(leftrights); imp != nil {
380            selected = append(selectedimp)
381        }
382    }
383
384    if !p.lastTry && len(selected) != len(p.missingRefs) {
385        return nilfalse
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                IdentNamep.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                StmtInfoImportInfo{
409                    Name:       name,
410                    ImportPathimp.ImportPath,
411                },
412                IdentNamep.importIdentifier(imp),
413                FixType:   SetImportName,
414            })
415        }
416    }
417
418    for _imp := range selected {
419        fixes = append(fixes, &ImportFix{
420            StmtInfoImportInfo{
421                Name:       p.importSpecName(imp),
422                ImportPathimp.ImportPath,
423            },
424            IdentNamep.importIdentifier(imp),
425            FixType:   AddImport,
426        })
427    }
428
429    return fixestrue
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 *passimportSpecName(imp *ImportInfostring {
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.FileSetf *ast.Filefixes []*ImportFix) {
452    for _fix := range fixes {
453        switch fix.FixType {
454        case DeleteImport:
455            astutil.DeleteNamedImport(fsetffix.StmtInfo.Namefix.StmtInfo.ImportPath)
456        case AddImport:
457            astutil.AddNamedImport(fsetffix.StmtInfo.Namefix.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                        NamePosspec.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 *passassumeSiblingImportsValid() {
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 leftrights := range refs {
484            if impok := importsByName[left]; ok {
485                if mok := 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                    exportsrights,
492                })
493            }
494        }
495    }
496}
497
498// addCandidate adds a candidate import to p, and merges in the information
499// in pkg.
500func (p *passaddCandidate(imp *ImportInfopkg *packageInfo) {
501    p.candidates = append(p.candidatesimp)
502    if existingok := 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.FileSetf *ast.Filefilename stringenv *ProcessEnverror {
522    fixeserr := getFixes(fsetffilenameenv)
523    if err != nil {
524        return err
525    }
526    apply(fsetffixes)
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.FileSetf *ast.Filefilename stringenv *ProcessEnv) ([]*ImportFixerror) {
533    abserr := filepath.Abs(filename)
534    if err != nil {
535        return nilerr
536    }
537    srcDir := filepath.Dir(abs)
538    if env.Logf != nil {
539        env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ..."filenameabssrcDir)
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{fsetfsetffsrcDirsrcDirenvenv}
547    if fixesdone := p.load(); done {
548        return fixesnil
549    }
550
551    otherFiles := parseOtherFiles(fsetsrcDirfilename)
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 fixesdone := p.load(); done {
557        return fixesnil
558    }
559
560    // Now we can try adding imports from the stdlib.
561    p.assumeSiblingImportsValid()
562    addStdlibCandidates(pp.missingRefs)
563    if fixesdone := p.fix(); done {
564        return fixesnil
565    }
566
567    // Third pass: get real package names where we had previously used
568    // the naive algorithm.
569    p = &pass{fsetfsetffsrcDirsrcDirenvenv}
570    p.loadRealPackageNames = true
571    p.otherFiles = otherFiles
572    if fixesdone := p.load(); done {
573        return fixesnil
574    }
575
576    if err := addStdlibCandidates(pp.missingRefs); err != nil {
577        return nilerr
578    }
579    p.assumeSiblingImportsValid()
580    if fixesdone := p.fix(); done {
581        return fixesnil
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(pp.missingRefsfilename); err != nil {
587        return nilerr
588    }
589
590    p.lastTry = true
591    fixes_ := p.fix()
592    return fixesnil
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.ContextwrappedCallback *scanCallbackfilenamefilePkg stringenv *ProcessEnverror {
603    notSelf := func(p *pkgbool {
604        return p.packageName != filePkg || p.dir != filepath.Dir(filename)
605    }
606    goenverr := 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 importPathexports := range stdlib {
616        p := &pkg{
617            dir:             filepath.Join(goenv["GOROOT"], "src"importPath),
618            importPathShortimportPath,
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(pexports)
625        }
626    }
627
628    scanFilter := &scanCallback{
629        rootFound: func(root gopathwalk.Rootbool {
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        dirFoundwrappedCallback.dirFound,
635        packageNameLoaded: func(pkg *pkgbool {
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 *pkgexports []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                _exportserr = loadExportsFromFiles(ctxenvpkg.dirtrue)
649                if err != nil {
650                    return
651                }
652            }
653            wrappedCallback.exportsLoaded(pkgexports)
654        },
655    }
656    resolvererr := env.GetResolver()
657    if err != nil {
658        return err
659    }
660    return resolver.scan(ctxscanFilter)
661}
662
663func ScoreImportPaths(ctx context.Contextenv *ProcessEnvpaths []string) (map[string]float64error) {
664    result := make(map[string]float64)
665    resolvererr := env.GetResolver()
666    if err != nil {
667        return nilerr
668    }
669    for _path := range paths {
670        result[path] = resolver.scoreImportPath(ctxpath)
671    }
672    return resultnil
673}
674
675func PrimeCache(ctx context.Contextenv *ProcessEnverror {
676    // Fully scan the disk for directories, but don't actually read any Go files.
677    callback := &scanCallback{
678        rootFound: func(gopathwalk.Rootbool {
679            return true
680        },
681        dirFound: func(pkg *pkgbool {
682            return false
683        },
684        packageNameLoaded: func(pkg *pkgbool {
685            return false
686        },
687    }
688    return getCandidatePkgs(ctxcallback""""env)
689}
690
691func candidateImportName(pkg *pkgstring {
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.
700//
701// Beware that the wrapped function may be called multiple times concurrently.
702// TODO(adonovan): encapsulate the concurrency.
703func GetAllCandidates(ctx context.Contextwrapped func(ImportFix), searchPrefixfilenamefilePkg stringenv *ProcessEnverror {
704    callback := &scanCallback{
705        rootFound: func(gopathwalk.Rootbool {
706            return true
707        },
708        dirFound: func(pkg *pkgbool {
709            if !canUse(filenamepkg.dir) {
710                return false
711            }
712            // Try the assumed package name first, then a simpler path match
713            // in case of packages named vN, which are not uncommon.
714            return strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) ||
715                strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix)
716        },
717        packageNameLoaded: func(pkg *pkgbool {
718            if !strings.HasPrefix(pkg.packageNamesearchPrefix) {
719                return false
720            }
721            wrapped(ImportFix{
722                StmtInfoImportInfo{
723                    ImportPathpkg.importPathShort,
724                    Name:       candidateImportName(pkg),
725                },
726                IdentNamepkg.packageName,
727                FixType:   AddImport,
728                Relevancepkg.relevance,
729            })
730            return false
731        },
732    }
733    return getCandidatePkgs(ctxcallbackfilenamefilePkgenv)
734}
735
736// GetImportPaths calls wrapped for each package whose import path starts with
737// searchPrefix, and can be imported from filename with the package name filePkg.
738func GetImportPaths(ctx context.Contextwrapped func(ImportFix), searchPrefixfilenamefilePkg stringenv *ProcessEnverror {
739    callback := &scanCallback{
740        rootFound: func(gopathwalk.Rootbool {
741            return true
742        },
743        dirFound: func(pkg *pkgbool {
744            if !canUse(filenamepkg.dir) {
745                return false
746            }
747            return strings.HasPrefix(pkg.importPathShortsearchPrefix)
748        },
749        packageNameLoaded: func(pkg *pkgbool {
750            wrapped(ImportFix{
751                StmtInfoImportInfo{
752                    ImportPathpkg.importPathShort,
753                    Name:       candidateImportName(pkg),
754                },
755                IdentNamepkg.packageName,
756                FixType:   AddImport,
757                Relevancepkg.relevance,
758            })
759            return false
760        },
761    }
762    return getCandidatePkgs(ctxcallbackfilenamefilePkgenv)
763}
764
765// A PackageExport is a package and its exports.
766type PackageExport struct {
767    Fix     *ImportFix
768    Exports []string
769}
770
771// GetPackageExports returns all known packages with name pkg and their exports.
772func GetPackageExports(ctx context.Contextwrapped func(PackageExport), searchPkgfilenamefilePkg stringenv *ProcessEnverror {
773    callback := &scanCallback{
774        rootFound: func(gopathwalk.Rootbool {
775            return true
776        },
777        dirFound: func(pkg *pkgbool {
778            return pkgIsCandidate(filenamereferences{searchPkgnil}, pkg)
779        },
780        packageNameLoaded: func(pkg *pkgbool {
781            return pkg.packageName == searchPkg
782        },
783        exportsLoaded: func(pkg *pkgexports []string) {
784            sort.Strings(exports)
785            wrapped(PackageExport{
786                Fix: &ImportFix{
787                    StmtInfoImportInfo{
788                        ImportPathpkg.importPathShort,
789                        Name:       candidateImportName(pkg),
790                    },
791                    IdentNamepkg.packageName,
792                    FixType:   AddImport,
793                    Relevancepkg.relevance,
794                },
795                Exportsexports,
796            })
797        },
798    }
799    return getCandidatePkgs(ctxcallbackfilenamefilePkgenv)
800}
801
802var RequiredGoEnvVars = []string{"GO111MODULE""GOFLAGS""GOINSECURE""GOMOD""GOMODCACHE""GONOPROXY""GONOSUMDB""GOPATH""GOPROXY""GOROOT""GOSUMDB""GOWORK"}
803
804// ProcessEnv contains environment variables and settings that affect the use of
805// the go command, the go/build package, etc.
806type ProcessEnv struct {
807    GocmdRunner *gocommand.Runner
808
809    BuildFlags []string
810    ModFlag    string
811    ModFile    string
812
813    // SkipPathInScan returns true if the path should be skipped from scans of
814    // the RootCurrentModule root type. The function argument is a clean,
815    // absolute path.
816    SkipPathInScan func(stringbool
817
818    // Env overrides the OS environment, and can be used to specify
819    // GOPROXY, GO111MODULE, etc. PATH cannot be set here, because
820    // exec.Command will not honor it.
821    // Specifying all of RequiredGoEnvVars avoids a call to `go env`.
822    Env map[string]string
823
824    WorkingDir string
825
826    // If Logf is non-nil, debug logging is enabled through this function.
827    Logf func(format stringargs ...interface{})
828
829    initialized bool
830
831    resolver Resolver
832}
833
834func (e *ProcessEnvgoEnv() (map[string]stringerror) {
835    if err := e.init(); err != nil {
836        return nilerr
837    }
838    return e.Envnil
839}
840
841func (e *ProcessEnvmatchFile(dirname string) (boolerror) {
842    bctxerr := e.buildContext()
843    if err != nil {
844        return falseerr
845    }
846    return bctx.MatchFile(dirname)
847}
848
849// CopyConfig copies the env's configuration into a new env.
850func (e *ProcessEnvCopyConfig() *ProcessEnv {
851    copy := &ProcessEnv{
852        GocmdRunnere.GocmdRunner,
853        initializede.initialized,
854        BuildFlags:  e.BuildFlags,
855        Logf:        e.Logf,
856        WorkingDir:  e.WorkingDir,
857        resolver:    nil,
858        Env:         map[string]string{},
859    }
860    for kv := range e.Env {
861        copy.Env[k] = v
862    }
863    return copy
864}
865
866func (e *ProcessEnvinit() error {
867    if e.initialized {
868        return nil
869    }
870
871    foundAllRequired := true
872    for _k := range RequiredGoEnvVars {
873        if _ok := e.Env[k]; !ok {
874            foundAllRequired = false
875            break
876        }
877    }
878    if foundAllRequired {
879        e.initialized = true
880        return nil
881    }
882
883    if e.Env == nil {
884        e.Env = map[string]string{}
885    }
886
887    goEnv := map[string]string{}
888    stdouterr := e.invokeGo(context.TODO(), "env"append([]string{"-json"}, RequiredGoEnvVars...)...)
889    if err != nil {
890        return err
891    }
892    if err := json.Unmarshal(stdout.Bytes(), &goEnv); err != nil {
893        return err
894    }
895    for kv := range goEnv {
896        e.Env[k] = v
897    }
898    e.initialized = true
899    return nil
900}
901
902func (e *ProcessEnvenv() []string {
903    var env []string // the gocommand package will prepend os.Environ.
904    for kv := range e.Env {
905        env = append(envk+"="+v)
906    }
907    return env
908}
909
910func (e *ProcessEnvGetResolver() (Resolvererror) {
911    if e.resolver != nil {
912        return e.resolvernil
913    }
914    if err := e.init(); err != nil {
915        return nilerr
916    }
917    if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 {
918        e.resolver = newGopathResolver(e)
919        return e.resolvernil
920    }
921    e.resolver = newModuleResolver(e)
922    return e.resolvernil
923}
924
925func (e *ProcessEnvbuildContext() (*build.Contexterror) {
926    ctx := build.Default
927    goenverr := e.goEnv()
928    if err != nil {
929        return nilerr
930    }
931    ctx.GOROOT = goenv["GOROOT"]
932    ctx.GOPATH = goenv["GOPATH"]
933
934    // As of Go 1.14, build.Context has a Dir field
935    // (see golang.org/issue/34860).
936    // Populate it only if present.
937    rc := reflect.ValueOf(&ctx).Elem()
938    dir := rc.FieldByName("Dir")
939    if dir.IsValid() && dir.Kind() == reflect.String {
940        dir.SetString(e.WorkingDir)
941    }
942
943    // Since Go 1.11, go/build.Context.Import may invoke 'go list' depending on
944    // the value in GO111MODULE in the process's environment. We always want to
945    // run in GOPATH mode when calling Import, so we need to prevent this from
946    // happening. In Go 1.16, GO111MODULE defaults to "on", so this problem comes
947    // up more frequently.
948    //
949    // HACK: setting any of the Context I/O hooks prevents Import from invoking
950    // 'go list', regardless of GO111MODULE. This is undocumented, but it's
951    // unlikely to change before GOPATH support is removed.
952    ctx.ReadDir = ioutil.ReadDir
953
954    return &ctxnil
955}
956
957func (e *ProcessEnvinvokeGo(ctx context.Contextverb stringargs ...string) (*bytes.Buffererror) {
958    inv := gocommand.Invocation{
959        Verb:       verb,
960        Args:       args,
961        BuildFlagse.BuildFlags,
962        Env:        e.env(),
963        Logf:       e.Logf,
964        WorkingDire.WorkingDir,
965    }
966    return e.GocmdRunner.Run(ctxinv)
967}
968
969func addStdlibCandidates(pass *passrefs referenceserror {
970    goenverr := pass.env.goEnv()
971    if err != nil {
972        return err
973    }
974    add := func(pkg string) {
975        // Prevent self-imports.
976        if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src"pkg) == pass.srcDir {
977            return
978        }
979        exports := copyExports(stdlib[pkg])
980        pass.addCandidate(
981            &ImportInfo{ImportPathpkg},
982            &packageInfo{namepath.Base(pkg), exportsexports})
983    }
984    for left := range refs {
985        if left == "rand" {
986            // Make sure we try crypto/rand before math/rand.
987            add("crypto/rand")
988            add("math/rand")
989            continue
990        }
991        for importPath := range stdlib {
992            if path.Base(importPath) == left {
993                add(importPath)
994            }
995        }
996    }
997    return nil
998}
999
1000// A Resolver does the build-system-specific parts of goimports.
1001type Resolver interface {
1002    // loadPackageNames loads the package names in importPaths.
1003    loadPackageNames(importPaths []stringsrcDir string) (map[string]stringerror)
1004    // scan works with callback to search for packages. See scanCallback for details.
1005    scan(ctx context.Contextcallback *scanCallbackerror
1006    // loadExports returns the set of exported symbols in the package at dir.
1007    // loadExports may be called concurrently.
1008    loadExports(ctx context.Contextpkg *pkgincludeTest bool) (string, []stringerror)
1009    // scoreImportPath returns the relevance for an import path.
1010    scoreImportPath(ctx context.Contextpath stringfloat64
1011
1012    ClearForNewScan()
1013}
1014
1015// A scanCallback controls a call to scan and receives its results.
1016// In general, minor errors will be silently discarded; a user should not
1017// expect to receive a full series of calls for everything.
1018type scanCallback struct {
1019    // rootFound is called before scanning a new root dir. If it returns true,
1020    // the root will be scanned. Returning false will not necessarily prevent
1021    // directories from that root making it to dirFound.
1022    rootFound func(gopathwalk.Rootbool
1023    // dirFound is called when a directory is found that is possibly a Go package.
1024    // pkg will be populated with everything except packageName.
1025    // If it returns true, the package's name will be loaded.
1026    dirFound func(pkg *pkgbool
1027    // packageNameLoaded is called when a package is found and its name is loaded.
1028    // If it returns true, the package's exports will be loaded.
1029    packageNameLoaded func(pkg *pkgbool
1030    // exportsLoaded is called when a package's exports have been loaded.
1031    exportsLoaded func(pkg *pkgexports []string)
1032}
1033
1034func addExternalCandidates(pass *passrefs referencesfilename stringerror {
1035    var mu sync.Mutex
1036    found := make(map[string][]pkgDistance)
1037    callback := &scanCallback{
1038        rootFound: func(gopathwalk.Rootbool {
1039            return true // We want everything.
1040        },
1041        dirFound: func(pkg *pkgbool {
1042            return pkgIsCandidate(filenamerefspkg)
1043        },
1044        packageNameLoaded: func(pkg *pkgbool {
1045            if _want := refs[pkg.packageName]; !want {
1046                return false
1047            }
1048            if pkg.dir == pass.srcDir && pass.f.Name.Name == pkg.packageName {
1049                // The candidate is in the same directory and has the
1050                // same package name. Don't try to import ourselves.
1051                return false
1052            }
1053            if !canUse(filenamepkg.dir) {
1054                return false
1055            }
1056            mu.Lock()
1057            defer mu.Unlock()
1058            found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkgdistance(pass.srcDirpkg.dir)})
1059            return false // We'll do our own loading after we sort.
1060        },
1061    }
1062    resolvererr := pass.env.GetResolver()
1063    if err != nil {
1064        return err
1065    }
1066    if err = resolver.scan(context.Background(), callback); err != nil {
1067        return err
1068    }
1069
1070    // Search for imports matching potential package references.
1071    type result struct {
1072        imp *ImportInfo
1073        pkg *packageInfo
1074    }
1075    results := make(chan resultlen(refs))
1076
1077    ctxcancel := context.WithCancel(context.TODO())
1078    var wg sync.WaitGroup
1079    defer func() {
1080        cancel()
1081        wg.Wait()
1082    }()
1083    var (
1084        firstErr     error
1085        firstErrOnce sync.Once
1086    )
1087    for pkgNamesymbols := range refs {
1088        wg.Add(1)
1089        go func(pkgName stringsymbols map[string]bool) {
1090            defer wg.Done()
1091
1092            founderr := findImport(ctxpassfound[pkgName], pkgNamesymbolsfilename)
1093
1094            if err != nil {
1095                firstErrOnce.Do(func() {
1096                    firstErr = err
1097                    cancel()
1098                })
1099                return
1100            }
1101
1102            if found == nil {
1103                return // No matching package.
1104            }
1105
1106            imp := &ImportInfo{
1107                ImportPathfound.importPathShort,
1108            }
1109
1110            pkg := &packageInfo{
1111                name:    pkgName,
1112                exportssymbols,
1113            }
1114            results <- result{imppkg}
1115        }(pkgNamesymbols)
1116    }
1117    go func() {
1118        wg.Wait()
1119        close(results)
1120    }()
1121
1122    for result := range results {
1123        pass.addCandidate(result.impresult.pkg)
1124    }
1125    return firstErr
1126}
1127
1128// notIdentifier reports whether ch is an invalid identifier character.
1129func notIdentifier(ch runebool {
1130    return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' ||
1131        '0' <= ch && ch <= '9' ||
1132        ch == '_' ||
1133        ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch)))
1134}
1135
1136// ImportPathToAssumedName returns the assumed package name of an import path.
1137// It does this using only string parsing of the import path.
1138// It picks the last element of the path that does not look like a major
1139// version, and then picks the valid identifier off the start of that element.
1140// It is used to determine if a local rename should be added to an import for
1141// clarity.
1142// This function could be moved to a standard package and exported if we want
1143// for use in other tools.
1144func ImportPathToAssumedName(importPath stringstring {
1145    base := path.Base(importPath)
1146    if strings.HasPrefix(base"v") {
1147        if _err := strconv.Atoi(base[1:]); err == nil {
1148            dir := path.Dir(importPath)
1149            if dir != "." {
1150                base = path.Base(dir)
1151            }
1152        }
1153    }
1154    base = strings.TrimPrefix(base"go-")
1155    if i := strings.IndexFunc(basenotIdentifier); i >= 0 {
1156        base = base[:i]
1157    }
1158    return base
1159}
1160
1161// gopathResolver implements resolver for GOPATH workspaces.
1162type gopathResolver struct {
1163    env      *ProcessEnv
1164    walked   bool
1165    cache    *dirInfoCache
1166    scanSema chan struct{} // scanSema prevents concurrent scans.
1167}
1168
1169func newGopathResolver(env *ProcessEnv) *gopathResolver {
1170    r := &gopathResolver{
1171        envenv,
1172        cache: &dirInfoCache{
1173            dirs:      map[string]*directoryPackageInfo{},
1174            listeners: map[*int]cacheListener{},
1175        },
1176        scanSemamake(chan struct{}, 1),
1177    }
1178    r.scanSema <- struct{}{}
1179    return r
1180}
1181
1182func (r *gopathResolverClearForNewScan() {
1183    <-r.scanSema
1184    r.cache = &dirInfoCache{
1185        dirs:      map[string]*directoryPackageInfo{},
1186        listeners: map[*int]cacheListener{},
1187    }
1188    r.walked = false
1189    r.scanSema <- struct{}{}
1190}
1191
1192func (r *gopathResolverloadPackageNames(importPaths []stringsrcDir string) (map[string]stringerror) {
1193    names := map[string]string{}
1194    bctxerr := r.env.buildContext()
1195    if err != nil {
1196        return nilerr
1197    }
1198    for _path := range importPaths {
1199        names[path] = importPathToName(bctxpathsrcDir)
1200    }
1201    return namesnil
1202}
1203
1204// importPathToName finds out the actual package name, as declared in its .go files.
1205func importPathToName(bctx *build.ContextimportPathsrcDir stringstring {
1206    // Fast path for standard library without going to disk.
1207    if _ok := stdlib[importPath]; ok {
1208        return path.Base(importPath// stdlib packages always match their paths.
1209    }
1210
1211    buildPkgerr := bctx.Import(importPathsrcDirbuild.FindOnly)
1212    if err != nil {
1213        return ""
1214    }
1215    pkgNameerr := packageDirToName(buildPkg.Dir)
1216    if err != nil {
1217        return ""
1218    }
1219    return pkgName
1220}
1221
1222// packageDirToName is a faster version of build.Import if
1223// the only thing desired is the package name. Given a directory,
1224// packageDirToName then only parses one file in the package,
1225// trusting that the files in the directory are consistent.
1226func packageDirToName(dir string) (packageName stringerr error) {
1227    derr := os.Open(dir)
1228    if err != nil {
1229        return ""err
1230    }
1231    nameserr := d.Readdirnames(-1)
1232    d.Close()
1233    if err != nil {
1234        return ""err
1235    }
1236    sort.Strings(names// to have predictable behavior
1237    var lastErr error
1238    var nfile int
1239    for _name := range names {
1240        if !strings.HasSuffix(name".go") {
1241            continue
1242        }
1243        if strings.HasSuffix(name"_test.go") {
1244            continue
1245        }
1246        nfile++
1247        fullFile := filepath.Join(dirname)
1248
1249        fset := token.NewFileSet()
1250        ferr := parser.ParseFile(fsetfullFilenilparser.PackageClauseOnly)
1251        if err != nil {
1252            lastErr = err
1253            continue
1254        }
1255        pkgName := f.Name.Name
1256        if pkgName == "documentation" {
1257            // Special case from go/build.ImportDir, not
1258            // handled by ctx.MatchFile.
1259            continue
1260        }
1261        if pkgName == "main" {
1262            // Also skip package main, assuming it's a +build ignore generator or example.
1263            // Since you can't import a package main anyway, there's no harm here.
1264            continue
1265        }
1266        return pkgNamenil
1267    }
1268    if lastErr != nil {
1269        return ""lastErr
1270    }
1271    return ""fmt.Errorf("no importable package found in %d Go files"nfile)
1272}
1273
1274type pkg struct {
1275    dir             string  // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
1276    importPathShort string  // vendorless import path ("net/http", "a/b")
1277    packageName     string  // package name loaded from source if requested
1278    relevance       float64 // a weakly-defined score of how relevant a package is. 0 is most relevant.
1279}
1280
1281type pkgDistance struct {
1282    pkg      *pkg
1283    distance int // relative distance to target
1284}
1285
1286// byDistanceOrImportPathShortLength sorts by relative distance breaking ties
1287// on the short import path length and then the import string itself.
1288type byDistanceOrImportPathShortLength []pkgDistance
1289
1290func (s byDistanceOrImportPathShortLengthLen() int { return len(s) }
1291func (s byDistanceOrImportPathShortLengthLess(ij intbool {
1292    didj := s[i].distances[j].distance
1293    if di == -1 {
1294        return false
1295    }
1296    if dj == -1 {
1297        return true
1298    }
1299    if di != dj {
1300        return di < dj
1301    }
1302
1303    vivj := s[i].pkg.importPathShorts[j].pkg.importPathShort
1304    if len(vi) != len(vj) {
1305        return len(vi) < len(vj)
1306    }
1307    return vi < vj
1308}
1309func (s byDistanceOrImportPathShortLengthSwap(ij int) { s[i], s[j] = s[j], s[i] }
1310
1311func distance(basepathtargetpath stringint {
1312    perr := filepath.Rel(basepathtargetpath)
1313    if err != nil {
1314        return -1
1315    }
1316    if p == "." {
1317        return 0
1318    }
1319    return strings.Count(pstring(filepath.Separator)) + 1
1320}
1321
1322func (r *gopathResolverscan(ctx context.Contextcallback *scanCallbackerror {
1323    add := func(root gopathwalk.Rootdir string) {
1324        // We assume cached directories have not changed. We can skip them and their
1325        // children.
1326        if _ok := r.cache.Load(dir); ok {
1327            return
1328        }
1329
1330        importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):])
1331        info := directoryPackageInfo{
1332            status:                 directoryScanned,
1333            dir:                    dir,
1334            rootType:               root.Type,
1335            nonCanonicalImportPathVendorlessPath(importpath),
1336        }
1337        r.cache.Store(dirinfo)
1338    }
1339    processDir := func(info directoryPackageInfo) {
1340        // Skip this directory if we were not able to get the package information successfully.
1341        if scannederr := info.reachedStatus(directoryScanned); !scanned || err != nil {
1342            return
1343        }
1344
1345        p := &pkg{
1346            importPathShortinfo.nonCanonicalImportPath,
1347            dir:             info.dir,
1348            relevance:       MaxRelevance - 1,
1349        }
1350        if info.rootType == gopathwalk.RootGOROOT {
1351            p.relevance = MaxRelevance
1352        }
1353
1354        if !callback.dirFound(p) {
1355            return
1356        }
1357        var err error
1358        p.packageNameerr = r.cache.CachePackageName(info)
1359        if err != nil {
1360            return
1361        }
1362
1363        if !callback.packageNameLoaded(p) {
1364            return
1365        }
1366        if _exportserr := r.loadExports(ctxpfalse); err == nil {
1367            callback.exportsLoaded(pexports)
1368        }
1369    }
1370    stop := r.cache.ScanAndListen(ctxprocessDir)
1371    defer stop()
1372
1373    goenverr := r.env.goEnv()
1374    if err != nil {
1375        return err
1376    }
1377    var roots []gopathwalk.Root
1378    roots = append(rootsgopathwalk.Root{Pathfilepath.Join(goenv["GOROOT"], "src"), Typegopathwalk.RootGOROOT})
1379    for _p := range filepath.SplitList(goenv["GOPATH"]) {
1380        roots = append(rootsgopathwalk.Root{Pathfilepath.Join(p"src"), Typegopathwalk.RootGOPATH})
1381    }
1382    // The callback is not necessarily safe to use in the goroutine below. Process roots eagerly.
1383    roots = filterRoots(rootscallback.rootFound)
1384    // We can't cancel walks, because we need them to finish to have a usable
1385    // cache. Instead, run them in a separate goroutine and detach.
1386    scanDone := make(chan struct{})
1387    go func() {
1388        select {
1389        case <-ctx.Done():
1390            return
1391        case <-r.scanSema:
1392        }
1393        defer func() { r.scanSema <- struct{}{} }()
1394        gopathwalk.Walk(rootsaddgopathwalk.Options{Logfr.env.LogfModulesEnabledfalse})
1395        close(scanDone)
1396    }()
1397    select {
1398    case <-ctx.Done():
1399    case <-scanDone:
1400    }
1401    return nil
1402}
1403
1404func (r *gopathResolverscoreImportPath(ctx context.Contextpath stringfloat64 {
1405    if _ok := stdlib[path]; ok {
1406        return MaxRelevance
1407    }
1408    return MaxRelevance - 1
1409}
1410
1411func filterRoots(roots []gopathwalk.Rootinclude func(gopathwalk.Rootbool) []gopathwalk.Root {
1412    var result []gopathwalk.Root
1413    for _root := range roots {
1414        if !include(root) {
1415            continue
1416        }
1417        result = append(resultroot)
1418    }
1419    return result
1420}
1421
1422func (r *gopathResolverloadExports(ctx context.Contextpkg *pkgincludeTest bool) (string, []stringerror) {
1423    if infook := r.cache.Load(pkg.dir); ok && !includeTest {
1424        return r.cache.CacheExports(ctxr.envinfo)
1425    }
1426    return loadExportsFromFiles(ctxr.envpkg.dirincludeTest)
1427}
1428
1429// VendorlessPath returns the devendorized version of the import path ipath.
1430// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
1431func VendorlessPath(ipath stringstring {
1432    // Devendorize for use in import statement.
1433    if i := strings.LastIndex(ipath"/vendor/"); i >= 0 {
1434        return ipath[i+len("/vendor/"):]
1435    }
1436    if strings.HasPrefix(ipath"vendor/") {
1437        return ipath[len("vendor/"):]
1438    }
1439    return ipath
1440}
1441
1442func loadExportsFromFiles(ctx context.Contextenv *ProcessEnvdir stringincludeTest bool) (string, []stringerror) {
1443    // Look for non-test, buildable .go files which could provide exports.
1444    allerr := ioutil.ReadDir(dir)
1445    if err != nil {
1446        return ""nilerr
1447    }
1448    var files []os.FileInfo
1449    for _fi := range all {
1450        name := fi.Name()
1451        if !strings.HasSuffix(name".go") || (!includeTest && strings.HasSuffix(name"_test.go")) {
1452            continue
1453        }
1454        matcherr := env.matchFile(dirfi.Name())
1455        if err != nil || !match {
1456            continue
1457        }
1458        files = append(filesfi)
1459    }
1460
1461    if len(files) == 0 {
1462        return ""nilfmt.Errorf("dir %v contains no buildable, non-test .go files"dir)
1463    }
1464
1465    var pkgName string
1466    var exports []string
1467    fset := token.NewFileSet()
1468    for _fi := range files {
1469        select {
1470        case <-ctx.Done():
1471            return ""nilctx.Err()
1472        default:
1473        }
1474
1475        fullFile := filepath.Join(dirfi.Name())
1476        ferr := parser.ParseFile(fsetfullFilenil0)
1477        if err != nil {
1478            if env.Logf != nil {
1479                env.Logf("error parsing %v: %v"fullFileerr)
1480            }
1481            continue
1482        }
1483        if f.Name.Name == "documentation" {
1484            // Special case from go/build.ImportDir, not
1485            // handled by MatchFile above.
1486            continue
1487        }
1488        if includeTest && strings.HasSuffix(f.Name.Name"_test") {
1489            // x_test package. We want internal test files only.
1490            continue
1491        }
1492        pkgName = f.Name.Name
1493        for name := range f.Scope.Objects {
1494            if ast.IsExported(name) {
1495                exports = append(exportsname)
1496            }
1497        }
1498    }
1499
1500    if env.Logf != nil {
1501        sortedExports := append([]string(nil), exports...)
1502        sort.Strings(sortedExports)
1503        env.Logf("loaded exports in dir %v (package %v): %v"dirpkgNamestrings.Join(sortedExports", "))
1504    }
1505    return pkgNameexportsnil
1506}
1507
1508// findImport searches for a package with the given symbols.
1509// If no package is found, findImport returns ("", false, nil)
1510func findImport(ctx context.Contextpass *passcandidates []pkgDistancepkgName stringsymbols map[string]boolfilename string) (*pkgerror) {
1511    // Sort the candidates by their import package length,
1512    // assuming that shorter package names are better than long
1513    // ones.  Note that this sorts by the de-vendored name, so
1514    // there's no "penalty" for vendoring.
1515    sort.Sort(byDistanceOrImportPathShortLength(candidates))
1516    if pass.env.Logf != nil {
1517        for ic := range candidates {
1518            pass.env.Logf("%s candidate %d/%d: %v in %v"pkgNamei+1len(candidates), c.pkg.importPathShortc.pkg.dir)
1519        }
1520    }
1521    resolvererr := pass.env.GetResolver()
1522    if err != nil {
1523        return nilerr
1524    }
1525
1526    // Collect exports for packages with matching names.
1527    rescv := make([]chan *pkglen(candidates))
1528    for i := range candidates {
1529        rescv[i] = make(chan *pkg1)
1530    }
1531    const maxConcurrentPackageImport = 4
1532    loadExportsSem := make(chan struct{}, maxConcurrentPackageImport)
1533
1534    ctxcancel := context.WithCancel(ctx)
1535    var wg sync.WaitGroup
1536    defer func() {
1537        cancel()
1538        wg.Wait()
1539    }()
1540
1541    wg.Add(1)
1542    go func() {
1543        defer wg.Done()
1544        for ic := range candidates {
1545            select {
1546            case loadExportsSem <- struct{}{}:
1547            case <-ctx.Done():
1548                return
1549            }
1550
1551            wg.Add(1)
1552            go func(c pkgDistanceresc chan<- *pkg) {
1553                defer func() {
1554                    <-loadExportsSem
1555                    wg.Done()
1556                }()
1557
1558                if pass.env.Logf != nil {
1559                    pass.env.Logf("loading exports in dir %s (seeking package %s)"c.pkg.dirpkgName)
1560                }
1561                // If we're an x_test, load the package under test's test variant.
1562                includeTest := strings.HasSuffix(pass.f.Name.Name"_test") && c.pkg.dir == pass.srcDir
1563                _exportserr := resolver.loadExports(ctxc.pkgincludeTest)
1564                if err != nil {
1565                    if pass.env.Logf != nil {
1566                        pass.env.Logf("loading exports in dir %s (seeking package %s): %v"c.pkg.dirpkgNameerr)
1567                    }
1568                    resc <- nil
1569                    return
1570                }
1571
1572                exportsMap := make(map[string]boollen(exports))
1573                for _sym := range exports {
1574                    exportsMap[sym] = true
1575                }
1576
1577                // If it doesn't have the right
1578                // symbols, send nil to mean no match.
1579                for symbol := range symbols {
1580                    if !exportsMap[symbol] {
1581                        resc <- nil
1582                        return
1583                    }
1584                }
1585                resc <- c.pkg
1586            }(crescv[i])
1587        }
1588    }()
1589
1590    for _resc := range rescv {
1591        pkg := <-resc
1592        if pkg == nil {
1593            continue
1594        }
1595        return pkgnil
1596    }
1597    return nilnil
1598}
1599
1600// pkgIsCandidate reports whether pkg is a candidate for satisfying the
1601// finding which package pkgIdent in the file named by filename is trying
1602// to refer to.
1603//
1604// This check is purely lexical and is meant to be as fast as possible
1605// because it's run over all $GOPATH directories to filter out poor
1606// candidates in order to limit the CPU and I/O later parsing the
1607// exports in candidate packages.
1608//
1609// filename is the file being formatted.
1610// pkgIdent is the package being searched for, like "client" (if
1611// searching for "client.New")
1612func pkgIsCandidate(filename stringrefs referencespkg *pkgbool {
1613    // Check "internal" and "vendor" visibility:
1614    if !canUse(filenamepkg.dir) {
1615        return false
1616    }
1617
1618    // Speed optimization to minimize disk I/O:
1619    // the last two components on disk must contain the
1620    // package name somewhere.
1621    //
1622    // This permits mismatch naming like directory
1623    // "go-foo" being package "foo", or "pkg.v3" being "pkg",
1624    // or directory "google.golang.org/api/cloudbilling/v1"
1625    // being package "cloudbilling", but doesn't
1626    // permit a directory "foo" to be package
1627    // "bar", which is strongly discouraged
1628    // anyway. There's no reason goimports needs
1629    // to be slow just to accommodate that.
1630    for pkgIdent := range refs {
1631        lastTwo := lastTwoComponents(pkg.importPathShort)
1632        if strings.Contains(lastTwopkgIdent) {
1633            return true
1634        }
1635        if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) {
1636            lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
1637            if strings.Contains(lastTwopkgIdent) {
1638                return true
1639            }
1640        }
1641    }
1642    return false
1643}
1644
1645func hasHyphenOrUpperASCII(s stringbool {
1646    for i := 0i < len(s); i++ {
1647        b := s[i]
1648        if b == '-' || ('A' <= b && b <= 'Z') {
1649            return true
1650        }
1651    }
1652    return false
1653}
1654
1655func lowerASCIIAndRemoveHyphen(s string) (ret string) {
1656    buf := make([]byte0len(s))
1657    for i := 0i < len(s); i++ {
1658        b := s[i]
1659        switch {
1660        case b == '-':
1661            continue
1662        case 'A' <= b && b <= 'Z':
1663            buf = append(bufb+('a'-'A'))
1664        default:
1665            buf = append(bufb)
1666        }
1667    }
1668    return string(buf)
1669}
1670
1671// canUse reports whether the package in dir is usable from filename,
1672// respecting the Go "internal" and "vendor" visibility rules.
1673func canUse(filenamedir stringbool {
1674    // Fast path check, before any allocations. If it doesn't contain vendor
1675    // or internal, it's not tricky:
1676    // Note that this can false-negative on directories like "notinternal",
1677    // but we check it correctly below. This is just a fast path.
1678    if !strings.Contains(dir"vendor") && !strings.Contains(dir"internal") {
1679        return true
1680    }
1681
1682    dirSlash := filepath.ToSlash(dir)
1683    if !strings.Contains(dirSlash"/vendor/") && !strings.Contains(dirSlash"/internal/") && !strings.HasSuffix(dirSlash"/internal") {
1684        return true
1685    }
1686    // Vendor or internal directory only visible from children of parent.
1687    // That means the path from the current directory to the target directory
1688    // can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
1689    // or bar/vendor or bar/internal.
1690    // After stripping all the leading ../, the only okay place to see vendor or internal
1691    // is at the very beginning of the path.
1692    absfileerr := filepath.Abs(filename)
1693    if err != nil {
1694        return false
1695    }
1696    absdirerr := filepath.Abs(dir)
1697    if err != nil {
1698        return false
1699    }
1700    relerr := filepath.Rel(absfileabsdir)
1701    if err != nil {
1702        return false
1703    }
1704    relSlash := filepath.ToSlash(rel)
1705    if i := strings.LastIndex(relSlash"../"); i >= 0 {
1706        relSlash = relSlash[i+len("../"):]
1707    }
1708    return !strings.Contains(relSlash"/vendor/") && !strings.Contains(relSlash"/internal/") && !strings.HasSuffix(relSlash"/internal")
1709}
1710
1711// lastTwoComponents returns at most the last two path components
1712// of v, using either / or \ as the path separator.
1713func lastTwoComponents(v stringstring {
1714    nslash := 0
1715    for i := len(v) - 1i >= 0i-- {
1716        if v[i] == '/' || v[i] == '\\' {
1717            nslash++
1718            if nslash == 2 {
1719                return v[i:]
1720            }
1721        }
1722    }
1723    return v
1724}
1725
1726type visitFn func(node ast.Nodeast.Visitor
1727
1728func (fn visitFnVisit(node ast.Nodeast.Visitor {
1729    return fn(node)
1730}
1731
1732func copyExports(pkg []string) map[string]bool {
1733    m := make(map[string]boollen(pkg))
1734    for _v := range pkg {
1735        m[v] = true
1736    }
1737    return m
1738}
1739
MembersX
ProcessEnv.GetResolver.err
addStdlibCandidates.RangeStmt_27932.left
findImport.BlockStmt.RangeStmt_43442.i
pass.missingRefs
ProcessEnv.init.goEnv
findImport.RangeStmt_43774.i
ImportFix
pass.fix.selected
gopathResolver.walked
gopathResolver.loadPackageNames.srcDir
byDistanceOrImportPathShortLength.Less.di
loadExportsFromFiles.BlockStmt.sortedExports
gopathwalk
importGroup.RangeStmt_1347.fn
gopathResolver.loadPackageNames.err
addGlobals.RangeStmt_3340.decl
collectImports.RangeStmt_4608.BlockStmt.name
pass.loadPackageNames.RangeStmt_7602.path
GetAllCandidates.callback
ProcessEnv.invokeGo.ctx
ImportPathToAssumedName.i
importPathToName.srcDir
packageDirToName.nfile
ImportFix.IdentName
ImportInfo.ImportPath
gopathResolver.scan.BlockStmt.p
canUse.rel
PackageExport
packageDirToName.RangeStmt_35397.BlockStmt.f
ImportPathToAssumedName
gopathResolver.scan.scanDone
pass.otherFiles
apply
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt._
addExternalCandidates.RangeStmt_31369.pkgName
addExternalCandidates.RangeStmt_31369.BlockStmt.BlockStmt.imp
gopathResolver.scoreImportPath.ctx
gocommand
packageDirToName.dir
GetAllCandidates.ctx
canUse.absfile
addStdlibCandidates.BlockStmt.exports
gopathResolver.env
findImport.err
findImport.RangeStmt_45246.BlockStmt.pkg
pass.findMissingImport.p
ProcessEnv.matchFile
packageDirToName.lastErr
distance.basepath
canUse.dir
ioutil
fixImportsDefault.fixes
pass.addCandidate.imp
getCandidatePkgs.filename
ScoreImportPaths.RangeStmt_19173.path
gopathResolver.scan
loadExportsFromFiles.env
loadExportsFromFiles.RangeStmt_41893.BlockStmt.f
addGlobals.globals
pass.load.globals
importPathToName.pkgName
collectImports.f
pass.importSpecName.p
filterRoots.include
pass.load.imports
ProcessEnv.goEnv
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.RangeStmt_13392.left
getFixes
ProcessEnv.buildContext.e
loadExportsFromFiles.RangeStmt_41893.BlockStmt.fullFile
canUse.filename
pass.loadPackageNames.unknown
pass.load.BlockStmt.err
importPathToName.buildPkg
pkg.packageName
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.imports
fixImportsDefault.f
byDistanceOrImportPathShortLength
parser
collectReferences.f
ProcessEnv.env
packageDirToName.err
gopathResolver.loadExports.r
parseOtherFiles.RangeStmt_2849.BlockStmt.err
GetPackageExports.searchPkg
GetImportPaths.env
ProcessEnv.init.RangeStmt_25482.k
addExternalCandidates.found
findImport.maxConcurrentPackageImport
canUse
pass.load.p
getFixes.env
addGlobals.RangeStmt_3340.BlockStmt.RangeStmt_3438.spec
pass.loadRealPackageNames
GetImportPaths.callback
gopathResolver.scan.BlockStmt.exports
strconv
strings
apply.RangeStmt_12439.BlockStmt.BlockStmt.RangeStmt_12772.spec
ProcessEnv.env.env
ProcessEnv.GetResolver.e
addStdlibCandidates.err
Resolver
gopathResolver.loadPackageNames.r
build
collectReferences.refs
gopathResolver.scan.BlockStmt._
gopathResolver.loadExports.ctx
getCandidatePkgs
canUse.dirSlash
PrimeCache.env
getCandidatePkgs.RangeStmt_17435.exports
GetAllCandidates
ProcessEnv.invokeGo.args
addExternalCandidates.result
findImport.resolver
pass.loadPackageNames.p
getCandidatePkgs.ctx
ProcessEnv.init.RangeStmt_25008.k
lowerASCIIAndRemoveHyphen
addExternalCandidates.result.pkg
hasHyphenOrUpperASCII
collectReferences.visitor
getFixes.done
ProcessEnv.CopyConfig.e
addExternalCandidates.resolver
gopathResolver.scanSema
gopathResolver.loadExports.info
getFixes.fset
GetImportPaths.ctx
ProcessEnv.buildContext.err
addStdlibCandidates.pass
addExternalCandidates.RangeStmt_31369.BlockStmt.BlockStmt.err
gopathResolver.scoreImportPath
VendorlessPath
loadExportsFromFiles.fset
apply.RangeStmt_12439.BlockStmt.BlockStmt.RangeStmt_12772.BlockStmt.path
GetImportPaths
ProcessEnv.BuildFlags
pkg.importPathShort
GetAllCandidates.filename
ProcessEnv.GocmdRunner
filepath
ScoreImportPaths
fixImports
visitFn.Visit
addGlobals
getFixes.fixes
context
parseOtherFiles.srcDir
getCandidatePkgs.Elts.BlockStmt.BlockStmt.err
addExternalCandidates.mu
packageDirToName.RangeStmt_35397.BlockStmt.fset
gopathResolver.scan.ctx
parseOtherFiles
parseOtherFiles.filename
fixImportsDefault.filename
ProcessEnv.matchFile.dir
ProcessEnv.buildContext.goenv
gopathResolver.ClearForNewScan
distance.targetpath
sort
pass.existingImports
getCandidatePkgs.env
byDistanceOrImportPathShortLength.Less.dj
ImportFixType
pass.findMissingImport
canUse.i
lastTwoComponents.nslash
lowerASCIIAndRemoveHyphen.buf
packageDirToName.RangeStmt_35397.name
lowerASCIIAndRemoveHyphen.ret
pass.importIdentifier
pass.addCandidate
GetImportPaths.filePkg
ProcessEnv.goEnv.e
pkg
pkgDistance.pkg
pass.findMissingImport.RangeStmt_5130.candidate
references
loadExportsFromFiles.RangeStmt_41431.BlockStmt.name
ImportInfo.Name
ProcessEnv.init
packageDirToName.RangeStmt_35397.BlockStmt.fullFile
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt.RangeStmt_45095.symbol
addGlobals.f
ProcessEnv.matchFile.bctx
pass.assumeSiblingImportsValid.RangeStmt_13167.f
GetImportPaths.searchPrefix
ProcessEnv.init.RangeStmt_25482.v
findImport
collectImports
pass.loadPackageNames.imports
scanCallback.rootFound
findImport.RangeStmt_45246.resc
os
pass.fix.p
pkgIsCandidate.refs
lowerASCIIAndRemoveHyphen.s
pass.env
byDistanceOrImportPathShortLength.Swap.i
byDistanceOrImportPathShortLength.Less.i
addExternalCandidates.filename
byDistanceOrImportPathShortLength.Len
GetPackageExports.callback
ProcessEnv.buildContext.dir
GetPackageExports.ctx
addStdlibCandidates
packageDirToName.names
loadExportsFromFiles
loadExportsFromFiles.ctx
lastTwoComponents
pass.allRefs
ScoreImportPaths.result
addExternalCandidates.firstErr
notIdentifier
getFixes.srcDir
getCandidatePkgs.resolver
PrimeCache
lowerASCIIAndRemoveHyphen.i
parseOtherFiles.considerTests
parseOtherFiles.RangeStmt_2849.BlockStmt.f
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt.err
pkgIsCandidate
gopathResolver.scoreImportPath.path
findImport.BlockStmt.RangeStmt_44095.c
getFixes.otherFiles
ProcessEnv.initialized
ProcessEnv.invokeGo
packageDirToName.RangeStmt_35397.BlockStmt.err
pass.findMissingImport.RangeStmt_5130.BlockStmt.allFound
pass.fix.RangeStmt_11445.imp
pkgDistance.distance
lastTwoComponents.v
ast
addStdlibCandidates.goenv
ProcessEnv.SkipPathInScan
bytes
Elts.RangeStmt_793.p
importPathToName.err
ProcessEnv.env.RangeStmt_25670.k
gopathResolver.cache
MaxRelevance
ProcessEnv.matchFile.name
ProcessEnv.CopyConfig.RangeStmt_24845.k
loadExportsFromFiles.RangeStmt_41431.BlockStmt.match
apply.fset
pass.assumeSiblingImportsValid
packageDirToName.d
loadExportsFromFiles.includeTest
findImport.ctx
pass
pass.importSpecName.imp
ProcessEnv
filterRoots
loadExportsFromFiles.RangeStmt_41893.BlockStmt.err
findImport.pkgName
ScoreImportPaths.resolver
GetImportPaths.filename
ProcessEnv.env.RangeStmt_25670.v
packageDirToName
byDistanceOrImportPathShortLength.Less.vj
visitFn.Visit.node
pass.importIdentifier.p
GetAllCandidates.searchPrefix
ProcessEnv.Logf
addExternalCandidates.RangeStmt_31369.symbols
gopathResolver.scan.BlockStmt.scanned
importGroup
collectImports.RangeStmt_4608.imp
gopathResolver.loadPackageNames.RangeStmt_34201.path
byDistanceOrImportPathShortLength.Less.vi
addExternalCandidates.callback
addExternalCandidates.err
importGroup.RangeStmt_1347.BlockStmt.ok
GetAllCandidates.env
addExternalCandidates.pass
loadExportsFromFiles.RangeStmt_41431.BlockStmt.err
ProcessEnv.matchFile.err
ImportPathToAssumedName.base
newGopathResolver
byDistanceOrImportPathShortLength.Len.s
gopathResolver.scan.stop
pass.load.RangeStmt_9660.left
ProcessEnv.buildContext.rc
ImportPathToAssumedName.BlockStmt.BlockStmt.dir
byDistanceOrImportPathShortLength.Less
byDistanceOrImportPathShortLength.Swap.s
distance.p
gopathResolver.scan.RangeStmt_39223.p
findImport.cancel
ProcessEnv.ModFile
addExternalCandidates.RangeStmt_31369.BlockStmt.BlockStmt.found
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt.exportsMap
addExternalCandidates.wg
ImportPathToAssumedName.BlockStmt._
gopathResolver.loadExports.pkg
pkgIsCandidate.pkg
pkgIsCandidate.RangeStmt_46591.pkgIdent
json
ImportFix.StmtInfo
distance.err
gopathResolver.loadExports.includeTest
gopathResolver.scan.BlockStmt.info
copyExports
pass.load.RangeStmt_9660.rights
pass.fix.fixes
candidateImportName
gopathResolver.scan.BlockStmt.ok
pass.findMissingImport.syms
pass.assumeSiblingImportsValid.p
PackageExport.Fix
VendorlessPath.ipath
canUse.err
pass.importSpecName.ident
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.refs
addExternalCandidates
findImport.BlockStmt.RangeStmt_44095.i
pkgIsCandidate.RangeStmt_46591.BlockStmt.lastTwo
pass.fset
getCandidatePkgs.dupCheck
addExternalCandidates.result.imp
notIdentifier.ch
parseOtherFiles.err
GetImportPaths.wrapped
ProcessEnv.CopyConfig.RangeStmt_24845.v
addExternalCandidates.RangeStmt_31989.result
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt.exports
GetAllCandidates.filePkg
ProcessEnv.buildContext
findImport.BlockStmt.RangeStmt_43442.c
utf8
pass.fix.RangeStmt_10235.left
fixImportsDefault.err
hasHyphenOrUpperASCII.s
byDistanceOrImportPathShortLength.Swap.j
hasHyphenOrUpperASCII.i
path
pass.fix.RangeStmt_10235.BlockStmt.imp
scanCallback.dirFound
addExternalCandidates.ctx
pass.fix.RangeStmt_10565.imp
ProcessEnv.ModFlag
fixImportsDefault.env
candidateImportName.pkg
gopathResolver.scan.roots
ImportFix.Relevance
collectImports.imports
ScoreImportPaths.env
gopathResolver.loadPackageNames.bctx
pass.fix.RangeStmt_10565.BlockStmt.name
pass.addCandidate.BlockStmt.RangeStmt_14036.export
ProcessEnv.resolver
filterRoots.result
pass.srcDir
pass.loadPackageNames
ProcessEnv.goEnv.err
ProcessEnv.buildContext.ctx
ProcessEnv.invokeGo.e
findImport.wg
pass.importIdentifier.imp
fixImportsDefault.fset
ImportPathToAssumedName.importPath
ProcessEnv.Env
addExternalCandidates.cancel
apply.f
getFixes._
getCandidatePkgs.err
ProcessEnv.invokeGo.inv
pkg.relevance
findImport.loadExportsSem
copyExports.pkg
pass.loadPackageNames.resolver
getFixes.err
pass.findMissingImport.RangeStmt_5130.BlockStmt.RangeStmt_5335.right
gopathResolver.loadPackageNames
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.RangeStmt_13308.imp
loadExportsFromFiles.exports
findImport.rescv
parseOtherFiles.fileBase
newGopathResolver.env
visitFn
parseOtherFiles.RangeStmt_2849.fi
pass.loadPackageNames.err
findImport.symbols
importPathToName.bctx
loadExportsFromFiles.dir
distance
gopathResolver.scan.goenv
loadExportsFromFiles.all
loadExportsFromFiles.RangeStmt_41893.fi
collectImports.RangeStmt_4608.BlockStmt.path
ImportPathToAssumedName.BlockStmt.err
getCandidatePkgs.wrappedCallback
getCandidatePkgs.RangeStmt_17435.importPath
GetPackageExports.wrapped
ProcessEnv.GetResolver
addExternalCandidates.firstErrOnce
gopathResolver
collectReferences.BlockStmt.BlockStmt.pkgName
pass.importSpecName
GetPackageExports.env
importPathToName
loadExportsFromFiles.err
copyExports.m
pass.fix.RangeStmt_10235.rights
getFixes.p
ProcessEnv.init.stdout
packageInfo
collectReferences
importPathToName.importPath
gopathResolver.scan.BlockStmt.importpath
getFixes.filename
ProcessEnv.init.e
findImport.BlockStmt.RangeStmt_44095.BlockStmt.BlockStmt.RangeStmt_44947.sym
pass.candidates
getCandidatePkgs.goenv
scanCallback
scanCallback.exportsLoaded
packageDirToName.RangeStmt_35397.BlockStmt.pkgName
ProcessEnv.WorkingDir
ProcessEnv.init.err
getCandidatePkgs.mu
GetPackageExports.filename
ProcessEnv.env.e
loadExportsFromFiles.RangeStmt_41431.fi
pass.load
getFixes.abs
ScoreImportPaths.paths
GetPackageExports.filePkg
ProcessEnv.matchFile.e
gopathResolver.loadPackageNames.importPaths
byDistanceOrImportPathShortLength.Less.s
byDistanceOrImportPathShortLength.Less.j
fmt
pass.f
gopathResolver.scan.r
canUse.relSlash
PrimeCache.callback
pass.loadPackageNames.names
pass.addCandidate.p
gopathResolver.ClearForNewScan.r
astutil
ImportFix.FixType
ProcessEnv.CopyConfig.copy
pass.load.RangeStmt_9545.imp
PrimeCache.ctx
pass.knownPackages
pass.loadPackageNames.RangeStmt_7289.imp
GetAllCandidates.wrapped
addStdlibCandidates.refs
importGroup.RangeStmt_1347.BlockStmt.n
packageInfo.name
ScoreImportPaths.ctx
gopathResolver.scoreImportPath.r
reflect
pkg.dir
pkgDistance
loadExportsFromFiles.pkgName
packageInfo.exports
addExternalCandidates.refs
byDistanceOrImportPathShortLength.Swap
pass.lastTry
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.importsByName
AddImport
ProcessEnv.CopyConfig
loadExportsFromFiles.files
sync
unicode
filterRoots.RangeStmt_40304.root
pass.findMissingImport.pkg
getCandidatePkgs.scanFilter
ImportInfo
gopathResolver.loadExports
addExternalCandidates.RangeStmt_31369.BlockStmt.BlockStmt.pkg
filterRoots.roots
importGroup.importPath
fixImportsDefault
ProcessEnv.init.foundAllRequired
pass.assumeSiblingImportsValid.RangeStmt_13167.BlockStmt.RangeStmt_13392.rights
PackageExport.Exports
getCandidatePkgs.filePkg
getCandidatePkgs.RangeStmt_17435.BlockStmt.p
findImport.pass
importGroup.localPrefix
apply.fixes
gopathResolver.loadExports.ok
canUse.absdir
gopathResolver.scan.callback
pass.load.RangeStmt_8845.otherFile
pass.addCandidate.pkg
loadExportsFromFiles.RangeStmt_41893.BlockStmt.RangeStmt_42505.name
GetPackageExports
gopathResolver.scan.BlockStmt.err
VendorlessPath.i
addStdlibCandidates.RangeStmt_27932.BlockStmt.RangeStmt_28092.importPath
newGopathResolver.r
findImport.filename
pass.loadPackageNames.RangeStmt_7602.name
ScoreImportPaths.err
gopathResolver.loadPackageNames.names
packageDirToName.packageName
gopathResolver.scan.err
findImport.candidates
parseOtherFiles.fset
getFixes.f
visitFn.Visit.fn
token
parseOtherFiles.files
copyExports.RangeStmt_49522.v
apply.RangeStmt_12439.fix
ProcessEnv.invokeGo.verb
scanCallback.packageNameLoaded
addExternalCandidates.results
pkgIsCandidate.filename
parseOtherFiles.packageFileInfos
pass.fix
Members
X