accounts/abi/bind: stop using goimports in the binding generator (#17768)
This commit is contained in:
		
							parent
							
								
									5b0c9c8ae5
								
							
						
					
					
						commit
						5ed3960b9b
					
				| @ -23,13 +23,13 @@ package bind | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/format" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
| 	"unicode" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/accounts/abi" | ||||
| 	"golang.org/x/tools/imports" | ||||
| ) | ||||
| 
 | ||||
| // Lang is a target programming language selector to generate bindings for.
 | ||||
| @ -145,9 +145,9 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La | ||||
| 	if err := tmpl.Execute(buffer, data); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	// For Go bindings pass the code through goimports to clean it up and double check
 | ||||
| 	// For Go bindings pass the code through gofmt to clean it up
 | ||||
| 	if lang == LangGo { | ||||
| 		code, err := imports.Process(".", buffer.Bytes(), nil) | ||||
| 		code, err := format.Source(buffer.Bytes()) | ||||
| 		if err != nil { | ||||
| 			return "", fmt.Errorf("%v\n%s", err, buffer) | ||||
| 		} | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -64,6 +64,30 @@ const tmplSourceGo = ` | ||||
| 
 | ||||
| package {{.Package}} | ||||
| 
 | ||||
| import ( | ||||
| 	"math/big" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	ethereum "github.com/ethereum/go-ethereum" | ||||
| 	"github.com/ethereum/go-ethereum/accounts/abi" | ||||
| 	"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/event" | ||||
| ) | ||||
| 
 | ||||
| // Reference imports to suppress errors if they are not otherwise used.
 | ||||
| var ( | ||||
| 	_ = big.NewInt | ||||
| 	_ = strings.NewReader | ||||
| 	_ = ethereum.NotFound | ||||
| 	_ = abi.U256 | ||||
| 	_ = bind.Bind | ||||
| 	_ = common.Big1 | ||||
| 	_ = types.BloomLookup | ||||
| 	_ = event.NewSubscription | ||||
| ) | ||||
| 
 | ||||
| {{range $contract := .Contracts}} | ||||
| 	// {{.Type}}ABI is the input ABI used to generate the binding from.
 | ||||
| 	const {{.Type}}ABI = "{{.InputABI}}" | ||||
|  | ||||
							
								
								
									
										172
									
								
								vendor/golang.org/x/tools/imports/fastwalk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								vendor/golang.org/x/tools/imports/fastwalk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,172 +0,0 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // A faster implementation of filepath.Walk.
 | ||||
| //
 | ||||
| // filepath.Walk's design necessarily calls os.Lstat on each file,
 | ||||
| // even if the caller needs less info. And goimports only need to know
 | ||||
| // the type of each file. The kernel interface provides the type in
 | ||||
| // the Readdir call but the standard library ignored it.
 | ||||
| // fastwalk_unix.go contains a fork of the syscall routines.
 | ||||
| //
 | ||||
| // See golang.org/issue/16399
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| ) | ||||
| 
 | ||||
| // traverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir.
 | ||||
| var traverseLink = errors.New("traverse symlink, assuming target is a directory") | ||||
| 
 | ||||
| // fastWalk walks the file tree rooted at root, calling walkFn for
 | ||||
| // each file or directory in the tree, including root.
 | ||||
| //
 | ||||
| // If fastWalk returns filepath.SkipDir, the directory is skipped.
 | ||||
| //
 | ||||
| // Unlike filepath.Walk:
 | ||||
| //   * file stat calls must be done by the user.
 | ||||
| //     The only provided metadata is the file type, which does not include
 | ||||
| //     any permission bits.
 | ||||
| //   * multiple goroutines stat the filesystem concurrently. The provided
 | ||||
| //     walkFn must be safe for concurrent use.
 | ||||
| //   * fastWalk can follow symlinks if walkFn returns the traverseLink
 | ||||
| //     sentinel error. It is the walkFn's responsibility to prevent
 | ||||
| //     fastWalk from going into symlink cycles.
 | ||||
| func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) error { | ||||
| 	// TODO(bradfitz): make numWorkers configurable? We used a
 | ||||
| 	// minimum of 4 to give the kernel more info about multiple
 | ||||
| 	// things we want, in hopes its I/O scheduling can take
 | ||||
| 	// advantage of that. Hopefully most are in cache. Maybe 4 is
 | ||||
| 	// even too low of a minimum. Profile more.
 | ||||
| 	numWorkers := 4 | ||||
| 	if n := runtime.NumCPU(); n > numWorkers { | ||||
| 		numWorkers = n | ||||
| 	} | ||||
| 	w := &walker{ | ||||
| 		fn:       walkFn, | ||||
| 		enqueuec: make(chan walkItem, numWorkers), // buffered for performance
 | ||||
| 		workc:    make(chan walkItem, numWorkers), // buffered for performance
 | ||||
| 		donec:    make(chan struct{}), | ||||
| 
 | ||||
| 		// buffered for correctness & not leaking goroutines:
 | ||||
| 		resc: make(chan error, numWorkers), | ||||
| 	} | ||||
| 	defer close(w.donec) | ||||
| 	// TODO(bradfitz): start the workers as needed? maybe not worth it.
 | ||||
| 	for i := 0; i < numWorkers; i++ { | ||||
| 		go w.doWork() | ||||
| 	} | ||||
| 	todo := []walkItem{{dir: root}} | ||||
| 	out := 0 | ||||
| 	for { | ||||
| 		workc := w.workc | ||||
| 		var workItem walkItem | ||||
| 		if len(todo) == 0 { | ||||
| 			workc = nil | ||||
| 		} else { | ||||
| 			workItem = todo[len(todo)-1] | ||||
| 		} | ||||
| 		select { | ||||
| 		case workc <- workItem: | ||||
| 			todo = todo[:len(todo)-1] | ||||
| 			out++ | ||||
| 		case it := <-w.enqueuec: | ||||
| 			todo = append(todo, it) | ||||
| 		case err := <-w.resc: | ||||
| 			out-- | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if out == 0 && len(todo) == 0 { | ||||
| 				// It's safe to quit here, as long as the buffered
 | ||||
| 				// enqueue channel isn't also readable, which might
 | ||||
| 				// happen if the worker sends both another unit of
 | ||||
| 				// work and its result before the other select was
 | ||||
| 				// scheduled and both w.resc and w.enqueuec were
 | ||||
| 				// readable.
 | ||||
| 				select { | ||||
| 				case it := <-w.enqueuec: | ||||
| 					todo = append(todo, it) | ||||
| 				default: | ||||
| 					return nil | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // doWork reads directories as instructed (via workc) and runs the
 | ||||
| // user's callback function.
 | ||||
| func (w *walker) doWork() { | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-w.donec: | ||||
| 			return | ||||
| 		case it := <-w.workc: | ||||
| 			w.resc <- w.walk(it.dir, !it.callbackDone) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type walker struct { | ||||
| 	fn func(path string, typ os.FileMode) error | ||||
| 
 | ||||
| 	donec    chan struct{} // closed on fastWalk's return
 | ||||
| 	workc    chan walkItem // to workers
 | ||||
| 	enqueuec chan walkItem // from workers
 | ||||
| 	resc     chan error    // from workers
 | ||||
| } | ||||
| 
 | ||||
| type walkItem struct { | ||||
| 	dir          string | ||||
| 	callbackDone bool // callback already called; don't do it again
 | ||||
| } | ||||
| 
 | ||||
| func (w *walker) enqueue(it walkItem) { | ||||
| 	select { | ||||
| 	case w.enqueuec <- it: | ||||
| 	case <-w.donec: | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { | ||||
| 	joined := dirName + string(os.PathSeparator) + baseName | ||||
| 	if typ == os.ModeDir { | ||||
| 		w.enqueue(walkItem{dir: joined}) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	err := w.fn(joined, typ) | ||||
| 	if typ == os.ModeSymlink { | ||||
| 		if err == traverseLink { | ||||
| 			// Set callbackDone so we don't call it twice for both the
 | ||||
| 			// symlink-as-symlink and the symlink-as-directory later:
 | ||||
| 			w.enqueue(walkItem{dir: joined, callbackDone: true}) | ||||
| 			return nil | ||||
| 		} | ||||
| 		if err == filepath.SkipDir { | ||||
| 			// Permit SkipDir on symlinks too.
 | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| func (w *walker) walk(root string, runUserCallback bool) error { | ||||
| 	if runUserCallback { | ||||
| 		err := w.fn(root, os.ModeDir) | ||||
| 		if err == filepath.SkipDir { | ||||
| 			return nil | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return readDir(root, w.onDirEnt) | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,13 +0,0 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build freebsd openbsd netbsd
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import "syscall" | ||||
| 
 | ||||
| func direntInode(dirent *syscall.Dirent) uint64 { | ||||
| 	return uint64(dirent.Fileno) | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/golang.org/x/tools/imports/fastwalk_dirent_ino.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/golang.org/x/tools/imports/fastwalk_dirent_ino.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,13 +0,0 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build linux,!appengine darwin
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import "syscall" | ||||
| 
 | ||||
| func direntInode(dirent *syscall.Dirent) uint64 { | ||||
| 	return uint64(dirent.Ino) | ||||
| } | ||||
							
								
								
									
										29
									
								
								vendor/golang.org/x/tools/imports/fastwalk_portable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/golang.org/x/tools/imports/fastwalk_portable.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,29 +0,0 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| // readDir calls fn for each directory entry in dirName.
 | ||||
| // It does not descend into directories or follow symlinks.
 | ||||
| // If fn returns a non-nil error, readDir returns with that error
 | ||||
| // immediately.
 | ||||
| func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { | ||||
| 	fis, err := ioutil.ReadDir(dirName) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, fi := range fis { | ||||
| 		if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										122
									
								
								vendor/golang.org/x/tools/imports/fastwalk_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/golang.org/x/tools/imports/fastwalk_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,122 +0,0 @@ | ||||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build linux,!appengine darwin freebsd openbsd netbsd
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| const blockSize = 8 << 10 | ||||
| 
 | ||||
| // unknownFileMode is a sentinel (and bogus) os.FileMode
 | ||||
| // value used to represent a syscall.DT_UNKNOWN Dirent.Type.
 | ||||
| const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | ||||
| 
 | ||||
| func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { | ||||
| 	fd, err := syscall.Open(dirName, 0, 0) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer syscall.Close(fd) | ||||
| 
 | ||||
| 	// The buffer must be at least a block long.
 | ||||
| 	buf := make([]byte, blockSize) // stack-allocated; doesn't escape
 | ||||
| 	bufp := 0                      // starting read position in buf
 | ||||
| 	nbuf := 0                      // end valid data in buf
 | ||||
| 	for { | ||||
| 		if bufp >= nbuf { | ||||
| 			bufp = 0 | ||||
| 			nbuf, err = syscall.ReadDirent(fd, buf) | ||||
| 			if err != nil { | ||||
| 				return os.NewSyscallError("readdirent", err) | ||||
| 			} | ||||
| 			if nbuf <= 0 { | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) | ||||
| 		bufp += consumed | ||||
| 		if name == "" || name == "." || name == ".." { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Fallback for filesystems (like old XFS) that don't
 | ||||
| 		// support Dirent.Type and have DT_UNKNOWN (0) there
 | ||||
| 		// instead.
 | ||||
| 		if typ == unknownFileMode { | ||||
| 			fi, err := os.Lstat(dirName + "/" + name) | ||||
| 			if err != nil { | ||||
| 				// It got deleted in the meantime.
 | ||||
| 				if os.IsNotExist(err) { | ||||
| 					continue | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 			typ = fi.Mode() & os.ModeType | ||||
| 		} | ||||
| 		if err := fn(dirName, name, typ); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { | ||||
| 	// golang.org/issue/15653
 | ||||
| 	dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0])) | ||||
| 	if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { | ||||
| 		panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) | ||||
| 	} | ||||
| 	if len(buf) < int(dirent.Reclen) { | ||||
| 		panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) | ||||
| 	} | ||||
| 	consumed = int(dirent.Reclen) | ||||
| 	if direntInode(dirent) == 0 { // File absent in directory.
 | ||||
| 		return | ||||
| 	} | ||||
| 	switch dirent.Type { | ||||
| 	case syscall.DT_REG: | ||||
| 		typ = 0 | ||||
| 	case syscall.DT_DIR: | ||||
| 		typ = os.ModeDir | ||||
| 	case syscall.DT_LNK: | ||||
| 		typ = os.ModeSymlink | ||||
| 	case syscall.DT_BLK: | ||||
| 		typ = os.ModeDevice | ||||
| 	case syscall.DT_FIFO: | ||||
| 		typ = os.ModeNamedPipe | ||||
| 	case syscall.DT_SOCK: | ||||
| 		typ = os.ModeSocket | ||||
| 	case syscall.DT_UNKNOWN: | ||||
| 		typ = unknownFileMode | ||||
| 	default: | ||||
| 		// Skip weird things.
 | ||||
| 		// It's probably a DT_WHT (http://lwn.net/Articles/325369/)
 | ||||
| 		// or something. Revisit if/when this package is moved outside
 | ||||
| 		// of goimports. goimports only cares about regular files,
 | ||||
| 		// symlinks, and directories.
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) | ||||
| 	nameLen := bytes.IndexByte(nameBuf[:], 0) | ||||
| 	if nameLen < 0 { | ||||
| 		panic("failed to find terminating 0 byte in dirent") | ||||
| 	} | ||||
| 
 | ||||
| 	// Special cases for common things:
 | ||||
| 	if nameLen == 1 && nameBuf[0] == '.' { | ||||
| 		name = "." | ||||
| 	} else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { | ||||
| 		name = ".." | ||||
| 	} else { | ||||
| 		name = string(nameBuf[:nameLen]) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										978
									
								
								vendor/golang.org/x/tools/imports/fix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										978
									
								
								vendor/golang.org/x/tools/imports/fix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,978 +0,0 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/build" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"golang.org/x/tools/go/ast/astutil" | ||||
| ) | ||||
| 
 | ||||
| // Debug controls verbose logging.
 | ||||
| var Debug = false | ||||
| 
 | ||||
| var ( | ||||
| 	inTests = false      // set true by fix_test.go; if false, no need to use testMu
 | ||||
| 	testMu  sync.RWMutex // guards globals reset by tests; used only if inTests
 | ||||
| ) | ||||
| 
 | ||||
| // If set, LocalPrefix instructs Process to sort import paths with the given
 | ||||
| // prefix into another group after 3rd-party packages.
 | ||||
| var LocalPrefix string | ||||
| 
 | ||||
| // importToGroup is a list of functions which map from an import path to
 | ||||
| // a group number.
 | ||||
| var importToGroup = []func(importPath string) (num int, ok bool){ | ||||
| 	func(importPath string) (num int, ok bool) { | ||||
| 		if LocalPrefix != "" && strings.HasPrefix(importPath, LocalPrefix) { | ||||
| 			return 3, true | ||||
| 		} | ||||
| 		return | ||||
| 	}, | ||||
| 	func(importPath string) (num int, ok bool) { | ||||
| 		if strings.HasPrefix(importPath, "appengine") { | ||||
| 			return 2, true | ||||
| 		} | ||||
| 		return | ||||
| 	}, | ||||
| 	func(importPath string) (num int, ok bool) { | ||||
| 		if strings.Contains(importPath, ".") { | ||||
| 			return 1, true | ||||
| 		} | ||||
| 		return | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func importGroup(importPath string) int { | ||||
| 	for _, fn := range importToGroup { | ||||
| 		if n, ok := fn(importPath); ok { | ||||
| 			return n | ||||
| 		} | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // packageInfo is a summary of features found in a package.
 | ||||
| type packageInfo struct { | ||||
| 	Globals map[string]bool // symbol => true
 | ||||
| } | ||||
| 
 | ||||
| // dirPackageInfo gets information from other files in the package.
 | ||||
| func dirPackageInfo(srcDir, filename string) (*packageInfo, error) { | ||||
| 	considerTests := strings.HasSuffix(filename, "_test.go") | ||||
| 
 | ||||
| 	// Handle file from stdin
 | ||||
| 	if _, err := os.Stat(filename); err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return &packageInfo{}, nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	fileBase := filepath.Base(filename) | ||||
| 	packageFileInfos, err := ioutil.ReadDir(srcDir) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	info := &packageInfo{Globals: make(map[string]bool)} | ||||
| 	for _, fi := range packageFileInfos { | ||||
| 		if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") { | ||||
| 			continue | ||||
| 		} | ||||
| 		if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		fileSet := token.NewFileSet() | ||||
| 		root, err := parser.ParseFile(fileSet, filepath.Join(srcDir, fi.Name()), nil, 0) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		for _, decl := range root.Decls { | ||||
| 			genDecl, ok := decl.(*ast.GenDecl) | ||||
| 			if !ok { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			for _, spec := range genDecl.Specs { | ||||
| 				valueSpec, ok := spec.(*ast.ValueSpec) | ||||
| 				if !ok { | ||||
| 					continue | ||||
| 				} | ||||
| 				info.Globals[valueSpec.Names[0].Name] = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return info, nil | ||||
| } | ||||
| 
 | ||||
| func fixImports(fset *token.FileSet, f *ast.File, filename string) (added []string, err error) { | ||||
| 	// refs are a set of possible package references currently unsatisfied by imports.
 | ||||
| 	// first key: either base package (e.g. "fmt") or renamed package
 | ||||
| 	// second key: referenced package symbol (e.g. "Println")
 | ||||
| 	refs := make(map[string]map[string]bool) | ||||
| 
 | ||||
| 	// decls are the current package imports. key is base package or renamed package.
 | ||||
| 	decls := make(map[string]*ast.ImportSpec) | ||||
| 
 | ||||
| 	abs, err := filepath.Abs(filename) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	srcDir := filepath.Dir(abs) | ||||
| 	if Debug { | ||||
| 		log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) | ||||
| 	} | ||||
| 
 | ||||
| 	var packageInfo *packageInfo | ||||
| 	var loadedPackageInfo bool | ||||
| 
 | ||||
| 	// collect potential uses of packages.
 | ||||
| 	var visitor visitFn | ||||
| 	visitor = visitFn(func(node ast.Node) ast.Visitor { | ||||
| 		if node == nil { | ||||
| 			return visitor | ||||
| 		} | ||||
| 		switch v := node.(type) { | ||||
| 		case *ast.ImportSpec: | ||||
| 			if v.Name != nil { | ||||
| 				decls[v.Name.Name] = v | ||||
| 				break | ||||
| 			} | ||||
| 			ipath := strings.Trim(v.Path.Value, `"`) | ||||
| 			if ipath == "C" { | ||||
| 				break | ||||
| 			} | ||||
| 			local := importPathToName(ipath, srcDir) | ||||
| 			decls[local] = v | ||||
| 		case *ast.SelectorExpr: | ||||
| 			xident, ok := v.X.(*ast.Ident) | ||||
| 			if !ok { | ||||
| 				break | ||||
| 			} | ||||
| 			if xident.Obj != nil { | ||||
| 				// if the parser can resolve it, it's not a package ref
 | ||||
| 				break | ||||
| 			} | ||||
| 			pkgName := xident.Name | ||||
| 			if refs[pkgName] == nil { | ||||
| 				refs[pkgName] = make(map[string]bool) | ||||
| 			} | ||||
| 			if !loadedPackageInfo { | ||||
| 				loadedPackageInfo = true | ||||
| 				packageInfo, _ = dirPackageInfo(srcDir, filename) | ||||
| 			} | ||||
| 			if decls[pkgName] == nil && (packageInfo == nil || !packageInfo.Globals[pkgName]) { | ||||
| 				refs[pkgName][v.Sel.Name] = true | ||||
| 			} | ||||
| 		} | ||||
| 		return visitor | ||||
| 	}) | ||||
| 	ast.Walk(visitor, f) | ||||
| 
 | ||||
| 	// Nil out any unused ImportSpecs, to be removed in following passes
 | ||||
| 	unusedImport := map[string]string{} | ||||
| 	for pkg, is := range decls { | ||||
| 		if refs[pkg] == nil && pkg != "_" && pkg != "." { | ||||
| 			name := "" | ||||
| 			if is.Name != nil { | ||||
| 				name = is.Name.Name | ||||
| 			} | ||||
| 			unusedImport[strings.Trim(is.Path.Value, `"`)] = name | ||||
| 		} | ||||
| 	} | ||||
| 	for ipath, name := range unusedImport { | ||||
| 		if ipath == "C" { | ||||
| 			// Don't remove cgo stuff.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		astutil.DeleteNamedImport(fset, f, name, ipath) | ||||
| 	} | ||||
| 
 | ||||
| 	for pkgName, symbols := range refs { | ||||
| 		if len(symbols) == 0 { | ||||
| 			// skip over packages already imported
 | ||||
| 			delete(refs, pkgName) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Search for imports matching potential package references.
 | ||||
| 	searches := 0 | ||||
| 	type result struct { | ||||
| 		ipath string // import path (if err == nil)
 | ||||
| 		name  string // optional name to rename import as
 | ||||
| 		err   error | ||||
| 	} | ||||
| 	results := make(chan result) | ||||
| 	for pkgName, symbols := range refs { | ||||
| 		go func(pkgName string, symbols map[string]bool) { | ||||
| 			ipath, rename, err := findImport(pkgName, symbols, filename) | ||||
| 			r := result{ipath: ipath, err: err} | ||||
| 			if rename { | ||||
| 				r.name = pkgName | ||||
| 			} | ||||
| 			results <- r | ||||
| 		}(pkgName, symbols) | ||||
| 		searches++ | ||||
| 	} | ||||
| 	for i := 0; i < searches; i++ { | ||||
| 		result := <-results | ||||
| 		if result.err != nil { | ||||
| 			return nil, result.err | ||||
| 		} | ||||
| 		if result.ipath != "" { | ||||
| 			if result.name != "" { | ||||
| 				astutil.AddNamedImport(fset, f, result.name, result.ipath) | ||||
| 			} else { | ||||
| 				astutil.AddImport(fset, f, result.ipath) | ||||
| 			} | ||||
| 			added = append(added, result.ipath) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return added, nil | ||||
| } | ||||
| 
 | ||||
| // importPathToName returns the package name for the given import path.
 | ||||
| var importPathToName func(importPath, srcDir string) (packageName string) = importPathToNameGoPath | ||||
| 
 | ||||
| // importPathToNameBasic assumes the package name is the base of import path.
 | ||||
| func importPathToNameBasic(importPath, srcDir string) (packageName string) { | ||||
| 	return path.Base(importPath) | ||||
| } | ||||
| 
 | ||||
| // importPathToNameGoPath finds out the actual package name, as declared in its .go files.
 | ||||
| // If there's a problem, it falls back to using importPathToNameBasic.
 | ||||
| func importPathToNameGoPath(importPath, srcDir string) (packageName string) { | ||||
| 	// Fast path for standard library without going to disk.
 | ||||
| 	if pkg, ok := stdImportPackage[importPath]; ok { | ||||
| 		return pkg | ||||
| 	} | ||||
| 
 | ||||
| 	pkgName, err := importPathToNameGoPathParse(importPath, srcDir) | ||||
| 	if Debug { | ||||
| 		log.Printf("importPathToNameGoPathParse(%q, srcDir=%q) = %q, %v", importPath, srcDir, pkgName, err) | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		return pkgName | ||||
| 	} | ||||
| 	return importPathToNameBasic(importPath, srcDir) | ||||
| } | ||||
| 
 | ||||
| // importPathToNameGoPathParse 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,
 | ||||
| // trusting that the files in the directory are consistent.
 | ||||
| func importPathToNameGoPathParse(importPath, srcDir string) (packageName string, err error) { | ||||
| 	buildPkg, err := build.Import(importPath, srcDir, build.FindOnly) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	d, err := os.Open(buildPkg.Dir) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	names, err := d.Readdirnames(-1) | ||||
| 	d.Close() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	sort.Strings(names) // to have predictable behavior
 | ||||
| 	var lastErr error | ||||
| 	var nfile int | ||||
| 	for _, name := range names { | ||||
| 		if !strings.HasSuffix(name, ".go") { | ||||
| 			continue | ||||
| 		} | ||||
| 		if strings.HasSuffix(name, "_test.go") { | ||||
| 			continue | ||||
| 		} | ||||
| 		nfile++ | ||||
| 		fullFile := filepath.Join(buildPkg.Dir, name) | ||||
| 
 | ||||
| 		fset := token.NewFileSet() | ||||
| 		f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly) | ||||
| 		if err != nil { | ||||
| 			lastErr = err | ||||
| 			continue | ||||
| 		} | ||||
| 		pkgName := f.Name.Name | ||||
| 		if pkgName == "documentation" { | ||||
| 			// Special case from go/build.ImportDir, not
 | ||||
| 			// handled by ctx.MatchFile.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if pkgName == "main" { | ||||
| 			// Also skip package main, assuming it's a +build ignore generator or example.
 | ||||
| 			// Since you can't import a package main anyway, there's no harm here.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		return pkgName, nil | ||||
| 	} | ||||
| 	if lastErr != nil { | ||||
| 		return "", lastErr | ||||
| 	} | ||||
| 	return "", fmt.Errorf("no importable package found in %d Go files", nfile) | ||||
| } | ||||
| 
 | ||||
| var stdImportPackage = map[string]string{} // "net/http" => "http"
 | ||||
| 
 | ||||
| func init() { | ||||
| 	// Nothing in the standard library has a package name not
 | ||||
| 	// matching its import base name.
 | ||||
| 	for _, pkg := range stdlib { | ||||
| 		if _, ok := stdImportPackage[pkg]; !ok { | ||||
| 			stdImportPackage[pkg] = path.Base(pkg) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Directory-scanning state.
 | ||||
| var ( | ||||
| 	// scanGoRootOnce guards calling scanGoRoot (for $GOROOT)
 | ||||
| 	scanGoRootOnce sync.Once | ||||
| 	// scanGoPathOnce guards calling scanGoPath (for $GOPATH)
 | ||||
| 	scanGoPathOnce sync.Once | ||||
| 
 | ||||
| 	// populateIgnoreOnce guards calling populateIgnore
 | ||||
| 	populateIgnoreOnce sync.Once | ||||
| 	ignoredDirs        []os.FileInfo | ||||
| 
 | ||||
| 	dirScanMu sync.RWMutex | ||||
| 	dirScan   map[string]*pkg // abs dir path => *pkg
 | ||||
| ) | ||||
| 
 | ||||
| type pkg struct { | ||||
| 	dir             string // absolute file path to pkg directory ("/usr/lib/go/src/net/http")
 | ||||
| 	importPath      string // full pkg import path ("net/http", "foo/bar/vendor/a/b")
 | ||||
| 	importPathShort string // vendorless import path ("net/http", "a/b")
 | ||||
| } | ||||
| 
 | ||||
| // byImportPathShortLength sorts by the short import path length, breaking ties on the
 | ||||
| // import string itself.
 | ||||
| type byImportPathShortLength []*pkg | ||||
| 
 | ||||
| func (s byImportPathShortLength) Len() int { return len(s) } | ||||
| func (s byImportPathShortLength) Less(i, j int) bool { | ||||
| 	vi, vj := s[i].importPathShort, s[j].importPathShort | ||||
| 	return len(vi) < len(vj) || (len(vi) == len(vj) && vi < vj) | ||||
| 
 | ||||
| } | ||||
| func (s byImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||||
| 
 | ||||
| // gate is a semaphore for limiting concurrency.
 | ||||
| type gate chan struct{} | ||||
| 
 | ||||
| func (g gate) enter() { g <- struct{}{} } | ||||
| func (g gate) leave() { <-g } | ||||
| 
 | ||||
| var visitedSymlinks struct { | ||||
| 	sync.Mutex | ||||
| 	m map[string]struct{} | ||||
| } | ||||
| 
 | ||||
| // guarded by populateIgnoreOnce; populates ignoredDirs.
 | ||||
| func populateIgnore() { | ||||
| 	for _, srcDir := range build.Default.SrcDirs() { | ||||
| 		if srcDir == filepath.Join(build.Default.GOROOT, "src") { | ||||
| 			continue | ||||
| 		} | ||||
| 		populateIgnoredDirs(srcDir) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // populateIgnoredDirs reads an optional config file at <path>/.goimportsignore
 | ||||
| // of relative directories to ignore when scanning for go files.
 | ||||
| // The provided path is one of the $GOPATH entries with "src" appended.
 | ||||
| func populateIgnoredDirs(path string) { | ||||
| 	file := filepath.Join(path, ".goimportsignore") | ||||
| 	slurp, err := ioutil.ReadFile(file) | ||||
| 	if Debug { | ||||
| 		if err != nil { | ||||
| 			log.Print(err) | ||||
| 		} else { | ||||
| 			log.Printf("Read %s", file) | ||||
| 		} | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	bs := bufio.NewScanner(bytes.NewReader(slurp)) | ||||
| 	for bs.Scan() { | ||||
| 		line := strings.TrimSpace(bs.Text()) | ||||
| 		if line == "" || strings.HasPrefix(line, "#") { | ||||
| 			continue | ||||
| 		} | ||||
| 		full := filepath.Join(path, line) | ||||
| 		if fi, err := os.Stat(full); err == nil { | ||||
| 			ignoredDirs = append(ignoredDirs, fi) | ||||
| 			if Debug { | ||||
| 				log.Printf("Directory added to ignore list: %s", full) | ||||
| 			} | ||||
| 		} else if Debug { | ||||
| 			log.Printf("Error statting entry in .goimportsignore: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func skipDir(fi os.FileInfo) bool { | ||||
| 	for _, ignoredDir := range ignoredDirs { | ||||
| 		if os.SameFile(fi, ignoredDir) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // shouldTraverse reports whether the symlink fi should, found in dir,
 | ||||
| // should be followed.  It makes sure symlinks were never visited
 | ||||
| // before to avoid symlink loops.
 | ||||
| func shouldTraverse(dir string, fi os.FileInfo) bool { | ||||
| 	path := filepath.Join(dir, fi.Name()) | ||||
| 	target, err := filepath.EvalSymlinks(path) | ||||
| 	if err != nil { | ||||
| 		if !os.IsNotExist(err) { | ||||
| 			fmt.Fprintln(os.Stderr, err) | ||||
| 		} | ||||
| 		return false | ||||
| 	} | ||||
| 	ts, err := os.Stat(target) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintln(os.Stderr, err) | ||||
| 		return false | ||||
| 	} | ||||
| 	if !ts.IsDir() { | ||||
| 		return false | ||||
| 	} | ||||
| 	if skipDir(ts) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	realParent, err := filepath.EvalSymlinks(dir) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprint(os.Stderr, err) | ||||
| 		return false | ||||
| 	} | ||||
| 	realPath := filepath.Join(realParent, fi.Name()) | ||||
| 	visitedSymlinks.Lock() | ||||
| 	defer visitedSymlinks.Unlock() | ||||
| 	if visitedSymlinks.m == nil { | ||||
| 		visitedSymlinks.m = make(map[string]struct{}) | ||||
| 	} | ||||
| 	if _, ok := visitedSymlinks.m[realPath]; ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	visitedSymlinks.m[realPath] = struct{}{} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| var testHookScanDir = func(dir string) {} | ||||
| 
 | ||||
| var scanGoRootDone = make(chan struct{}) // closed when scanGoRoot is done
 | ||||
| 
 | ||||
| func scanGoRoot() { | ||||
| 	go func() { | ||||
| 		scanGoDirs(true) | ||||
| 		close(scanGoRootDone) | ||||
| 	}() | ||||
| } | ||||
| 
 | ||||
| func scanGoPath() { scanGoDirs(false) } | ||||
| 
 | ||||
| func scanGoDirs(goRoot bool) { | ||||
| 	if Debug { | ||||
| 		which := "$GOROOT" | ||||
| 		if !goRoot { | ||||
| 			which = "$GOPATH" | ||||
| 		} | ||||
| 		log.Printf("scanning " + which) | ||||
| 		defer log.Printf("scanned " + which) | ||||
| 	} | ||||
| 	dirScanMu.Lock() | ||||
| 	if dirScan == nil { | ||||
| 		dirScan = make(map[string]*pkg) | ||||
| 	} | ||||
| 	dirScanMu.Unlock() | ||||
| 
 | ||||
| 	for _, srcDir := range build.Default.SrcDirs() { | ||||
| 		isGoroot := srcDir == filepath.Join(build.Default.GOROOT, "src") | ||||
| 		if isGoroot != goRoot { | ||||
| 			continue | ||||
| 		} | ||||
| 		testHookScanDir(srcDir) | ||||
| 		walkFn := func(path string, typ os.FileMode) error { | ||||
| 			dir := filepath.Dir(path) | ||||
| 			if typ.IsRegular() { | ||||
| 				if dir == srcDir { | ||||
| 					// Doesn't make sense to have regular files
 | ||||
| 					// directly in your $GOPATH/src or $GOROOT/src.
 | ||||
| 					return nil | ||||
| 				} | ||||
| 				if !strings.HasSuffix(path, ".go") { | ||||
| 					return nil | ||||
| 				} | ||||
| 				dirScanMu.Lock() | ||||
| 				if _, dup := dirScan[dir]; !dup { | ||||
| 					importpath := filepath.ToSlash(dir[len(srcDir)+len("/"):]) | ||||
| 					dirScan[dir] = &pkg{ | ||||
| 						importPath:      importpath, | ||||
| 						importPathShort: vendorlessImportPath(importpath), | ||||
| 						dir:             dir, | ||||
| 					} | ||||
| 				} | ||||
| 				dirScanMu.Unlock() | ||||
| 				return nil | ||||
| 			} | ||||
| 			if typ == os.ModeDir { | ||||
| 				base := filepath.Base(path) | ||||
| 				if base == "" || base[0] == '.' || base[0] == '_' || | ||||
| 					base == "testdata" || base == "node_modules" { | ||||
| 					return filepath.SkipDir | ||||
| 				} | ||||
| 				fi, err := os.Lstat(path) | ||||
| 				if err == nil && skipDir(fi) { | ||||
| 					if Debug { | ||||
| 						log.Printf("skipping directory %q under %s", fi.Name(), dir) | ||||
| 					} | ||||
| 					return filepath.SkipDir | ||||
| 				} | ||||
| 				return nil | ||||
| 			} | ||||
| 			if typ == os.ModeSymlink { | ||||
| 				base := filepath.Base(path) | ||||
| 				if strings.HasPrefix(base, ".#") { | ||||
| 					// Emacs noise.
 | ||||
| 					return nil | ||||
| 				} | ||||
| 				fi, err := os.Lstat(path) | ||||
| 				if err != nil { | ||||
| 					// Just ignore it.
 | ||||
| 					return nil | ||||
| 				} | ||||
| 				if shouldTraverse(dir, fi) { | ||||
| 					return traverseLink | ||||
| 				} | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		if err := fastWalk(srcDir, walkFn); err != nil { | ||||
| 			log.Printf("goimports: scanning directory %v: %v", srcDir, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // vendorlessImportPath returns the devendorized version of the provided import path.
 | ||||
| // e.g. "foo/bar/vendor/a/b" => "a/b"
 | ||||
| func vendorlessImportPath(ipath string) string { | ||||
| 	// Devendorize for use in import statement.
 | ||||
| 	if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { | ||||
| 		return ipath[i+len("/vendor/"):] | ||||
| 	} | ||||
| 	if strings.HasPrefix(ipath, "vendor/") { | ||||
| 		return ipath[len("vendor/"):] | ||||
| 	} | ||||
| 	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.
 | ||||
| var loadExports func(expectPackage, dir string) map[string]bool = loadExportsGoPath | ||||
| 
 | ||||
| func loadExportsGoPath(expectPackage, dir string) map[string]bool { | ||||
| 	if Debug { | ||||
| 		log.Printf("loading exports in dir %s (seeking package %s)", dir, expectPackage) | ||||
| 	} | ||||
| 	exports := make(map[string]bool) | ||||
| 
 | ||||
| 	ctx := build.Default | ||||
| 
 | ||||
| 	// ReadDir is like ioutil.ReadDir, but only returns *.go files
 | ||||
| 	// and filters out _test.go files since they're not relevant
 | ||||
| 	// and only slow things down.
 | ||||
| 	ctx.ReadDir = func(dir string) (notTests []os.FileInfo, err error) { | ||||
| 		all, err := ioutil.ReadDir(dir) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		notTests = all[:0] | ||||
| 		for _, fi := range all { | ||||
| 			name := fi.Name() | ||||
| 			if strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") { | ||||
| 				notTests = append(notTests, fi) | ||||
| 			} | ||||
| 		} | ||||
| 		return notTests, nil | ||||
| 	} | ||||
| 
 | ||||
| 	files, err := ctx.ReadDir(dir) | ||||
| 	if err != nil { | ||||
| 		log.Print(err) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	fset := token.NewFileSet() | ||||
| 
 | ||||
| 	for _, fi := range files { | ||||
| 		match, err := ctx.MatchFile(dir, fi.Name()) | ||||
| 		if err != nil || !match { | ||||
| 			continue | ||||
| 		} | ||||
| 		fullFile := filepath.Join(dir, fi.Name()) | ||||
| 		f, err := parser.ParseFile(fset, fullFile, nil, 0) | ||||
| 		if err != nil { | ||||
| 			if Debug { | ||||
| 				log.Printf("Parsing %s: %v", fullFile, err) | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		pkgName := f.Name.Name | ||||
| 		if pkgName == "documentation" { | ||||
| 			// Special case from go/build.ImportDir, not
 | ||||
| 			// handled by ctx.MatchFile.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if pkgName != expectPackage { | ||||
| 			if Debug { | ||||
| 				log.Printf("scan of dir %v is not expected package %v (actually %v)", dir, expectPackage, pkgName) | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		for name := range f.Scope.Objects { | ||||
| 			if ast.IsExported(name) { | ||||
| 				exports[name] = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if Debug { | ||||
| 		exportList := make([]string, 0, len(exports)) | ||||
| 		for k := range exports { | ||||
| 			exportList = append(exportList, k) | ||||
| 		} | ||||
| 		sort.Strings(exportList) | ||||
| 		log.Printf("loaded exports in dir %v (package %v): %v", dir, expectPackage, strings.Join(exportList, ", ")) | ||||
| 	} | ||||
| 	return exports | ||||
| } | ||||
| 
 | ||||
| // findImport searches for a package with the given symbols.
 | ||||
| // If no package is found, findImport returns ("", false, nil)
 | ||||
| //
 | ||||
| // This is declared as a variable rather than a function so goimports
 | ||||
| // can be easily extended by adding a file with an init function.
 | ||||
| //
 | ||||
| // The rename value tells goimports whether to use the package name as
 | ||||
| // a local qualifier in an import. For example, if findImports("pkg",
 | ||||
| // "X") returns ("foo/bar", rename=true), then goimports adds the
 | ||||
| // import line:
 | ||||
| // 	import pkg "foo/bar"
 | ||||
| // to satisfy uses of pkg.X in the file.
 | ||||
| var findImport func(pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) = findImportGoPath | ||||
| 
 | ||||
| // findImportGoPath is the normal implementation of findImport.
 | ||||
| // (Some companies have their own internally.)
 | ||||
| func findImportGoPath(pkgName string, symbols map[string]bool, filename string) (foundPkg string, rename bool, err error) { | ||||
| 	if inTests { | ||||
| 		testMu.RLock() | ||||
| 		defer testMu.RUnlock() | ||||
| 	} | ||||
| 
 | ||||
| 	// Fast path for the standard library.
 | ||||
| 	// In the common case we hopefully never have to scan the GOPATH, which can
 | ||||
| 	// be slow with moving disks.
 | ||||
| 	if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok { | ||||
| 		return pkg, rename, nil | ||||
| 	} | ||||
| 	if pkgName == "rand" && symbols["Read"] { | ||||
| 		// Special-case rand.Read.
 | ||||
| 		//
 | ||||
| 		// If findImportStdlib didn't find it above, don't go
 | ||||
| 		// searching for it, lest it find and pick math/rand
 | ||||
| 		// in GOROOT (new as of Go 1.6)
 | ||||
| 		//
 | ||||
| 		// crypto/rand is the safer choice.
 | ||||
| 		return "", false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(sameer): look at the import lines for other Go files in the
 | ||||
| 	// local directory, since the user is likely to import the same packages
 | ||||
| 	// in the current Go file.  Return rename=true when the other Go files
 | ||||
| 	// use a renamed package that's also used in the current file.
 | ||||
| 
 | ||||
| 	// Read all the $GOPATH/src/.goimportsignore files before scanning directories.
 | ||||
| 	populateIgnoreOnce.Do(populateIgnore) | ||||
| 
 | ||||
| 	// Start scanning the $GOROOT asynchronously, then run the
 | ||||
| 	// GOPATH scan synchronously if needed, and then wait for the
 | ||||
| 	// $GOROOT to finish.
 | ||||
| 	//
 | ||||
| 	// TODO(bradfitz): run each $GOPATH entry async. But nobody
 | ||||
| 	// really has more than one anyway, so low priority.
 | ||||
| 	scanGoRootOnce.Do(scanGoRoot) // async
 | ||||
| 	if !fileInDir(filename, build.Default.GOROOT) { | ||||
| 		scanGoPathOnce.Do(scanGoPath) // blocking
 | ||||
| 	} | ||||
| 	<-scanGoRootDone | ||||
| 
 | ||||
| 	// Find candidate packages, looking only at their directory names first.
 | ||||
| 	var candidates []*pkg | ||||
| 	for _, pkg := range dirScan { | ||||
| 		if pkgIsCandidate(filename, pkgName, pkg) { | ||||
| 			candidates = append(candidates, pkg) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Sort the candidates by their import package length,
 | ||||
| 	// assuming that shorter package names are better than long
 | ||||
| 	// ones.  Note that this sorts by the de-vendored name, so
 | ||||
| 	// there's no "penalty" for vendoring.
 | ||||
| 	sort.Sort(byImportPathShortLength(candidates)) | ||||
| 	if Debug { | ||||
| 		for i, pkg := range candidates { | ||||
| 			log.Printf("%s candidate %d/%d: %v", pkgName, i+1, len(candidates), pkg.importPathShort) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Collect exports for packages with matching names.
 | ||||
| 
 | ||||
| 	done := make(chan struct{}) // closed when we find the answer
 | ||||
| 	defer close(done) | ||||
| 
 | ||||
| 	rescv := make([]chan *pkg, len(candidates)) | ||||
| 	for i := range candidates { | ||||
| 		rescv[i] = make(chan *pkg) | ||||
| 	} | ||||
| 	const maxConcurrentPackageImport = 4 | ||||
| 	loadExportsSem := make(chan struct{}, maxConcurrentPackageImport) | ||||
| 
 | ||||
| 	go func() { | ||||
| 		for i, pkg := range candidates { | ||||
| 			select { | ||||
| 			case loadExportsSem <- struct{}{}: | ||||
| 				select { | ||||
| 				case <-done: | ||||
| 				default: | ||||
| 				} | ||||
| 			case <-done: | ||||
| 				return | ||||
| 			} | ||||
| 			pkg := pkg | ||||
| 			resc := rescv[i] | ||||
| 			go func() { | ||||
| 				if inTests { | ||||
| 					testMu.RLock() | ||||
| 					defer testMu.RUnlock() | ||||
| 				} | ||||
| 				defer func() { <-loadExportsSem }() | ||||
| 				exports := loadExports(pkgName, pkg.dir) | ||||
| 
 | ||||
| 				// If it doesn't have the right
 | ||||
| 				// symbols, send nil to mean no match.
 | ||||
| 				for symbol := range symbols { | ||||
| 					if !exports[symbol] { | ||||
| 						pkg = nil | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
| 				select { | ||||
| 				case resc <- pkg: | ||||
| 				case <-done: | ||||
| 				} | ||||
| 			}() | ||||
| 		} | ||||
| 	}() | ||||
| 	for _, resc := range rescv { | ||||
| 		pkg := <-resc | ||||
| 		if pkg == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		// If the package name in the source doesn't match the import path's base,
 | ||||
| 		// return true so the rewriter adds a name (import foo "github.com/bar/go-foo")
 | ||||
| 		needsRename := path.Base(pkg.importPath) != pkgName | ||||
| 		return pkg.importPathShort, needsRename, nil | ||||
| 	} | ||||
| 	return "", false, nil | ||||
| } | ||||
| 
 | ||||
| // pkgIsCandidate reports whether pkg is a candidate for satisfying the
 | ||||
| // finding which package pkgIdent in the file named by filename is trying
 | ||||
| // to refer to.
 | ||||
| //
 | ||||
| // This check is purely lexical and is meant to be as fast as possible
 | ||||
| // because it's run over all $GOPATH directories to filter out poor
 | ||||
| // candidates in order to limit the CPU and I/O later parsing the
 | ||||
| // exports in candidate packages.
 | ||||
| //
 | ||||
| // filename is the file being formatted.
 | ||||
| // pkgIdent is the package being searched for, like "client" (if
 | ||||
| // searching for "client.New")
 | ||||
| func pkgIsCandidate(filename, pkgIdent string, pkg *pkg) bool { | ||||
| 	// Check "internal" and "vendor" visibility:
 | ||||
| 	if !canUse(filename, pkg.dir) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	// Speed optimization to minimize disk I/O:
 | ||||
| 	// the last two components on disk must contain the
 | ||||
| 	// package name somewhere.
 | ||||
| 	//
 | ||||
| 	// This permits mismatch naming like directory
 | ||||
| 	// "go-foo" being package "foo", or "pkg.v3" being "pkg",
 | ||||
| 	// or directory "google.golang.org/api/cloudbilling/v1"
 | ||||
| 	// being package "cloudbilling", but doesn't
 | ||||
| 	// permit a directory "foo" to be package
 | ||||
| 	// "bar", which is strongly discouraged
 | ||||
| 	// anyway. There's no reason goimports needs
 | ||||
| 	// to be slow just to accomodate that.
 | ||||
| 	lastTwo := lastTwoComponents(pkg.importPathShort) | ||||
| 	if strings.Contains(lastTwo, pkgIdent) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) { | ||||
| 		lastTwo = lowerASCIIAndRemoveHyphen(lastTwo) | ||||
| 		if strings.Contains(lastTwo, pkgIdent) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func hasHyphenOrUpperASCII(s string) bool { | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		b := s[i] | ||||
| 		if b == '-' || ('A' <= b && b <= 'Z') { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func lowerASCIIAndRemoveHyphen(s string) (ret string) { | ||||
| 	buf := make([]byte, 0, len(s)) | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		b := s[i] | ||||
| 		switch { | ||||
| 		case b == '-': | ||||
| 			continue | ||||
| 		case 'A' <= b && b <= 'Z': | ||||
| 			buf = append(buf, b+('a'-'A')) | ||||
| 		default: | ||||
| 			buf = append(buf, b) | ||||
| 		} | ||||
| 	} | ||||
| 	return string(buf) | ||||
| } | ||||
| 
 | ||||
| // canUse reports whether the package in dir is usable from filename,
 | ||||
| // respecting the Go "internal" and "vendor" visibility rules.
 | ||||
| func canUse(filename, dir string) bool { | ||||
| 	// Fast path check, before any allocations. If it doesn't contain vendor
 | ||||
| 	// or internal, it's not tricky:
 | ||||
| 	// Note that this can false-negative on directories like "notinternal",
 | ||||
| 	// but we check it correctly below. This is just a fast path.
 | ||||
| 	if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	dirSlash := filepath.ToSlash(dir) | ||||
| 	if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") { | ||||
| 		return true | ||||
| 	} | ||||
| 	// Vendor or internal directory only visible from children of parent.
 | ||||
| 	// That means the path from the current directory to the target directory
 | ||||
| 	// can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal
 | ||||
| 	// or bar/vendor or bar/internal.
 | ||||
| 	// After stripping all the leading ../, the only okay place to see vendor or internal
 | ||||
| 	// is at the very beginning of the path.
 | ||||
| 	absfile, err := filepath.Abs(filename) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	absdir, err := filepath.Abs(dir) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	rel, err := filepath.Rel(absfile, absdir) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	relSlash := filepath.ToSlash(rel) | ||||
| 	if i := strings.LastIndex(relSlash, "../"); i >= 0 { | ||||
| 		relSlash = relSlash[i+len("../"):] | ||||
| 	} | ||||
| 	return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal") | ||||
| } | ||||
| 
 | ||||
| // lastTwoComponents returns at most the last two path components
 | ||||
| // of v, using either / or \ as the path separator.
 | ||||
| func lastTwoComponents(v string) string { | ||||
| 	nslash := 0 | ||||
| 	for i := len(v) - 1; i >= 0; i-- { | ||||
| 		if v[i] == '/' || v[i] == '\\' { | ||||
| 			nslash++ | ||||
| 			if nslash == 2 { | ||||
| 				return v[i:] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
| 
 | ||||
| type visitFn func(node ast.Node) ast.Visitor | ||||
| 
 | ||||
| func (fn visitFn) Visit(node ast.Node) ast.Visitor { | ||||
| 	return fn(node) | ||||
| } | ||||
| 
 | ||||
| func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) { | ||||
| 	for symbol := range symbols { | ||||
| 		key := shortPkg + "." + symbol | ||||
| 		path := stdlib[key] | ||||
| 		if path == "" { | ||||
| 			if key == "rand.Read" { | ||||
| 				continue | ||||
| 			} | ||||
| 			return "", false, false | ||||
| 		} | ||||
| 		if importPath != "" && importPath != path { | ||||
| 			// Ambiguous. Symbols pointed to different things.
 | ||||
| 			return "", false, false | ||||
| 		} | ||||
| 		importPath = path | ||||
| 	} | ||||
| 	if importPath == "" && shortPkg == "rand" && symbols["Read"] { | ||||
| 		return "crypto/rand", false, true | ||||
| 	} | ||||
| 	return importPath, false, importPath != "" | ||||
| } | ||||
| 
 | ||||
| // fileInDir reports whether the provided file path looks like
 | ||||
| // it's in dir. (without hitting the filesystem)
 | ||||
| func fileInDir(file, dir string) bool { | ||||
| 	rest := strings.TrimPrefix(file, dir) | ||||
| 	if len(rest) == len(file) { | ||||
| 		// dir is not a prefix of file.
 | ||||
| 		return false | ||||
| 	} | ||||
| 	// Check for boundary: either nothing (file == dir), or a slash.
 | ||||
| 	return len(rest) == 0 || rest[0] == '/' || rest[0] == '\\' | ||||
| } | ||||
							
								
								
									
										289
									
								
								vendor/golang.org/x/tools/imports/imports.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										289
									
								
								vendor/golang.org/x/tools/imports/imports.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,289 +0,0 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| //go:generate go run mkstdlib.go
 | ||||
| 
 | ||||
| // Package imports implements a Go pretty-printer (like package "go/format")
 | ||||
| // that also adds or removes import statements as necessary.
 | ||||
| package imports // import "golang.org/x/tools/imports"
 | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/printer" | ||||
| 	"go/token" | ||||
| 	"io" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"golang.org/x/tools/go/ast/astutil" | ||||
| ) | ||||
| 
 | ||||
| // Options specifies options for processing files.
 | ||||
| type Options struct { | ||||
| 	Fragment  bool // Accept fragment of a source file (no package statement)
 | ||||
| 	AllErrors bool // Report all errors (not just the first 10 on different lines)
 | ||||
| 
 | ||||
| 	Comments  bool // Print comments (true if nil *Options provided)
 | ||||
| 	TabIndent bool // Use tabs for indent (true if nil *Options provided)
 | ||||
| 	TabWidth  int  // Tab width (8 if nil *Options provided)
 | ||||
| 
 | ||||
| 	FormatOnly bool // Disable the insertion and deletion of imports
 | ||||
| } | ||||
| 
 | ||||
| // Process formats and adjusts imports for the provided file.
 | ||||
| // If opt is nil the defaults are used.
 | ||||
| //
 | ||||
| // Note that filename's directory influences which imports can be chosen,
 | ||||
| // so it is important that filename be accurate.
 | ||||
| // To process data ``as if'' it were in filename, pass the data as a non-nil src.
 | ||||
| func Process(filename string, src []byte, opt *Options) ([]byte, error) { | ||||
| 	if opt == nil { | ||||
| 		opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} | ||||
| 	} | ||||
| 
 | ||||
| 	fileSet := token.NewFileSet() | ||||
| 	file, adjust, err := parse(fileSet, filename, src, opt) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if !opt.FormatOnly { | ||||
| 		_, err = fixImports(fileSet, file, filename) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sortImports(fileSet, file) | ||||
| 	imps := astutil.Imports(fileSet, file) | ||||
| 
 | ||||
| 	var spacesBefore []string // import paths we need spaces before
 | ||||
| 	for _, impSection := range imps { | ||||
| 		// Within each block of contiguous imports, see if any
 | ||||
| 		// import lines are in different group numbers. If so,
 | ||||
| 		// we'll need to put a space between them so it's
 | ||||
| 		// compatible with gofmt.
 | ||||
| 		lastGroup := -1 | ||||
| 		for _, importSpec := range impSection { | ||||
| 			importPath, _ := strconv.Unquote(importSpec.Path.Value) | ||||
| 			groupNum := importGroup(importPath) | ||||
| 			if groupNum != lastGroup && lastGroup != -1 { | ||||
| 				spacesBefore = append(spacesBefore, importPath) | ||||
| 			} | ||||
| 			lastGroup = groupNum | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	printerMode := printer.UseSpaces | ||||
| 	if opt.TabIndent { | ||||
| 		printerMode |= printer.TabIndent | ||||
| 	} | ||||
| 	printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} | ||||
| 
 | ||||
| 	var buf bytes.Buffer | ||||
| 	err = printConfig.Fprint(&buf, fileSet, file) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	out := buf.Bytes() | ||||
| 	if adjust != nil { | ||||
| 		out = adjust(src, out) | ||||
| 	} | ||||
| 	if len(spacesBefore) > 0 { | ||||
| 		out = addImportSpaces(bytes.NewReader(out), spacesBefore) | ||||
| 	} | ||||
| 
 | ||||
| 	out, err = format.Source(out) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| // parse parses src, which was read from filename,
 | ||||
| // as a Go source file or statement list.
 | ||||
| func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) { | ||||
| 	parserMode := parser.Mode(0) | ||||
| 	if opt.Comments { | ||||
| 		parserMode |= parser.ParseComments | ||||
| 	} | ||||
| 	if opt.AllErrors { | ||||
| 		parserMode |= parser.AllErrors | ||||
| 	} | ||||
| 
 | ||||
| 	// Try as whole source file.
 | ||||
| 	file, err := parser.ParseFile(fset, filename, src, parserMode) | ||||
| 	if err == nil { | ||||
| 		return file, nil, nil | ||||
| 	} | ||||
| 	// If the error is that the source file didn't begin with a
 | ||||
| 	// package line and we accept fragmented input, fall through to
 | ||||
| 	// try as a source fragment.  Stop and return on any other error.
 | ||||
| 	if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// If this is a declaration list, make it a source file
 | ||||
| 	// by inserting a package clause.
 | ||||
| 	// Insert using a ;, not a newline, so that the line numbers
 | ||||
| 	// in psrc match the ones in src.
 | ||||
| 	psrc := append([]byte("package main;"), src...) | ||||
| 	file, err = parser.ParseFile(fset, filename, psrc, parserMode) | ||||
| 	if err == nil { | ||||
| 		// If a main function exists, we will assume this is a main
 | ||||
| 		// package and leave the file.
 | ||||
| 		if containsMainFunc(file) { | ||||
| 			return file, nil, nil | ||||
| 		} | ||||
| 
 | ||||
| 		adjust := func(orig, src []byte) []byte { | ||||
| 			// Remove the package clause.
 | ||||
| 			// Gofmt has turned the ; into a \n.
 | ||||
| 			src = src[len("package main\n"):] | ||||
| 			return matchSpace(orig, src) | ||||
| 		} | ||||
| 		return file, adjust, nil | ||||
| 	} | ||||
| 	// If the error is that the source file didn't begin with a
 | ||||
| 	// declaration, fall through to try as a statement list.
 | ||||
| 	// Stop and return on any other error.
 | ||||
| 	if !strings.Contains(err.Error(), "expected declaration") { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// If this is a statement list, make it a source file
 | ||||
| 	// by inserting a package clause and turning the list
 | ||||
| 	// into a function body.  This handles expressions too.
 | ||||
| 	// Insert using a ;, not a newline, so that the line numbers
 | ||||
| 	// in fsrc match the ones in src.
 | ||||
| 	fsrc := append(append([]byte("package p; func _() {"), src...), '}') | ||||
| 	file, err = parser.ParseFile(fset, filename, fsrc, parserMode) | ||||
| 	if err == nil { | ||||
| 		adjust := func(orig, src []byte) []byte { | ||||
| 			// Remove the wrapping.
 | ||||
| 			// Gofmt has turned the ; into a \n\n.
 | ||||
| 			src = src[len("package p\n\nfunc _() {"):] | ||||
| 			src = src[:len(src)-len("}\n")] | ||||
| 			// Gofmt has also indented the function body one level.
 | ||||
| 			// Remove that indent.
 | ||||
| 			src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) | ||||
| 			return matchSpace(orig, src) | ||||
| 		} | ||||
| 		return file, adjust, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Failed, and out of options.
 | ||||
| 	return nil, nil, err | ||||
| } | ||||
| 
 | ||||
| // containsMainFunc checks if a file contains a function declaration with the
 | ||||
| // function signature 'func main()'
 | ||||
| func containsMainFunc(file *ast.File) bool { | ||||
| 	for _, decl := range file.Decls { | ||||
| 		if f, ok := decl.(*ast.FuncDecl); ok { | ||||
| 			if f.Name.Name != "main" { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			if len(f.Type.Params.List) != 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			if f.Type.Results != nil && len(f.Type.Results.List) != 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func cutSpace(b []byte) (before, middle, after []byte) { | ||||
| 	i := 0 | ||||
| 	for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { | ||||
| 		i++ | ||||
| 	} | ||||
| 	j := len(b) | ||||
| 	for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { | ||||
| 		j-- | ||||
| 	} | ||||
| 	if i <= j { | ||||
| 		return b[:i], b[i:j], b[j:] | ||||
| 	} | ||||
| 	return nil, nil, b[j:] | ||||
| } | ||||
| 
 | ||||
| // matchSpace reformats src to use the same space context as orig.
 | ||||
| // 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
 | ||||
| // 2) matchSpace copies the indentation of the first non-blank line in orig
 | ||||
| //    to every non-blank line in src.
 | ||||
| // 3) matchSpace copies the trailing space from orig and uses it in place
 | ||||
| //   of src's trailing space.
 | ||||
| func matchSpace(orig []byte, src []byte) []byte { | ||||
| 	before, _, after := cutSpace(orig) | ||||
| 	i := bytes.LastIndex(before, []byte{'\n'}) | ||||
| 	before, indent := before[:i+1], before[i+1:] | ||||
| 
 | ||||
| 	_, src, _ = cutSpace(src) | ||||
| 
 | ||||
| 	var b bytes.Buffer | ||||
| 	b.Write(before) | ||||
| 	for len(src) > 0 { | ||||
| 		line := src | ||||
| 		if i := bytes.IndexByte(line, '\n'); i >= 0 { | ||||
| 			line, src = line[:i+1], line[i+1:] | ||||
| 		} else { | ||||
| 			src = nil | ||||
| 		} | ||||
| 		if len(line) > 0 && line[0] != '\n' { // not blank
 | ||||
| 			b.Write(indent) | ||||
| 		} | ||||
| 		b.Write(line) | ||||
| 	} | ||||
| 	b.Write(after) | ||||
| 	return b.Bytes() | ||||
| } | ||||
| 
 | ||||
| var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`) | ||||
| 
 | ||||
| func addImportSpaces(r io.Reader, breaks []string) []byte { | ||||
| 	var out bytes.Buffer | ||||
| 	sc := bufio.NewScanner(r) | ||||
| 	inImports := false | ||||
| 	done := false | ||||
| 	for sc.Scan() { | ||||
| 		s := sc.Text() | ||||
| 
 | ||||
| 		if !inImports && !done && strings.HasPrefix(s, "import") { | ||||
| 			inImports = true | ||||
| 		} | ||||
| 		if inImports && (strings.HasPrefix(s, "var") || | ||||
| 			strings.HasPrefix(s, "func") || | ||||
| 			strings.HasPrefix(s, "const") || | ||||
| 			strings.HasPrefix(s, "type")) { | ||||
| 			done = true | ||||
| 			inImports = false | ||||
| 		} | ||||
| 		if inImports && len(breaks) > 0 { | ||||
| 			if m := impLine.FindStringSubmatch(s); m != nil { | ||||
| 				if m[1] == breaks[0] { | ||||
| 					out.WriteByte('\n') | ||||
| 					breaks = breaks[1:] | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		fmt.Fprintln(&out, s) | ||||
| 	} | ||||
| 	return out.Bytes() | ||||
| } | ||||
							
								
								
									
										173
									
								
								vendor/golang.org/x/tools/imports/mkindex.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										173
									
								
								vendor/golang.org/x/tools/imports/mkindex.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,173 +0,0 @@ | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // Copyright 2013 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // Command mkindex creates the file "pkgindex.go" containing an index of the Go
 | ||||
| // standard library. The file is intended to be built as part of the imports
 | ||||
| // package, so that the package may be used in environments where a GOROOT is
 | ||||
| // not available (such as App Engine).
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/build" | ||||
| 	"go/format" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	pkgIndex = make(map[string][]pkg) | ||||
| 	exports  = make(map[string]map[string]bool) | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	// Don't use GOPATH.
 | ||||
| 	ctx := build.Default | ||||
| 	ctx.GOPATH = "" | ||||
| 
 | ||||
| 	// Populate pkgIndex global from GOROOT.
 | ||||
| 	for _, path := range ctx.SrcDirs() { | ||||
| 		f, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			log.Print(err) | ||||
| 			continue | ||||
| 		} | ||||
| 		children, err := f.Readdir(-1) | ||||
| 		f.Close() | ||||
| 		if err != nil { | ||||
| 			log.Print(err) | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, child := range children { | ||||
| 			if child.IsDir() { | ||||
| 				loadPkg(path, child.Name()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// Populate exports global.
 | ||||
| 	for _, ps := range pkgIndex { | ||||
| 		for _, p := range ps { | ||||
| 			e := loadExports(p.dir) | ||||
| 			if e != nil { | ||||
| 				exports[p.dir] = e | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Construct source file.
 | ||||
| 	var buf bytes.Buffer | ||||
| 	fmt.Fprint(&buf, pkgIndexHead) | ||||
| 	fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex) | ||||
| 	fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports) | ||||
| 	src := buf.Bytes() | ||||
| 
 | ||||
| 	// Replace main.pkg type name with pkg.
 | ||||
| 	src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1) | ||||
| 	// Replace actual GOROOT with "/go".
 | ||||
| 	src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1) | ||||
| 	// Add some line wrapping.
 | ||||
| 	src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1) | ||||
| 	src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1) | ||||
| 
 | ||||
| 	var err error | ||||
| 	src, err = format.Source(src) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Write out source file.
 | ||||
| 	err = ioutil.WriteFile("pkgindex.go", src, 0644) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const pkgIndexHead = `package imports | ||||
| 
 | ||||
| func init() { | ||||
| 	pkgIndexOnce.Do(func() { | ||||
| 		pkgIndex.m = pkgIndexMaster | ||||
| 	}) | ||||
| 	loadExports = func(dir string) map[string]bool { | ||||
| 		return exportsMaster[dir] | ||||
| 	} | ||||
| } | ||||
| ` | ||||
| 
 | ||||
| type pkg struct { | ||||
| 	importpath string // full pkg import path, e.g. "net/http"
 | ||||
| 	dir        string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
 | ||||
| } | ||||
| 
 | ||||
| var fset = token.NewFileSet() | ||||
| 
 | ||||
| func loadPkg(root, importpath string) { | ||||
| 	shortName := path.Base(importpath) | ||||
| 	if shortName == "testdata" { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	dir := filepath.Join(root, importpath) | ||||
| 	pkgIndex[shortName] = append(pkgIndex[shortName], pkg{ | ||||
| 		importpath: importpath, | ||||
| 		dir:        dir, | ||||
| 	}) | ||||
| 
 | ||||
| 	pkgDir, err := os.Open(dir) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	children, err := pkgDir.Readdir(-1) | ||||
| 	pkgDir.Close() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, child := range children { | ||||
| 		name := child.Name() | ||||
| 		if name == "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		if c := name[0]; c == '.' || ('0' <= c && c <= '9') { | ||||
| 			continue | ||||
| 		} | ||||
| 		if child.IsDir() { | ||||
| 			loadPkg(root, filepath.Join(importpath, name)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func loadExports(dir string) map[string]bool { | ||||
| 	exports := make(map[string]bool) | ||||
| 	buildPkg, err := build.ImportDir(dir, 0) | ||||
| 	if err != nil { | ||||
| 		if strings.Contains(err.Error(), "no buildable Go source files in") { | ||||
| 			return nil | ||||
| 		} | ||||
| 		log.Printf("could not import %q: %v", dir, err) | ||||
| 		return nil | ||||
| 	} | ||||
| 	for _, file := range buildPkg.GoFiles { | ||||
| 		f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0) | ||||
| 		if err != nil { | ||||
| 			log.Printf("could not parse %q: %v", file, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		for name := range f.Scope.Objects { | ||||
| 			if ast.IsExported(name) { | ||||
| 				exports[name] = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return exports | ||||
| } | ||||
							
								
								
									
										103
									
								
								vendor/golang.org/x/tools/imports/mkstdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										103
									
								
								vendor/golang.org/x/tools/imports/mkstdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,103 +0,0 @@ | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // mkstdlib generates the zstdlib.go file, containing the Go standard
 | ||||
| // library API symbols. It's baked into the binary to avoid scanning
 | ||||
| // GOPATH in the common case.
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/format" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| func mustOpen(name string) io.Reader { | ||||
| 	f, err := os.Open(name) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	return f | ||||
| } | ||||
| 
 | ||||
| func api(base string) string { | ||||
| 	return filepath.Join(os.Getenv("GOROOT"), "api", base) | ||||
| } | ||||
| 
 | ||||
| var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`) | ||||
| 
 | ||||
| func main() { | ||||
| 	var buf bytes.Buffer | ||||
| 	outf := func(format string, args ...interface{}) { | ||||
| 		fmt.Fprintf(&buf, format, args...) | ||||
| 	} | ||||
| 	outf("// AUTO-GENERATED BY mkstdlib.go\n\n") | ||||
| 	outf("package imports\n") | ||||
| 	outf("var stdlib = map[string]string{\n") | ||||
| 	f := io.MultiReader( | ||||
| 		mustOpen(api("go1.txt")), | ||||
| 		mustOpen(api("go1.1.txt")), | ||||
| 		mustOpen(api("go1.2.txt")), | ||||
| 		mustOpen(api("go1.3.txt")), | ||||
| 		mustOpen(api("go1.4.txt")), | ||||
| 		mustOpen(api("go1.5.txt")), | ||||
| 		mustOpen(api("go1.6.txt")), | ||||
| 		mustOpen(api("go1.7.txt")), | ||||
| 	) | ||||
| 	sc := bufio.NewScanner(f) | ||||
| 	fullImport := map[string]string{} // "zip.NewReader" => "archive/zip"
 | ||||
| 	ambiguous := map[string]bool{} | ||||
| 	var keys []string | ||||
| 	for sc.Scan() { | ||||
| 		l := sc.Text() | ||||
| 		has := func(v string) bool { return strings.Contains(l, v) } | ||||
| 		if has("struct, ") || has("interface, ") || has(", method (") { | ||||
| 			continue | ||||
| 		} | ||||
| 		if m := sym.FindStringSubmatch(l); m != nil { | ||||
| 			full := m[1] | ||||
| 			key := path.Base(full) + "." + m[2] | ||||
| 			if exist, ok := fullImport[key]; ok { | ||||
| 				if exist != full { | ||||
| 					ambiguous[key] = true | ||||
| 				} | ||||
| 			} else { | ||||
| 				fullImport[key] = full | ||||
| 				keys = append(keys, key) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if err := sc.Err(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 	for _, key := range keys { | ||||
| 		if ambiguous[key] { | ||||
| 			outf("\t// %q is ambiguous\n", key) | ||||
| 		} else { | ||||
| 			outf("\t%q: %q,\n", key, fullImport[key]) | ||||
| 		} | ||||
| 	} | ||||
| 	outf("\n") | ||||
| 	for _, sym := range [...]string{"Alignof", "ArbitraryType", "Offsetof", "Pointer", "Sizeof"} { | ||||
| 		outf("\t%q: %q,\n", "unsafe."+sym, "unsafe") | ||||
| 	} | ||||
| 	outf("}\n") | ||||
| 	fmtbuf, err := format.Source(buf.Bytes()) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	err = ioutil.WriteFile("zstdlib.go", fmtbuf, 0666) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										212
									
								
								vendor/golang.org/x/tools/imports/sortimports.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										212
									
								
								vendor/golang.org/x/tools/imports/sortimports.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,212 +0,0 @@ | ||||
| // Copyright 2013 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // Hacked up copy of go/ast/import.go
 | ||||
| 
 | ||||
| package imports | ||||
| 
 | ||||
| import ( | ||||
| 	"go/ast" | ||||
| 	"go/token" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // sortImports sorts runs of consecutive import lines in import blocks in f.
 | ||||
| // It also removes duplicate imports when it is possible to do so without data loss.
 | ||||
| func sortImports(fset *token.FileSet, f *ast.File) { | ||||
| 	for i, d := range f.Decls { | ||||
| 		d, ok := d.(*ast.GenDecl) | ||||
| 		if !ok || d.Tok != token.IMPORT { | ||||
| 			// Not an import declaration, so we're done.
 | ||||
| 			// Imports are always first.
 | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		if len(d.Specs) == 0 { | ||||
| 			// Empty import block, remove it.
 | ||||
| 			f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) | ||||
| 		} | ||||
| 
 | ||||
| 		if !d.Lparen.IsValid() { | ||||
| 			// Not a block: sorted by default.
 | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		// Identify and sort runs of specs on successive lines.
 | ||||
| 		i := 0 | ||||
| 		specs := d.Specs[:0] | ||||
| 		for j, s := range d.Specs { | ||||
| 			if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { | ||||
| 				// j begins a new run.  End this one.
 | ||||
| 				specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...) | ||||
| 				i = j | ||||
| 			} | ||||
| 		} | ||||
| 		specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...) | ||||
| 		d.Specs = specs | ||||
| 
 | ||||
| 		// Deduping can leave a blank line before the rparen; clean that up.
 | ||||
| 		if len(d.Specs) > 0 { | ||||
| 			lastSpec := d.Specs[len(d.Specs)-1] | ||||
| 			lastLine := fset.Position(lastSpec.Pos()).Line | ||||
| 			if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 { | ||||
| 				fset.File(d.Rparen).MergeLine(rParenLine - 1) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func importPath(s ast.Spec) string { | ||||
| 	t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) | ||||
| 	if err == nil { | ||||
| 		return t | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func importName(s ast.Spec) string { | ||||
| 	n := s.(*ast.ImportSpec).Name | ||||
| 	if n == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return n.Name | ||||
| } | ||||
| 
 | ||||
| func importComment(s ast.Spec) string { | ||||
| 	c := s.(*ast.ImportSpec).Comment | ||||
| 	if c == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return c.Text() | ||||
| } | ||||
| 
 | ||||
| // collapse indicates whether prev may be removed, leaving only next.
 | ||||
| func collapse(prev, next ast.Spec) bool { | ||||
| 	if importPath(next) != importPath(prev) || importName(next) != importName(prev) { | ||||
| 		return false | ||||
| 	} | ||||
| 	return prev.(*ast.ImportSpec).Comment == nil | ||||
| } | ||||
| 
 | ||||
| type posSpan struct { | ||||
| 	Start token.Pos | ||||
| 	End   token.Pos | ||||
| } | ||||
| 
 | ||||
| func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { | ||||
| 	// Can't short-circuit here even if specs are already sorted,
 | ||||
| 	// since they might yet need deduplication.
 | ||||
| 	// A lone import, however, may be safely ignored.
 | ||||
| 	if len(specs) <= 1 { | ||||
| 		return specs | ||||
| 	} | ||||
| 
 | ||||
| 	// Record positions for specs.
 | ||||
| 	pos := make([]posSpan, len(specs)) | ||||
| 	for i, s := range specs { | ||||
| 		pos[i] = posSpan{s.Pos(), s.End()} | ||||
| 	} | ||||
| 
 | ||||
| 	// Identify comments in this range.
 | ||||
| 	// Any comment from pos[0].Start to the final line counts.
 | ||||
| 	lastLine := fset.Position(pos[len(pos)-1].End).Line | ||||
| 	cstart := len(f.Comments) | ||||
| 	cend := len(f.Comments) | ||||
| 	for i, g := range f.Comments { | ||||
| 		if g.Pos() < pos[0].Start { | ||||
| 			continue | ||||
| 		} | ||||
| 		if i < cstart { | ||||
| 			cstart = i | ||||
| 		} | ||||
| 		if fset.Position(g.End()).Line > lastLine { | ||||
| 			cend = i | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	comments := f.Comments[cstart:cend] | ||||
| 
 | ||||
| 	// Assign each comment to the import spec preceding it.
 | ||||
| 	importComment := map[*ast.ImportSpec][]*ast.CommentGroup{} | ||||
| 	specIndex := 0 | ||||
| 	for _, g := range comments { | ||||
| 		for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { | ||||
| 			specIndex++ | ||||
| 		} | ||||
| 		s := specs[specIndex].(*ast.ImportSpec) | ||||
| 		importComment[s] = append(importComment[s], g) | ||||
| 	} | ||||
| 
 | ||||
| 	// Sort the import specs by import path.
 | ||||
| 	// Remove duplicates, when possible without data loss.
 | ||||
| 	// Reassign the import paths to have the same position sequence.
 | ||||
| 	// Reassign each comment to abut the end of its spec.
 | ||||
| 	// Sort the comments by new position.
 | ||||
| 	sort.Sort(byImportSpec(specs)) | ||||
| 
 | ||||
| 	// Dedup. Thanks to our sorting, we can just consider
 | ||||
| 	// adjacent pairs of imports.
 | ||||
| 	deduped := specs[:0] | ||||
| 	for i, s := range specs { | ||||
| 		if i == len(specs)-1 || !collapse(s, specs[i+1]) { | ||||
| 			deduped = append(deduped, s) | ||||
| 		} else { | ||||
| 			p := s.Pos() | ||||
| 			fset.File(p).MergeLine(fset.Position(p).Line) | ||||
| 		} | ||||
| 	} | ||||
| 	specs = deduped | ||||
| 
 | ||||
| 	// Fix up comment positions
 | ||||
| 	for i, s := range specs { | ||||
| 		s := s.(*ast.ImportSpec) | ||||
| 		if s.Name != nil { | ||||
| 			s.Name.NamePos = pos[i].Start | ||||
| 		} | ||||
| 		s.Path.ValuePos = pos[i].Start | ||||
| 		s.EndPos = pos[i].End | ||||
| 		for _, g := range importComment[s] { | ||||
| 			for _, c := range g.List { | ||||
| 				c.Slash = pos[i].End | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sort.Sort(byCommentPos(comments)) | ||||
| 
 | ||||
| 	return specs | ||||
| } | ||||
| 
 | ||||
| type byImportSpec []ast.Spec // slice of *ast.ImportSpec
 | ||||
| 
 | ||||
| func (x byImportSpec) Len() int      { return len(x) } | ||||
| func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | ||||
| func (x byImportSpec) Less(i, j int) bool { | ||||
| 	ipath := importPath(x[i]) | ||||
| 	jpath := importPath(x[j]) | ||||
| 
 | ||||
| 	igroup := importGroup(ipath) | ||||
| 	jgroup := importGroup(jpath) | ||||
| 	if igroup != jgroup { | ||||
| 		return igroup < jgroup | ||||
| 	} | ||||
| 
 | ||||
| 	if ipath != jpath { | ||||
| 		return ipath < jpath | ||||
| 	} | ||||
| 	iname := importName(x[i]) | ||||
| 	jname := importName(x[j]) | ||||
| 
 | ||||
| 	if iname != jname { | ||||
| 		return iname < jname | ||||
| 	} | ||||
| 	return importComment(x[i]) < importComment(x[j]) | ||||
| } | ||||
| 
 | ||||
| type byCommentPos []*ast.CommentGroup | ||||
| 
 | ||||
| func (x byCommentPos) Len() int           { return len(x) } | ||||
| func (x byCommentPos) Swap(i, j int)      { x[i], x[j] = x[j], x[i] } | ||||
| func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } | ||||
							
								
								
									
										9289
									
								
								vendor/golang.org/x/tools/imports/zstdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9289
									
								
								vendor/golang.org/x/tools/imports/zstdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							| @ -880,12 +880,6 @@ | ||||
| 			"revision": "be0fcc31ae2332374e800dfff29b721c585b35df", | ||||
| 			"revisionTime": "2016-11-04T18:56:24Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "2ko3hvt1vrfwG+p7SLW+zqDEeV4=", | ||||
| 			"path": "golang.org/x/tools/imports", | ||||
| 			"revision": "be0fcc31ae2332374e800dfff29b721c585b35df", | ||||
| 			"revisionTime": "2016-11-04T18:56:24Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "CEFTYXtWmgSh+3Ik1NmDaJcz4E0=", | ||||
| 			"path": "gopkg.in/check.v1", | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user