.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / internal / go / gcimporter / gcimporter.go
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 modified copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go,
6 // but it also contains the original source-based importer code for Go1.6.
7 // Once we stop supporting 1.6, we can remove that code.
8
9 // Package gcimporter provides various functions for reading
10 // gc-generated object files that can be used to implement the
11 // Importer interface defined by the Go 1.5 standard library package.
12 package gcimporter
13
14 import (
15         "bufio"
16         "fmt"
17         "go/build"
18         "go/token"
19         "go/types"
20         "io"
21         "io/ioutil"
22         "os"
23         "path/filepath"
24         "strings"
25 )
26
27 var pkgExts = [...]string{".a", ".o"}
28
29 // FindPkg returns the filename and unique package id for an import
30 // path based on package information provided by build.Import (using
31 // the build.Default build.Context). A relative srcDir is interpreted
32 // relative to the current working directory.
33 // If no file was found, an empty filename is returned.
34 //
35 func FindPkg(path, srcDir string) (filename, id string) {
36         if path == "" {
37                 return
38         }
39
40         var noext string
41         switch {
42         default:
43                 // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
44                 // Don't require the source files to be present.
45                 if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
46                         srcDir = abs
47                 }
48                 bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
49                 if bp.PkgObj == "" {
50                         id = path // make sure we have an id to print in error message
51                         return
52                 }
53                 noext = strings.TrimSuffix(bp.PkgObj, ".a")
54                 id = bp.ImportPath
55
56         case build.IsLocalImport(path):
57                 // "./x" -> "/this/directory/x.ext", "/this/directory/x"
58                 noext = filepath.Join(srcDir, path)
59                 id = noext
60
61         case filepath.IsAbs(path):
62                 // for completeness only - go/build.Import
63                 // does not support absolute imports
64                 // "/x" -> "/x.ext", "/x"
65                 noext = path
66                 id = path
67         }
68
69         if false { // for debugging
70                 if path != id {
71                         fmt.Printf("%s -> %s\n", path, id)
72                 }
73         }
74
75         // try extensions
76         for _, ext := range pkgExts {
77                 filename = noext + ext
78                 if f, err := os.Stat(filename); err == nil && !f.IsDir() {
79                         return
80                 }
81         }
82
83         filename = "" // not found
84         return
85 }
86
87 // Import imports a gc-generated package given its import path and srcDir, adds
88 // the corresponding package object to the packages map, and returns the object.
89 // The packages map must contain all packages already imported.
90 //
91 func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
92         var rc io.ReadCloser
93         var filename, id string
94         if lookup != nil {
95                 // With custom lookup specified, assume that caller has
96                 // converted path to a canonical import path for use in the map.
97                 if path == "unsafe" {
98                         return types.Unsafe, nil
99                 }
100                 id = path
101
102                 // No need to re-import if the package was imported completely before.
103                 if pkg = packages[id]; pkg != nil && pkg.Complete() {
104                         return
105                 }
106                 f, err := lookup(path)
107                 if err != nil {
108                         return nil, err
109                 }
110                 rc = f
111         } else {
112                 filename, id = FindPkg(path, srcDir)
113                 if filename == "" {
114                         if path == "unsafe" {
115                                 return types.Unsafe, nil
116                         }
117                         return nil, fmt.Errorf("can't find import: %q", id)
118                 }
119
120                 // no need to re-import if the package was imported completely before
121                 if pkg = packages[id]; pkg != nil && pkg.Complete() {
122                         return
123                 }
124
125                 // open file
126                 f, err := os.Open(filename)
127                 if err != nil {
128                         return nil, err
129                 }
130                 defer func() {
131                         if err != nil {
132                                 // add file name to error
133                                 err = fmt.Errorf("%s: %v", filename, err)
134                         }
135                 }()
136                 rc = f
137         }
138         defer rc.Close()
139
140         var hdr string
141         buf := bufio.NewReader(rc)
142         if hdr, _, err = findExportData(buf); err != nil {
143                 return
144         }
145
146         switch hdr {
147         case "$$B\n":
148                 var data []byte
149                 data, err = ioutil.ReadAll(buf)
150                 if err != nil {
151                         break
152                 }
153
154                 // TODO(gri): allow clients of go/importer to provide a FileSet.
155                 // Or, define a new standard go/types/gcexportdata package.
156                 fset := token.NewFileSet()
157
158                 // The indexed export format starts with an 'i'.
159                 if len(data) == 0 || data[0] != 'i' {
160                         return nil, fmt.Errorf("unknown export data format %c", data[0])
161                 }
162                 _, pkg, err = IImportData(fset, packages, data[1:], id)
163
164         default:
165                 err = fmt.Errorf("unknown export data header: %q", hdr)
166         }
167
168         return
169 }
170
171 type byPath []*types.Package
172
173 func (a byPath) Len() int           { return len(a) }
174 func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
175 func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }