1
0
mirror of https://github.com/golang/go synced 2024-11-18 23:34:45 -07:00

go/packages: splitting the scratch fields out of Package

This makes Package a struct we can re-use in other places/algorithms.

Change-Id: I2e095a624bf44223319ba1ea3d60deb727b38f81
Reviewed-on: https://go-review.googlesource.com/124855
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Ian Cottrell 2018-07-18 19:45:17 -04:00
parent 96ee42108a
commit ded554d068
2 changed files with 49 additions and 38 deletions

View File

@ -31,7 +31,7 @@ type GoTooOldError struct {
// golistPackages 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 golistPackages(ctx context.Context, dir string, env []string, cgo, export, tests bool, words []string) ([]*Package, error) {
func golistPackages(ctx context.Context, dir string, env []string, cgo, export, tests bool, words []string) ([]*loaderPackage, error) {
// Fields must match go list;
// see $GOROOT/src/cmd/go/internal/load/pkg.go.
type jsonPackage struct {
@ -73,7 +73,7 @@ func golistPackages(ctx context.Context, dir string, env []string, cgo, export,
return nil, err
}
// Decode the JSON and convert it to Package form.
var result []*Package
var result []*loaderPackage
for dec := json.NewDecoder(buf); dec.More(); {
p := new(jsonPackage)
if err := dec.Decode(p); err != nil {
@ -152,15 +152,17 @@ func golistPackages(ctx context.Context, dir string, env []string, cgo, export,
imports[id] = id // identity import
}
pkg := &Package{
ID: id,
Name: p.Name,
PkgPath: pkgpath,
Srcs: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
OtherSrcs: absJoin(p.Dir, p.SFiles, p.CFiles),
imports: imports,
export: export,
indirect: p.DepOnly,
pkg := &loaderPackage{
Package: &Package{
ID: id,
Name: p.Name,
PkgPath: pkgpath,
Srcs: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
OtherSrcs: absJoin(p.Dir, p.SFiles, p.CFiles),
},
imports: imports,
export: export,
indirect: p.DepOnly,
}
result = append(result, pkg)
}

View File

@ -229,9 +229,11 @@ type Package struct {
// It is set only when Files is set.
// All packages loaded together share a single Fset.
Fset *token.FileSet
}
// ---- temporary state ----
// the Package struct should be pure exported data.
// loaderPackage augments Package with state used during the loading phase
type loaderPackage struct {
*Package
// export holds the path to the export data file
// for this package, if mode == TypeCheck.
@ -255,6 +257,7 @@ func (lpkg *Package) String() string { return lpkg.ID }
type loader struct {
mode mode
cgo bool
pkgs map[string]*loaderPackage
Options
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
}
@ -306,10 +309,10 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
if err != nil {
return nil, err
}
pkgs := make(map[string]*Package)
var initial []*Package
ld.pkgs = make(map[string]*loaderPackage)
var initial []*loaderPackage
for _, pkg := range list {
pkgs[pkg.ID] = pkg
ld.pkgs[pkg.ID] = pkg
// Record the set of initial packages
// corresponding to the patterns.
@ -321,7 +324,7 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
}
}
}
if len(pkgs) == 0 {
if len(ld.pkgs) == 0 {
return nil, fmt.Errorf("packages not found")
}
@ -343,9 +346,9 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
// visit returns whether the package is initial or has a transitive
// dependency on an initial package. These are the only packages
// for which we load source code in typeCheck mode.
var stack []*Package
var visit func(lpkg *Package) bool
visit = func(lpkg *Package) bool {
var stack []*loaderPackage
var visit func(lpkg *loaderPackage) bool
visit = func(lpkg *loaderPackage) bool {
switch lpkg.color {
case black:
return lpkg.needsrc
@ -358,7 +361,7 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
imports := make(map[string]*Package)
for importPath, id := range lpkg.imports {
var importErr error
imp := pkgs[id]
imp := ld.pkgs[id]
if imp == nil {
// (includes package "C" when DisableCgo)
importErr = fmt.Errorf("missing package: %q", id)
@ -376,7 +379,7 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
if visit(imp) {
lpkg.needsrc = true
}
imports[importPath] = imp
imports[importPath] = imp.Package
}
lpkg.imports = nil // no longer needed
lpkg.Imports = imports
@ -398,7 +401,7 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
var wg sync.WaitGroup
for _, lpkg := range initial {
wg.Add(1)
go func(lpkg *Package) {
go func(lpkg *loaderPackage) {
ld.loadRecursive(lpkg)
wg.Done()
}(lpkg)
@ -406,7 +409,11 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
wg.Wait()
}
return initial, nil
result := make([]*Package, len(initial))
for i, lpkg := range initial {
result[i] = lpkg.Package
}
return result, nil
}
// loadRecursive loads, parses, and type-checks the specified package and its
@ -414,13 +421,14 @@ func (ld *loader) load(patterns ...string) ([]*Package, error) {
// It is atomic and idempotent.
// Precondition: ld.mode != Metadata.
// In typeCheck mode, only needsrc packages are loaded.
func (ld *loader) loadRecursive(lpkg *Package) {
func (ld *loader) loadRecursive(lpkg *loaderPackage) {
lpkg.loadOnce.Do(func() {
// Load the direct dependencies, in parallel.
var wg sync.WaitGroup
for _, imp := range lpkg.Imports {
for _, ipkg := range lpkg.Imports {
imp := ld.pkgs[ipkg.ID]
wg.Add(1)
go func(imp *Package) {
go func(imp *loaderPackage) {
ld.loadRecursive(imp)
wg.Done()
}(imp)
@ -436,7 +444,7 @@ func (ld *loader) loadRecursive(lpkg *Package) {
// It must be called only once per Package,
// after immediate dependencies are loaded.
// Precondition: ld.mode != Metadata.
func (ld *loader) loadPackage(lpkg *Package) {
func (ld *loader) loadPackage(lpkg *loaderPackage) {
if lpkg.PkgPath == "unsafe" {
// Fill in the blanks to avoid surprises.
lpkg.Type = types.Unsafe
@ -494,8 +502,8 @@ func (ld *loader) loadPackage(lpkg *Package) {
}
// The imports map is keyed by import path.
imp := lpkg.Imports[path]
if imp == nil {
ipkg := lpkg.Imports[path]
if ipkg == nil {
if err := lpkg.importErrors[path]; err != nil {
return nil, err
}
@ -505,9 +513,10 @@ func (ld *loader) loadPackage(lpkg *Package) {
// used to supply alternative file contents.
return nil, fmt.Errorf("no metadata for %s", path)
}
if imp.Type != nil && imp.Type.Complete() {
return imp.Type, nil
if ipkg.Type != nil && ipkg.Type.Complete() {
return ipkg.Type, nil
}
imp := ld.pkgs[ipkg.ID]
if ld.mode == typeCheck && !imp.needsrc {
return ld.loadFromExportData(imp)
}
@ -611,7 +620,7 @@ func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) {
// loadFromExportData returns type information for the specified
// package, loading it from an export data file on the first request.
func (ld *loader) loadFromExportData(lpkg *Package) (*types.Package, error) {
func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error) {
if lpkg.PkgPath == "" {
log.Fatalf("internal error: Package %s has no PkgPath", lpkg)
}
@ -689,10 +698,10 @@ func (ld *loader) loadFromExportData(lpkg *Package) (*types.Package, error) {
// get-or-create a package instead of a map.
//
view := make(map[string]*types.Package) // view seen by gcexportdata
seen := make(map[*Package]bool) // all visited packages
var copyback []*Package // candidates for copying back to global cache
var visit func(p *Package)
visit = func(p *Package) {
seen := make(map[*loaderPackage]bool) // all visited packages
var copyback []*loaderPackage // candidates for copying back to global cache
var visit func(p *loaderPackage)
visit = func(p *loaderPackage) {
if !seen[p] {
seen[p] = true
if p.Type != nil {
@ -701,7 +710,7 @@ func (ld *loader) loadFromExportData(lpkg *Package) (*types.Package, error) {
copyback = append(copyback, p)
}
for _, p := range p.Imports {
visit(p)
visit(ld.pkgs[p.ID])
}
}
}