.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / go / internal / gccgoimporter / importer.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/internal/gccgoimporter/importer.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/internal/gccgoimporter/importer.go
new file mode 100644 (file)
index 0000000..1094af2
--- /dev/null
@@ -0,0 +1,250 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Except for this comment and the import path, this file is a verbatim copy of the file
+// with the same name in $GOROOT/src/go/internal/gccgoimporter.
+
+// Package gccgoimporter implements Import for gccgo-generated object files.
+package gccgoimporter // import "golang.org/x/tools/go/internal/gccgoimporter"
+
+import (
+       "debug/elf"
+       "fmt"
+       "go/types"
+       "io"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+// A PackageInit describes an imported package that needs initialization.
+type PackageInit struct {
+       Name     string // short package name
+       InitFunc string // name of init function
+       Priority int    // priority of init function, see InitData.Priority
+}
+
+// The gccgo-specific init data for a package.
+type InitData struct {
+       // Initialization priority of this package relative to other packages.
+       // This is based on the maximum depth of the package's dependency graph;
+       // it is guaranteed to be greater than that of its dependencies.
+       Priority int
+
+       // The list of packages which this package depends on to be initialized,
+       // including itself if needed. This is the subset of the transitive closure of
+       // the package's dependencies that need initialization.
+       Inits []PackageInit
+}
+
+// Locate the file from which to read export data.
+// This is intended to replicate the logic in gofrontend.
+func findExportFile(searchpaths []string, pkgpath string) (string, error) {
+       for _, spath := range searchpaths {
+               pkgfullpath := filepath.Join(spath, pkgpath)
+               pkgdir, name := filepath.Split(pkgfullpath)
+
+               for _, filepath := range [...]string{
+                       pkgfullpath,
+                       pkgfullpath + ".gox",
+                       pkgdir + "lib" + name + ".so",
+                       pkgdir + "lib" + name + ".a",
+                       pkgfullpath + ".o",
+               } {
+                       fi, err := os.Stat(filepath)
+                       if err == nil && !fi.IsDir() {
+                               return filepath, nil
+                       }
+               }
+       }
+
+       return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
+}
+
+const (
+       gccgov1Magic    = "v1;\n"
+       gccgov2Magic    = "v2;\n"
+       gccgov3Magic    = "v3;\n"
+       goimporterMagic = "\n$$ "
+       archiveMagic    = "!<ar"
+)
+
+// Opens the export data file at the given path. If this is an ELF file,
+// searches for and opens the .go_export section. If this is an archive,
+// reads the export data from the first member, which is assumed to be an ELF file.
+// This is intended to replicate the logic in gofrontend.
+func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
+       f, err := os.Open(fpath)
+       if err != nil {
+               return
+       }
+       closer = f
+       defer func() {
+               if err != nil && closer != nil {
+                       f.Close()
+               }
+       }()
+
+       var magic [4]byte
+       _, err = f.ReadAt(magic[:], 0)
+       if err != nil {
+               return
+       }
+
+       var elfreader io.ReaderAt
+       switch string(magic[:]) {
+       case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
+               // Raw export data.
+               reader = f
+               return
+
+       case archiveMagic:
+               reader, err = arExportData(f)
+               return
+
+       default:
+               elfreader = f
+       }
+
+       ef, err := elf.NewFile(elfreader)
+       if err != nil {
+               return
+       }
+
+       sec := ef.Section(".go_export")
+       if sec == nil {
+               err = fmt.Errorf("%s: .go_export section not found", fpath)
+               return
+       }
+
+       reader = sec.Open()
+       return
+}
+
+// An Importer resolves import paths to Packages. The imports map records
+// packages already known, indexed by package path.
+// An importer must determine the canonical package path and check imports
+// to see if it is already present in the map. If so, the Importer can return
+// the map entry. Otherwise, the importer must load the package data for the
+// given path into a new *Package, record it in imports map, and return the
+// package.
+type Importer func(imports map[string]*types.Package, path, srcDir string, lookup func(string) (io.ReadCloser, error)) (*types.Package, error)
+
+func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Importer {
+       return func(imports map[string]*types.Package, pkgpath, srcDir string, lookup func(string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
+               // TODO(gri): Use srcDir.
+               // Or not. It's possible that srcDir will fade in importance as
+               // the go command and other tools provide a translation table
+               // for relative imports (like ./foo or vendored imports).
+               if pkgpath == "unsafe" {
+                       return types.Unsafe, nil
+               }
+
+               var reader io.ReadSeeker
+               var fpath string
+               var rc io.ReadCloser
+               if lookup != nil {
+                       if p := imports[pkgpath]; p != nil && p.Complete() {
+                               return p, nil
+                       }
+                       rc, err = lookup(pkgpath)
+                       if err != nil {
+                               return nil, err
+                       }
+               }
+               if rc != nil {
+                       defer rc.Close()
+                       rs, ok := rc.(io.ReadSeeker)
+                       if !ok {
+                               return nil, fmt.Errorf("gccgo importer requires lookup to return an io.ReadSeeker, have %T", rc)
+                       }
+                       reader = rs
+                       fpath = "<lookup " + pkgpath + ">"
+                       // Take name from Name method (like on os.File) if present.
+                       if n, ok := rc.(interface{ Name() string }); ok {
+                               fpath = n.Name()
+                       }
+               } else {
+                       fpath, err = findExportFile(searchpaths, pkgpath)
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       r, closer, err := openExportFile(fpath)
+                       if err != nil {
+                               return nil, err
+                       }
+                       if closer != nil {
+                               defer closer.Close()
+                       }
+                       reader = r
+               }
+
+               var magics string
+               magics, err = readMagic(reader)
+               if err != nil {
+                       return
+               }
+
+               if magics == archiveMagic {
+                       reader, err = arExportData(reader)
+                       if err != nil {
+                               return
+                       }
+                       magics, err = readMagic(reader)
+                       if err != nil {
+                               return
+                       }
+               }
+
+               switch magics {
+               case gccgov1Magic, gccgov2Magic, gccgov3Magic:
+                       var p parser
+                       p.init(fpath, reader, imports)
+                       pkg = p.parsePackage()
+                       if initmap != nil {
+                               initmap[pkg] = p.initdata
+                       }
+
+               // Excluded for now: Standard gccgo doesn't support this import format currently.
+               // case goimporterMagic:
+               //      var data []byte
+               //      data, err = ioutil.ReadAll(reader)
+               //      if err != nil {
+               //              return
+               //      }
+               //      var n int
+               //      n, pkg, err = importer.ImportData(imports, data)
+               //      if err != nil {
+               //              return
+               //      }
+
+               //      if initmap != nil {
+               //              suffixreader := bytes.NewReader(data[n:])
+               //              var p parser
+               //              p.init(fpath, suffixreader, nil)
+               //              p.parseInitData()
+               //              initmap[pkg] = p.initdata
+               //      }
+
+               default:
+                       err = fmt.Errorf("unrecognized magic string: %q", magics)
+               }
+
+               return
+       }
+}
+
+// readMagic reads the four bytes at the start of a ReadSeeker and
+// returns them as a string.
+func readMagic(reader io.ReadSeeker) (string, error) {
+       var magic [4]byte
+       if _, err := reader.Read(magic[:]); err != nil {
+               return "", err
+       }
+       if _, err := reader.Seek(0, io.SeekStart); err != nil {
+               return "", err
+       }
+       return string(magic[:]), nil
+}