1 // Copyright 2011 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 // This file is a reduced copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go.
6 7 // Package gcimporter provides various functions for reading
8 // gc-generated object files that can be used to implement the
9 // Importer interface defined by the Go 1.5 standard library package.
10 //
11 // The encoding is deterministic: if the encoder is applied twice to
12 // the same types.Package data structure, both encodings are equal.
13 // This property may be important to avoid spurious changes in
14 // applications such as build systems.
15 //
16 // However, the encoder is not necessarily idempotent. Importing an
17 // exported package may yield a types.Package that, while it
18 // represents the same set of Go types as the original, may differ in
19 // the details of its internal representation. Because of these
20 // differences, re-encoding the imported package may yield a
21 // different, but equally valid, encoding of the package.
22 package gcimporter // import "golang.org/x/tools/internal/gcimporter"
23 24 import (
25 "bufio"
26 "fmt"
27 "go/token"
28 "go/types"
29 "io"
30 "os"
31 )
32 33 const (
34 // Enable debug during development: it adds some additional checks, and
35 // prevents errors from being recovered.
36 debug = false
37 38 // If trace is set, debugging output is printed to std out.
39 trace = false
40 )
41 42 // Import imports a gc-generated package given its import path and srcDir, adds
43 // the corresponding package object to the packages map, and returns the object.
44 // The packages map must contain all packages already imported.
45 //
46 // Import is only used in tests.
47 func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
48 var rc io.ReadCloser
49 var id string
50 if lookup != nil {
51 // With custom lookup specified, assume that caller has
52 // converted path to a canonical import path for use in the map.
53 if path == "unsafe" {
54 return types.Unsafe, nil
55 }
56 id = path
57 58 // No need to re-import if the package was imported completely before.
59 if pkg = packages[id]; pkg != nil && pkg.Complete() {
60 return
61 }
62 f, err := lookup(path)
63 if err != nil {
64 return nil, err
65 }
66 rc = f
67 } else {
68 var filename string
69 filename, id, err = FindPkg(path, srcDir)
70 if filename == "" {
71 if path == "unsafe" {
72 return types.Unsafe, nil
73 }
74 return nil, err
75 }
76 77 // no need to re-import if the package was imported completely before
78 if pkg = packages[id]; pkg != nil && pkg.Complete() {
79 return
80 }
81 82 // open file
83 f, err := os.Open(filename)
84 if err != nil {
85 return nil, err
86 }
87 defer func() {
88 if err != nil {
89 // add file name to error
90 err = fmt.Errorf("%s: %v", filename, err)
91 }
92 }()
93 rc = f
94 }
95 defer rc.Close()
96 97 buf := bufio.NewReader(rc)
98 data, err := ReadUnified(buf)
99 if err != nil {
100 err = fmt.Errorf("import %q: %v", path, err)
101 return
102 }
103 104 // unified: emitted by cmd/compile since go1.20.
105 _, pkg, err = UImportData(fset, packages, data, id)
106 107 return
108 }
109