importer.go

 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
 5package gcexportdata
 6
 7import (
 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//
26func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom {
27	return importer{fset, imports}
28}
29
30type importer struct {
31	fset    *token.FileSet
32	imports map[string]*types.Package
33}
34
35func (imp importer) Import(importPath string) (*types.Package, error) {
36	return imp.ImportFrom(importPath, "", 0)
37}
38
39func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) {
40	filename, path := Find(importPath, srcDir)
41	if filename == "" {
42		if importPath == "unsafe" {
43			// Even for unsafe, call Find first in case
44			// the package was vendored.
45			return types.Unsafe, nil
46		}
47		return nil, fmt.Errorf("can't find import: %s", importPath)
48	}
49
50	if pkg, ok := imp.imports[path]; ok && pkg.Complete() {
51		return pkg, nil // cache hit
52	}
53
54	// open file
55	f, err := os.Open(filename)
56	if err != nil {
57		return nil, err
58	}
59	defer func() {
60		f.Close()
61		if err != nil {
62			// add file name to error
63			err = fmt.Errorf("reading export data: %s: %v", filename, err)
64		}
65	}()
66
67	r, err := NewReader(f)
68	if err != nil {
69		return nil, err
70	}
71
72	return Read(r, imp.fset, imp.imports, path)
73}