Update go dependencies to v1.17.0

This commit is contained in:
Manuel Alejandro de Brito Fontes 2019-12-10 21:55:54 -03:00
parent 67dce30ba6
commit 75c3c47f81
516 changed files with 48300 additions and 15154 deletions

View file

@ -13,7 +13,6 @@ import (
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
@ -68,10 +67,27 @@ func importGroup(env *ProcessEnv, importPath string) int {
return 0
}
// An importInfo represents a single import statement.
type importInfo struct {
importPath string // import path, e.g. "crypto/rand".
name string // import name, e.g. "crand", or "" if none.
type ImportFixType int
const (
AddImport ImportFixType = iota
DeleteImport
SetImportName
)
type ImportFix struct {
// StmtInfo represents the import statement this fix will add, remove, or change.
StmtInfo ImportInfo
// IdentName is the identifier that this fix will add or remove.
IdentName string
// FixType is the type of fix this is (AddImport, DeleteImport, SetImportName).
FixType ImportFixType
}
// An ImportInfo represents a single import statement.
type ImportInfo struct {
ImportPath string // import path, e.g. "crypto/rand".
Name string // import name, e.g. "crand", or "" if none.
}
// A packageInfo represents what's known about a package.
@ -169,10 +185,10 @@ func collectReferences(f *ast.File) references {
return refs
}
// collectImports returns all the imports in f, keyed by their package name as
// determined by pathToName. Unnamed imports (., _) and "C" are ignored.
func collectImports(f *ast.File) []*importInfo {
var imports []*importInfo
// collectImports returns all the imports in f.
// Unnamed imports (., _) and "C" are ignored.
func collectImports(f *ast.File) []*ImportInfo {
var imports []*ImportInfo
for _, imp := range f.Imports {
var name string
if imp.Name != nil {
@ -182,9 +198,9 @@ func collectImports(f *ast.File) []*importInfo {
continue
}
path := strings.Trim(imp.Path.Value, `"`)
imports = append(imports, &importInfo{
name: name,
importPath: path,
imports = append(imports, &ImportInfo{
Name: name,
ImportPath: path,
})
}
return imports
@ -192,9 +208,9 @@ func collectImports(f *ast.File) []*importInfo {
// findMissingImport searches pass's candidates for an import that provides
// pkg, containing all of syms.
func (p *pass) findMissingImport(pkg string, syms map[string]bool) *importInfo {
func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo {
for _, candidate := range p.candidates {
pkgInfo, ok := p.knownPackages[candidate.importPath]
pkgInfo, ok := p.knownPackages[candidate.ImportPath]
if !ok {
continue
}
@ -234,27 +250,33 @@ type pass struct {
otherFiles []*ast.File // sibling files.
// Intermediate state, generated by load.
existingImports map[string]*importInfo
existingImports map[string]*ImportInfo
allRefs references
missingRefs references
// Inputs to fix. These can be augmented between successive fix calls.
lastTry bool // indicates that this is the last call and fix should clean up as best it can.
candidates []*importInfo // candidate imports in priority order.
candidates []*ImportInfo // candidate imports in priority order.
knownPackages map[string]*packageInfo // information about all known packages.
}
// loadPackageNames saves the package names for everything referenced by imports.
func (p *pass) loadPackageNames(imports []*importInfo) error {
func (p *pass) loadPackageNames(imports []*ImportInfo) error {
if p.env.Debug {
p.env.Logf("loading package names for %v packages", len(imports))
defer func() {
p.env.Logf("done loading package names for %v packages", len(imports))
}()
}
var unknown []string
for _, imp := range imports {
if _, ok := p.knownPackages[imp.importPath]; ok {
if _, ok := p.knownPackages[imp.ImportPath]; ok {
continue
}
unknown = append(unknown, imp.importPath)
unknown = append(unknown, imp.ImportPath)
}
names, err := p.env.getResolver().loadPackageNames(unknown, p.srcDir)
names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir)
if err != nil {
return err
}
@ -271,24 +293,24 @@ func (p *pass) loadPackageNames(imports []*importInfo) error {
// importIdentifier returns the identifier that imp will introduce. It will
// guess if the package name has not been loaded, e.g. because the source
// is not available.
func (p *pass) importIdentifier(imp *importInfo) string {
if imp.name != "" {
return imp.name
func (p *pass) importIdentifier(imp *ImportInfo) string {
if imp.Name != "" {
return imp.Name
}
known := p.knownPackages[imp.importPath]
known := p.knownPackages[imp.ImportPath]
if known != nil && known.name != "" {
return known.name
}
return importPathToAssumedName(imp.importPath)
return importPathToAssumedName(imp.ImportPath)
}
// load reads in everything necessary to run a pass, and reports whether the
// file already has all the imports it needs. It fills in p.missingRefs with the
// file's missing symbols, if any, or removes unused imports if not.
func (p *pass) load() bool {
func (p *pass) load() ([]*ImportFix, bool) {
p.knownPackages = map[string]*packageInfo{}
p.missingRefs = references{}
p.existingImports = map[string]*importInfo{}
p.existingImports = map[string]*ImportInfo{}
// Load basic information about the file in question.
p.allRefs = collectReferences(p.f)
@ -313,9 +335,9 @@ func (p *pass) load() bool {
err := p.loadPackageNames(append(imports, p.candidates...))
if err != nil {
if p.env.Debug {
log.Printf("loading package names: %v", err)
p.env.Logf("loading package names: %v", err)
}
return false
return nil, false
}
}
for _, imp := range imports {
@ -334,18 +356,18 @@ func (p *pass) load() bool {
}
}
if len(p.missingRefs) != 0 {
return false
return nil, false
}
return p.fix()
}
// fix attempts to satisfy missing imports using p.candidates. If it finds
// everything, or if p.lastTry is true, it adds the imports it found,
// removes anything unused, and returns true.
func (p *pass) fix() bool {
// everything, or if p.lastTry is true, it updates fixes to add the imports it found,
// delete anything unused, and update import names, and returns true.
func (p *pass) fix() ([]*ImportFix, bool) {
// Find missing imports.
var selected []*importInfo
var selected []*ImportInfo
for left, rights := range p.missingRefs {
if imp := p.findMissingImport(left, rights); imp != nil {
selected = append(selected, imp)
@ -353,10 +375,11 @@ func (p *pass) fix() bool {
}
if !p.lastTry && len(selected) != len(p.missingRefs) {
return false
return nil, false
}
// Found everything, or giving up. Add the new imports and remove any unused.
var fixes []*ImportFix
for _, imp := range p.existingImports {
// We deliberately ignore globals here, because we can't be sure
// they're in the same package. People do things like put multiple
@ -364,28 +387,80 @@ func (p *pass) fix() bool {
// remove imports if they happen to have the same name as a var in
// a different package.
if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok {
astutil.DeleteNamedImport(p.fset, p.f, imp.name, imp.importPath)
fixes = append(fixes, &ImportFix{
StmtInfo: *imp,
IdentName: p.importIdentifier(imp),
FixType: DeleteImport,
})
continue
}
// An existing import may need to update its import name to be correct.
if name := p.importSpecName(imp); name != imp.Name {
fixes = append(fixes, &ImportFix{
StmtInfo: ImportInfo{
Name: name,
ImportPath: imp.ImportPath,
},
IdentName: p.importIdentifier(imp),
FixType: SetImportName,
})
}
}
for _, imp := range selected {
astutil.AddNamedImport(p.fset, p.f, imp.name, imp.importPath)
fixes = append(fixes, &ImportFix{
StmtInfo: ImportInfo{
Name: p.importSpecName(imp),
ImportPath: imp.ImportPath,
},
IdentName: p.importIdentifier(imp),
FixType: AddImport,
})
}
if p.loadRealPackageNames {
for _, imp := range p.f.Imports {
if imp.Name != nil {
continue
}
path := strings.Trim(imp.Path.Value, `""`)
ident := p.importIdentifier(&importInfo{importPath: path})
if ident != importPathToAssumedName(path) {
imp.Name = &ast.Ident{Name: ident, NamePos: imp.Pos()}
return fixes, true
}
// importSpecName gets the import name of imp in the import spec.
//
// When the import identifier matches the assumed import name, the import name does
// not appear in the import spec.
func (p *pass) importSpecName(imp *ImportInfo) string {
// If we did not load the real package names, or the name is already set,
// we just return the existing name.
if !p.loadRealPackageNames || imp.Name != "" {
return imp.Name
}
ident := p.importIdentifier(imp)
if ident == importPathToAssumedName(imp.ImportPath) {
return "" // ident not needed since the assumed and real names are the same.
}
return ident
}
// apply will perform the fixes on f in order.
func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) {
for _, fix := range fixes {
switch fix.FixType {
case DeleteImport:
astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
case AddImport:
astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath)
case SetImportName:
// Find the matching import path and change the name.
for _, spec := range f.Imports {
path := strings.Trim(spec.Path.Value, `"`)
if path == fix.StmtInfo.ImportPath {
spec.Name = &ast.Ident{
Name: fix.StmtInfo.Name,
NamePos: spec.Pos(),
}
}
}
}
}
return true
}
// assumeSiblingImportsValid assumes that siblings' use of packages is valid,
@ -394,15 +469,15 @@ func (p *pass) assumeSiblingImportsValid() {
for _, f := range p.otherFiles {
refs := collectReferences(f)
imports := collectImports(f)
importsByName := map[string]*importInfo{}
importsByName := map[string]*ImportInfo{}
for _, imp := range imports {
importsByName[p.importIdentifier(imp)] = imp
}
for left, rights := range refs {
if imp, ok := importsByName[left]; ok {
if _, ok := stdlib[imp.importPath]; ok {
if _, ok := stdlib[imp.ImportPath]; ok {
// We have the stdlib in memory; no need to guess.
rights = stdlib[imp.importPath]
rights = stdlib[imp.ImportPath]
}
p.addCandidate(imp, &packageInfo{
// no name; we already know it.
@ -415,9 +490,9 @@ func (p *pass) assumeSiblingImportsValid() {
// addCandidate adds a candidate import to p, and merges in the information
// in pkg.
func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) {
func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) {
p.candidates = append(p.candidates, imp)
if existing, ok := p.knownPackages[imp.importPath]; ok {
if existing, ok := p.knownPackages[imp.ImportPath]; ok {
if existing.name == "" {
existing.name = pkg.name
}
@ -425,7 +500,7 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) {
existing.exports[export] = true
}
} else {
p.knownPackages[imp.importPath] = pkg
p.knownPackages[imp.ImportPath] = pkg
}
}
@ -437,13 +512,24 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) {
var fixImports = fixImportsDefault
func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error {
abs, err := filepath.Abs(filename)
fixes, err := getFixes(fset, f, filename, env)
if err != nil {
return err
}
apply(fset, f, fixes)
return err
}
// getFixes gets the import fixes that need to be made to f in order to fix the imports.
// It does not modify the ast.
func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) {
abs, err := filepath.Abs(filename)
if err != nil {
return nil, err
}
srcDir := filepath.Dir(abs)
if env.Debug {
log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
}
// First pass: looking only at f, and using the naive algorithm to
@ -451,8 +537,8 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P
// complete. We can't add any imports yet, because we don't know
// if missing references are actually package vars.
p := &pass{fset: fset, f: f, srcDir: srcDir}
if p.load() {
return nil
if fixes, done := p.load(); done {
return fixes, nil
}
otherFiles := parseOtherFiles(fset, srcDir, filename)
@ -460,15 +546,15 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P
// Second pass: add information from other files in the same package,
// like their package vars and imports.
p.otherFiles = otherFiles
if p.load() {
return nil
if fixes, done := p.load(); done {
return fixes, nil
}
// Now we can try adding imports from the stdlib.
p.assumeSiblingImportsValid()
addStdlibCandidates(p, p.missingRefs)
if p.fix() {
return nil
if fixes, done := p.fix(); done {
return fixes, nil
}
// Third pass: get real package names where we had previously used
@ -477,25 +563,50 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P
p = &pass{fset: fset, f: f, srcDir: srcDir, env: env}
p.loadRealPackageNames = true
p.otherFiles = otherFiles
if p.load() {
return nil
if fixes, done := p.load(); done {
return fixes, nil
}
addStdlibCandidates(p, p.missingRefs)
p.assumeSiblingImportsValid()
if p.fix() {
return nil
if fixes, done := p.fix(); done {
return fixes, nil
}
// Go look for candidates in $GOPATH, etc. We don't necessarily load
// the real exports of sibling imports, so keep assuming their contents.
if err := addExternalCandidates(p, p.missingRefs, filename); err != nil {
return err
return nil, err
}
p.lastTry = true
p.fix()
return nil
fixes, _ := p.fix()
return fixes, nil
}
// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed.
func getAllCandidates(filename string, env *ProcessEnv) ([]ImportFix, error) {
// TODO(suzmue): scan for additional candidates and filter out
// current package.
// Get the stdlib candidates and sort by import path.
var paths []string
for importPath := range stdlib {
paths = append(paths, importPath)
}
sort.Strings(paths)
var imports []ImportFix
for _, importPath := range paths {
imports = append(imports, ImportFix{
StmtInfo: ImportInfo{
ImportPath: importPath,
},
IdentName: path.Base(importPath),
FixType: AddImport,
})
}
return imports, nil
}
// ProcessEnv contains environment variables and settings that affect the use of
@ -512,7 +623,10 @@ type ProcessEnv struct {
// If true, use go/packages regardless of the environment.
ForceGoPackages bool
resolver resolver
// Logf is the default logger for the ProcessEnv.
Logf func(format string, args ...interface{})
resolver Resolver
}
func (e *ProcessEnv) env() []string {
@ -534,7 +648,7 @@ func (e *ProcessEnv) env() []string {
return env
}
func (e *ProcessEnv) getResolver() resolver {
func (e *ProcessEnv) GetResolver() Resolver {
if e.resolver != nil {
return e.resolver
}
@ -548,7 +662,7 @@ func (e *ProcessEnv) getResolver() resolver {
e.resolver = &gopathResolver{env: e}
return e.resolver
}
e.resolver = &moduleResolver{env: e}
e.resolver = &ModuleResolver{env: e}
return e.resolver
}
@ -577,7 +691,7 @@ func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) {
cmd.Dir = e.WorkingDir
if e.Debug {
defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
defer func(start time.Time) { e.Logf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
}
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("running go: %v (stderr:\n%s)", err, stderr)
@ -599,7 +713,7 @@ func cmdDebugStr(cmd *exec.Cmd) string {
func addStdlibCandidates(pass *pass, refs references) {
add := func(pkg string) {
pass.addCandidate(
&importInfo{importPath: pkg},
&ImportInfo{ImportPath: pkg},
&packageInfo{name: path.Base(pkg), exports: stdlib[pkg]})
}
for left := range refs {
@ -617,20 +731,27 @@ func addStdlibCandidates(pass *pass, refs references) {
}
}
// A resolver does the build-system-specific parts of goimports.
type resolver interface {
// A Resolver does the build-system-specific parts of goimports.
type Resolver interface {
// loadPackageNames loads the package names in importPaths.
loadPackageNames(importPaths []string, srcDir string) (map[string]string, error)
// scan finds (at least) the packages satisfying refs. The returned slice is unordered.
scan(refs references) ([]*pkg, error)
// loadExports returns the set of exported symbols in the package at dir.
// It returns an error if the package name in dir does not match expectPackage.
// loadExports may be called concurrently.
loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error)
}
// gopathResolver implements resolver for GOPATH and module workspaces using go/packages.
// gopackagesResolver implements resolver for GOPATH and module workspaces using go/packages.
type goPackagesResolver struct {
env *ProcessEnv
}
func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
if len(importPaths) == 0 {
return nil, nil
}
cfg := r.env.newPackagesConfig(packages.LoadFiles)
pkgs, err := packages.Load(cfg, importPaths...)
if err != nil {
@ -674,15 +795,35 @@ func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) {
return scan, nil
}
func (r *goPackagesResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) {
if pkg.goPackage == nil {
return nil, fmt.Errorf("goPackage not set")
}
exports := map[string]bool{}
fset := token.NewFileSet()
for _, fname := range pkg.goPackage.CompiledGoFiles {
f, err := parser.ParseFile(fset, fname, nil, 0)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", fname, err)
}
for name := range f.Scope.Objects {
if ast.IsExported(name) {
exports[name] = true
}
}
}
return exports, nil
}
func addExternalCandidates(pass *pass, refs references, filename string) error {
dirScan, err := pass.env.getResolver().scan(refs)
dirScan, err := pass.env.GetResolver().scan(refs)
if err != nil {
return err
}
// Search for imports matching potential package references.
type result struct {
imp *importInfo
imp *ImportInfo
pkg *packageInfo
}
results := make(chan result, len(refs))
@ -716,8 +857,8 @@ func addExternalCandidates(pass *pass, refs references, filename string) error {
return // No matching package.
}
imp := &importInfo{
importPath: found.importPathShort,
imp := &ImportInfo{
ImportPath: found.importPathShort,
}
pkg := &packageInfo{
@ -784,7 +925,7 @@ func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (
return names, nil
}
// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
// importPathToName finds out the actual package name, as declared in its .go files.
// If there's a problem, it returns "".
func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) {
// Fast path for standard library without going to disk.
@ -804,8 +945,8 @@ func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName s
}
// packageDirToName is a faster version of build.Import if
// the only thing desired is the package name. It uses build.FindOnly
// to find the directory and then only parses one file in the package,
// the only thing desired is the package name. Given a directory,
// packageDirToName then only parses one file in the package,
// trusting that the files in the directory are consistent.
func packageDirToName(dir string) (packageName string, err error) {
d, err := os.Open(dir)
@ -926,6 +1067,10 @@ func (r *gopathResolver) scan(_ references) ([]*pkg, error) {
return result, nil
}
func (r *gopathResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) {
return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir)
}
// VendorlessPath returns the devendorized version of the import path ipath.
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
func VendorlessPath(ipath string) string {
@ -939,33 +1084,11 @@ func VendorlessPath(ipath string) string {
return ipath
}
// loadExports returns the set of exported symbols in the package at dir.
// It returns nil on error or if the package name in dir does not match expectPackage.
func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg *pkg) (map[string]bool, error) {
if env.Debug {
log.Printf("loading exports in dir %s (seeking package %s)", pkg.dir, expectPackage)
}
if pkg.goPackage != nil {
exports := map[string]bool{}
fset := token.NewFileSet()
for _, fname := range pkg.goPackage.CompiledGoFiles {
f, err := parser.ParseFile(fset, fname, nil, 0)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", fname, err)
}
for name := range f.Scope.Objects {
if ast.IsExported(name) {
exports[name] = true
}
}
}
return exports, nil
}
func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, expectPackage string, dir string) (map[string]bool, error) {
exports := make(map[string]bool)
// Look for non-test, buildable .go files which could provide exports.
all, err := ioutil.ReadDir(pkg.dir)
all, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
}
@ -975,7 +1098,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
continue
}
match, err := env.buildContext().MatchFile(pkg.dir, fi.Name())
match, err := env.buildContext().MatchFile(dir, fi.Name())
if err != nil || !match {
continue
}
@ -983,7 +1106,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg
}
if len(files) == 0 {
return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", pkg.dir)
return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir)
}
fset := token.NewFileSet()
@ -994,7 +1117,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg
default:
}
fullFile := filepath.Join(pkg.dir, fi.Name())
fullFile := filepath.Join(dir, fi.Name())
f, err := parser.ParseFile(fset, fullFile, nil, 0)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", fullFile, err)
@ -1006,7 +1129,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg
continue
}
if pkgName != expectPackage {
return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName)
return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName)
}
for name := range f.Scope.Objects {
if ast.IsExported(name) {
@ -1021,7 +1144,7 @@ func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg
exportList = append(exportList, k)
}
sort.Strings(exportList)
log.Printf("loaded exports in dir %v (package %v): %v", pkg.dir, expectPackage, strings.Join(exportList, ", "))
env.Logf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", "))
}
return exports, nil
}
@ -1058,7 +1181,7 @@ func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string,
sort.Sort(byDistanceOrImportPathShortLength(candidates))
if pass.env.Debug {
for i, c := range candidates {
log.Printf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
}
}
@ -1095,10 +1218,13 @@ func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string,
wg.Done()
}()
exports, err := loadExports(ctx, pass.env, pkgName, c.pkg)
if pass.env.Debug {
pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
}
exports, err := pass.env.GetResolver().loadExports(ctx, pkgName, c.pkg)
if err != nil {
if pass.env.Debug {
log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
}
resc <- nil
return

View file

@ -13,12 +13,14 @@ import (
"bytes"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/printer"
"go/token"
"io"
"io/ioutil"
"log"
"regexp"
"strconv"
"strings"
@ -41,13 +43,10 @@ type Options struct {
}
// Process implements golang.org/x/tools/imports.Process with explicit context in env.
func Process(filename string, src []byte, opt *Options) ([]byte, error) {
if src == nil {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
src = b
func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) {
src, opt, err = initialize(filename, src, opt)
if err != nil {
return nil, err
}
fileSet := token.NewFileSet()
@ -61,7 +60,93 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) {
return nil, err
}
}
return formatFile(fileSet, file, src, adjust, opt)
}
// FixImports returns a list of fixes to the imports that, when applied,
// will leave the imports in the same state as Process.
//
// Note that filename's directory influences which imports can be chosen,
// so it is important that filename be accurate.
func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) {
src, opt, err = initialize(filename, src, opt)
if err != nil {
return nil, err
}
fileSet := token.NewFileSet()
file, _, err := parse(fileSet, filename, src, opt)
if err != nil {
return nil, err
}
return getFixes(fileSet, file, filename, opt.Env)
}
// ApplyFix will apply all of the fixes to the file and format it.
func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options) (formatted []byte, err error) {
src, opt, err = initialize(filename, src, opt)
if err != nil {
return nil, err
}
fileSet := token.NewFileSet()
file, adjust, err := parse(fileSet, filename, src, opt)
if err != nil {
return nil, err
}
// Apply the fixes to the file.
apply(fileSet, file, fixes)
return formatFile(fileSet, file, src, adjust, opt)
}
// GetAllCandidates gets all of the standard library candidate packages to import in
// sorted order on import path.
func GetAllCandidates(filename string, opt *Options) (pkgs []ImportFix, err error) {
_, opt, err = initialize(filename, []byte{}, opt)
if err != nil {
return nil, err
}
return getAllCandidates(filename, opt.Env)
}
// initialize sets the values for opt and src.
// If they are provided, they are not changed. Otherwise opt is set to the
// default values and src is read from the file system.
func initialize(filename string, src []byte, opt *Options) ([]byte, *Options, error) {
// Use defaults if opt is nil.
if opt == nil {
opt = &Options{Comments: true, TabIndent: true, TabWidth: 8}
}
// Set the env if the user has not provided it.
if opt.Env == nil {
opt.Env = &ProcessEnv{
GOPATH: build.Default.GOPATH,
GOROOT: build.Default.GOROOT,
}
}
// Set the logger if the user has not provided it.
if opt.Env.Logf == nil {
opt.Env.Logf = log.Printf
}
if src == nil {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, nil, err
}
src = b
}
return src, opt, nil
}
func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) {
mergeImports(opt.Env, fileSet, file)
sortImports(opt.Env, fileSet, file)
imps := astutil.Imports(fileSet, file)
var spacesBefore []string // import paths we need spaces before
@ -89,7 +174,7 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) {
printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth}
var buf bytes.Buffer
err = printConfig.Fprint(&buf, fileSet, file)
err := printConfig.Fprint(&buf, fileSet, file)
if err != nil {
return nil, err
}

View file

@ -2,9 +2,10 @@ package imports
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
@ -19,37 +20,41 @@ import (
"golang.org/x/tools/internal/module"
)
// moduleResolver implements resolver for modules using the go command as little
// ModuleResolver implements resolver for modules using the go command as little
// as feasible.
type moduleResolver struct {
env *ProcessEnv
type ModuleResolver struct {
env *ProcessEnv
moduleCacheDir string
initialized bool
main *moduleJSON
modsByModPath []*moduleJSON // All modules, ordered by # of path components in module Path...
modsByDir []*moduleJSON // ...or Dir.
Initialized bool
Main *ModuleJSON
ModsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path...
ModsByDir []*ModuleJSON // ...or Dir.
// moduleCacheInfo stores information about the module cache.
moduleCacheInfo *moduleCacheInfo
}
type moduleJSON struct {
type ModuleJSON struct {
Path string // module path
Version string // module version
Versions []string // available module versions (with -versions)
Replace *moduleJSON // replaced by this module
Replace *ModuleJSON // replaced by this module
Time *time.Time // time version was created
Update *moduleJSON // available update, if any (with -u)
Update *ModuleJSON // available update, if any (with -u)
Main bool // is this the main module?
Indirect bool // is this module only an indirect dependency of main module?
Dir string // directory holding files for this module, if any
GoMod string // path to go.mod file for this module, if any
Error *moduleErrorJSON // error loading module
Error *ModuleErrorJSON // error loading module
}
type moduleErrorJSON struct {
type ModuleErrorJSON struct {
Err string // the error itself
}
func (r *moduleResolver) init() error {
if r.initialized {
func (r *ModuleResolver) init() error {
if r.Initialized {
return nil
}
stdout, err := r.env.invokeGo("list", "-m", "-json", "...")
@ -57,54 +62,73 @@ func (r *moduleResolver) init() error {
return err
}
for dec := json.NewDecoder(stdout); dec.More(); {
mod := &moduleJSON{}
mod := &ModuleJSON{}
if err := dec.Decode(mod); err != nil {
return err
}
if mod.Dir == "" {
if r.env.Debug {
log.Printf("module %v has not been downloaded and will be ignored", mod.Path)
r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path)
}
// Can't do anything with a module that's not downloaded.
continue
}
r.modsByModPath = append(r.modsByModPath, mod)
r.modsByDir = append(r.modsByDir, mod)
r.ModsByModPath = append(r.ModsByModPath, mod)
r.ModsByDir = append(r.ModsByDir, mod)
if mod.Main {
r.main = mod
r.Main = mod
}
}
sort.Slice(r.modsByModPath, func(i, j int) bool {
sort.Slice(r.ModsByModPath, func(i, j int) bool {
count := func(x int) int {
return strings.Count(r.modsByModPath[x].Path, "/")
return strings.Count(r.ModsByModPath[x].Path, "/")
}
return count(j) < count(i) // descending order
})
sort.Slice(r.modsByDir, func(i, j int) bool {
sort.Slice(r.ModsByDir, func(i, j int) bool {
count := func(x int) int {
return strings.Count(r.modsByDir[x].Dir, "/")
return strings.Count(r.ModsByDir[x].Dir, "/")
}
return count(j) < count(i) // descending order
})
r.initialized = true
if r.moduleCacheInfo == nil {
r.moduleCacheInfo = &moduleCacheInfo{
modCacheDirInfo: make(map[string]*directoryPackageInfo),
}
}
r.Initialized = true
return nil
}
// findPackage returns the module and directory that contains the package at
// the given import path, or returns nil, "" if no module is in scope.
func (r *moduleResolver) findPackage(importPath string) (*moduleJSON, string) {
for _, m := range r.modsByModPath {
func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) {
// This can't find packages in the stdlib, but that's harmless for all
// the existing code paths.
for _, m := range r.ModsByModPath {
if !strings.HasPrefix(importPath, m.Path) {
continue
}
pathInModule := importPath[len(m.Path):]
pkgDir := filepath.Join(m.Dir, pathInModule)
if dirIsNestedModule(pkgDir, m) {
if r.dirIsNestedModule(pkgDir, m) {
continue
}
if info, ok := r.moduleCacheInfo.Load(pkgDir); ok {
if packageScanned, err := info.reachedStatus(directoryScanned); packageScanned {
if err != nil {
// There was some error with scanning this directory.
// It does not contain a valid package.
continue
}
return m, pkgDir
}
}
pkgFiles, err := ioutil.ReadDir(pkgDir)
if err != nil {
continue
@ -124,7 +148,7 @@ func (r *moduleResolver) findPackage(importPath string) (*moduleJSON, string) {
// findModuleByDir returns the module that contains dir, or nil if no such
// module is in scope.
func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON {
func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON {
// This is quite tricky and may not be correct. dir could be:
// - a package in the main module.
// - a replace target underneath the main module's directory.
@ -135,12 +159,12 @@ func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON {
// - in /vendor/ in -mod=vendor mode.
// - nested module? Dunno.
// Rumor has it that replace targets cannot contain other replace targets.
for _, m := range r.modsByDir {
for _, m := range r.ModsByDir {
if !strings.HasPrefix(dir, m.Dir) {
continue
}
if dirIsNestedModule(dir, m) {
if r.dirIsNestedModule(dir, m) {
continue
}
@ -151,18 +175,28 @@ func (r *moduleResolver) findModuleByDir(dir string) *moduleJSON {
// dirIsNestedModule reports if dir is contained in a nested module underneath
// mod, not actually in mod.
func dirIsNestedModule(dir string, mod *moduleJSON) bool {
func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool {
if !strings.HasPrefix(dir, mod.Dir) {
return false
}
mf := findModFile(dir)
if r.dirInModuleCache(dir) {
// Nested modules in the module cache are pruned,
// so it cannot be a nested module.
return false
}
mf := r.findModFile(dir)
if mf == "" {
return false
}
return filepath.Dir(mf) != mod.Dir
}
func findModFile(dir string) string {
func (r *ModuleResolver) findModFile(dir string) string {
if r.dirInModuleCache(dir) {
matches := modCacheRegexp.FindStringSubmatch(dir)
index := strings.Index(dir, matches[1]+"@"+matches[2])
return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod")
}
for {
f := filepath.Join(dir, "go.mod")
info, err := os.Stat(f)
@ -177,7 +211,14 @@ func findModFile(dir string) string {
}
}
func (r *moduleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
func (r *ModuleResolver) dirInModuleCache(dir string) bool {
if r.moduleCacheDir == "" {
return false
}
return strings.HasPrefix(dir, r.moduleCacheDir)
}
func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
if err := r.init(); err != nil {
return nil, err
}
@ -196,7 +237,7 @@ func (r *moduleResolver) loadPackageNames(importPaths []string, srcDir string) (
return names, nil
}
func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
func (r *ModuleResolver) scan(_ references) ([]*pkg, error) {
if err := r.init(); err != nil {
return nil, err
}
@ -205,15 +246,16 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
roots := []gopathwalk.Root{
{filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT},
}
if r.main != nil {
roots = append(roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
if r.Main != nil {
roots = append(roots, gopathwalk.Root{r.Main.Dir, gopathwalk.RootCurrentModule})
}
for _, p := range filepath.SplitList(r.env.GOPATH) {
roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache})
if r.moduleCacheDir == "" {
r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod")
}
roots = append(roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache})
// Walk replace targets, just in case they're not in any of the above.
for _, mod := range r.modsByModPath {
for _, mod := range r.ModsByModPath {
if mod.Replace != nil {
roots = append(roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther})
}
@ -223,87 +265,190 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
dupCheck := make(map[string]bool)
var mu sync.Mutex
gopathwalk.Walk(roots, func(root gopathwalk.Root, dir string) {
// Packages in the module cache are immutable. If we have
// already seen this package on a previous scan of the module
// cache, return that result.
skip := func(root gopathwalk.Root, dir string) bool {
mu.Lock()
defer mu.Unlock()
// If we have already processed this directory on this walk, skip it.
if _, dup := dupCheck[dir]; dup {
return true
}
// If we have saved this directory information, skip it.
info, ok := r.moduleCacheInfo.Load(dir)
if !ok {
return false
}
// This directory can be skipped as long as we have already scanned it.
// Packages with errors will continue to have errors, so there is no need
// to rescan them.
packageScanned, _ := info.reachedStatus(directoryScanned)
return packageScanned
}
add := func(root gopathwalk.Root, dir string) {
mu.Lock()
defer mu.Unlock()
if _, dup := dupCheck[dir]; dup {
return
}
dupCheck[dir] = true
subdir := ""
if dir != root.Path {
subdir = dir[len(root.Path)+len("/"):]
}
importPath := filepath.ToSlash(subdir)
if strings.HasPrefix(importPath, "vendor/") {
// Ignore vendor dirs. If -mod=vendor is on, then things
// should mostly just work, but when it's not vendor/
// is a mess. There's no easy way to tell if it's on.
// We can still find things in the mod cache and
// map them into /vendor when -mod=vendor is on.
info, err := r.scanDirForPackage(root, dir)
if err != nil {
return
}
switch root.Type {
case gopathwalk.RootCurrentModule:
importPath = path.Join(r.main.Path, filepath.ToSlash(subdir))
case gopathwalk.RootModuleCache:
matches := modCacheRegexp.FindStringSubmatch(subdir)
modPath, err := module.DecodePath(filepath.ToSlash(matches[1]))
if err != nil {
if r.env.Debug {
log.Printf("decoding module cache path %q: %v", subdir, err)
}
return
}
importPath = path.Join(modPath, filepath.ToSlash(matches[3]))
case gopathwalk.RootGOROOT:
importPath = subdir
if root.Type == gopathwalk.RootModuleCache {
// Save this package information in the cache and return.
// Packages from the module cache are added after Walk.
r.moduleCacheInfo.Store(dir, info)
return
}
// Check if the directory is underneath a module that's in scope.
if mod := r.findModuleByDir(dir); mod != nil {
// It is. If dir is the target of a replace directive,
// our guessed import path is wrong. Use the real one.
if mod.Dir == dir {
importPath = mod.Path
} else {
dirInMod := dir[len(mod.Dir)+len("/"):]
importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod))
}
} else {
// The package is in an unknown module. Check that it's
// not obviously impossible to import.
var modFile string
switch root.Type {
case gopathwalk.RootModuleCache:
matches := modCacheRegexp.FindStringSubmatch(subdir)
modFile = filepath.Join(matches[1], "@", matches[2], "go.mod")
default:
modFile = findModFile(dir)
}
modBytes, err := ioutil.ReadFile(modFile)
if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) {
// The module's declared path does not match
// its expected path. It probably needs a
// replace directive we don't have.
return
}
}
// We may have discovered a package that has a different version
// in scope already. Canonicalize to that one if possible.
if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" {
dir = canonicalDir
// Skip this package if there was an error loading package info.
if info.err != nil {
return
}
result = append(result, &pkg{
importPathShort: VendorlessPath(importPath),
// The rest of this function canonicalizes the packages using the results
// of initializing the resolver from 'go list -m'.
res, err := r.canonicalize(root.Type, info.nonCanonicalImportPath, info.dir, info.needsReplace)
if err != nil {
return
}
result = append(result, res)
}
gopathwalk.WalkSkip(roots, add, skip, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true})
// Add the packages from the modules in the mod cache that were skipped.
for _, dir := range r.moduleCacheInfo.Keys() {
info, ok := r.moduleCacheInfo.Load(dir)
if !ok {
continue
}
// Skip this directory if we were not able to get the package information successfully.
if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil {
continue
}
res, err := r.canonicalize(gopathwalk.RootModuleCache, info.nonCanonicalImportPath, info.dir, info.needsReplace)
if err != nil {
continue
}
result = append(result, res)
}
return result, nil
}
// canonicalize gets the result of canonicalizing the packages using the results
// of initializing the resolver from 'go list -m'.
func (r *ModuleResolver) canonicalize(rootType gopathwalk.RootType, importPath, dir string, needsReplace bool) (res *pkg, err error) {
// Packages in GOROOT are already canonical, regardless of the std/cmd modules.
if rootType == gopathwalk.RootGOROOT {
return &pkg{
importPathShort: importPath,
dir: dir,
})
}, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true})
}, nil
}
// Check if the directory is underneath a module that's in scope.
if mod := r.findModuleByDir(dir); mod != nil {
// It is. If dir is the target of a replace directive,
// our guessed import path is wrong. Use the real one.
if mod.Dir == dir {
importPath = mod.Path
} else {
dirInMod := dir[len(mod.Dir)+len("/"):]
importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod))
}
} else if needsReplace {
return nil, fmt.Errorf("needed this package to be in scope: %s", dir)
}
// We may have discovered a package that has a different version
// in scope already. Canonicalize to that one if possible.
if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" {
dir = canonicalDir
}
return &pkg{
importPathShort: VendorlessPath(importPath),
dir: dir,
}, nil
}
func (r *ModuleResolver) loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[string]bool, error) {
if err := r.init(); err != nil {
return nil, err
}
return loadExportsFromFiles(ctx, r.env, expectPackage, pkg.dir)
}
func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) (directoryPackageInfo, error) {
subdir := ""
if dir != root.Path {
subdir = dir[len(root.Path)+len("/"):]
}
importPath := filepath.ToSlash(subdir)
if strings.HasPrefix(importPath, "vendor/") {
// Ignore vendor dirs. If -mod=vendor is on, then things
// should mostly just work, but when it's not vendor/
// is a mess. There's no easy way to tell if it's on.
// We can still find things in the mod cache and
// map them into /vendor when -mod=vendor is on.
return directoryPackageInfo{}, fmt.Errorf("vendor directory")
}
switch root.Type {
case gopathwalk.RootCurrentModule:
importPath = path.Join(r.Main.Path, filepath.ToSlash(subdir))
case gopathwalk.RootModuleCache:
matches := modCacheRegexp.FindStringSubmatch(subdir)
if len(matches) == 0 {
return directoryPackageInfo{
status: directoryScanned,
err: fmt.Errorf("invalid module cache path: %v", subdir),
}, nil
}
modPath, err := module.DecodePath(filepath.ToSlash(matches[1]))
if err != nil {
if r.env.Debug {
r.env.Logf("decoding module cache path %q: %v", subdir, err)
}
return directoryPackageInfo{
status: directoryScanned,
err: fmt.Errorf("decoding module cache path %q: %v", subdir, err),
}, nil
}
importPath = path.Join(modPath, filepath.ToSlash(matches[3]))
case gopathwalk.RootGOROOT:
importPath = subdir
}
result := directoryPackageInfo{
status: directoryScanned,
dir: dir,
nonCanonicalImportPath: importPath,
needsReplace: false,
}
if root.Type == gopathwalk.RootGOROOT {
// stdlib packages are always in scope, despite the confusing go.mod
return result, nil
}
// Check that this package is not obviously impossible to import.
modFile := r.findModFile(dir)
modBytes, err := ioutil.ReadFile(modFile)
if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) {
// The module's declared path does not match
// its expected path. It probably needs a
// replace directive we don't have.
result.needsReplace = true
}
return result, nil
}

121
vendor/golang.org/x/tools/internal/imports/mod_cache.go generated vendored Normal file
View file

@ -0,0 +1,121 @@
package imports
import (
"sync"
)
// ModuleResolver implements Resolver for modules using the go command as little
// as feasible.
//
// To find packages to import, the resolver needs to know about all of the
// the packages that could be imported. This includes packages that are
// already in modules that are in (1) the current module, (2) replace targets,
// and (3) packages in the module cache. Packages in (1) and (2) may change over
// time, as the client may edit the current module and locally replaced modules.
// The module cache (which includes all of the packages in (3)) can only
// ever be added to.
//
// The resolver can thus save state about packages in the module cache
// and guarantee that this will not change over time. To obtain information
// about new modules added to the module cache, the module cache should be
// rescanned.
//
// It is OK to serve information about modules that have been deleted,
// as they do still exist.
// TODO(suzmue): can we share information with the caller about
// what module needs to be downloaded to import this package?
type directoryPackageStatus int
const (
_ directoryPackageStatus = iota
directoryScanned
)
type directoryPackageInfo struct {
// status indicates the extent to which this struct has been filled in.
status directoryPackageStatus
// err is non-nil when there was an error trying to reach status.
err error
// Set when status > directoryScanned.
// dir is the absolute directory of this package.
dir string
// nonCanonicalImportPath is the expected import path for this package.
// This may not be an import path that can be used to import this package.
nonCanonicalImportPath string
// needsReplace is true if the nonCanonicalImportPath does not match the
// the modules declared path, making it impossible to import without a
// replace directive.
needsReplace bool
}
// reachedStatus returns true when info has a status at least target and any error associated with
// an attempt to reach target.
func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (bool, error) {
if info.err == nil {
return info.status >= target, nil
}
if info.status == target {
return true, info.err
}
return true, nil
}
// moduleCacheInfo is a concurrency safe map for storing information about
// the directories in the module cache.
//
// The information in this cache is built incrementally. Entries are initialized in scan.
// No new keys should be added in any other functions, as all directories containing
// packages are identified in scan.
//
// Other functions, including loadExports and findPackage, may update entries in this cache
// as they discover new things about the directory.
//
// We do not need to protect the data in the cache for multiple writes, because it only stores
// module cache directories, which do not change. If two competing stores take place, there will be
// one store that wins. Although this could result in a loss of information it will not be incorrect
// and may just result in recomputing the same result later.
//
// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc)
type moduleCacheInfo struct {
mu sync.Mutex
// modCacheDirInfo stores information about packages in
// module cache directories. Keyed by absolute directory.
modCacheDirInfo map[string]*directoryPackageInfo
}
// Store stores the package info for dir.
func (d *moduleCacheInfo) Store(dir string, info directoryPackageInfo) {
d.mu.Lock()
defer d.mu.Unlock()
d.modCacheDirInfo[dir] = &directoryPackageInfo{
status: info.status,
err: info.err,
dir: info.dir,
nonCanonicalImportPath: info.nonCanonicalImportPath,
needsReplace: info.needsReplace,
}
}
// Load returns a copy of the directoryPackageInfo for absolute directory dir.
func (d *moduleCacheInfo) Load(dir string) (directoryPackageInfo, bool) {
d.mu.Lock()
defer d.mu.Unlock()
info, ok := d.modCacheDirInfo[dir]
if !ok {
return directoryPackageInfo{}, false
}
return *info, true
}
// Keys returns the keys currently present in d.
func (d *moduleCacheInfo) Keys() (keys []string) {
d.mu.Lock()
defer d.mu.Unlock()
for key := range d.modCacheDirInfo {
keys = append(keys, key)
}
return keys
}

View file

@ -58,6 +58,53 @@ func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) {
}
}
// mergeImports merges all the import declarations into the first one.
// Taken from golang.org/x/tools/ast/astutil.
func mergeImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) {
if len(f.Decls) <= 1 {
return
}
// Merge all the import declarations into the first one.
var first *ast.GenDecl
for i := 0; i < len(f.Decls); i++ {
decl := f.Decls[i]
gen, ok := decl.(*ast.GenDecl)
if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") {
continue
}
if first == nil {
first = gen
continue // Don't touch the first one.
}
// We now know there is more than one package in this import
// declaration. Ensure that it ends up parenthesized.
first.Lparen = first.Pos()
// Move the imports of the other import declaration to the first one.
for _, spec := range gen.Specs {
spec.(*ast.ImportSpec).Path.ValuePos = first.Pos()
first.Specs = append(first.Specs, spec)
}
f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
i--
}
}
// declImports reports whether gen contains an import of path.
// Taken from golang.org/x/tools/ast/astutil.
func declImports(gen *ast.GenDecl, path string) bool {
if gen.Tok != token.IMPORT {
return false
}
for _, spec := range gen.Specs {
impspec := spec.(*ast.ImportSpec)
if importPath(impspec) == path {
return true
}
}
return false
}
func importPath(s ast.Spec) string {
t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value)
if err == nil {

View file

@ -125,6 +125,7 @@ var stdlib = map[string]map[string]bool{
"ToTitleSpecial": true,
"ToUpper": true,
"ToUpperSpecial": true,
"ToValidUTF8": true,
"Trim": true,
"TrimFunc": true,
"TrimLeft": true,
@ -304,6 +305,18 @@ var stdlib = map[string]map[string]bool{
"Sign": true,
"Verify": true,
},
"crypto/ed25519": map[string]bool{
"GenerateKey": true,
"NewKeyFromSeed": true,
"PrivateKey": true,
"PrivateKeySize": true,
"PublicKey": true,
"PublicKeySize": true,
"SeedSize": true,
"Sign": true,
"SignatureSize": true,
"Verify": true,
},
"crypto/elliptic": map[string]bool{
"Curve": true,
"CurveParams": true,
@ -420,6 +433,7 @@ var stdlib = map[string]map[string]bool{
"ECDSAWithP384AndSHA384": true,
"ECDSAWithP521AndSHA512": true,
"ECDSAWithSHA1": true,
"Ed25519": true,
"Listen": true,
"LoadX509KeyPair": true,
"NewLRUClientSessionCache": true,
@ -478,35 +492,36 @@ var stdlib = map[string]map[string]bool{
"X509KeyPair": true,
},
"crypto/x509": map[string]bool{
"CANotAuthorizedForExtKeyUsage": true,
"CANotAuthorizedForThisName": true,
"CertPool": true,
"Certificate": true,
"CertificateInvalidError": true,
"CertificateRequest": true,
"ConstraintViolationError": true,
"CreateCertificate": true,
"CreateCertificateRequest": true,
"DSA": true,
"DSAWithSHA1": true,
"DSAWithSHA256": true,
"DecryptPEMBlock": true,
"ECDSA": true,
"ECDSAWithSHA1": true,
"ECDSAWithSHA256": true,
"ECDSAWithSHA384": true,
"ECDSAWithSHA512": true,
"EncryptPEMBlock": true,
"ErrUnsupportedAlgorithm": true,
"Expired": true,
"ExtKeyUsage": true,
"ExtKeyUsageAny": true,
"ExtKeyUsageClientAuth": true,
"ExtKeyUsageCodeSigning": true,
"ExtKeyUsageEmailProtection": true,
"ExtKeyUsageIPSECEndSystem": true,
"ExtKeyUsageIPSECTunnel": true,
"ExtKeyUsageIPSECUser": true,
"CANotAuthorizedForExtKeyUsage": true,
"CANotAuthorizedForThisName": true,
"CertPool": true,
"Certificate": true,
"CertificateInvalidError": true,
"CertificateRequest": true,
"ConstraintViolationError": true,
"CreateCertificate": true,
"CreateCertificateRequest": true,
"DSA": true,
"DSAWithSHA1": true,
"DSAWithSHA256": true,
"DecryptPEMBlock": true,
"ECDSA": true,
"ECDSAWithSHA1": true,
"ECDSAWithSHA256": true,
"ECDSAWithSHA384": true,
"ECDSAWithSHA512": true,
"Ed25519": true,
"EncryptPEMBlock": true,
"ErrUnsupportedAlgorithm": true,
"Expired": true,
"ExtKeyUsage": true,
"ExtKeyUsageAny": true,
"ExtKeyUsageClientAuth": true,
"ExtKeyUsageCodeSigning": true,
"ExtKeyUsageEmailProtection": true,
"ExtKeyUsageIPSECEndSystem": true,
"ExtKeyUsageIPSECTunnel": true,
"ExtKeyUsageIPSECUser": true,
"ExtKeyUsageMicrosoftCommercialCodeSigning": true,
"ExtKeyUsageMicrosoftKernelCodeSigning": true,
"ExtKeyUsageMicrosoftServerGatedCrypto": true,
@ -558,6 +573,7 @@ var stdlib = map[string]map[string]bool{
"ParsePKCS8PrivateKey": true,
"ParsePKIXPublicKey": true,
"PublicKeyAlgorithm": true,
"PureEd25519": true,
"RSA": true,
"SHA1WithRSA": true,
"SHA256WithRSA": true,
@ -612,8 +628,10 @@ var stdlib = map[string]map[string]bool{
"NamedArg": true,
"NullBool": true,
"NullFloat64": true,
"NullInt32": true,
"NullInt64": true,
"NullString": true,
"NullTime": true,
"Open": true,
"OpenDB": true,
"Out": true,
@ -860,6 +878,7 @@ var stdlib = map[string]map[string]bool{
"UcharType": true,
"UintType": true,
"UnspecifiedType": true,
"UnsupportedType": true,
"VoidType": true,
},
"debug/elf": map[string]bool{
@ -2505,7 +2524,10 @@ var stdlib = map[string]map[string]bool{
"UnsupportedTypeError": true,
},
"errors": map[string]bool{
"New": true,
"As": true,
"Is": true,
"New": true,
"Unwrap": true,
},
"expvar": map[string]bool{
"Do": true,
@ -2615,10 +2637,12 @@ var stdlib = map[string]map[string]bool{
"CommentMap": true,
"CompositeLit": true,
"Con": true,
"Decl": true,
"DeclStmt": true,
"DeferStmt": true,
"Ellipsis": true,
"EmptyStmt": true,
"Expr": true,
"ExprStmt": true,
"Field": true,
"FieldFilter": true,
@ -2679,7 +2703,9 @@ var stdlib = map[string]map[string]bool{
"SendStmt": true,
"SliceExpr": true,
"SortImports": true,
"Spec": true,
"StarExpr": true,
"Stmt": true,
"StructType": true,
"SwitchStmt": true,
"Typ": true,
@ -2725,6 +2751,7 @@ var stdlib = map[string]map[string]bool{
"Int": true,
"Int64Val": true,
"Kind": true,
"Make": true,
"MakeBool": true,
"MakeFloat64": true,
"MakeFromBytes": true,
@ -2746,6 +2773,8 @@ var stdlib = map[string]map[string]bool{
"Uint64Val": true,
"UnaryOp": true,
"Unknown": true,
"Val": true,
"Value": true,
},
"go/doc": map[string]bool{
"AllDecls": true,
@ -2855,6 +2884,9 @@ var stdlib = map[string]map[string]bool{
"INC": true,
"INT": true,
"INTERFACE": true,
"IsExported": true,
"IsIdentifier": true,
"IsKeyword": true,
"LAND": true,
"LBRACE": true,
"LBRACK": true,
@ -2916,6 +2948,7 @@ var stdlib = map[string]map[string]bool{
"Byte": true,
"Chan": true,
"ChanDir": true,
"CheckExpr": true,
"Checker": true,
"Comparable": true,
"Complex128": true,
@ -2991,6 +3024,7 @@ var stdlib = map[string]map[string]bool{
"NewTypeName": true,
"NewVar": true,
"Nil": true,
"Object": true,
"ObjectString": true,
"Package": true,
"PkgName": true,
@ -3349,6 +3383,7 @@ var stdlib = map[string]map[string]bool{
"SetFlags": true,
"SetOutput": true,
"SetPrefix": true,
"Writer": true,
},
"log/syslog": map[string]bool{
"Dial": true,
@ -3801,6 +3836,7 @@ var stdlib = map[string]map[string]bool{
"MethodTrace": true,
"NewFileTransport": true,
"NewRequest": true,
"NewRequestWithContext": true,
"NewServeMux": true,
"NoBody": true,
"NotFound": true,
@ -3825,6 +3861,7 @@ var stdlib = map[string]map[string]bool{
"SameSite": true,
"SameSiteDefaultMode": true,
"SameSiteLaxMode": true,
"SameSiteNoneMode": true,
"SameSiteStrictMode": true,
"Serve": true,
"ServeContent": true,
@ -3846,6 +3883,7 @@ var stdlib = map[string]map[string]bool{
"StatusConflict": true,
"StatusContinue": true,
"StatusCreated": true,
"StatusEarlyHints": true,
"StatusExpectationFailed": true,
"StatusFailedDependency": true,
"StatusForbidden": true,
@ -4163,6 +4201,7 @@ var stdlib = map[string]map[string]bool{
"Truncate": true,
"Unsetenv": true,
"UserCacheDir": true,
"UserConfigDir": true,
"UserHomeDir": true,
},
"os/exec": map[string]bool{
@ -4293,6 +4332,7 @@ var stdlib = map[string]map[string]bool{
"StructOf": true,
"StructTag": true,
"Swapper": true,
"Type": true,
"TypeOf": true,
"Uint": true,
"Uint16": true,
@ -4588,6 +4628,7 @@ var stdlib = map[string]map[string]bool{
"ToTitleSpecial": true,
"ToUpper": true,
"ToUpperSpecial": true,
"ToValidUTF8": true,
"Trim": true,
"TrimFunc": true,
"TrimLeft": true,
@ -7989,6 +8030,7 @@ var stdlib = map[string]map[string]bool{
"Rmdir": true,
"RouteMessage": true,
"RouteRIB": true,
"RoutingMessage": true,
"RtAttr": true,
"RtGenmsg": true,
"RtMetrics": true,
@ -9357,6 +9399,7 @@ var stdlib = map[string]map[string]bool{
"SlicePtrFromStrings": true,
"SockFilter": true,
"SockFprog": true,
"Sockaddr": true,
"SockaddrDatalink": true,
"SockaddrGen": true,
"SockaddrInet4": true,
@ -9784,6 +9827,8 @@ var stdlib = map[string]map[string]bool{
"XP1_UNI_SEND": true,
},
"syscall/js": map[string]bool{
"CopyBytesToGo": true,
"CopyBytesToJS": true,
"Error": true,
"Func": true,
"FuncOf": true,
@ -9798,8 +9843,6 @@ var stdlib = map[string]map[string]bool{
"TypeString": true,
"TypeSymbol": true,
"TypeUndefined": true,
"TypedArray": true,
"TypedArrayOf": true,
"Undefined": true,
"Value": true,
"ValueError": true,
@ -9815,6 +9858,7 @@ var stdlib = map[string]map[string]bool{
"CoverBlock": true,
"CoverMode": true,
"Coverage": true,
"Init": true,
"InternalBenchmark": true,
"InternalExample": true,
"InternalTest": true,
@ -9828,6 +9872,7 @@ var stdlib = map[string]map[string]bool{
"RunTests": true,
"Short": true,
"T": true,
"TB": true,
"Verbose": true,
},
"testing/iotest": map[string]bool{
@ -10063,6 +10108,7 @@ var stdlib = map[string]map[string]bool{
"Devanagari": true,
"Diacritic": true,
"Digit": true,
"Dogra": true,
"Duployan": true,
"Egyptian_Hieroglyphs": true,
"Elbasan": true,
@ -10077,9 +10123,11 @@ var stdlib = map[string]map[string]bool{
"GraphicRanges": true,
"Greek": true,
"Gujarati": true,
"Gunjala_Gondi": true,
"Gurmukhi": true,
"Han": true,
"Hangul": true,
"Hanifi_Rohingya": true,
"Hanunoo": true,
"Hatran": true,
"Hebrew": true,
@ -10140,6 +10188,7 @@ var stdlib = map[string]map[string]bool{
"Lydian": true,
"M": true,
"Mahajani": true,
"Makasar": true,
"Malayalam": true,
"Mandaic": true,
"Manichaean": true,
@ -10152,6 +10201,7 @@ var stdlib = map[string]map[string]bool{
"MaxRune": true,
"Mc": true,
"Me": true,
"Medefaidrin": true,
"Meetei_Mayek": true,
"Mende_Kikakui": true,
"Meroitic_Cursive": true,
@ -10181,6 +10231,7 @@ var stdlib = map[string]map[string]bool{
"Old_North_Arabian": true,
"Old_Permic": true,
"Old_Persian": true,
"Old_Sogdian": true,
"Old_South_Arabian": true,
"Old_Turkic": true,
"Oriya": true,
@ -10241,6 +10292,7 @@ var stdlib = map[string]map[string]bool{
"Sm": true,
"So": true,
"Soft_Dotted": true,
"Sogdian": true,
"Sora_Sompeng": true,
"Soyombo": true,
"Space": true,