Update go dependencies

This commit is contained in:
Manuel Alejandro de Brito Fontes 2019-07-31 20:55:11 -04:00
parent c8a3710fb8
commit fcb1b6217b
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
162 changed files with 6806 additions and 7275 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 || cfg.Mode&NeedTypes != 0 {
if cfg.Mode&NeedTypesSizes != 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 := golistDriver(cfg, restPatterns...)
dr, err := golistDriverCurrent(cfg, restPatterns...)
if err != nil {
return nil, err
}
@ -147,13 +147,13 @@ extractQueries:
var containsCandidates []string
if len(containFiles) != 0 {
if err := runContainsQueries(cfg, golistDriver, response, containFiles); err != nil {
if err := runContainsQueries(cfg, golistDriverCurrent, response, containFiles); err != nil {
return nil, err
}
}
if len(packagesNamed) != 0 {
if err := runNamedQueries(cfg, golistDriver, response, packagesNamed); err != nil {
if err := runNamedQueries(cfg, golistDriverCurrent, response, packagesNamed); err != nil {
return nil, err
}
}
@ -166,25 +166,17 @@ extractQueries:
containsCandidates = append(containsCandidates, modifiedPkgs...)
containsCandidates = append(containsCandidates, needPkgs...)
}
if err := addNeededOverlayPackages(cfg, golistDriver, response, needPkgs); err != nil {
return nil, err
if len(needPkgs) > 0 {
addNeededOverlayPackages(cfg, golistDriverCurrent, response, needPkgs)
if err != nil {
return nil, err
}
}
// Check candidate packages for containFiles.
if len(containFiles) > 0 {
for _, id := range containsCandidates {
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
}
pkg := response.seenPackages[id]
for _, f := range containFiles {
for _, g := range pkg.GoFiles {
if sameFile(f, g) {
@ -199,9 +191,6 @@ 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
@ -209,11 +198,6 @@ 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
}
@ -556,10 +540,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}
}
// 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) {
// 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) {
// go list uses the following identifiers in ImportPath and Imports:
//
// "p" -- importable package or main (command)
@ -777,31 +761,8 @@ 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": "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"))
output := fmt.Sprintf(`{"ImportPath": "","Incomplete": true,"Error": {"Pos": "","Err": %s}}`,
strconv.Quote(strings.Trim(stderr.String(), "\n")))
return bytes.NewBufferString(output), nil
}

View file

@ -1,15 +1,11 @@
package packages
import (
"bytes"
"encoding/json"
"go/parser"
"go/token"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
)
// processGolistOverlay provides rudimentary support for adding
@ -31,123 +27,50 @@ func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs,
havePkgs[pkg.PkgPath] = pkg.ID
}
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") {
outer:
for path, contents := range cfg.Overlay {
base := filepath.Base(path)
if strings.HasSuffix(path, "_test.go") {
// Overlays don't support adding new test files yet.
// TODO(matloob): support adding new test files.
continue
}
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
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
}
pkg = p
if filepath.Base(f) == base {
fileExists = true
}
}
}
// 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 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)
if err != nil {
continue
// Let the parser or type checker report errors later.
continue outer
}
pkgPath = filepath.ToSlash(r)
if rpath != "" {
pkgPath = path.Join(rpath, pkgPath)
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}
}
}
// 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
continue outer
}
}
}
@ -163,46 +86,6 @@ func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs,
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 {
@ -219,44 +102,3 @@ 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,16 +25,24 @@ import (
"golang.org/x/tools/go/gcexportdata"
)
// 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.
// 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.
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
@ -69,24 +77,30 @@ const (
)
const (
// Deprecated: LoadFiles exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
// LoadFiles finds the packages and computes their source file lists.
// Package fields: ID, Name, Errors, GoFiles, CompiledGoFiles, and OtherFiles.
LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles
// Deprecated: LoadImports exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
// LoadImports adds import information for each package
// and its dependencies.
// Package fields added: Imports.
LoadImports = LoadFiles | NeedImports | NeedDeps
// 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
// 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: LoadSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo
// 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: LoadAllSyntax exists for historical compatibility
// and should not be used. Please directly specify the needed fields using the Need values.
// 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.
LoadAllSyntax = LoadSyntax
)
@ -123,7 +137,7 @@ type Config struct {
BuildFlags []string
// Fset provides source position information for syntax trees and types.
// If Fset is nil, Load will use a new fileset, but preserve Fset's value.
// If Fset is nil, the loader will create a new FileSet.
Fset *token.FileSet
// ParseFile is called to read and parse each file
@ -261,9 +275,9 @@ type Package struct {
Imports map[string]*Package
// Types provides type information for the package.
// 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.
// 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.
Types *types.Package
// Fset provides position information for Types, TypesInfo, and Syntax.
@ -276,9 +290,8 @@ type Package struct {
// Syntax is the package's syntax trees, for the files listed in CompiledGoFiles.
//
// 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.
// Mode LoadSyntax sets this field for packages matching the patterns.
// Mode LoadAllSyntax sets this field for all packages, including dependencies.
Syntax []*ast.File
// TypesInfo provides type information about the package's syntax trees.
@ -405,33 +418,17 @@ type loaderPackage struct {
type loader struct {
pkgs map[string]*loaderPackage
Config
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{}
sizes types.Sizes
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
}
func newLoader(cfg *Config) *loader {
ld := &loader{
parseCache: map[string]*parseValue{},
}
ld := &loader{}
if cfg != nil {
ld.Config = *cfg
}
if ld.Config.Mode == 0 {
ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility.
ld.Config.Mode = LoadFiles // Preserve zero behavior of Mode for backwards compatibility.
}
if ld.Config.Env == nil {
ld.Config.Env = os.Environ()
@ -454,8 +451,12 @@ 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, src, mode)
return parser.ParseFile(fset, filename, isrc, mode)
}
}
}
@ -553,16 +554,13 @@ 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|NeedDeps) == 0 {
if ld.Mode&NeedImports == 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
@ -573,7 +571,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
visit(lpkg)
}
}
if ld.Mode&NeedDeps != 0 { // TODO(matloob): This is only the case if NeedTypes is also set, right?
if ld.Mode&NeedDeps != 0 {
for _, lpkg := range srcPkgs {
// Complete type information is required for the
// immediate dependencies of each source package.
@ -601,48 +599,46 @@ 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 {
ld.pkgs[i].Name = ""
ld.pkgs[i].PkgPath = ""
result[i].Name = ""
result[i].PkgPath = ""
}
if ld.Mode&NeedFiles == 0 {
ld.pkgs[i].GoFiles = nil
ld.pkgs[i].OtherFiles = nil
result[i].GoFiles = nil
result[i].OtherFiles = nil
}
if ld.Mode&NeedCompiledGoFiles == 0 {
ld.pkgs[i].CompiledGoFiles = nil
result[i].CompiledGoFiles = nil
}
if ld.Mode&NeedImports == 0 {
ld.pkgs[i].Imports = nil
result[i].Imports = nil
}
if ld.Mode&NeedExportsFile == 0 {
ld.pkgs[i].ExportFile = ""
result[i].ExportFile = ""
}
if ld.Mode&NeedTypes == 0 {
ld.pkgs[i].Types = nil
ld.pkgs[i].Fset = nil
ld.pkgs[i].IllTyped = false
result[i].Types = nil
result[i].Fset = nil
result[i].IllTyped = false
}
if ld.Mode&NeedSyntax == 0 {
ld.pkgs[i].Syntax = nil
result[i].Syntax = nil
}
if ld.Mode&NeedTypesInfo == 0 {
ld.pkgs[i].TypesInfo = nil
result[i].TypesInfo = nil
}
if ld.Mode&NeedTypesSizes == 0 {
ld.pkgs[i].TypesSizes = nil
result[i].TypesSizes = nil
}
if ld.Mode&NeedDeps == 0 {
for j, pkg := range ld.pkgs[i].Imports {
for j, pkg := range result[i].Imports {
ph, ok := importPlaceholders[pkg.ID]
if !ok {
ph = &Package{ID: pkg.ID}
importPlaceholders[pkg.ID] = ph
}
ld.pkgs[i].Imports[j] = ph
result[i].Imports[j] = ph
}
}
}
@ -674,7 +670,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 & NeedTypes.
// Precondition: ld.Mode >= LoadTypes.
func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" {
// Fill in the blanks to avoid surprises.
@ -857,42 +853,6 @@ 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.
@ -913,7 +873,24 @@ func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
}
wg.Add(1)
go func(i int, filename string) {
parsed[i], errors[i] = ld.parseFile(filename)
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
wg.Done()
}(i, file)
}