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	"bufio"
   9	"bytes"
  10	"context"
  11	"fmt"
  12	"go/ast"
  13	"go/build"
  14	"go/parser"
  15	"go/token"
  16	"io/ioutil"
  17	"log"
  18	"os"
  19	"path"
  20	"path/filepath"
  21	"sort"
  22	"strconv"
  23	"strings"
  24	"sync"
  25
  26	"golang.org/x/tools/go/ast/astutil"
  27	"golang.org/x/tools/internal/fastwalk"
  28)
  29
  30// Debug controls verbose logging.
  31var Debug = false
  32
  33// LocalPrefix is a comma-separated string of import path prefixes, which, if
  34// set, instructs Process to sort the import paths with the given prefixes
  35// into another group after 3rd-party packages.
  36var LocalPrefix string
  37
  38func localPrefixes() []string {
  39	if LocalPrefix != "" {
  40		return strings.Split(LocalPrefix, ",")
  41	}
  42	return nil
  43}
  44
  45// importToGroup is a list of functions which map from an import path to
  46// a group number.
  47var importToGroup = []func(importPath string) (num int, ok bool){
  48	func(importPath string) (num int, ok bool) {
  49		for _, p := range localPrefixes() {
  50			if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath {
  51				return 3, true
  52			}
  53		}
  54		return
  55	},
  56	func(importPath string) (num int, ok bool) {
  57		if strings.HasPrefix(importPath, "appengine") {
  58			return 2, true
  59		}
  60		return
  61	},
  62	func(importPath string) (num int, ok bool) {
  63		if strings.Contains(importPath, ".") {
  64			return 1, true
  65		}
  66		return
  67	},
  68}
  69
  70func importGroup(importPath string) int {
  71	for _, fn := range importToGroup {
  72		if n, ok := fn(importPath); ok {
  73			return n
  74		}
  75	}
  76	return 0
  77}
  78
  79// importInfo is a summary of information about one import.
  80type importInfo struct {
  81	Path  string // full import path (e.g. "crypto/rand")
  82	Alias string // import alias, if present (e.g. "crand")
  83}
  84
  85// packageInfo is a summary of features found in a package.
  86type packageInfo struct {
  87	Globals map[string]bool       // symbol => true
  88	Imports map[string]importInfo // pkg base name or alias => info
  89	// refs are a set of package references currently satisfied by imports.
  90	// first key: either base package (e.g. "fmt") or renamed package
  91	// second key: referenced package symbol (e.g. "Println")
  92	Refs map[string]map[string]bool
  93}
  94
  95// dirPackageInfo exposes the dirPackageInfoFile function so that it can be overridden.
  96var dirPackageInfo = dirPackageInfoFile
  97
  98// dirPackageInfoFile gets information from other files in the package.
  99func dirPackageInfoFile(pkgName, srcDir, filename string) (*packageInfo, error) {
 100	considerTests := strings.HasSuffix(filename, "_test.go")
 101
 102	fileBase := filepath.Base(filename)
 103	packageFileInfos, err := ioutil.ReadDir(srcDir)
 104	if err != nil {
 105		return nil, err
 106	}
 107
 108	info := &packageInfo{
 109		Globals: make(map[string]bool),
 110		Imports: make(map[string]importInfo),
 111		Refs:    make(map[string]map[string]bool),
 112	}
 113
 114	visitor := collectReferences(info.Refs)
 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		fileSet := token.NewFileSet()
 124		root, err := parser.ParseFile(fileSet, filepath.Join(srcDir, fi.Name()), nil, 0)
 125		if err != nil {
 126			continue
 127		}
 128
 129		for _, decl := range root.Decls {
 130			genDecl, ok := decl.(*ast.GenDecl)
 131			if !ok {
 132				continue
 133			}
 134
 135			for _, spec := range genDecl.Specs {
 136				valueSpec, ok := spec.(*ast.ValueSpec)
 137				if !ok {
 138					continue
 139				}
 140				info.Globals[valueSpec.Names[0].Name] = true
 141			}
 142		}
 143
 144		for _, imp := range root.Imports {
 145			impInfo := importInfo{Path: strings.Trim(imp.Path.Value, `"`)}
 146			name := path.Base(impInfo.Path)
 147			if imp.Name != nil {
 148				name = strings.Trim(imp.Name.Name, `"`)
 149				impInfo.Alias = name
 150			}
 151			info.Imports[name] = impInfo
 152		}
 153
 154		ast.Walk(visitor, root)
 155	}
 156	return info, nil
 157}
 158
 159// collectReferences returns a visitor that collects all exported package
 160// references
 161func collectReferences(refs map[string]map[string]bool) visitFn {
 162	var visitor visitFn
 163	visitor = func(node ast.Node) ast.Visitor {
 164		if node == nil {
 165			return visitor
 166		}
 167		switch v := node.(type) {
 168		case *ast.SelectorExpr:
 169			xident, ok := v.X.(*ast.Ident)
 170			if !ok {
 171				break
 172			}
 173			if xident.Obj != nil {
 174				// if the parser can resolve it, it's not a package ref
 175				break
 176			}
 177			pkgName := xident.Name
 178			r := refs[pkgName]
 179			if r == nil {
 180				r = make(map[string]bool)
 181				refs[pkgName] = r
 182			}
 183			if ast.IsExported(v.Sel.Name) {
 184				r[v.Sel.Name] = true
 185			}
 186		}
 187		return visitor
 188	}
 189	return visitor
 190}
 191
 192func fixImports(fset *token.FileSet, f *ast.File, filename string) (added []string, err error) {
 193	// refs are a set of possible package references currently unsatisfied by imports.
 194	// first key: either base package (e.g. "fmt") or renamed package
 195	// second key: referenced package symbol (e.g. "Println")
 196	refs := make(map[string]map[string]bool)
 197
 198	// decls are the current package imports. key is base package or renamed package.
 199	decls := make(map[string]*ast.ImportSpec)
 200
 201	abs, err := filepath.Abs(filename)
 202	if err != nil {
 203		return nil, err
 204	}
 205	srcDir := filepath.Dir(abs)
 206	if Debug {
 207		log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
 208	}
 209
 210	var packageInfo *packageInfo
 211	var loadedPackageInfo bool
 212
 213	// collect potential uses of packages.
 214	var visitor visitFn
 215	visitor = visitFn(func(node ast.Node) ast.Visitor {
 216		if node == nil {
 217			return visitor
 218		}
 219		switch v := node.(type) {
 220		case *ast.ImportSpec:
 221			if v.Name != nil {
 222				decls[v.Name.Name] = v
 223				break
 224			}
 225			ipath := strings.Trim(v.Path.Value, `"`)
 226			if ipath == "C" {
 227				break
 228			}
 229			local := importPathToName(ipath, srcDir)
 230			decls[local] = v
 231		case *ast.SelectorExpr:
 232			xident, ok := v.X.(*ast.Ident)
 233			if !ok {
 234				break
 235			}
 236			if xident.Obj != nil {
 237				// if the parser can resolve it, it's not a package ref
 238				break
 239			}
 240			pkgName := xident.Name
 241			if refs[pkgName] == nil {
 242				refs[pkgName] = make(map[string]bool)
 243			}
 244			if !loadedPackageInfo {
 245				loadedPackageInfo = true
 246				packageInfo, _ = dirPackageInfo(f.Name.Name, srcDir, filename)
 247			}
 248			if decls[pkgName] == nil && (packageInfo == nil || !packageInfo.Globals[pkgName]) {
 249				refs[pkgName][v.Sel.Name] = true
 250			}
 251		}
 252		return visitor
 253	})
 254	ast.Walk(visitor, f)
 255
 256	// Nil out any unused ImportSpecs, to be removed in following passes
 257	unusedImport := map[string]string{}
 258	for pkg, is := range decls {
 259		if refs[pkg] == nil && pkg != "_" && pkg != "." {
 260			name := ""
 261			if is.Name != nil {
 262				name = is.Name.Name
 263			}
 264			unusedImport[strings.Trim(is.Path.Value, `"`)] = name
 265		}
 266	}
 267	for ipath, name := range unusedImport {
 268		if ipath == "C" {
 269			// Don't remove cgo stuff.
 270			continue
 271		}
 272		astutil.DeleteNamedImport(fset, f, name, ipath)
 273	}
 274
 275	for pkgName, symbols := range refs {
 276		if len(symbols) == 0 {
 277			// skip over packages already imported
 278			delete(refs, pkgName)
 279		}
 280	}
 281
 282	// Fast path, all references already imported.
 283	if len(refs) == 0 {
 284		return nil, nil
 285	}
 286
 287	// Can assume this will be necessary in all cases now.
 288	if !loadedPackageInfo {
 289		packageInfo, _ = dirPackageInfo(f.Name.Name, srcDir, filename)
 290	}
 291
 292	// Search for imports matching potential package references.
 293	type result struct {
 294		ipath string // import path
 295		name  string // optional name to rename import as
 296	}
 297	results := make(chan result, len(refs))
 298
 299	ctx, cancel := context.WithCancel(context.TODO())
 300	var wg sync.WaitGroup
 301	defer func() {
 302		cancel()
 303		wg.Wait()
 304	}()
 305	var (
 306		firstErr     error
 307		firstErrOnce sync.Once
 308	)
 309	for pkgName, symbols := range refs {
 310		wg.Add(1)
 311		go func(pkgName string, symbols map[string]bool) {
 312			defer wg.Done()
 313
 314			if packageInfo != nil {
 315				sibling := packageInfo.Imports[pkgName]
 316				if sibling.Path != "" {
 317					refs := packageInfo.Refs[pkgName]
 318					for symbol := range symbols {
 319						if refs[symbol] {
 320							results <- result{ipath: sibling.Path, name: sibling.Alias}
 321							return
 322						}
 323					}
 324				}
 325			}
 326
 327			ipath, rename, err := findImport(ctx, pkgName, symbols, filename)
 328			if err != nil {
 329				firstErrOnce.Do(func() {
 330					firstErr = err
 331					cancel()
 332				})
 333				return
 334			}
 335
 336			if ipath == "" {
 337				return // No matching package.
 338			}
 339
 340			r := result{ipath: ipath}
 341			if rename {
 342				r.name = pkgName
 343			}
 344			results <- r
 345			return
 346		}(pkgName, symbols)
 347	}
 348	go func() {
 349		wg.Wait()
 350		close(results)
 351	}()
 352
 353	for result := range results {
 354		if result.name != "" {
 355			astutil.AddNamedImport(fset, f, result.name, result.ipath)
 356		} else {
 357			astutil.AddImport(fset, f, result.ipath)
 358		}
 359		added = append(added, result.ipath)
 360	}
 361
 362	if firstErr != nil {
 363		return nil, firstErr
 364	}
 365	return added, nil
 366}
 367
 368// importPathToName returns the package name for the given import path.
 369var importPathToName func(importPath, srcDir string) (packageName string) = importPathToNameGoPath
 370
 371// importPathToNameBasic assumes the package name is the base of import path,
 372// except that if the path ends in foo/vN, it assumes the package name is foo.
 373func importPathToNameBasic(importPath, srcDir string) (packageName string) {
 374	base := path.Base(importPath)
 375	if strings.HasPrefix(base, "v") {
 376		if _, err := strconv.Atoi(base[1:]); err == nil {
 377			dir := path.Dir(importPath)
 378			if dir != "." {
 379				return path.Base(dir)
 380			}
 381		}
 382	}
 383	return base
 384}
 385
 386// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
 387// If there's a problem, it falls back to using importPathToNameBasic.
 388func importPathToNameGoPath(importPath, srcDir string) (packageName string) {
 389	// Fast path for standard library without going to disk.
 390	if pkg, ok := stdImportPackage[importPath]; ok {
 391		return pkg
 392	}
 393
 394	pkgName, err := importPathToNameGoPathParse(importPath, srcDir)
 395	if Debug {
 396		log.Printf("importPathToNameGoPathParse(%q, srcDir=%q) = %q, %v", importPath, srcDir, pkgName, err)
 397	}
 398	if err == nil {
 399		return pkgName
 400	}
 401	return importPathToNameBasic(importPath, srcDir)
 402}
 403
 404// importPathToNameGoPathParse is a faster version of build.Import if
 405// the only thing desired is the package name. It uses build.FindOnly
 406// to find the directory and then only parses one file in the package,
 407// trusting that the files in the directory are consistent.
 408func importPathToNameGoPathParse(importPath, srcDir string) (packageName string, err error) {
 409	buildPkg, err := build.Import(importPath, srcDir, build.FindOnly)
 410	if err != nil {
 411		return "", err
 412	}
 413	d, err := os.Open(buildPkg.Dir)
 414	if err != nil {
 415		return "", err
 416	}
 417	names, err := d.Readdirnames(-1)
 418	d.Close()
 419	if err != nil {
 420		return "", err
 421	}
 422	sort.Strings(names) // to have predictable behavior
 423	var lastErr error
 424	var nfile int
 425	for _, name := range names {
 426		if !strings.HasSuffix(name, ".go") {
 427			continue
 428		}
 429		if strings.HasSuffix(name, "_test.go") {
 430			continue
 431		}
 432		nfile++
 433		fullFile := filepath.Join(buildPkg.Dir, name)
 434
 435		fset := token.NewFileSet()
 436		f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly)
 437		if err != nil {
 438			lastErr = err
 439			continue
 440		}
 441		pkgName := f.Name.Name
 442		if pkgName == "documentation" {
 443			// Special case from go/build.ImportDir, not
 444			// handled by ctx.MatchFile.
 445			continue
 446		}
 447		if pkgName == "main" {
 448			// Also skip package main, assuming it's a +build ignore generator or example.
 449			// Since you can't import a package main anyway, there's no harm here.
 450			continue
 451		}
 452		return pkgName, nil
 453	}
 454	if lastErr != nil {
 455		return "", lastErr
 456	}
 457	return "", fmt.Errorf("no importable package found in %d Go files", nfile)
 458}
 459
 460var stdImportPackage = map[string]string{} // "net/http" => "http"
 461
 462func init() {
 463	// Nothing in the standard library has a package name not
 464	// matching its import base name.
 465	for _, pkg := range stdlib {
 466		if _, ok := stdImportPackage[pkg]; !ok {
 467			stdImportPackage[pkg] = path.Base(pkg)
 468		}
 469	}
 470}
 471
 472// Directory-scanning state.
 473var (
 474	// scanGoRootOnce guards calling scanGoRoot (for $GOROOT)
 475	scanGoRootOnce sync.Once
 476	// scanGoPathOnce guards calling scanGoPath (for $GOPATH)
 477	scanGoPathOnce sync.Once
 478
 479	// populateIgnoreOnce guards calling populateIgnore
 480	populateIgnoreOnce sync.Once
 481	ignoredDirs        []os.FileInfo
 482
 483	dirScanMu sync.Mutex
 484	dirScan   map[string]*pkg // abs dir path => *pkg
 485)
 486
 487type pkg struct {
 488	dir             string // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
 489	importPath      string // full pkg import path ("net/http", "foo/bar/vendor/a/b")
 490	importPathShort string // vendorless import path ("net/http", "a/b")
 491}
 492
 493type pkgDistance struct {
 494	pkg      *pkg
 495	distance int // relative distance to target
 496}
 497
 498// byDistanceOrImportPathShortLength sorts by relative distance breaking ties
 499// on the short import path length and then the import string itself.
 500type byDistanceOrImportPathShortLength []pkgDistance
 501
 502func (s byDistanceOrImportPathShortLength) Len() int { return len(s) }
 503func (s byDistanceOrImportPathShortLength) Less(i, j int) bool {
 504	di, dj := s[i].distance, s[j].distance
 505	if di == -1 {
 506		return false
 507	}
 508	if dj == -1 {
 509		return true
 510	}
 511	if di != dj {
 512		return di < dj
 513	}
 514
 515	vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort
 516	if len(vi) != len(vj) {
 517		return len(vi) < len(vj)
 518	}
 519	return vi < vj
 520}
 521func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 522
 523func distance(basepath, targetpath string) int {
 524	p, err := filepath.Rel(basepath, targetpath)
 525	if err != nil {
 526		return -1
 527	}
 528	if p == "." {
 529		return 0
 530	}
 531	return strings.Count(p, string(filepath.Separator)) + 1
 532}
 533
 534// guarded by populateIgnoreOnce; populates ignoredDirs.
 535func populateIgnore() {
 536	for _, srcDir := range build.Default.SrcDirs() {
 537		if srcDir == filepath.Join(build.Default.GOROOT, "src") {
 538			continue
 539		}
 540		populateIgnoredDirs(srcDir)
 541	}
 542}
 543
 544// populateIgnoredDirs reads an optional config file at <path>/.goimportsignore
 545// of relative directories to ignore when scanning for go files.
 546// The provided path is one of the $GOPATH entries with "src" appended.
 547func populateIgnoredDirs(path string) {
 548	file := filepath.Join(path, ".goimportsignore")
 549	slurp, err := ioutil.ReadFile(file)
 550	if Debug {
 551		if err != nil {
 552			log.Print(err)
 553		} else {
 554			log.Printf("Read %s", file)
 555		}
 556	}
 557	if err != nil {
 558		return
 559	}
 560	bs := bufio.NewScanner(bytes.NewReader(slurp))
 561	for bs.Scan() {
 562		line := strings.TrimSpace(bs.Text())
 563		if line == "" || strings.HasPrefix(line, "#") {
 564			continue
 565		}
 566		full := filepath.Join(path, line)
 567		if fi, err := os.Stat(full); err == nil {
 568			ignoredDirs = append(ignoredDirs, fi)
 569			if Debug {
 570				log.Printf("Directory added to ignore list: %s", full)
 571			}
 572		} else if Debug {
 573			log.Printf("Error statting entry in .goimportsignore: %v", err)
 574		}
 575	}
 576}
 577
 578func skipDir(fi os.FileInfo) bool {
 579	for _, ignoredDir := range ignoredDirs {
 580		if os.SameFile(fi, ignoredDir) {
 581			return true
 582		}
 583	}
 584	return false
 585}
 586
 587// shouldTraverse reports whether the symlink fi, found in dir,
 588// should be followed.  It makes sure symlinks were never visited
 589// before to avoid symlink loops.
 590func shouldTraverse(dir string, fi os.FileInfo) bool {
 591	path := filepath.Join(dir, fi.Name())
 592	target, err := filepath.EvalSymlinks(path)
 593	if err != nil {
 594		return false
 595	}
 596	ts, err := os.Stat(target)
 597	if err != nil {
 598		fmt.Fprintln(os.Stderr, err)
 599		return false
 600	}
 601	if !ts.IsDir() {
 602		return false
 603	}
 604	if skipDir(ts) {
 605		return false
 606	}
 607	// Check for symlink loops by statting each directory component
 608	// and seeing if any are the same file as ts.
 609	for {
 610		parent := filepath.Dir(path)
 611		if parent == path {
 612			// Made it to the root without seeing a cycle.
 613			// Use this symlink.
 614			return true
 615		}
 616		parentInfo, err := os.Stat(parent)
 617		if err != nil {
 618			return false
 619		}
 620		if os.SameFile(ts, parentInfo) {
 621			// Cycle. Don't traverse.
 622			return false
 623		}
 624		path = parent
 625	}
 626
 627}
 628
 629var testHookScanDir = func(dir string) {}
 630
 631type goDirType string
 632
 633const (
 634	goRoot goDirType = "$GOROOT"
 635	goPath goDirType = "$GOPATH"
 636)
 637
 638var scanGoRootDone = make(chan struct{}) // closed when scanGoRoot is done
 639
 640// scanGoDirs populates the dirScan map for the given directory type. It may be
 641// called concurrently (and usually is, if both directory types are needed).
 642func scanGoDirs(which goDirType) {
 643	if Debug {
 644		log.Printf("scanning %s", which)
 645		defer log.Printf("scanned %s", which)
 646	}
 647
 648	for _, srcDir := range build.Default.SrcDirs() {
 649		isGoroot := srcDir == filepath.Join(build.Default.GOROOT, "src")
 650		if isGoroot != (which == goRoot) {
 651			continue
 652		}
 653		testHookScanDir(srcDir)
 654		srcV := filepath.Join(srcDir, "v")
 655		srcMod := filepath.Join(srcDir, "mod")
 656		walkFn := func(path string, typ os.FileMode) error {
 657			if path == srcV || path == srcMod {
 658				return filepath.SkipDir
 659			}
 660			dir := filepath.Dir(path)
 661			if typ.IsRegular() {
 662				if dir == srcDir {
 663					// Doesn't make sense to have regular files
 664					// directly in your $GOPATH/src or $GOROOT/src.
 665					return nil
 666				}
 667				if !strings.HasSuffix(path, ".go") {
 668					return nil
 669				}
 670
 671				dirScanMu.Lock()
 672				defer dirScanMu.Unlock()
 673				if _, dup := dirScan[dir]; dup {
 674					return nil
 675				}
 676				if dirScan == nil {
 677					dirScan = make(map[string]*pkg)
 678				}
 679				importpath := filepath.ToSlash(dir[len(srcDir)+len("/"):])
 680				dirScan[dir] = &pkg{
 681					importPath:      importpath,
 682					importPathShort: VendorlessPath(importpath),
 683					dir:             dir,
 684				}
 685				return nil
 686			}
 687			if typ == os.ModeDir {
 688				base := filepath.Base(path)
 689				if base == "" || base[0] == '.' || base[0] == '_' ||
 690					base == "testdata" || base == "node_modules" {
 691					return filepath.SkipDir
 692				}
 693				fi, err := os.Lstat(path)
 694				if err == nil && skipDir(fi) {
 695					if Debug {
 696						log.Printf("skipping directory %q under %s", fi.Name(), dir)
 697					}
 698					return filepath.SkipDir
 699				}
 700				return nil
 701			}
 702			if typ == os.ModeSymlink {
 703				base := filepath.Base(path)
 704				if strings.HasPrefix(base, ".#") {
 705					// Emacs noise.
 706					return nil
 707				}
 708				fi, err := os.Lstat(path)
 709				if err != nil {
 710					// Just ignore it.
 711					return nil
 712				}
 713				if shouldTraverse(dir, fi) {
 714					return fastwalk.TraverseLink
 715				}
 716			}
 717			return nil
 718		}
 719		if err := fastwalk.Walk(srcDir, walkFn); err != nil {
 720			log.Printf("goimports: scanning directory %v: %v", srcDir, err)
 721		}
 722	}
 723}
 724
 725// VendorlessPath returns the devendorized version of the import path ipath.
 726// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
 727func VendorlessPath(ipath string) string {
 728	// Devendorize for use in import statement.
 729	if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
 730		return ipath[i+len("/vendor/"):]
 731	}
 732	if strings.HasPrefix(ipath, "vendor/") {
 733		return ipath[len("vendor/"):]
 734	}
 735	return ipath
 736}
 737
 738// loadExports returns the set of exported symbols in the package at dir.
 739// It returns nil on error or if the package name in dir does not match expectPackage.
 740var loadExports func(ctx context.Context, expectPackage, dir string) (map[string]bool, error) = loadExportsGoPath
 741
 742func loadExportsGoPath(ctx context.Context, expectPackage, dir string) (map[string]bool, error) {
 743	if Debug {
 744		log.Printf("loading exports in dir %s (seeking package %s)", dir, expectPackage)
 745	}
 746	exports := make(map[string]bool)
 747
 748	buildCtx := build.Default
 749
 750	// ReadDir is like ioutil.ReadDir, but only returns *.go files
 751	// and filters out _test.go files since they're not relevant
 752	// and only slow things down.
 753	buildCtx.ReadDir = func(dir string) (notTests []os.FileInfo, err error) {
 754		all, err := ioutil.ReadDir(dir)
 755		if err != nil {
 756			return nil, err
 757		}
 758		notTests = all[:0]
 759		for _, fi := range all {
 760			name := fi.Name()
 761			if strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") {
 762				notTests = append(notTests, fi)
 763			}
 764		}
 765		return notTests, nil
 766	}
 767
 768	files, err := buildCtx.ReadDir(dir)
 769	if err != nil {
 770		log.Print(err)
 771		return nil, err
 772	}
 773
 774	fset := token.NewFileSet()
 775
 776	for _, fi := range files {
 777		select {
 778		case <-ctx.Done():
 779			return nil, ctx.Err()
 780		default:
 781		}
 782
 783		match, err := buildCtx.MatchFile(dir, fi.Name())
 784		if err != nil || !match {
 785			continue
 786		}
 787		fullFile := filepath.Join(dir, fi.Name())
 788		f, err := parser.ParseFile(fset, fullFile, nil, 0)
 789		if err != nil {
 790			if Debug {
 791				log.Printf("Parsing %s: %v", fullFile, err)
 792			}
 793			return nil, err
 794		}
 795		pkgName := f.Name.Name
 796		if pkgName == "documentation" {
 797			// Special case from go/build.ImportDir, not
 798			// handled by buildCtx.MatchFile.
 799			continue
 800		}
 801		if pkgName != expectPackage {
 802			err := fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName)
 803			if Debug {
 804				log.Print(err)
 805			}
 806			return nil, err
 807		}
 808		for name := range f.Scope.Objects {
 809			if ast.IsExported(name) {
 810				exports[name] = true
 811			}
 812		}
 813	}
 814
 815	if Debug {
 816		exportList := make([]string, 0, len(exports))
 817		for k := range exports {
 818			exportList = append(exportList, k)
 819		}
 820		sort.Strings(exportList)
 821		log.Printf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", "))
 822	}
 823	return exports, nil
 824}
 825
 826// findImport searches for a package with the given symbols.
 827// If no package is found, findImport returns ("", false, nil)
 828//
 829// This is declared as a variable rather than a function so goimports
 830// can be easily extended by adding a file with an init function.
 831//
 832// The rename value tells goimports whether to use the package name as
 833// a local qualifier in an import. For example, if findImports("pkg",
 834// "X") returns ("foo/bar", rename=true), then goimports adds the
 835// import line:
 836// 	import pkg "foo/bar"
 837// to satisfy uses of pkg.X in the file.
 838var findImport func(ctx context.Context, pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) = findImportGoPath
 839
 840// findImportGoPath is the normal implementation of findImport.
 841// (Some companies have their own internally.)
 842func findImportGoPath(ctx context.Context, pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) {
 843	pkgDir, err := filepath.Abs(filename)
 844	if err != nil {
 845		return "", false, err
 846	}
 847	pkgDir = filepath.Dir(pkgDir)
 848
 849	// Fast path for the standard library.
 850	// In the common case we hopefully never have to scan the GOPATH, which can
 851	// be slow with moving disks.
 852	if pkg, ok := findImportStdlib(pkgName, symbols); ok {
 853		return pkg, false, nil
 854	}
 855	if pkgName == "rand" && symbols["Read"] {
 856		// Special-case rand.Read.
 857		//
 858		// If findImportStdlib didn't find it above, don't go
 859		// searching for it, lest it find and pick math/rand
 860		// in GOROOT (new as of Go 1.6)
 861		//
 862		// crypto/rand is the safer choice.
 863		return "", false, nil
 864	}
 865
 866	// TODO(sameer): look at the import lines for other Go files in the
 867	// local directory, since the user is likely to import the same packages
 868	// in the current Go file.  Return rename=true when the other Go files
 869	// use a renamed package that's also used in the current file.
 870
 871	// Read all the $GOPATH/src/.goimportsignore files before scanning directories.
 872	populateIgnoreOnce.Do(populateIgnore)
 873
 874	// Start scanning the $GOROOT asynchronously, then run the
 875	// GOPATH scan synchronously if needed, and then wait for the
 876	// $GOROOT to finish.
 877	//
 878	// TODO(bradfitz): run each $GOPATH entry async. But nobody
 879	// really has more than one anyway, so low priority.
 880	scanGoRootOnce.Do(func() {
 881		go func() {
 882			scanGoDirs(goRoot)
 883			close(scanGoRootDone)
 884		}()
 885	})
 886	if !fileInDir(filename, build.Default.GOROOT) {
 887		scanGoPathOnce.Do(func() { scanGoDirs(goPath) })
 888	}
 889	<-scanGoRootDone
 890
 891	// Find candidate packages, looking only at their directory names first.
 892	var candidates []pkgDistance
 893	for _, pkg := range dirScan {
 894		if pkgIsCandidate(filename, pkgName, pkg) {
 895			candidates = append(candidates, pkgDistance{
 896				pkg:      pkg,
 897				distance: distance(pkgDir, pkg.dir),
 898			})
 899		}
 900	}
 901
 902	// Sort the candidates by their import package length,
 903	// assuming that shorter package names are better than long
 904	// ones.  Note that this sorts by the de-vendored name, so
 905	// there's no "penalty" for vendoring.
 906	sort.Sort(byDistanceOrImportPathShortLength(candidates))
 907	if Debug {
 908		for i, c := range candidates {
 909			log.Printf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
 910		}
 911	}
 912
 913	// Collect exports for packages with matching names.
 914
 915	rescv := make([]chan *pkg, len(candidates))
 916	for i := range candidates {
 917		rescv[i] = make(chan *pkg, 1)
 918	}
 919	const maxConcurrentPackageImport = 4
 920	loadExportsSem := make(chan struct{}, maxConcurrentPackageImport)
 921
 922	ctx, cancel := context.WithCancel(ctx)
 923	var wg sync.WaitGroup
 924	defer func() {
 925		cancel()
 926		wg.Wait()
 927	}()
 928
 929	wg.Add(1)
 930	go func() {
 931		defer wg.Done()
 932		for i, c := range candidates {
 933			select {
 934			case loadExportsSem <- struct{}{}:
 935			case <-ctx.Done():
 936				return
 937			}
 938
 939			wg.Add(1)
 940			go func(c pkgDistance, resc chan<- *pkg) {
 941				defer func() {
 942					<-loadExportsSem
 943					wg.Done()
 944				}()
 945
 946				exports, err := loadExports(ctx, pkgName, c.pkg.dir)
 947				if err != nil {
 948					resc <- nil
 949					return
 950				}
 951
 952				// If it doesn't have the right
 953				// symbols, send nil to mean no match.
 954				for symbol := range symbols {
 955					if !exports[symbol] {
 956						resc <- nil
 957						return
 958					}
 959				}
 960				resc <- c.pkg
 961			}(c, rescv[i])
 962		}
 963	}()
 964
 965	for _, resc := range rescv {
 966		pkg := <-resc
 967		if pkg == nil {
 968			continue
 969		}
 970		// If the package name in the source doesn't match the import path's base,
 971		// return true so the rewriter adds a name (import foo "github.com/bar/go-foo")
 972		needsRename := path.Base(pkg.importPath) != pkgName
 973		return pkg.importPathShort, needsRename, nil
 974	}
 975	return "", false, nil
 976}
 977
 978// pkgIsCandidate reports whether pkg is a candidate for satisfying the
 979// finding which package pkgIdent in the file named by filename is trying
 980// to refer to.
 981//
 982// This check is purely lexical and is meant to be as fast as possible
 983// because it's run over all $GOPATH directories to filter out poor
 984// candidates in order to limit the CPU and I/O later parsing the
 985// exports in candidate packages.
 986//
 987// filename is the file being formatted.
 988// pkgIdent is the package being searched for, like "client" (if
 989// searching for "client.New")
 990func pkgIsCandidate(filename, pkgIdent string, pkg *pkg) bool {
 991	// Check "internal" and "vendor" visibility:
 992	if !canUse(filename, pkg.dir) {
 993		return false
 994	}
 995
 996	// Speed optimization to minimize disk I/O:
 997	// the last two components on disk must contain the
 998	// package name somewhere.
 999	//
1000	// This permits mismatch naming like directory
1001	// "go-foo" being package "foo", or "pkg.v3" being "pkg",
1002	// or directory "google.golang.org/api/cloudbilling/v1"
1003	// being package "cloudbilling", but doesn't
1004	// permit a directory "foo" to be package
1005	// "bar", which is strongly discouraged
1006	// anyway. There's no reason goimports needs
1007	// to be slow just to accommodate that.
1008	lastTwo := lastTwoComponents(pkg.importPathShort)
1009	if strings.Contains(lastTwo, pkgIdent) {
1010		return true
1011	}
1012	if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) {
1013		lastTwo = lowerASCIIAndRemoveHyphen(lastTwo)
1014		if strings.Contains(lastTwo, pkgIdent) {
1015			return true
1016		}
1017	}
1018
1019	return false
1020}
1021
1022func hasHyphenOrUpperASCII(s string) bool {
1023	for i := 0; i < len(s); i++ {
1024		b := s[i]
1025		if b == '-' || ('A' <= b && b <= 'Z') {
1026			return true
1027		}
1028	}
1029	return false
1030}
1031
1032func lowerASCIIAndRemoveHyphen(s string) (ret string) {
1033	buf := make([]byte, 0, len(s))
1034	for i := 0; i < len(s); i++ {
1035		b := s[i]
1036		switch {
1037		case b == '-':
1038			continue
1039		case 'A' <= b && b <= 'Z':
1040			buf = append(buf, b+('a'-'A'))
1041		default:
1042			buf = append(buf, b)
1043		}
1044	}
1045	return string(buf)
1046}
1047
1048// canUse reports whether the package in dir is usable from filename,
1049// respecting the Go "internal" and "vendor" visibility rules.
1050func canUse(filename, dir string) bool {
1051	// Fast path check, before any allocations. If it doesn't contain vendor
1052	// or internal, it's not tricky:
1053	// Note that this can false-negative on directories like "notinternal",
1054	// but we check it correctly below. This is just a fast path.
1055	if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") {
1056		return true
1057	}
1058
1059	dirSlash := filepath.ToSlash(dir)
1060	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") {
1061		return true
1062	}
1063	// Vendor or internal directory only visible from children of parent.
1064	// That means the path from the current directory to the target directory
1065	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
1066	// or bar/vendor or bar/internal.
1067	// After stripping all the leading ../, the only okay place to see vendor or internal
1068	// is at the very beginning of the path.
1069	absfile, err := filepath.Abs(filename)
1070	if err != nil {
1071		return false
1072	}
1073	absdir, err := filepath.Abs(dir)
1074	if err != nil {
1075		return false
1076	}
1077	rel, err := filepath.Rel(absfile, absdir)
1078	if err != nil {
1079		return false
1080	}
1081	relSlash := filepath.ToSlash(rel)
1082	if i := strings.LastIndex(relSlash, "../"); i >= 0 {
1083		relSlash = relSlash[i+len("../"):]
1084	}
1085	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal")
1086}
1087
1088// lastTwoComponents returns at most the last two path components
1089// of v, using either / or \ as the path separator.
1090func lastTwoComponents(v string) string {
1091	nslash := 0
1092	for i := len(v) - 1; i >= 0; i-- {
1093		if v[i] == '/' || v[i] == '\\' {
1094			nslash++
1095			if nslash == 2 {
1096				return v[i:]
1097			}
1098		}
1099	}
1100	return v
1101}
1102
1103type visitFn func(node ast.Node) ast.Visitor
1104
1105func (fn visitFn) Visit(node ast.Node) ast.Visitor {
1106	return fn(node)
1107}
1108
1109func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, ok bool) {
1110	for symbol := range symbols {
1111		key := shortPkg + "." + symbol
1112		path := stdlib[key]
1113		if path == "" {
1114			if key == "rand.Read" {
1115				continue
1116			}
1117			return "", false
1118		}
1119		if importPath != "" && importPath != path {
1120			// Ambiguous. Symbols pointed to different things.
1121			return "", false
1122		}
1123		importPath = path
1124	}
1125	if importPath == "" && shortPkg == "rand" && symbols["Read"] {
1126		return "crypto/rand", true
1127	}
1128	return importPath, importPath != ""
1129}
1130
1131// fileInDir reports whether the provided file path looks like
1132// it's in dir. (without hitting the filesystem)
1133func fileInDir(file, dir string) bool {
1134	rest := strings.TrimPrefix(file, dir)
1135	if len(rest) == len(file) {
1136		// dir is not a prefix of file.
1137		return false
1138	}
1139	// Check for boundary: either nothing (file == dir), or a slash.
1140	return len(rest) == 0 || rest[0] == '/' || rest[0] == '\\'
1141}