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

View File

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