blob: 37a7247e26867306df8cb607c0643e0975e8ed7a [file] [log] [blame]
Alan Donovan1a954d52016-10-06 17:39:25 -04001// 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.
Russ Cox2a900562022-06-28 09:12:07 -040025//
26// Deprecated: Use the higher-level API in golang.org/x/tools/go/packages,
27// which is more efficient.
Alan Donovan1a954d52016-10-06 17:39:25 -040028func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom {
29 return importer{fset, imports}
30}
31
32type importer struct {
33 fset *token.FileSet
34 imports map[string]*types.Package
35}
36
37func (imp importer) Import(importPath string) (*types.Package, error) {
38 return imp.ImportFrom(importPath, "", 0)
39}
40
41func (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}