Update go dependencies (#4322)

This commit is contained in:
Manuel Alejandro de Brito Fontes 2019-07-17 09:21:14 -04:00 committed by GitHub
parent 28cc3bb5e2
commit a54ab3341e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
507 changed files with 50566 additions and 40414 deletions

View file

@ -18,7 +18,7 @@ import (
// Driver
type driverRequest struct {
Command string `json "command"`
Command string `json:"command"`
Mode LoadMode `json:"mode"`
Env []string `json:"env"`
BuildFlags []string `json:"build_flags"`

View file

@ -78,7 +78,7 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
var sizes types.Sizes
var sizeserr error
var sizeswg sync.WaitGroup
if cfg.Mode&NeedTypesSizes != 0 {
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
sizeswg.Add(1)
go func() {
sizes, sizeserr = getSizes(cfg)
@ -128,7 +128,7 @@ extractQueries:
// patterns also requires a go list call, since it's the equivalent of
// ".".
if len(restPatterns) > 0 || len(patterns) == 0 {
dr, err := golistDriverCurrent(cfg, restPatterns...)
dr, err := golistDriver(cfg, restPatterns...)
if err != nil {
return nil, err
}
@ -147,13 +147,13 @@ extractQueries:
var containsCandidates []string
if len(containFiles) != 0 {
if err := runContainsQueries(cfg, golistDriverCurrent, response, containFiles); err != nil {
if err := runContainsQueries(cfg, golistDriver, response, containFiles); err != nil {
return nil, err
}
}
if len(packagesNamed) != 0 {
if err := runNamedQueries(cfg, golistDriverCurrent, response, packagesNamed); err != nil {
if err := runNamedQueries(cfg, golistDriver, response, packagesNamed); err != nil {
return nil, err
}
}
@ -166,17 +166,25 @@ extractQueries:
containsCandidates = append(containsCandidates, modifiedPkgs...)
containsCandidates = append(containsCandidates, needPkgs...)
}
if len(needPkgs) > 0 {
addNeededOverlayPackages(cfg, golistDriverCurrent, response, needPkgs)
if err != nil {
return nil, err
}
if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs); err != nil {
return nil, err
}
// Check candidate packages for containFiles.
if len(containFiles) > 0 {
for _, id := range containsCandidates {
pkg := response.seenPackages[id]
pkg, ok := response.seenPackages[id]
if !ok {
response.addPackage(&Package{
ID: id,
Errors: []Error{
{
Kind: ListError,
Msg: fmt.Sprintf("package %s expected but not seen", id),
},
},
})
continue
}
for _, f := range containFiles {
for _, g := range pkg.GoFiles {
if sameFile(f, g) {
@ -191,6 +199,9 @@ extractQueries:
}
func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDeduper, pkgs []string) error {
if len(pkgs) == 0 {
return nil
}
dr, err := driver(cfg, pkgs...)
if err != nil {
return err
@ -198,6 +209,11 @@ func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDedu
for _, pkg := range dr.Packages {
response.addPackage(pkg)
}
_, needPkgs, err := processGolistOverlay(cfg, response.dr)
if err != nil {
return err
}
addNeededOverlayPackages(cfg, driver, response, needPkgs)
return nil
}
@ -540,10 +556,10 @@ func otherFiles(p *jsonPackage) [][]string {
return [][]string{p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.SwigFiles, p.SwigCXXFiles, p.SysoFiles}
}
// golistDriverCurrent uses the "go list" command to expand the
// pattern words and return metadata for the specified packages.
// dir may be "" and env may be nil, as per os/exec.Command.
func golistDriverCurrent(cfg *Config, words ...string) (*driverResponse, error) {
// golistDriver uses the "go list" command to expand the pattern
// words and return metadata for the specified packages. dir may be
// "" and env may be nil, as per os/exec.Command.
func golistDriver(cfg *Config, words ...string) (*driverResponse, error) {
// go list uses the following identifiers in ImportPath and Imports:
//
// "p" -- importable package or main (command)
@ -761,8 +777,31 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) {
// the error in the Err section of stdout in case -e option is provided.
// This fix is provided for backwards compatibility.
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must be .go files") {
output := fmt.Sprintf(`{"ImportPath": "","Incomplete": true,"Error": {"Pos": "","Err": %s}}`,
strconv.Quote(strings.Trim(stderr.String(), "\n")))
output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
strings.Trim(stderr.String(), "\n"))
return bytes.NewBufferString(output), nil
}
// Workaround for #29280: go list -e has incorrect behavior when an ad-hoc package doesn't exist.
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no such file or directory") {
output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
strings.Trim(stderr.String(), "\n"))
return bytes.NewBufferString(output), nil
}
// Workaround for an instance of golang.org/issue/26755: go list -e will return a non-zero exit
// status if there's a dependency on a package that doesn't exist. But it should return
// a zero exit status and set an error on that package.
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") {
// try to extract package name from string
stderrStr := stderr.String()
var importPath string
colon := strings.Index(stderrStr, ":")
if colon > 0 && strings.HasPrefix(stderrStr, "go build ") {
importPath = stderrStr[len("go build "):colon]
}
output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
importPath, strings.Trim(stderrStr, "\n"))
return bytes.NewBufferString(output), nil
}

View file

@ -1,11 +1,15 @@
package packages
import (
"bytes"
"encoding/json"
"go/parser"
"go/token"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
)
// processGolistOverlay provides rudimentary support for adding
@ -27,50 +31,123 @@ func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs,
havePkgs[pkg.PkgPath] = pkg.ID
}
outer:
for path, contents := range cfg.Overlay {
base := filepath.Base(path)
if strings.HasSuffix(path, "_test.go") {
var rootDirs map[string]string
var onceGetRootDirs sync.Once
for opath, contents := range cfg.Overlay {
base := filepath.Base(opath)
if strings.HasSuffix(opath, "_test.go") {
// Overlays don't support adding new test files yet.
// TODO(matloob): support adding new test files.
continue
}
dir := filepath.Dir(path)
for _, pkg := range response.Packages {
var dirContains, fileExists bool
for _, f := range pkg.GoFiles {
if sameFile(filepath.Dir(f), dir) {
dirContains = true
dir := filepath.Dir(opath)
var pkg *Package
var fileExists bool
for _, p := range response.Packages {
for _, f := range p.GoFiles {
if !sameFile(filepath.Dir(f), dir) {
continue
}
pkg = p
if filepath.Base(f) == base {
fileExists = true
}
}
if dirContains {
if !fileExists {
pkg.GoFiles = append(pkg.GoFiles, path) // TODO(matloob): should the file just be added to GoFiles?
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, path)
modifiedPkgsSet[pkg.ID] = true
}
imports, err := extractImports(path, contents)
}
// The overlay could have included an entirely new package.
if pkg == nil {
onceGetRootDirs.Do(func() {
rootDirs = determineRootDirs(cfg)
})
// Try to find the module or gopath dir the file is contained in.
// Then for modules, add the module opath to the beginning.
var pkgPath string
for rdir, rpath := range rootDirs {
// TODO(matloob): This doesn't properly handle symlinks.
r, err := filepath.Rel(rdir, dir)
if err != nil {
// Let the parser or type checker report errors later.
continue outer
continue
}
for _, imp := range imports {
_, found := pkg.Imports[imp]
if !found {
needPkgsSet[imp] = true
// TODO(matloob): Handle cases when the following block isn't correct.
// These include imports of test variants, imports of vendored packages, etc.
id, ok := havePkgs[imp]
if !ok {
id = imp
}
pkg.Imports[imp] = &Package{ID: id}
}
pkgPath = filepath.ToSlash(r)
if rpath != "" {
pkgPath = path.Join(rpath, pkgPath)
}
continue outer
// We only create one new package even it can belong in multiple modules or GOPATH entries.
// This is okay because tools (such as the LSP) that use overlays will recompute the overlay
// once the file is saved, and golist will do the right thing.
// TODO(matloob): Implement module tiebreaking?
break
}
if pkgPath == "" {
continue
}
pkgName, ok := extractPackageName(opath, contents)
if !ok {
continue
}
id := pkgPath
// Try to reclaim a package with the same id if it exists in the response.
for _, p := range response.Packages {
if reclaimPackage(p, id, opath, contents) {
pkg = p
break
}
}
// Otherwise, create a new package
if pkg == nil {
pkg = &Package{PkgPath: pkgPath, ID: id, Name: pkgName, Imports: make(map[string]*Package)}
// TODO(matloob): Is it okay to amend response.Packages this way?
response.Packages = append(response.Packages, pkg)
havePkgs[pkg.PkgPath] = id
}
}
if !fileExists {
pkg.GoFiles = append(pkg.GoFiles, opath)
// TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior
// if the file will be ignored due to its build tags.
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath)
modifiedPkgsSet[pkg.ID] = true
}
imports, err := extractImports(opath, contents)
if err != nil {
// Let the parser or type checker report errors later.
continue
}
for _, imp := range imports {
_, found := pkg.Imports[imp]
if !found {
// TODO(matloob): Handle cases when the following block isn't correct.
// These include imports of test variants, imports of vendored packages, etc.
id, ok := havePkgs[imp]
if !ok {
id = imp
}
pkg.Imports[imp] = &Package{ID: id}
}
}
continue
}
// toPkgPath tries to guess the package path given the id.
// This isn't always correct -- it's certainly wrong for
// vendored packages' paths.
toPkgPath := func(id string) string {
// TODO(matloob): Handle vendor paths.
i := strings.IndexByte(id, ' ')
if i >= 0 {
return id[:i]
}
return id
}
// Do another pass now that new packages have been created to determine the
// set of missing packages.
for _, pkg := range response.Packages {
for _, imp := range pkg.Imports {
pkgPath := toPkgPath(imp.ID)
if _, ok := havePkgs[pkgPath]; !ok {
needPkgsSet[pkgPath] = true
}
}
}
@ -86,6 +163,46 @@ outer:
return modifiedPkgs, needPkgs, err
}
// determineRootDirs returns a mapping from directories code can be contained in to the
// corresponding import path prefixes of those directories.
// Its result is used to try to determine the import path for a package containing
// an overlay file.
func determineRootDirs(cfg *Config) map[string]string {
// Assume modules first:
out, err := invokeGo(cfg, "list", "-m", "-json", "all")
if err != nil {
return determineRootDirsGOPATH(cfg)
}
m := map[string]string{}
type jsonMod struct{ Path, Dir string }
for dec := json.NewDecoder(out); dec.More(); {
mod := new(jsonMod)
if err := dec.Decode(mod); err != nil {
return m // Give up and return an empty map. Package won't be found for overlay.
}
if mod.Dir != "" && mod.Path != "" {
// This is a valid module; add it to the map.
m[mod.Dir] = mod.Path
}
}
return m
}
func determineRootDirsGOPATH(cfg *Config) map[string]string {
m := map[string]string{}
out, err := invokeGo(cfg, "env", "GOPATH")
if err != nil {
// Could not determine root dir mapping. Everything is best-effort, so just return an empty map.
// When we try to find the import path for a directory, there will be no root-dir match and
// we'll give up.
return m
}
for _, p := range filepath.SplitList(string(bytes.TrimSpace(out.Bytes()))) {
m[filepath.Join(p, "src")] = ""
}
return m
}
func extractImports(filename string, contents []byte) ([]string, error) {
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset?
if err != nil {
@ -102,3 +219,44 @@ func extractImports(filename string, contents []byte) ([]string, error) {
}
return res, nil
}
// reclaimPackage attempts to reuse a package that failed to load in an overlay.
//
// If the package has errors and has no Name, GoFiles, or Imports,
// then it's possible that it doesn't yet exist on disk.
func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool {
// TODO(rstambler): Check the message of the actual error?
// It differs between $GOPATH and module mode.
if pkg.ID != id {
return false
}
if len(pkg.Errors) != 1 {
return false
}
if pkg.Name != "" || pkg.ExportFile != "" {
return false
}
if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 {
return false
}
if len(pkg.Imports) > 0 {
return false
}
pkgName, ok := extractPackageName(filename, contents)
if !ok {
return false
}
pkg.Name = pkgName
pkg.Errors = nil
return true
}
func extractPackageName(filename string, contents []byte) (string, bool) {
// TODO(rstambler): Check the message of the actual error?
// It differs between $GOPATH and module mode.
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset?
if err != nil {
return "", false
}
return f.Name.Name, true
}

View file

@ -25,24 +25,16 @@ import (
"golang.org/x/tools/go/gcexportdata"
)
// A LoadMode specifies the amount of detail to return when loading.
// Higher-numbered modes cause Load to return more information,
// but may be slower. Load may return more information than requested.
// A LoadMode controls the amount of detail to return when loading.
// The bits below can be combined to specify which fields should be
// filled in the result packages.
// The zero value is a special case, equivalent to combining
// the NeedName, NeedFiles, and NeedCompiledGoFiles bits.
// ID and Errors (if present) will always be filled.
// Load may return more information than requested.
type LoadMode int
const (
// The following constants are used to specify which fields of the Package
// should be filled when loading is done. As a special case to provide
// backwards compatibility, a LoadMode of 0 is equivalent to LoadFiles.
// For all other LoadModes, the bits below specify which fields will be filled
// in the result packages.
// WARNING: This part of the go/packages API is EXPERIMENTAL. It might
// be changed or removed up until April 15 2019. After that date it will
// be frozen.
// TODO(matloob): Remove this comment on April 15.
// ID and Errors (if present) will always be filled.
// NeedName adds Name and PkgPath.
NeedName LoadMode = 1 << iota
@ -77,30 +69,24 @@ const (
)
const (
// LoadFiles finds the packages and computes their source file lists.
// Package fields: ID, Name, Errors, GoFiles, CompiledGoFiles, and OtherFiles.
// Deprecated: LoadFiles exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles
// LoadImports adds import information for each package
// and its dependencies.
// Package fields added: Imports.
// Deprecated: LoadImports exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadImports = LoadFiles | NeedImports | NeedDeps
// LoadTypes adds type information for package-level
// declarations in the packages matching the patterns.
// Package fields added: Types, Fset, and IllTyped.
// This mode uses type information provided by the build system when
// possible, and may fill in the ExportFile field.
LoadTypes = LoadImports | NeedTypes
// Deprecated: LoadTypes exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadTypes = LoadImports | NeedTypes | NeedTypesSizes
// LoadSyntax adds typed syntax trees for the packages matching the patterns.
// Package fields added: Syntax, and TypesInfo, for direct pattern matches only.
LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo | NeedTypesSizes
// Deprecated: LoadSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo
// LoadAllSyntax adds typed syntax trees for the packages matching the patterns
// and all dependencies.
// Package fields added: Types, Fset, IllTyped, Syntax, and TypesInfo,
// for all packages in the import graph.
// Deprecated: LoadAllSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadAllSyntax = LoadSyntax
)
@ -137,7 +123,7 @@ type Config struct {
BuildFlags []string
// Fset provides source position information for syntax trees and types.
// If Fset is nil, the loader will create a new FileSet.
// If Fset is nil, Load will use a new fileset, but preserve Fset's value.
Fset *token.FileSet
// ParseFile is called to read and parse each file
@ -275,9 +261,9 @@ type Package struct {
Imports map[string]*Package
// Types provides type information for the package.
// Modes LoadTypes and above set this field for packages matching the
// patterns; type information for dependencies may be missing or incomplete.
// Mode LoadAllSyntax sets this field for all packages, including dependencies.
// The NeedTypes LoadMode bit sets this field for packages matching the
// patterns; type information for dependencies may be missing or incomplete,
// unless NeedDeps and NeedImports are also set.
Types *types.Package
// Fset provides position information for Types, TypesInfo, and Syntax.
@ -290,8 +276,9 @@ type Package struct {
// Syntax is the package's syntax trees, for the files listed in CompiledGoFiles.
//
// Mode LoadSyntax sets this field for packages matching the patterns.
// Mode LoadAllSyntax sets this field for all packages, including dependencies.
// The NeedSyntax LoadMode bit populates this field for packages matching the patterns.
// If NeedDeps and NeedImports are also set, this field will also be populated
// for dependencies.
Syntax []*ast.File
// TypesInfo provides type information about the package's syntax trees.
@ -418,17 +405,33 @@ type loaderPackage struct {
type loader struct {
pkgs map[string]*loaderPackage
Config
sizes types.Sizes
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
sizes types.Sizes
parseCache map[string]*parseValue
parseCacheMu sync.Mutex
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
// TODO(matloob): Add an implied mode here and use that instead of mode.
// Implied mode would contain all the fields we need the data for so we can
// get the actually requested fields. We'll zero them out before returning
// packages to the user. This will make it easier for us to get the conditions
// where we need certain modes right.
}
type parseValue struct {
f *ast.File
err error
ready chan struct{}
}
func newLoader(cfg *Config) *loader {
ld := &loader{}
ld := &loader{
parseCache: map[string]*parseValue{},
}
if cfg != nil {
ld.Config = *cfg
}
if ld.Config.Mode == 0 {
ld.Config.Mode = LoadFiles // Preserve zero behavior of Mode for backwards compatibility.
ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility.
}
if ld.Config.Env == nil {
ld.Config.Env = os.Environ()
@ -451,12 +454,8 @@ func newLoader(cfg *Config) *loader {
// because we load source if export data is missing.
if ld.ParseFile == nil {
ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
var isrc interface{}
if src != nil {
isrc = src
}
const mode = parser.AllErrors | parser.ParseComments
return parser.ParseFile(fset, filename, isrc, mode)
return parser.ParseFile(fset, filename, src, mode)
}
}
}
@ -554,13 +553,16 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
if lpkg.needsrc {
srcPkgs = append(srcPkgs, lpkg)
}
if ld.Mode&NeedTypesSizes != 0 {
lpkg.TypesSizes = ld.sizes
}
stack = stack[:len(stack)-1] // pop
lpkg.color = black
return lpkg.needsrc
}
if ld.Mode&NeedImports == 0 {
if ld.Mode&(NeedImports|NeedDeps) == 0 {
// We do this to drop the stub import packages that we are not even going to try to resolve.
for _, lpkg := range initial {
lpkg.Imports = nil
@ -571,7 +573,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
visit(lpkg)
}
}
if ld.Mode&NeedDeps != 0 {
if ld.Mode&NeedDeps != 0 { // TODO(matloob): This is only the case if NeedTypes is also set, right?
for _, lpkg := range srcPkgs {
// Complete type information is required for the
// immediate dependencies of each source package.
@ -599,46 +601,48 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
importPlaceholders := make(map[string]*Package)
for i, lpkg := range initial {
result[i] = lpkg.Package
}
for i := range ld.pkgs {
// Clear all unrequested fields, for extra de-Hyrum-ization.
if ld.Mode&NeedName == 0 {
result[i].Name = ""
result[i].PkgPath = ""
ld.pkgs[i].Name = ""
ld.pkgs[i].PkgPath = ""
}
if ld.Mode&NeedFiles == 0 {
result[i].GoFiles = nil
result[i].OtherFiles = nil
ld.pkgs[i].GoFiles = nil
ld.pkgs[i].OtherFiles = nil
}
if ld.Mode&NeedCompiledGoFiles == 0 {
result[i].CompiledGoFiles = nil
ld.pkgs[i].CompiledGoFiles = nil
}
if ld.Mode&NeedImports == 0 {
result[i].Imports = nil
ld.pkgs[i].Imports = nil
}
if ld.Mode&NeedExportsFile == 0 {
result[i].ExportFile = ""
ld.pkgs[i].ExportFile = ""
}
if ld.Mode&NeedTypes == 0 {
result[i].Types = nil
result[i].Fset = nil
result[i].IllTyped = false
ld.pkgs[i].Types = nil
ld.pkgs[i].Fset = nil
ld.pkgs[i].IllTyped = false
}
if ld.Mode&NeedSyntax == 0 {
result[i].Syntax = nil
ld.pkgs[i].Syntax = nil
}
if ld.Mode&NeedTypesInfo == 0 {
result[i].TypesInfo = nil
ld.pkgs[i].TypesInfo = nil
}
if ld.Mode&NeedTypesSizes == 0 {
result[i].TypesSizes = nil
ld.pkgs[i].TypesSizes = nil
}
if ld.Mode&NeedDeps == 0 {
for j, pkg := range result[i].Imports {
for j, pkg := range ld.pkgs[i].Imports {
ph, ok := importPlaceholders[pkg.ID]
if !ok {
ph = &Package{ID: pkg.ID}
importPlaceholders[pkg.ID] = ph
}
result[i].Imports[j] = ph
ld.pkgs[i].Imports[j] = ph
}
}
}
@ -670,7 +674,7 @@ func (ld *loader) loadRecursive(lpkg *loaderPackage) {
// loadPackage loads the specified package.
// It must be called only once per Package,
// after immediate dependencies are loaded.
// Precondition: ld.Mode >= LoadTypes.
// Precondition: ld.Mode & NeedTypes.
func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" {
// Fill in the blanks to avoid surprises.
@ -853,6 +857,42 @@ func (f importerFunc) Import(path string) (*types.Package, error) { return f(pat
// the number of parallel I/O calls per process.
var ioLimit = make(chan bool, 20)
func (ld *loader) parseFile(filename string) (*ast.File, error) {
ld.parseCacheMu.Lock()
v, ok := ld.parseCache[filename]
if ok {
// cache hit
ld.parseCacheMu.Unlock()
<-v.ready
} else {
// cache miss
v = &parseValue{ready: make(chan struct{})}
ld.parseCache[filename] = v
ld.parseCacheMu.Unlock()
var src []byte
for f, contents := range ld.Config.Overlay {
if sameFile(f, filename) {
src = contents
}
}
var err error
if src == nil {
ioLimit <- true // wait
src, err = ioutil.ReadFile(filename)
<-ioLimit // signal
}
if err != nil {
v.err = err
} else {
v.f, v.err = ld.ParseFile(ld.Fset, filename, src)
}
close(v.ready)
}
return v.f, v.err
}
// parseFiles reads and parses the Go source files and returns the ASTs
// of the ones that could be at least partially parsed, along with a
// list of I/O and parse errors encountered.
@ -873,24 +913,7 @@ func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
}
wg.Add(1)
go func(i int, filename string) {
ioLimit <- true // wait
// ParseFile may return both an AST and an error.
var src []byte
for f, contents := range ld.Config.Overlay {
if sameFile(f, filename) {
src = contents
}
}
var err error
if src == nil {
src, err = ioutil.ReadFile(filename)
}
if err != nil {
parsed[i], errors[i] = nil, err
} else {
parsed[i], errors[i] = ld.ParseFile(ld.Fset, filename, src)
}
<-ioLimit // signal
parsed[i], errors[i] = ld.parseFile(filename)
wg.Done()
}(i, file)
}

62
vendor/golang.org/x/tools/imports/forward.go generated vendored Normal file
View file

@ -0,0 +1,62 @@
// 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 (
"go/build"
intimp "golang.org/x/tools/internal/imports"
)
// 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
}
// Debug controls verbose logging.
var Debug = false
// LocalPrefix is a comma-separated string of import path prefixes, which, if
// set, instructs Process to sort the import paths with the given prefixes
// into another group after 3rd-party packages.
var LocalPrefix string
// 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}
}
intopt := &intimp.Options{
Env: &intimp.ProcessEnv{
GOPATH: build.Default.GOPATH,
GOROOT: build.Default.GOROOT,
Debug: Debug,
LocalPrefix: LocalPrefix,
},
AllErrors: opt.AllErrors,
Comments: opt.Comments,
FormatOnly: opt.FormatOnly,
Fragment: opt.Fragment,
TabIndent: opt.TabIndent,
TabWidth: opt.TabWidth,
}
return intimp.Process(filename, src, intopt)
}
// VendorlessPath returns the devendorized version of the import path ipath.
// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b".
func VendorlessPath(ipath string) string {
return intimp.VendorlessPath(ipath)
}

View file

@ -31,39 +31,27 @@ import (
"golang.org/x/tools/internal/gopathwalk"
)
// Debug controls verbose logging.
var Debug = false
// LocalPrefix is a comma-separated string of import path prefixes, which, if
// set, instructs Process to sort the import paths with the given prefixes
// into another group after 3rd-party packages.
var LocalPrefix string
func localPrefixes() []string {
if LocalPrefix != "" {
return strings.Split(LocalPrefix, ",")
}
return nil
}
// 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) {
for _, p := range localPrefixes() {
var importToGroup = []func(env *ProcessEnv, importPath string) (num int, ok bool){
func(env *ProcessEnv, importPath string) (num int, ok bool) {
if env.LocalPrefix == "" {
return
}
for _, p := range strings.Split(env.LocalPrefix, ",") {
if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath {
return 3, true
}
}
return
},
func(importPath string) (num int, ok bool) {
func(_ *ProcessEnv, importPath string) (num int, ok bool) {
if strings.HasPrefix(importPath, "appengine") {
return 2, true
}
return
},
func(importPath string) (num int, ok bool) {
func(_ *ProcessEnv, importPath string) (num int, ok bool) {
if strings.Contains(importPath, ".") {
return 1, true
}
@ -71,9 +59,9 @@ var importToGroup = []func(importPath string) (num int, ok bool){
},
}
func importGroup(importPath string) int {
func importGroup(env *ProcessEnv, importPath string) int {
for _, fn := range importToGroup {
if n, ok := fn(importPath); ok {
if n, ok := fn(env, importPath); ok {
return n
}
}
@ -241,7 +229,7 @@ type pass struct {
fset *token.FileSet // fset used to parse f and its siblings.
f *ast.File // the file being fixed.
srcDir string // the directory containing f.
fixEnv *fixEnv // the environment to use for go commands, etc.
env *ProcessEnv // the environment to use for go commands, etc.
loadRealPackageNames bool // if true, load package names from disk rather than guessing them.
otherFiles []*ast.File // sibling files.
@ -266,7 +254,7 @@ func (p *pass) loadPackageNames(imports []*importInfo) error {
unknown = append(unknown, imp.importPath)
}
names, err := p.fixEnv.getResolver().loadPackageNames(unknown, p.srcDir)
names, err := p.env.getResolver().loadPackageNames(unknown, p.srcDir)
if err != nil {
return err
}
@ -324,7 +312,7 @@ func (p *pass) load() bool {
if p.loadRealPackageNames {
err := p.loadPackageNames(append(imports, p.candidates...))
if err != nil {
if Debug {
if p.env.Debug {
log.Printf("loading package names: %v", err)
}
return false
@ -448,13 +436,13 @@ func (p *pass) addCandidate(imp *importInfo, pkg *packageInfo) {
// easily be extended by adding a file with an init function.
var fixImports = fixImportsDefault
func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *fixEnv) error {
func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error {
abs, err := filepath.Abs(filename)
if err != nil {
return err
}
srcDir := filepath.Dir(abs)
if Debug {
if env.Debug {
log.Printf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir)
}
@ -486,7 +474,7 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *f
// Third pass: get real package names where we had previously used
// the naive algorithm. This is the first step that will use the
// environment, so we provide it here for the first time.
p = &pass{fset: fset, f: f, srcDir: srcDir, fixEnv: env}
p = &pass{fset: fset, f: f, srcDir: srcDir, env: env}
p.loadRealPackageNames = true
p.otherFiles = otherFiles
if p.load() {
@ -510,13 +498,16 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *f
return nil
}
// fixEnv contains environment variables and settings that affect the use of
// ProcessEnv contains environment variables and settings that affect the use of
// the go command, the go/build package, etc.
type fixEnv struct {
type ProcessEnv struct {
LocalPrefix string
Debug bool
// If non-empty, these will be used instead of the
// process-wide values.
GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS string
WorkingDir string
GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS, GOSUMDB string
WorkingDir string
// If true, use go/packages regardless of the environment.
ForceGoPackages bool
@ -524,7 +515,7 @@ type fixEnv struct {
resolver resolver
}
func (e *fixEnv) env() []string {
func (e *ProcessEnv) env() []string {
env := os.Environ()
add := func(k, v string) {
if v != "" {
@ -536,28 +527,32 @@ func (e *fixEnv) env() []string {
add("GO111MODULE", e.GO111MODULE)
add("GOPROXY", e.GOPROXY)
add("GOFLAGS", e.GOFLAGS)
add("GOSUMDB", e.GOSUMDB)
if e.WorkingDir != "" {
add("PWD", e.WorkingDir)
}
return env
}
func (e *fixEnv) getResolver() resolver {
func (e *ProcessEnv) getResolver() resolver {
if e.resolver != nil {
return e.resolver
}
if e.ForceGoPackages {
return &goPackagesResolver{env: e}
e.resolver = &goPackagesResolver{env: e}
return e.resolver
}
out, err := e.invokeGo("env", "GOMOD")
if err != nil || len(bytes.TrimSpace(out.Bytes())) == 0 {
return &gopathResolver{env: e}
e.resolver = &gopathResolver{env: e}
return e.resolver
}
return &moduleResolver{env: e}
e.resolver = &moduleResolver{env: e}
return e.resolver
}
func (e *fixEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config {
func (e *ProcessEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config {
return &packages.Config{
Mode: mode,
Dir: e.WorkingDir,
@ -565,14 +560,14 @@ func (e *fixEnv) newPackagesConfig(mode packages.LoadMode) *packages.Config {
}
}
func (e *fixEnv) buildContext() *build.Context {
func (e *ProcessEnv) buildContext() *build.Context {
ctx := build.Default
ctx.GOROOT = e.GOROOT
ctx.GOPATH = e.GOPATH
return &ctx
}
func (e *fixEnv) invokeGo(args ...string) (*bytes.Buffer, error) {
func (e *ProcessEnv) invokeGo(args ...string) (*bytes.Buffer, error) {
cmd := exec.Command("go", args...)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
@ -581,7 +576,7 @@ func (e *fixEnv) invokeGo(args ...string) (*bytes.Buffer, error) {
cmd.Env = e.env()
cmd.Dir = e.WorkingDir
if Debug {
if e.Debug {
defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
}
if err := cmd.Run(); err != nil {
@ -632,7 +627,7 @@ type resolver interface {
// gopathResolver implements resolver for GOPATH and module workspaces using go/packages.
type goPackagesResolver struct {
env *fixEnv
env *ProcessEnv
}
func (r *goPackagesResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
@ -680,7 +675,7 @@ func (r *goPackagesResolver) scan(refs references) ([]*pkg, error) {
}
func addExternalCandidates(pass *pass, refs references, filename string) error {
dirScan, err := pass.fixEnv.getResolver().scan(refs)
dirScan, err := pass.env.getResolver().scan(refs)
if err != nil {
return err
}
@ -707,7 +702,7 @@ func addExternalCandidates(pass *pass, refs references, filename string) error {
go func(pkgName string, symbols map[string]bool) {
defer wg.Done()
found, err := findImport(ctx, pass.fixEnv, dirScan, pkgName, symbols, filename)
found, err := findImport(ctx, pass, dirScan, pkgName, symbols, filename)
if err != nil {
firstErrOnce.Do(func() {
@ -778,7 +773,7 @@ func importPathToAssumedName(importPath string) string {
// gopathResolver implements resolver for GOPATH workspaces.
type gopathResolver struct {
env *fixEnv
env *ProcessEnv
}
func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
@ -791,7 +786,7 @@ func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (
// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
// If there's a problem, it returns "".
func importPathToName(env *fixEnv, importPath, srcDir string) (packageName string) {
func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) {
// Fast path for standard library without going to disk.
if _, ok := stdlib[importPath]; ok {
return path.Base(importPath) // stdlib packages always match their paths.
@ -927,7 +922,7 @@ func (r *gopathResolver) scan(_ references) ([]*pkg, error) {
dir: dir,
})
}
gopathwalk.Walk(gopathwalk.SrcDirsRoots(r.env.buildContext()), add, gopathwalk.Options{Debug: Debug, ModulesEnabled: false})
gopathwalk.Walk(gopathwalk.SrcDirsRoots(r.env.buildContext()), add, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: false})
return result, nil
}
@ -946,8 +941,8 @@ func VendorlessPath(ipath string) string {
// loadExports returns the set of exported symbols in the package at dir.
// It returns nil on error or if the package name in dir does not match expectPackage.
func loadExports(ctx context.Context, env *fixEnv, expectPackage string, pkg *pkg) (map[string]bool, error) {
if Debug {
func loadExports(ctx context.Context, env *ProcessEnv, expectPackage string, pkg *pkg) (map[string]bool, error) {
if env.Debug {
log.Printf("loading exports in dir %s (seeking package %s)", pkg.dir, expectPackage)
}
if pkg.goPackage != nil {
@ -1020,7 +1015,7 @@ func loadExports(ctx context.Context, env *fixEnv, expectPackage string, pkg *pk
}
}
if Debug {
if env.Debug {
exportList := make([]string, 0, len(exports))
for k := range exports {
exportList = append(exportList, k)
@ -1033,7 +1028,7 @@ func loadExports(ctx context.Context, env *fixEnv, expectPackage string, pkg *pk
// findImport searches for a package with the given symbols.
// If no package is found, findImport returns ("", false, nil)
func findImport(ctx context.Context, env *fixEnv, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) {
func findImport(ctx context.Context, pass *pass, dirScan []*pkg, pkgName string, symbols map[string]bool, filename string) (*pkg, error) {
pkgDir, err := filepath.Abs(filename)
if err != nil {
return nil, err
@ -1043,6 +1038,11 @@ func findImport(ctx context.Context, env *fixEnv, dirScan []*pkg, pkgName string
// Find candidate packages, looking only at their directory names first.
var candidates []pkgDistance
for _, pkg := range dirScan {
if pkg.dir == pkgDir && pass.f.Name.Name == pkgName {
// The candidate is in the same directory and has the
// same package name. Don't try to import ourselves.
continue
}
if pkgIsCandidate(filename, pkgName, pkg) {
candidates = append(candidates, pkgDistance{
pkg: pkg,
@ -1056,7 +1056,7 @@ func findImport(ctx context.Context, env *fixEnv, dirScan []*pkg, pkgName string
// ones. Note that this sorts by the de-vendored name, so
// there's no "penalty" for vendoring.
sort.Sort(byDistanceOrImportPathShortLength(candidates))
if Debug {
if pass.env.Debug {
for i, c := range candidates {
log.Printf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir)
}
@ -1095,9 +1095,9 @@ func findImport(ctx context.Context, env *fixEnv, dirScan []*pkg, pkgName string
wg.Done()
}()
exports, err := loadExports(ctx, env, pkgName, c.pkg)
exports, err := loadExports(ctx, pass.env, pkgName, c.pkg)
if err != nil {
if Debug {
if pass.env.Debug {
log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
}
resc <- nil

View file

@ -6,14 +6,13 @@
// 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"
package imports
import (
"bufio"
"bytes"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/printer"
@ -27,8 +26,10 @@ import (
"golang.org/x/tools/go/ast/astutil"
)
// Options specifies options for processing files.
// Options is golang.org/x/tools/imports.Options with extra internal-only options.
type Options struct {
Env *ProcessEnv // The environment to use. Note: this contains the cached module and filesystem state.
Fragment bool // Accept fragment of a source file (no package statement)
AllErrors bool // Report all errors (not just the first 10 on different lines)
@ -39,21 +40,8 @@ type Options struct {
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.
// Process implements golang.org/x/tools/imports.Process with explicit context in env.
func Process(filename string, src []byte, opt *Options) ([]byte, error) {
env := &fixEnv{GOPATH: build.Default.GOPATH, GOROOT: build.Default.GOROOT}
return process(filename, src, opt, env)
}
func process(filename string, src []byte, opt *Options, env *fixEnv) ([]byte, error) {
if opt == nil {
opt = &Options{Comments: true, TabIndent: true, TabWidth: 8}
}
if src == nil {
b, err := ioutil.ReadFile(filename)
if err != nil {
@ -69,12 +57,12 @@ func process(filename string, src []byte, opt *Options, env *fixEnv) ([]byte, er
}
if !opt.FormatOnly {
if err := fixImports(fileSet, file, filename, env); err != nil {
if err := fixImports(fileSet, file, filename, opt.Env); err != nil {
return nil, err
}
}
sortImports(fileSet, file)
sortImports(opt.Env, fileSet, file)
imps := astutil.Imports(fileSet, file)
var spacesBefore []string // import paths we need spaces before
for _, impSection := range imps {
@ -85,7 +73,7 @@ func process(filename string, src []byte, opt *Options, env *fixEnv) ([]byte, er
lastGroup := -1
for _, importSpec := range impSection {
importPath, _ := strconv.Unquote(importSpec.Path.Value)
groupNum := importGroup(importPath)
groupNum := importGroup(opt.Env, importPath)
if groupNum != lastGroup && lastGroup != -1 {
spacesBefore = append(spacesBefore, importPath)
}

View file

@ -8,7 +8,7 @@
// 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
package imports
import (
"bytes"

View file

@ -3,7 +3,7 @@
// 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
package imports
import (
"bufio"
@ -14,6 +14,7 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
@ -59,6 +60,10 @@ func main() {
mustOpen(api("go1.10.txt")),
mustOpen(api("go1.11.txt")),
mustOpen(api("go1.12.txt")),
// The API of the syscall/js package needs to be computed explicitly,
// because it's not included in the GOROOT/api/go1.*.txt files at this time.
syscallJSAPI(),
)
sc := bufio.NewScanner(f)
@ -110,3 +115,18 @@ func main() {
log.Fatal(err)
}
}
// syscallJSAPI returns the API of the syscall/js package.
// It's computed from the contents of $(go env GOROOT)/src/syscall/js.
func syscallJSAPI() io.Reader {
var exeSuffix string
if runtime.GOOS == "windows" {
exeSuffix = ".exe"
}
cmd := exec.Command("go"+exeSuffix, "run", "cmd/api", "-contexts", "js-wasm", "syscall/js")
out, err := cmd.Output()
if err != nil {
log.Fatalln(err)
}
return bytes.NewReader(out)
}

View file

@ -22,7 +22,7 @@ import (
// moduleResolver implements resolver for modules using the go command as little
// as feasible.
type moduleResolver struct {
env *fixEnv
env *ProcessEnv
initialized bool
main *moduleJSON
@ -62,7 +62,7 @@ func (r *moduleResolver) init() error {
return err
}
if mod.Dir == "" {
if Debug {
if r.env.Debug {
log.Printf("module %v has not been downloaded and will be ignored", mod.Path)
}
// Can't do anything with a module that's not downloaded.
@ -253,7 +253,7 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
matches := modCacheRegexp.FindStringSubmatch(subdir)
modPath, err := module.DecodePath(filepath.ToSlash(matches[1]))
if err != nil {
if Debug {
if r.env.Debug {
log.Printf("decoding module cache path %q: %v", subdir, err)
}
return
@ -303,7 +303,7 @@ func (r *moduleResolver) scan(_ references) ([]*pkg, error) {
importPathShort: VendorlessPath(importPath),
dir: dir,
})
}, gopathwalk.Options{Debug: Debug, ModulesEnabled: true})
}, gopathwalk.Options{Debug: r.env.Debug, ModulesEnabled: true})
return result, nil
}

View file

@ -15,7 +15,7 @@ import (
// 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) {
func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) {
for i, d := range f.Decls {
d, ok := d.(*ast.GenDecl)
if !ok || d.Tok != token.IMPORT {
@ -40,11 +40,11 @@ func sortImports(fset *token.FileSet, f *ast.File) {
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])...)
specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:j])...)
i = j
}
}
specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...)
specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:])...)
d.Specs = specs
// Deduping can leave a blank line before the rparen; clean that up.
@ -95,7 +95,7 @@ type posSpan struct {
End token.Pos
}
func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec {
func sortSpecs(env *ProcessEnv, 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.
@ -144,7 +144,7 @@ func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec {
// 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))
sort.Sort(byImportSpec{env, specs})
// Dedup. Thanks to our sorting, we can just consider
// adjacent pairs of imports.
@ -197,16 +197,19 @@ func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec {
return specs
}
type byImportSpec []ast.Spec // slice of *ast.ImportSpec
type byImportSpec struct {
env *ProcessEnv
specs []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) Len() int { return len(x.specs) }
func (x byImportSpec) Swap(i, j int) { x.specs[i], x.specs[j] = x.specs[j], x.specs[i] }
func (x byImportSpec) Less(i, j int) bool {
ipath := importPath(x[i])
jpath := importPath(x[j])
ipath := importPath(x.specs[i])
jpath := importPath(x.specs[j])
igroup := importGroup(ipath)
jgroup := importGroup(jpath)
igroup := importGroup(x.env, ipath)
jgroup := importGroup(x.env, jpath)
if igroup != jgroup {
return igroup < jgroup
}
@ -214,13 +217,13 @@ func (x byImportSpec) Less(i, j int) bool {
if ipath != jpath {
return ipath < jpath
}
iname := importName(x[i])
jname := importName(x[j])
iname := importName(x.specs[i])
jname := importName(x.specs[j])
if iname != jname {
return iname < jname
}
return importComment(x[i]) < importComment(x[j])
return importComment(x.specs[i]) < importComment(x.specs[j])
}
type byCommentPos []*ast.CommentGroup

View file

@ -9783,6 +9783,29 @@ var stdlib = map[string]map[string]bool{
"XP1_UNI_RECV": true,
"XP1_UNI_SEND": true,
},
"syscall/js": map[string]bool{
"Error": true,
"Func": true,
"FuncOf": true,
"Global": true,
"Null": true,
"Type": true,
"TypeBoolean": true,
"TypeFunction": true,
"TypeNull": true,
"TypeNumber": true,
"TypeObject": true,
"TypeString": true,
"TypeSymbol": true,
"TypeUndefined": true,
"TypedArray": true,
"TypedArrayOf": true,
"Undefined": true,
"Value": true,
"ValueError": true,
"ValueOf": true,
"Wrapper": true,
},
"testing": map[string]bool{
"AllocsPerRun": true,
"B": true,