go.tools/importer: honor the client's TypeChecker.{Import,Error} values.

This requires us to make a copy of (not clobber) the supplied
config, and retain their Import hook separately so that it can
be wrapped by Importer.doImport.

Fixes bug 6562.

R=gri
CC=golang-dev
https://golang.org/cl/14523054
This commit is contained in:
Alan Donovan 2013-10-10 13:34:24 -04:00
parent e1e9089196
commit 548052f0fa
1 changed files with 20 additions and 10 deletions

View File

@ -56,10 +56,14 @@ import (
"code.google.com/p/go.tools/go/types" "code.google.com/p/go.tools/go/types"
) )
// Alias for type of types.Config.Import function.
type importfn func(map[string]*types.Package, string) (*types.Package, error)
// An Importer's exported methods are not thread-safe. // An Importer's exported methods are not thread-safe.
type Importer struct { type Importer struct {
Fset *token.FileSet // position info for all files seen Fset *token.FileSet // position info for all files seen
config *Config // the client configuration config Config // the client configuration, modified by us
importfn importfn // client's type import function
augment map[string]bool // packages to be augmented by TestFiles when imported augment map[string]bool // packages to be augmented by TestFiles when imported
allPackagesMu sync.Mutex // guards 'allPackages' during internal concurrency allPackagesMu sync.Mutex // guards 'allPackages' during internal concurrency
allPackages []*PackageInfo // all packages, including non-importable ones allPackages []*PackageInfo // all packages, including non-importable ones
@ -78,9 +82,7 @@ type importInfo struct {
// Config specifies the configuration for the importer. // Config specifies the configuration for the importer.
type Config struct { type Config struct {
// TypeChecker contains options relating to the type checker. // TypeChecker contains options relating to the type checker.
// The Importer will override any user-supplied values for its // All callbacks must be thread-safe.
// Error and Import fields; other fields will be passed
// through to the type checker. All callbacks must be thread-safe.
TypeChecker types.Config TypeChecker types.Config
// If Build is non-nil, it is used to satisfy imports. // If Build is non-nil, it is used to satisfy imports.
@ -99,17 +101,25 @@ type Config struct {
// specified by config. // specified by config.
// //
func New(config *Config) *Importer { func New(config *Config) *Importer {
importfn := config.TypeChecker.Import
if importfn == nil {
importfn = types.GcImport
}
imp := &Importer{ imp := &Importer{
Fset: token.NewFileSet(), Fset: token.NewFileSet(),
config: config, config: *config, // copy (don't clobber client input)
importfn: importfn,
augment: make(map[string]bool), augment: make(map[string]bool),
imported: make(map[string]*importInfo), imported: make(map[string]*importInfo),
} }
// TODO(adonovan): get typechecker to supply us with a source // TODO(adonovan): get typechecker to supply us with a source
// position, then pass errors back to the application // position, then pass errors back to the application
// (e.g. oracle). // (e.g. oracle).
imp.config.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) } if imp.config.TypeChecker.Error == nil {
imp.config.TypeChecker.Import = imp.doImport imp.config.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
}
imp.config.TypeChecker.Import = imp.doImport // wraps importfn, effectively
return imp return imp
} }
@ -201,11 +211,11 @@ func (imp *Importer) doImport0(imports map[string]*types.Package, path string) (
return ii.info, ii.err return ii.info, ii.err
} }
// importBinary implements package loading from object files from the // importBinary implements package loading from the client-supplied
// gc compiler. // external source, e.g. object files from the gc compiler.
// //
func (imp *Importer) importBinary(imports map[string]*types.Package, ii *importInfo) { func (imp *Importer) importBinary(imports map[string]*types.Package, ii *importInfo) {
pkg, err := types.GcImport(imports, ii.path) pkg, err := imp.importfn(imports, ii.path)
if pkg != nil { if pkg != nil {
ii.info = &PackageInfo{Pkg: pkg} ii.info = &PackageInfo{Pkg: pkg}
imp.addPackage(ii.info) imp.addPackage(ii.info)