165
vendor/golang.org/x/tools/internal/imports/fix.go
generated
vendored
165
vendor/golang.org/x/tools/internal/imports/fix.go
generated
vendored
@@ -13,7 +13,6 @@ import (
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -68,6 +67,19 @@ func importGroup(env *ProcessEnv, importPath string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type importFixType int
|
||||
|
||||
const (
|
||||
addImport importFixType = iota
|
||||
deleteImport
|
||||
setImportName
|
||||
)
|
||||
|
||||
type importFix struct {
|
||||
info importInfo
|
||||
fixType importFixType
|
||||
}
|
||||
|
||||
// An importInfo represents a single import statement.
|
||||
type importInfo struct {
|
||||
importPath string // import path, e.g. "crypto/rand".
|
||||
@@ -246,6 +258,12 @@ type pass struct {
|
||||
|
||||
// loadPackageNames saves the package names for everything referenced by imports.
|
||||
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 {
|
||||
@@ -285,7 +303,7 @@ func (p *pass) importIdentifier(imp *importInfo) string {
|
||||
// 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{}
|
||||
@@ -313,9 +331,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,16 +352,16 @@ 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
|
||||
for left, rights := range p.missingRefs {
|
||||
@@ -353,10 +371,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,27 +383,77 @@ 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{
|
||||
info: *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{
|
||||
info: importInfo{
|
||||
name: name,
|
||||
importPath: imp.importPath,
|
||||
},
|
||||
fixType: setImportName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, imp := range selected {
|
||||
astutil.AddNamedImport(p.fset, p.f, imp.name, imp.importPath)
|
||||
fixes = append(fixes, &importFix{
|
||||
info: importInfo{
|
||||
name: p.importSpecName(imp),
|
||||
importPath: imp.importPath,
|
||||
},
|
||||
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) bool {
|
||||
for _, fix := range fixes {
|
||||
switch fix.fixType {
|
||||
case deleteImport:
|
||||
astutil.DeleteNamedImport(fset, f, fix.info.name, fix.info.importPath)
|
||||
case addImport:
|
||||
astutil.AddNamedImport(fset, f, fix.info.name, fix.info.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.info.importPath {
|
||||
spec.Name = &ast.Ident{
|
||||
Name: fix.info.name,
|
||||
NamePos: spec.Pos(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -437,13 +506,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 getFixes 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 +531,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 +540,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 +557,25 @@ 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
|
||||
}
|
||||
|
||||
// ProcessEnv contains environment variables and settings that affect the use of
|
||||
@@ -512,6 +592,9 @@ type ProcessEnv struct {
|
||||
// If true, use go/packages regardless of the environment.
|
||||
ForceGoPackages bool
|
||||
|
||||
// Logf is the default logger for the ProcessEnv.
|
||||
Logf func(format string, args ...interface{})
|
||||
|
||||
resolver resolver
|
||||
}
|
||||
|
||||
@@ -577,7 +660,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)
|
||||
@@ -943,7 +1026,7 @@ func VendorlessPath(ipath string) string {
|
||||
// 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)
|
||||
env.Logf("loading exports in dir %s (seeking package %s)", pkg.dir, expectPackage)
|
||||
}
|
||||
if pkg.goPackage != nil {
|
||||
exports := map[string]bool{}
|
||||
@@ -1021,7 +1104,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", pkg.dir, expectPackage, strings.Join(exportList, ", "))
|
||||
}
|
||||
return exports, nil
|
||||
}
|
||||
@@ -1058,7 +1141,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,7 +1181,7 @@ func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string,
|
||||
exports, err := loadExports(ctx, pass.env, 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
|
||||
|
||||
6
vendor/golang.org/x/tools/internal/imports/imports.go
generated
vendored
6
vendor/golang.org/x/tools/internal/imports/imports.go
generated
vendored
@@ -19,6 +19,7 @@ import (
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -50,6 +51,11 @@ func Process(filename string, src []byte, opt *Options) ([]byte, error) {
|
||||
src = b
|
||||
}
|
||||
|
||||
// Set the logger if the user has not provided it.
|
||||
if opt.Env.Logf == nil {
|
||||
opt.Env.Logf = log.Printf
|
||||
}
|
||||
|
||||
fileSet := token.NewFileSet()
|
||||
file, adjust, err := parse(fileSet, filename, src, opt)
|
||||
if err != nil {
|
||||
|
||||
5
vendor/golang.org/x/tools/internal/imports/mod.go
generated
vendored
5
vendor/golang.org/x/tools/internal/imports/mod.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -63,7 +62,7 @@ func (r *moduleResolver) init() error {
|
||||
}
|
||||
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
|
||||
@@ -254,7 +253,7 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
|
||||
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)
|
||||
r.env.Logf("decoding module cache path %q: %v", subdir, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user