importer.go raw

   1  // Copyright 2016 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package gcexportdata
   6  
   7  import (
   8  	"fmt"
   9  	"go/token"
  10  	"go/types"
  11  	"os"
  12  )
  13  
  14  // NewImporter returns a new instance of the types.Importer interface
  15  // that reads type information from export data files written by gc.
  16  // The Importer also satisfies types.ImporterFrom.
  17  //
  18  // Export data files are located using "go build" workspace conventions
  19  // and the build.Default context.
  20  //
  21  // Use this importer instead of go/importer.For("gc", ...) to avoid the
  22  // version-skew problems described in the documentation of this package,
  23  // or to control the FileSet or access the imports map populated during
  24  // package loading.
  25  //
  26  // Deprecated: Use the higher-level API in golang.org/x/tools/go/packages,
  27  // which is more efficient.
  28  func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom {
  29  	return importer{fset, imports}
  30  }
  31  
  32  type importer struct {
  33  	fset    *token.FileSet
  34  	imports map[string]*types.Package
  35  }
  36  
  37  func (imp importer) Import(importPath string) (*types.Package, error) {
  38  	return imp.ImportFrom(importPath, "", 0)
  39  }
  40  
  41  func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) {
  42  	filename, path := Find(importPath, srcDir)
  43  	if filename == "" {
  44  		if importPath == "unsafe" {
  45  			// Even for unsafe, call Find first in case
  46  			// the package was vendored.
  47  			return types.Unsafe, nil
  48  		}
  49  		return nil, fmt.Errorf("can't find import: %s", importPath)
  50  	}
  51  
  52  	if pkg, ok := imp.imports[path]; ok && pkg.Complete() {
  53  		return pkg, nil // cache hit
  54  	}
  55  
  56  	// open file
  57  	f, err := os.Open(filename)
  58  	if err != nil {
  59  		return nil, err
  60  	}
  61  	defer func() {
  62  		f.Close()
  63  		if err != nil {
  64  			// add file name to error
  65  			err = fmt.Errorf("reading export data: %s: %v", filename, err)
  66  		}
  67  	}()
  68  
  69  	r, err := NewReader(f)
  70  	if err != nil {
  71  		return nil, err
  72  	}
  73  
  74  	return Read(r, imp.fset, imp.imports, path)
  75  }
  76