go.tools/ssa: fix crash in SSA builder when using GCImporter to satisfy imports (ssadump -build=G).
Packages were not being created for all types.Packages, specifically, indirectly imported packages were missing. (*Program).CreatePackages now iterates over the type-checker's package map too. Also: removed all concurrency from importer. I think it was incorrect (and hard to fix). Also: change LoadInitialPackages so that all named packages are loaded from source. This happens regardless of whether GCImporter is used to satisfy imports. Details: - importer.Config.SourceImports flag determines whether to load all packages from *.go source. (Before, this was indicated by Config.Build != nil.) - importer.Config.Build field effectively defaults to &go/build.Default. A zero importer.Config is now usable. - importer.Importer.Config field is now exported. - LoadPackage renamed to ImportPackage since the resulting packages may come from GCImporter (and be incomplete). - doImport and ImportPackage fused. Fixes golang/go#7028 R=gri, axwalk CC=golang-codereviews https://golang.org/cl/48770043
This commit is contained in:
parent
df3357d07f
commit
3d82e7e94a
|
@ -73,7 +73,10 @@ func main() {
|
|||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
impctx := importer.Config{Build: &build.Default}
|
||||
impctx := importer.Config{
|
||||
Build: &build.Default,
|
||||
SourceImports: true,
|
||||
}
|
||||
// TODO(adonovan): make go/types choose its default Sizes from
|
||||
// build.Default or a specified *build.Context.
|
||||
var wordSize int64 = 8
|
||||
|
@ -103,7 +106,7 @@ func main() {
|
|||
case 'N':
|
||||
mode |= ssa.NaiveForm
|
||||
case 'G':
|
||||
impctx.Build = nil
|
||||
impctx.SourceImports = false
|
||||
case 'L':
|
||||
mode |= ssa.BuildSerially
|
||||
default:
|
||||
|
@ -147,8 +150,8 @@ func main() {
|
|||
|
||||
// The interpreter needs the runtime package.
|
||||
if *runFlag {
|
||||
if _, err := imp.LoadPackage("runtime"); err != nil {
|
||||
log.Fatalf("LoadPackage(runtime) failed: %s", err)
|
||||
if _, err := imp.ImportPackage("runtime"); err != nil {
|
||||
log.Fatalf("ImportPackage(runtime) failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ import (
|
|||
"go/token"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"code.google.com/p/go.tools/astutil"
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
|
@ -61,12 +60,10 @@ import (
|
|||
// An Importer's exported methods are not thread-safe.
|
||||
type Importer struct {
|
||||
Fset *token.FileSet // position info for all files seen
|
||||
config *Config // the client configuration, unmodified
|
||||
Config *Config // the client configuration, unmodified
|
||||
importfn types.Importer // client's type import function
|
||||
augment map[string]bool // packages to be augmented by TestFiles when imported
|
||||
allPackagesMu sync.Mutex // guards 'allPackages' during internal concurrency
|
||||
srcpkgs map[string]bool // for each package to load from source, whether to augment
|
||||
allPackages []*PackageInfo // all packages, including non-importable ones
|
||||
importedMu sync.Mutex // guards 'imported'
|
||||
imported map[string]*importInfo // all imported packages (incl. failures) by import path
|
||||
}
|
||||
|
||||
|
@ -75,17 +72,15 @@ type importInfo struct {
|
|||
path string // import path
|
||||
info *PackageInfo // results of typechecking (including type errors)
|
||||
err error // reason for failure to construct a package
|
||||
ready chan struct{} // channel close is notification of ready state
|
||||
}
|
||||
|
||||
// Config specifies the configuration for the importer.
|
||||
// The zero value for Config is a ready-to-use default configuration.
|
||||
type Config struct {
|
||||
// TypeChecker contains options relating to the type checker.
|
||||
//
|
||||
// The supplied IgnoreFuncBodies is not used; the effective
|
||||
// value comes from the TypeCheckFuncBodies func below.
|
||||
//
|
||||
// All callbacks must be thread-safe.
|
||||
TypeChecker types.Config
|
||||
|
||||
// TypeCheckFuncBodies is a predicate over package import
|
||||
|
@ -94,23 +89,35 @@ type Config struct {
|
|||
// its function bodies; this can be used to quickly load
|
||||
// dependencies from source. If nil, all func bodies are type
|
||||
// checked.
|
||||
//
|
||||
// Must be thread-safe.
|
||||
//
|
||||
TypeCheckFuncBodies func(string) bool
|
||||
|
||||
// If Build is non-nil, it is used to satisfy imports.
|
||||
// SourceImports determines whether to satisfy all imports by
|
||||
// loading Go source code.
|
||||
//
|
||||
// If it is nil, binary object files produced by the gc
|
||||
// compiler will be loaded instead of source code for all
|
||||
// imported packages. Such files supply only the types of
|
||||
// If false, the TypeChecker.Import mechanism will be used
|
||||
// instead. Since that typically supplies only the types of
|
||||
// package-level declarations and values of constants, but no
|
||||
// code, so this mode will not yield a whole program. It is
|
||||
// intended for analyses that perform intraprocedural analysis
|
||||
// of a single package.
|
||||
// code, it will not yield a whole program. It is intended
|
||||
// for analyses that perform intraprocedural analysis of a
|
||||
// single package.
|
||||
//
|
||||
// The importer's initial packages are always loaded from
|
||||
// source, regardless of this flag's setting.
|
||||
SourceImports bool
|
||||
|
||||
// If Build is non-nil, it is used to locate source packages.
|
||||
// Otherwise &build.Default is used.
|
||||
Build *build.Context
|
||||
}
|
||||
|
||||
// build returns the effective build context.
|
||||
func (c *Config) build() *build.Context {
|
||||
if c.Build != nil {
|
||||
return c.Build
|
||||
}
|
||||
return &build.Default
|
||||
}
|
||||
|
||||
// New returns a new, empty Importer using configuration options
|
||||
// specified by config.
|
||||
//
|
||||
|
@ -129,27 +136,27 @@ func New(config *Config) *Importer {
|
|||
|
||||
imp := &Importer{
|
||||
Fset: token.NewFileSet(),
|
||||
config: config,
|
||||
Config: config,
|
||||
importfn: importfn,
|
||||
augment: make(map[string]bool),
|
||||
srcpkgs: make(map[string]bool),
|
||||
imported: make(map[string]*importInfo),
|
||||
}
|
||||
return imp
|
||||
}
|
||||
|
||||
// AllPackages returns a new slice containing all packages loaded by
|
||||
// importer imp.
|
||||
// AllPackages returns a new slice containing all complete packages
|
||||
// loaded by importer imp.
|
||||
//
|
||||
// This returns only packages that were loaded from source or directly
|
||||
// imported from a source package. It does not include packages
|
||||
// indirectly referenced by a binary package; they are found in
|
||||
// config.TypeChecker.Packages.
|
||||
// TODO(adonovan): rethink this API.
|
||||
//
|
||||
func (imp *Importer) AllPackages() []*PackageInfo {
|
||||
return append([]*PackageInfo(nil), imp.allPackages...)
|
||||
}
|
||||
|
||||
func (imp *Importer) addPackage(info *PackageInfo) {
|
||||
imp.allPackagesMu.Lock()
|
||||
imp.allPackages = append(imp.allPackages, info)
|
||||
imp.allPackagesMu.Unlock()
|
||||
}
|
||||
|
||||
// doImport imports the package denoted by path.
|
||||
// It implements the types.Importer prototype.
|
||||
//
|
||||
|
@ -163,40 +170,7 @@ func (imp *Importer) addPackage(info *PackageInfo) {
|
|||
// the types.Config.Error callback (the first of which is also saved
|
||||
// in the package's PackageInfo).
|
||||
//
|
||||
// Idempotent and thread-safe.
|
||||
//
|
||||
//
|
||||
// TODO(gri): The imports map (an alias for TypeChecker.Packages) must
|
||||
// not be concurrently accessed. Today, the only (non-test) accesses
|
||||
// of this map are in the client-supplied implementation of the
|
||||
// importer function, i.e. the function below. But this is a fragile
|
||||
// API because if go/types ever starts to access this map, it and its
|
||||
// clients will have to agree to use the same mutex.
|
||||
// Two better ideas:
|
||||
//
|
||||
// (1) require that the importer functions be stateful and have this
|
||||
// map be part of that internal state.
|
||||
// Pro: good encapsulation.
|
||||
// Con: we can't have different importers collaborate, e.g.
|
||||
// we can't use a source importer for some packages and
|
||||
// GcImport for others since they'd each have a distinct map.
|
||||
//
|
||||
// (2) have there be a single map in go/types.Config, but expose
|
||||
// lookup and update behind an interface and pass that interface
|
||||
// to the importer implementations.
|
||||
// Pro: sharing of the map among importers.
|
||||
//
|
||||
// This is idempotent but still doesn't address the issue of
|
||||
// atomicity: when loading packages concurrently, we want to avoid
|
||||
// the benign but suboptimal situation of two goroutines both
|
||||
// importing "fmt", finding it not present, doing all the work, and
|
||||
// double-updating the map.
|
||||
// The interface to the map needs to express the idea that when a
|
||||
// caller requests an import from the map and finds it not present,
|
||||
// then it (and no other goroutine) becomes responsible for loading
|
||||
// the package and updating the map; other goroutines should block
|
||||
// until then. That's exactly what doImport0 below does; I think
|
||||
// some of that logic should migrate into go/types.check.resolveFiles.
|
||||
// Idempotent.
|
||||
//
|
||||
func (imp *Importer) doImport(imports map[string]*types.Package, path string) (*types.Package, error) {
|
||||
// Package unsafe is handled specially, and has no PackageInfo.
|
||||
|
@ -205,99 +179,67 @@ func (imp *Importer) doImport(imports map[string]*types.Package, path string) (*
|
|||
return types.Unsafe, nil
|
||||
}
|
||||
|
||||
info, err := imp.doImport0(imports, path)
|
||||
info, err := imp.ImportPackage(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if imports != nil {
|
||||
// Update the package's imports map, whether success or failure.
|
||||
//
|
||||
// types.Package.Imports() is used by PackageInfo.Imports and
|
||||
// thence by ssa.builder.
|
||||
// TODO(gri): given that it doesn't specify whether it
|
||||
// contains direct or transitive dependencies, it probably
|
||||
// shouldn't be exposed. This package can make its own
|
||||
// arrangements to implement PackageInfo.Imports().
|
||||
importsMu.Lock()
|
||||
// Update the type checker's package map on success.
|
||||
imports[path] = info.Pkg
|
||||
importsMu.Unlock()
|
||||
}
|
||||
|
||||
return info.Pkg, nil
|
||||
}
|
||||
|
||||
var importsMu sync.Mutex // hack; see comment at doImport
|
||||
|
||||
// Like doImport, but returns a PackageInfo.
|
||||
// ImportPackage imports the package whose import path is path, plus
|
||||
// its necessary dependencies.
|
||||
//
|
||||
// Precondition: path != "unsafe".
|
||||
func (imp *Importer) doImport0(imports map[string]*types.Package, path string) (*PackageInfo, error) {
|
||||
imp.importedMu.Lock()
|
||||
//
|
||||
func (imp *Importer) ImportPackage(path string) (*PackageInfo, error) {
|
||||
ii, ok := imp.imported[path]
|
||||
if !ok {
|
||||
ii = &importInfo{path: path, ready: make(chan struct{})}
|
||||
ii = &importInfo{path: path}
|
||||
imp.imported[path] = ii
|
||||
}
|
||||
imp.importedMu.Unlock()
|
||||
|
||||
if !ok {
|
||||
// Find and create the actual package.
|
||||
if imp.config.Build != nil {
|
||||
imp.importSource(path, ii)
|
||||
if augment, ok := imp.srcpkgs[ii.path]; ok || imp.Config.SourceImports {
|
||||
which := "g" // load *.go files
|
||||
if augment {
|
||||
which = "gt" // augment package by in-package *_test.go files
|
||||
}
|
||||
imp.loadFromSource(ii, which)
|
||||
} else {
|
||||
imp.importBinary(imports, ii)
|
||||
imp.loadFromBinary(ii)
|
||||
}
|
||||
if ii.info != nil {
|
||||
ii.info.Importable = true
|
||||
}
|
||||
|
||||
close(ii.ready) // enter ready state and wake up waiters
|
||||
} else {
|
||||
<-ii.ready // wait for ready condition
|
||||
}
|
||||
|
||||
// Invariant: ii is ready.
|
||||
|
||||
return ii.info, ii.err
|
||||
}
|
||||
|
||||
// importBinary implements package loading from the client-supplied
|
||||
// loadFromBinary implements package loading from the client-supplied
|
||||
// external source, e.g. object files from the gc compiler.
|
||||
//
|
||||
func (imp *Importer) importBinary(imports map[string]*types.Package, ii *importInfo) {
|
||||
pkg, err := imp.importfn(imports, ii.path)
|
||||
func (imp *Importer) loadFromBinary(ii *importInfo) {
|
||||
pkg, err := imp.importfn(imp.Config.TypeChecker.Packages, ii.path)
|
||||
if pkg != nil {
|
||||
ii.info = &PackageInfo{Pkg: pkg}
|
||||
imp.addPackage(ii.info)
|
||||
imp.allPackages = append(imp.allPackages, ii.info)
|
||||
} else {
|
||||
ii.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// importSource implements package loading by parsing Go source files
|
||||
// located by go/build.
|
||||
// loadFromSource implements package loading by parsing Go source files
|
||||
// located by go/build. which indicates which files to include in the
|
||||
// package.
|
||||
//
|
||||
func (imp *Importer) importSource(path string, ii *importInfo) {
|
||||
which := "g" // load *.go files
|
||||
if imp.augment[path] {
|
||||
which = "gt" // augment package by in-package *_test.go files
|
||||
}
|
||||
if files, err := parsePackageFiles(imp.config.Build, imp.Fset, path, which); err == nil {
|
||||
// Prefetch the imports asynchronously.
|
||||
for path := range importsOf(path, files) {
|
||||
go func(path string) { imp.doImport(nil, path) }(path)
|
||||
}
|
||||
|
||||
func (imp *Importer) loadFromSource(ii *importInfo, which string) {
|
||||
if files, err := parsePackageFiles(imp.Config.build(), imp.Fset, ii.path, which); err == nil {
|
||||
// Type-check the package.
|
||||
ii.info = imp.CreatePackage(path, files...)
|
||||
|
||||
// We needn't wait for the prefetching goroutines to
|
||||
// finish. Each one either runs quickly and populates
|
||||
// the imported map, in which case the type checker
|
||||
// will wait for the map entry to become ready; or, it
|
||||
// runs slowly, even after we return, but then becomes
|
||||
// just another map waiter, in which case it won't
|
||||
// mutate anything.
|
||||
ii.info = imp.CreatePackage(ii.path, files...)
|
||||
} else {
|
||||
ii.err = err
|
||||
}
|
||||
|
@ -335,9 +277,9 @@ func (imp *Importer) CreatePackage(path string, files ...*ast.File) *PackageInfo
|
|||
}
|
||||
|
||||
// Use a copy of the types.Config so we can vary IgnoreFuncBodies.
|
||||
tc := imp.config.TypeChecker
|
||||
tc := imp.Config.TypeChecker
|
||||
tc.IgnoreFuncBodies = false
|
||||
if f := imp.config.TypeCheckFuncBodies; f != nil {
|
||||
if f := imp.Config.TypeCheckFuncBodies; f != nil {
|
||||
tc.IgnoreFuncBodies = !f(path)
|
||||
}
|
||||
if tc.Error == nil {
|
||||
|
@ -345,7 +287,7 @@ func (imp *Importer) CreatePackage(path string, files ...*ast.File) *PackageInfo
|
|||
}
|
||||
tc.Import = imp.doImport // doImport wraps the user's importfn, effectively
|
||||
info.Pkg, info.Err = tc.Check(path, imp.Fset, files, &info.Info)
|
||||
imp.addPackage(info)
|
||||
imp.allPackages = append(imp.allPackages, info)
|
||||
return info
|
||||
}
|
||||
|
||||
|
@ -418,6 +360,7 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
|
|||
|
||||
// Pass 1: parse the sets of files for each package.
|
||||
var pkgs []*initialPkg
|
||||
var seenAugmented bool
|
||||
for len(args) > 0 {
|
||||
arg := args[0]
|
||||
args = args[1:]
|
||||
|
@ -444,28 +387,24 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
|
|||
continue // ignore; has no PackageInfo
|
||||
}
|
||||
|
||||
pkg := &initialPkg{
|
||||
pkgs = append(pkgs, &initialPkg{
|
||||
path: path,
|
||||
importable: true,
|
||||
}
|
||||
pkgs = append(pkgs, pkg)
|
||||
})
|
||||
imp.srcpkgs[path] = false // unaugmented source package
|
||||
|
||||
if path != arg {
|
||||
continue // had "notest:" prefix
|
||||
}
|
||||
|
||||
if imp.config.Build == nil {
|
||||
continue // can't locate *_test.go files
|
||||
}
|
||||
|
||||
// TODO(adonovan): due to limitations of the current type
|
||||
// checker design, we can augment at most one package.
|
||||
if len(imp.augment) > 0 {
|
||||
if seenAugmented {
|
||||
continue // don't attempt a second
|
||||
}
|
||||
|
||||
// Load the external test package.
|
||||
xtestFiles, err := parsePackageFiles(imp.config.Build, imp.Fset, path, "x")
|
||||
xtestFiles, err := parsePackageFiles(imp.Config.build(), imp.Fset, path, "x")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -479,24 +418,22 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
|
|||
|
||||
// Mark the non-xtest package for augmentation with
|
||||
// in-package *_test.go files when we import it below.
|
||||
imp.augment[pkg.path] = true
|
||||
imp.srcpkgs[path] = true
|
||||
seenAugmented = true
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: type-check each set of files to make a package.
|
||||
var infos []*PackageInfo
|
||||
imports := make(map[string]*types.Package) // keep importBinary happy
|
||||
for _, pkg := range pkgs {
|
||||
var info *PackageInfo
|
||||
if pkg.importable {
|
||||
// import package
|
||||
var err error
|
||||
info, err = imp.doImport0(imports, pkg.path)
|
||||
info, err = imp.ImportPackage(pkg.path)
|
||||
if err != nil {
|
||||
return nil, nil, err // e.g. parse error (but not type error)
|
||||
}
|
||||
} else {
|
||||
// create package
|
||||
info = imp.CreatePackage(pkg.path, pkg.files...)
|
||||
}
|
||||
infos = append(infos, info)
|
||||
|
@ -509,17 +446,9 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
|
|||
return infos, args, nil
|
||||
}
|
||||
|
||||
// LoadPackage loads and type-checks the package whose import path is
|
||||
// path, plus its necessary dependencies.
|
||||
//
|
||||
func (imp *Importer) LoadPackage(path string) (*PackageInfo, error) {
|
||||
imports := make(map[string]*types.Package) // keep importBinary happy
|
||||
return imp.doImport0(imports, path)
|
||||
}
|
||||
|
||||
type initialPkg struct {
|
||||
path string // the package's import path
|
||||
importable bool // add package to import map false for main and xtests)
|
||||
importable bool // add package to import map (false for main and xtests)
|
||||
files []*ast.File // set of files (non-importable packages only)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,18 +6,15 @@ package importer_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/importer"
|
||||
)
|
||||
|
||||
func TestLoadInitialPackages(t *testing.T) {
|
||||
ctxt := &importer.Config{Build: &build.Default}
|
||||
|
||||
// Failed load: bad first import path causes parsePackageFiles to fail.
|
||||
args := []string{"nosuchpkg", "errors"}
|
||||
if _, _, err := importer.New(ctxt).LoadInitialPackages(args); err == nil {
|
||||
if _, _, err := importer.New(&importer.Config{}).LoadInitialPackages(args); err == nil {
|
||||
t.Errorf("LoadInitialPackages(%q) succeeded, want failure", args)
|
||||
} else {
|
||||
// cannot find package: ok.
|
||||
|
@ -25,7 +22,7 @@ func TestLoadInitialPackages(t *testing.T) {
|
|||
|
||||
// Failed load: bad second import path proceeds to doImport0, which fails.
|
||||
args = []string{"errors", "nosuchpkg"}
|
||||
if _, _, err := importer.New(ctxt).LoadInitialPackages(args); err == nil {
|
||||
if _, _, err := importer.New(&importer.Config{}).LoadInitialPackages(args); err == nil {
|
||||
t.Errorf("LoadInitialPackages(%q) succeeded, want failure", args)
|
||||
} else {
|
||||
// cannot find package: ok
|
||||
|
@ -33,7 +30,7 @@ func TestLoadInitialPackages(t *testing.T) {
|
|||
|
||||
// Successful load.
|
||||
args = []string{"fmt", "errors", "testdata/a.go,testdata/b.go", "--", "surplus"}
|
||||
imp := importer.New(ctxt)
|
||||
imp := importer.New(&importer.Config{})
|
||||
infos, rest, err := imp.LoadInitialPackages(args)
|
||||
if err != nil {
|
||||
t.Errorf("LoadInitialPackages(%q) failed: %s", args, err)
|
||||
|
|
|
@ -82,7 +82,7 @@ func TestEnclosingFunction(t *testing.T) {
|
|||
"900", "func@2.27"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
imp := importer.New(new(importer.Config)) // (NB: no go/build.Config)
|
||||
imp := importer.New(&importer.Config{})
|
||||
f, start, end := findInterval(t, imp.Fset, test.input, test.substr)
|
||||
if f == nil {
|
||||
continue
|
||||
|
|
|
@ -192,7 +192,7 @@ func (res *Result) Serial() *serial.Result {
|
|||
// Clients that intend to perform multiple queries against the same
|
||||
// analysis scope should use this pattern instead:
|
||||
//
|
||||
// imp := importer.New(&importer.Config{Build: buildContext})
|
||||
// imp := importer.New(&importer.Config{Build: buildContext, SourceImports: true})
|
||||
// o, err := oracle.New(imp, args, nil)
|
||||
// if err != nil { ... }
|
||||
// for ... {
|
||||
|
@ -219,7 +219,7 @@ func Query(args []string, mode, pos string, ptalog io.Writer, buildContext *buil
|
|||
return nil, fmt.Errorf("invalid mode type: %q", mode)
|
||||
}
|
||||
|
||||
impcfg := importer.Config{Build: buildContext}
|
||||
impcfg := importer.Config{Build: buildContext, SourceImports: true}
|
||||
|
||||
// For queries needing only a single typed package,
|
||||
// reduce the analysis scope to that package.
|
||||
|
|
|
@ -6,7 +6,6 @@ package pointer_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"sort"
|
||||
|
||||
|
@ -41,8 +40,7 @@ func main() {
|
|||
}
|
||||
`
|
||||
// Construct an importer.
|
||||
// Imports will be loaded as if by 'go build'.
|
||||
imp := importer.New(&importer.Config{Build: &build.Default})
|
||||
imp := importer.New(&importer.Config{SourceImports: true})
|
||||
|
||||
// Parse the input file.
|
||||
file, err := parser.ParseFile(imp.Fset, "myprog.go", myprog, 0)
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
|
@ -152,7 +151,7 @@ func findProbe(prog *ssa.Program, probes map[*ssa.CallCommon]pointer.Pointer, e
|
|||
}
|
||||
|
||||
func doOneInput(input, filename string) bool {
|
||||
impctx := &importer.Config{Build: &build.Default}
|
||||
impctx := &importer.Config{SourceImports: true}
|
||||
imp := importer.New(impctx)
|
||||
|
||||
// Parsing.
|
||||
|
|
|
@ -810,9 +810,6 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
|||
c.Method = obj
|
||||
} else {
|
||||
// "Call"-mode call.
|
||||
// TODO(adonovan): fix: in -build=G
|
||||
// mode, declaredFunc panics for
|
||||
// cross-package calls.
|
||||
c.Value = fn.Prog.declaredFunc(obj)
|
||||
c.Args = append(c.Args, v)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func main() {
|
|||
w.Write(nil) // interface invoke of external declared method
|
||||
}
|
||||
`
|
||||
imp := importer.New(new(importer.Config)) // no go/build.Context; uses GC importer
|
||||
imp := importer.New(&importer.Config{})
|
||||
|
||||
f, err := parser.ParseFile(imp.Fset, "<input>", test, 0)
|
||||
if err != nil {
|
||||
|
@ -58,10 +58,16 @@ func main() {
|
|||
mainPkg := prog.Package(mainInfo.Pkg)
|
||||
mainPkg.Build()
|
||||
|
||||
// Only the main package and its immediate dependencies are loaded.
|
||||
deps := []string{"bytes", "io", "testing"}
|
||||
// The main package, its direct and indirect dependencies are loaded.
|
||||
deps := []string{
|
||||
// directly imported dependencies:
|
||||
"bytes", "io", "testing",
|
||||
// indirect dependencies (partial list):
|
||||
"errors", "fmt", "os", "runtime",
|
||||
}
|
||||
|
||||
all := prog.AllPackages()
|
||||
if len(all) != 1+len(deps) {
|
||||
if len(all) <= len(deps) {
|
||||
t.Errorf("unexpected set of loaded packages: %q", all)
|
||||
}
|
||||
for _, path := range deps {
|
||||
|
@ -198,7 +204,7 @@ func TestTypesWithMethodSets(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
imp := importer.New(new(importer.Config)) // no go/build.Context; uses GC importer
|
||||
imp := importer.New(&importer.Config{})
|
||||
|
||||
f, err := parser.ParseFile(imp.Fset, "<input>", test.input, 0)
|
||||
if err != nil {
|
||||
|
|
|
@ -250,6 +250,8 @@ func (prog *Program) CreatePackage(info *importer.PackageInfo) *Package {
|
|||
//
|
||||
func (prog *Program) CreatePackages(imp *importer.Importer) error {
|
||||
var errpkgs []string
|
||||
|
||||
// Create source packages and directly imported packages.
|
||||
for _, info := range imp.AllPackages() {
|
||||
if info.Err != nil {
|
||||
errpkgs = append(errpkgs, info.Pkg.Path())
|
||||
|
@ -257,6 +259,15 @@ func (prog *Program) CreatePackages(imp *importer.Importer) error {
|
|||
prog.CreatePackage(info)
|
||||
}
|
||||
}
|
||||
|
||||
// Create indirectly imported packages.
|
||||
for _, obj := range imp.Config.TypeChecker.Packages {
|
||||
prog.CreatePackage(&importer.PackageInfo{
|
||||
Pkg: obj,
|
||||
Importable: true,
|
||||
})
|
||||
}
|
||||
|
||||
if errpkgs != nil {
|
||||
return fmt.Errorf("couldn't create these SSA packages due to type errors: %s",
|
||||
strings.Join(errpkgs, ", "))
|
||||
|
|
|
@ -6,7 +6,6 @@ package ssa_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"os"
|
||||
|
||||
|
@ -42,8 +41,8 @@ func main() {
|
|||
fmt.Println(message)
|
||||
}
|
||||
`
|
||||
// Construct an importer. Imports will be loaded as if by 'go build'.
|
||||
imp := importer.New(&importer.Config{Build: &build.Default})
|
||||
// Construct an importer.
|
||||
imp := importer.New(&importer.Config{})
|
||||
|
||||
// Parse the input file.
|
||||
file, err := parser.ParseFile(imp.Fset, "hello.go", hello, 0)
|
||||
|
|
|
@ -168,7 +168,7 @@ func run(t *testing.T, dir, input string, success successPredicate) bool {
|
|||
inputs = append(inputs, dir+i)
|
||||
}
|
||||
|
||||
imp := importer.New(&importer.Config{Build: &build.Default})
|
||||
imp := importer.New(&importer.Config{SourceImports: true})
|
||||
// TODO(adonovan): use LoadInitialPackages, then un-export ParseFiles.
|
||||
// Then add the following packages' tests, which pass:
|
||||
// "flag", "unicode", "unicode/utf8", "testing", "log", "path".
|
||||
|
@ -194,8 +194,8 @@ func run(t *testing.T, dir, input string, success successPredicate) bool {
|
|||
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
|
||||
mainInfo := imp.CreatePackage(files[0].Name.Name, files...)
|
||||
|
||||
if _, err := imp.LoadPackage("runtime"); err != nil {
|
||||
t.Errorf("LoadPackage(runtime) failed: %s", err)
|
||||
if _, err := imp.ImportPackage("runtime"); err != nil {
|
||||
t.Errorf("ImportPackage(runtime) failed: %s", err)
|
||||
}
|
||||
|
||||
prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
|
||||
|
@ -321,7 +321,7 @@ func TestTestmainPackage(t *testing.T) {
|
|||
|
||||
// CreateTestMainPackage should return nil if there were no tests.
|
||||
func TestNullTestmainPackage(t *testing.T) {
|
||||
imp := importer.New(&importer.Config{Build: &build.Default})
|
||||
imp := importer.New(&importer.Config{})
|
||||
files, err := importer.ParseFiles(imp.Fset, ".", "testdata/b_test.go")
|
||||
if err != nil {
|
||||
t.Fatalf("ParseFiles failed: %s", err)
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
)
|
||||
|
||||
func TestObjValueLookup(t *testing.T) {
|
||||
imp := importer.New(new(importer.Config)) // (uses GCImporter)
|
||||
imp := importer.New(&importer.Config{})
|
||||
f, err := parser.ParseFile(imp.Fset, "testdata/objlookup.go", nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -186,7 +186,7 @@ func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.
|
|||
// Ensure that, in debug mode, we can determine the ssa.Value
|
||||
// corresponding to every ast.Expr.
|
||||
func TestValueForExpr(t *testing.T) {
|
||||
imp := importer.New(new(importer.Config)) // (uses GCImporter)
|
||||
imp := importer.New(&importer.Config{})
|
||||
f, err := parser.ParseFile(imp.Fset, "testdata/valueforexpr.go", nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
func TestSwitches(t *testing.T) {
|
||||
imp := importer.New(new(importer.Config)) // (uses GCImporter)
|
||||
imp := importer.New(&importer.Config{})
|
||||
f, err := parser.ParseFile(imp.Fset, "testdata/switches.go", nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
|
|
@ -10,7 +10,6 @@ package ssa_test
|
|||
// Run test with GOMAXPROCS=8.
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -52,12 +51,10 @@ func allPackages() []string {
|
|||
}
|
||||
|
||||
func TestStdlib(t *testing.T) {
|
||||
impctx := importer.Config{Build: &build.Default}
|
||||
|
||||
// Load, parse and type-check the program.
|
||||
t0 := time.Now()
|
||||
|
||||
imp := importer.New(&impctx)
|
||||
imp := importer.New(&importer.Config{})
|
||||
|
||||
if _, _, err := imp.LoadInitialPackages(allPackages()); err != nil {
|
||||
t.Errorf("LoadInitialPackages failed: %s", err)
|
||||
|
|
Loading…
Reference in New Issue