.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / loader / loader.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.1.1/go/loader/loader.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.1.1/go/loader/loader.go
new file mode 100644 (file)
index 0000000..678f3d4
--- /dev/null
@@ -0,0 +1,340 @@
+package loader
+
+import (
+       "errors"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "go/types"
+       "os"
+       "time"
+
+       "honnef.co/go/tools/config"
+       "honnef.co/go/tools/internal/cache"
+       "honnef.co/go/tools/internal/go/gcimporter"
+
+       "golang.org/x/tools/go/packages"
+)
+
+const MaxFileSize = 50 * 1024 * 1024 // 50 MB
+
+var errMaxFileSize = errors.New("file exceeds max file size")
+
+type PackageSpec struct {
+       ID      string
+       Name    string
+       PkgPath string
+       // Errors that occured while building the import graph. These will
+       // primarily be parse errors or failure to resolve imports, but
+       // may also be other errors.
+       Errors          []packages.Error
+       GoFiles         []string
+       CompiledGoFiles []string
+       OtherFiles      []string
+       ExportFile      string
+       Imports         map[string]*PackageSpec
+       TypesSizes      types.Sizes
+       Hash            cache.ActionID
+
+       Config config.Config
+}
+
+func (spec *PackageSpec) String() string {
+       return spec.ID
+}
+
+type Package struct {
+       *PackageSpec
+
+       // Errors that occured while loading the package. These will
+       // primarily be parse or type errors, but may also be lower-level
+       // failures such as file-system ones.
+       Errors    []packages.Error
+       Types     *types.Package
+       Fset      *token.FileSet
+       Syntax    []*ast.File
+       TypesInfo *types.Info
+}
+
+// Graph resolves patterns and returns packages with all the
+// information required to later load type information, and optionally
+// syntax trees.
+//
+// The provided config can set any setting with the exception of Mode.
+func Graph(cfg *packages.Config, patterns ...string) ([]*PackageSpec, error) {
+       var dcfg packages.Config
+       if cfg != nil {
+               dcfg = *cfg
+       }
+       dcfg.Mode = packages.NeedName |
+               packages.NeedImports |
+               packages.NeedDeps |
+               packages.NeedExportsFile |
+               packages.NeedFiles |
+               packages.NeedCompiledGoFiles |
+               packages.NeedTypesSizes
+       pkgs, err := packages.Load(&dcfg, patterns...)
+       if err != nil {
+               return nil, err
+       }
+
+       m := map[*packages.Package]*PackageSpec{}
+       packages.Visit(pkgs, nil, func(pkg *packages.Package) {
+               spec := &PackageSpec{
+                       ID:              pkg.ID,
+                       Name:            pkg.Name,
+                       PkgPath:         pkg.PkgPath,
+                       Errors:          pkg.Errors,
+                       GoFiles:         pkg.GoFiles,
+                       CompiledGoFiles: pkg.CompiledGoFiles,
+                       OtherFiles:      pkg.OtherFiles,
+                       ExportFile:      pkg.ExportFile,
+                       Imports:         map[string]*PackageSpec{},
+                       TypesSizes:      pkg.TypesSizes,
+               }
+               for path, imp := range pkg.Imports {
+                       spec.Imports[path] = m[imp]
+               }
+               if cdir := config.Dir(pkg.GoFiles); cdir != "" {
+                       cfg, err := config.Load(cdir)
+                       if err != nil {
+                               spec.Errors = append(spec.Errors, convertError(err)...)
+                       }
+                       spec.Config = cfg
+               } else {
+                       spec.Config = config.DefaultConfig
+               }
+               spec.Hash, err = computeHash(spec)
+               if err != nil {
+                       spec.Errors = append(spec.Errors, convertError(err)...)
+               }
+               m[pkg] = spec
+       })
+       out := make([]*PackageSpec, 0, len(pkgs))
+       for _, pkg := range pkgs {
+               if len(pkg.CompiledGoFiles) == 0 && len(pkg.Errors) == 0 && pkg.PkgPath != "unsafe" {
+                       // If a package consists only of test files, then
+                       // go/packages incorrectly(?) returns an empty package for
+                       // the non-test variant. Get rid of those packages. See
+                       // #646.
+                       //
+                       // Do not, however, skip packages that have errors. Those,
+                       // too, may have no files, but we want to print the
+                       // errors.
+                       continue
+               }
+               out = append(out, m[pkg])
+       }
+
+       return out, nil
+}
+
+type program struct {
+       fset     *token.FileSet
+       packages map[string]*types.Package
+}
+
+type Stats struct {
+       Source time.Duration
+       Export map[*PackageSpec]time.Duration
+}
+
+// Load loads the package described in spec. Imports will be loaded
+// from export data, while the package itself will be loaded from
+// source.
+//
+// An error will only be returned for system failures, such as failure
+// to read export data from disk. Syntax and type errors, among
+// others, will only populate the returned package's Errors field.
+func Load(spec *PackageSpec) (*Package, Stats, error) {
+       prog := &program{
+               fset:     token.NewFileSet(),
+               packages: map[string]*types.Package{},
+       }
+
+       stats := Stats{
+               Export: map[*PackageSpec]time.Duration{},
+       }
+       var b []byte
+       for _, imp := range spec.Imports {
+               if imp.PkgPath == "unsafe" {
+                       continue
+               }
+               t := time.Now()
+               var err error
+               _, b, err = prog.loadFromExport(imp, b)
+               stats.Export[imp] = time.Since(t)
+               if err != nil {
+                       return nil, stats, err
+               }
+       }
+       t := time.Now()
+       pkg, err := prog.loadFromSource(spec)
+       if err == errMaxFileSize {
+               pkg, _, err = prog.loadFromExport(spec, b)
+       }
+       stats.Source = time.Since(t)
+       return pkg, stats, err
+}
+
+// loadFromExport loads a package from export data.
+func (prog *program) loadFromExport(spec *PackageSpec, b []byte) (*Package, []byte, error) {
+       // log.Printf("Loading package %s from export", spec)
+       if spec.ExportFile == "" {
+               return nil, b, fmt.Errorf("no export data for %q", spec.ID)
+       }
+       f, err := os.Open(spec.ExportFile)
+       if err != nil {
+               return nil, b, err
+       }
+       defer f.Close()
+
+       b, err = gcimporter.GetExportData(f, b)
+       if err != nil {
+               return nil, b, err
+       }
+
+       _, tpkg, err := gcimporter.IImportData(prog.fset, prog.packages, b[1:], spec.PkgPath)
+       if err != nil {
+               return nil, b, err
+       }
+       pkg := &Package{
+               PackageSpec: spec,
+               Types:       tpkg,
+               Fset:        prog.fset,
+       }
+       // runtime.SetFinalizer(pkg, func(pkg *Package) {
+       //      log.Println("Unloading package", pkg.PkgPath)
+       // })
+       return pkg, b, nil
+}
+
+// loadFromSource loads a package from source. All of its dependencies
+// must have been loaded already.
+func (prog *program) loadFromSource(spec *PackageSpec) (*Package, error) {
+       if len(spec.Errors) > 0 {
+               panic("LoadFromSource called on package with errors")
+       }
+
+       pkg := &Package{
+               PackageSpec: spec,
+               Types:       types.NewPackage(spec.PkgPath, spec.Name),
+               Syntax:      make([]*ast.File, len(spec.CompiledGoFiles)),
+               Fset:        prog.fset,
+               TypesInfo: &types.Info{
+                       Types:      make(map[ast.Expr]types.TypeAndValue),
+                       Defs:       make(map[*ast.Ident]types.Object),
+                       Uses:       make(map[*ast.Ident]types.Object),
+                       Implicits:  make(map[ast.Node]types.Object),
+                       Scopes:     make(map[ast.Node]*types.Scope),
+                       Selections: make(map[*ast.SelectorExpr]*types.Selection),
+               },
+       }
+       // runtime.SetFinalizer(pkg, func(pkg *Package) {
+       //      log.Println("Unloading package", pkg.PkgPath)
+       // })
+
+       // OPT(dh): many packages have few files, much fewer than there
+       // are CPU cores. Additionally, parsing each individual file is
+       // very fast. A naive parallel implementation of this loop won't
+       // be faster, and tends to be slower due to extra scheduling,
+       // bookkeeping and potentially false sharing of cache lines.
+       for i, file := range spec.CompiledGoFiles {
+               f, err := os.Open(file)
+               if err != nil {
+                       return nil, err
+               }
+               fi, err := f.Stat()
+               if err != nil {
+                       return nil, err
+               }
+               if fi.Size() >= MaxFileSize {
+                       return nil, errMaxFileSize
+               }
+               af, err := parser.ParseFile(prog.fset, file, f, parser.ParseComments)
+               f.Close()
+               if err != nil {
+                       pkg.Errors = append(pkg.Errors, convertError(err)...)
+                       return pkg, nil
+               }
+               pkg.Syntax[i] = af
+       }
+       importer := func(path string) (*types.Package, error) {
+               if path == "unsafe" {
+                       return types.Unsafe, nil
+               }
+               if path == "C" {
+                       // go/packages doesn't tell us that cgo preprocessing
+                       // failed. When we subsequently try to parse the package,
+                       // we'll encounter the raw C import.
+                       return nil, errors.New("cgo preprocessing failed")
+               }
+               ispecpkg := spec.Imports[path]
+               if ispecpkg == nil {
+                       return nil, fmt.Errorf("trying to import %q in the context of %q returned nil PackageSpec", path, spec)
+               }
+               ipkg := prog.packages[ispecpkg.PkgPath]
+               if ipkg == nil {
+                       return nil, fmt.Errorf("trying to import %q (%q) in the context of %q returned nil PackageSpec", ispecpkg.PkgPath, path, spec)
+               }
+               return ipkg, nil
+       }
+       tc := &types.Config{
+               Importer: importerFunc(importer),
+               Error: func(err error) {
+                       pkg.Errors = append(pkg.Errors, convertError(err)...)
+               },
+       }
+       types.NewChecker(tc, pkg.Fset, pkg.Types, pkg.TypesInfo).Files(pkg.Syntax)
+       return pkg, nil
+}
+
+func convertError(err error) []packages.Error {
+       var errs []packages.Error
+       // taken from go/packages
+       switch err := err.(type) {
+       case packages.Error:
+               // from driver
+               errs = append(errs, err)
+
+       case *os.PathError:
+               // from parser
+               errs = append(errs, packages.Error{
+                       Pos:  err.Path + ":1",
+                       Msg:  err.Err.Error(),
+                       Kind: packages.ParseError,
+               })
+
+       case scanner.ErrorList:
+               // from parser
+               for _, err := range err {
+                       errs = append(errs, packages.Error{
+                               Pos:  err.Pos.String(),
+                               Msg:  err.Msg,
+                               Kind: packages.ParseError,
+                       })
+               }
+
+       case types.Error:
+               // from type checker
+               errs = append(errs, packages.Error{
+                       Pos:  err.Fset.Position(err.Pos).String(),
+                       Msg:  err.Msg,
+                       Kind: packages.TypeError,
+               })
+
+       default:
+               errs = append(errs, packages.Error{
+                       Pos:  "-",
+                       Msg:  err.Error(),
+                       Kind: packages.UnknownError,
+               })
+       }
+       return errs
+}
+
+type importerFunc func(path string) (*types.Package, error)
+
+func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }