chore: update deps
This commit is contained in:
parent
95803010d5
commit
d514cf41c3
525 changed files with 43230 additions and 14901 deletions
4
vendor/golang.org/x/tools/LICENSE
generated
vendored
4
vendor/golang.org/x/tools/LICENSE
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
|
142
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
142
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
|
@ -2,22 +2,64 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gcexportdata provides functions for locating, reading, and
|
||||
// writing export data files containing type information produced by the
|
||||
// gc compiler. This package supports go1.7 export data format and all
|
||||
// later versions.
|
||||
// Package gcexportdata provides functions for reading and writing
|
||||
// export data, which is a serialized description of the API of a Go
|
||||
// package including the names, kinds, types, and locations of all
|
||||
// exported declarations.
|
||||
//
|
||||
// Although it might seem convenient for this package to live alongside
|
||||
// go/types in the standard library, this would cause version skew
|
||||
// problems for developer tools that use it, since they must be able to
|
||||
// consume the outputs of the gc compiler both before and after a Go
|
||||
// update such as from Go 1.7 to Go 1.8. Because this package lives in
|
||||
// golang.org/x/tools, sites can update their version of this repo some
|
||||
// time before the Go 1.8 release and rebuild and redeploy their
|
||||
// developer tools, which will then be able to consume both Go 1.7 and
|
||||
// Go 1.8 export data files, so they will work before and after the
|
||||
// Go update. (See discussion at https://golang.org/issue/15651.)
|
||||
package gcexportdata // import "golang.org/x/tools/go/gcexportdata"
|
||||
// The standard Go compiler (cmd/compile) writes an export data file
|
||||
// for each package it compiles, which it later reads when compiling
|
||||
// packages that import the earlier one. The compiler must thus
|
||||
// contain logic to both write and read export data.
|
||||
// (See the "Export" section in the cmd/compile/README file.)
|
||||
//
|
||||
// The [Read] function in this package can read files produced by the
|
||||
// compiler, producing [go/types] data structures. As a matter of
|
||||
// policy, Read supports export data files produced by only the last
|
||||
// two Go releases plus tip; see https://go.dev/issue/68898. The
|
||||
// export data files produced by the compiler contain additional
|
||||
// details related to generics, inlining, and other optimizations that
|
||||
// cannot be decoded by the [Read] function.
|
||||
//
|
||||
// In files written by the compiler, the export data is not at the
|
||||
// start of the file. Before calling Read, use [NewReader] to locate
|
||||
// the desired portion of the file.
|
||||
//
|
||||
// The [Write] function in this package encodes the exported API of a
|
||||
// Go package ([types.Package]) as a file. Such files can be later
|
||||
// decoded by Read, but cannot be consumed by the compiler.
|
||||
//
|
||||
// # Future changes
|
||||
//
|
||||
// Although Read supports the formats written by both Write and the
|
||||
// compiler, the two are quite different, and there is an open
|
||||
// proposal (https://go.dev/issue/69491) to separate these APIs.
|
||||
//
|
||||
// Under that proposal, this package would ultimately provide only the
|
||||
// Read operation for compiler export data, which must be defined in
|
||||
// this module (golang.org/x/tools), not in the standard library, to
|
||||
// avoid version skew for developer tools that need to read compiler
|
||||
// export data both before and after a Go release, such as from Go
|
||||
// 1.23 to Go 1.24. Because this package lives in the tools module,
|
||||
// clients can update their version of the module some time before the
|
||||
// Go 1.24 release and rebuild and redeploy their tools, which will
|
||||
// then be able to consume both Go 1.23 and Go 1.24 export data files,
|
||||
// so they will work before and after the Go update. (See discussion
|
||||
// at https://go.dev/issue/15651.)
|
||||
//
|
||||
// The operations to import and export [go/types] data structures
|
||||
// would be defined in the go/types package as Import and Export.
|
||||
// [Write] would (eventually) delegate to Export,
|
||||
// and [Read], when it detects a file produced by Export,
|
||||
// would delegate to Import.
|
||||
//
|
||||
// # Deprecations
|
||||
//
|
||||
// The [NewImporter] and [Find] functions are deprecated and should
|
||||
// not be used in new code. The [WriteBundle] and [ReadBundle]
|
||||
// functions are experimental, and there is an open proposal to
|
||||
// deprecate them (https://go.dev/issue/69573).
|
||||
package gcexportdata
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -27,7 +69,6 @@ import (
|
|||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
|
||||
"golang.org/x/tools/internal/gcimporter"
|
||||
|
@ -48,7 +89,7 @@ import (
|
|||
func Find(importPath, srcDir string) (filename, path string) {
|
||||
cmd := exec.Command("go", "list", "-json", "-export", "--", importPath)
|
||||
cmd.Dir = srcDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", ""
|
||||
}
|
||||
|
@ -65,29 +106,41 @@ func Find(importPath, srcDir string) (filename, path string) {
|
|||
// additional trailing data beyond the end of the export data.
|
||||
func NewReader(r io.Reader) (io.Reader, error) {
|
||||
buf := bufio.NewReader(r)
|
||||
_, size, err := gcimporter.FindExportData(buf)
|
||||
size, err := gcimporter.FindExportData(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if size >= 0 {
|
||||
// We were given an archive and found the __.PKGDEF in it.
|
||||
// This tells us the size of the export data, and we don't
|
||||
// need to return the entire file.
|
||||
return &io.LimitedReader{
|
||||
R: buf,
|
||||
N: size,
|
||||
}, nil
|
||||
} else {
|
||||
// We were given an object file. As such, we don't know how large
|
||||
// the export data is and must return the entire file.
|
||||
return buf, nil
|
||||
// We were given an archive and found the __.PKGDEF in it.
|
||||
// This tells us the size of the export data, and we don't
|
||||
// need to return the entire file.
|
||||
return &io.LimitedReader{
|
||||
R: buf,
|
||||
N: size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// readAll works the same way as io.ReadAll, but avoids allocations and copies
|
||||
// by preallocating a byte slice of the necessary size if the size is known up
|
||||
// front. This is always possible when the input is an archive. In that case,
|
||||
// NewReader will return the known size using an io.LimitedReader.
|
||||
func readAll(r io.Reader) ([]byte, error) {
|
||||
if lr, ok := r.(*io.LimitedReader); ok {
|
||||
data := make([]byte, lr.N)
|
||||
_, err := io.ReadFull(lr, data)
|
||||
return data, err
|
||||
}
|
||||
return io.ReadAll(r)
|
||||
}
|
||||
|
||||
// Read reads export data from in, decodes it, and returns type
|
||||
// information for the package.
|
||||
//
|
||||
// Read is capable of reading export data produced by [Write] at the
|
||||
// same source code version, or by the last two Go releases (plus tip)
|
||||
// of the standard Go compiler. Reading files from older compilers may
|
||||
// produce an error.
|
||||
//
|
||||
// The package path (effectively its linker symbol prefix) is
|
||||
// specified by path, since unlike the package name, this information
|
||||
// may not be recorded in the export data.
|
||||
|
@ -102,7 +155,7 @@ func NewReader(r io.Reader) (io.Reader, error) {
|
|||
//
|
||||
// On return, the state of the reader is undefined.
|
||||
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
|
||||
data, err := ioutil.ReadAll(in)
|
||||
data, err := readAll(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading export data for %q: %v", path, err)
|
||||
}
|
||||
|
@ -111,26 +164,31 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package,
|
|||
return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path)
|
||||
}
|
||||
|
||||
// The App Engine Go runtime v1.6 uses the old export data format.
|
||||
// TODO(adonovan): delete once v1.7 has been around for a while.
|
||||
if bytes.HasPrefix(data, []byte("package ")) {
|
||||
return gcimporter.ImportData(imports, path, path, bytes.NewReader(data))
|
||||
}
|
||||
|
||||
// The indexed export format starts with an 'i'; the older
|
||||
// binary export format starts with a 'c', 'd', or 'v'
|
||||
// (from "version"). Select appropriate importer.
|
||||
if len(data) > 0 {
|
||||
switch data[0] {
|
||||
case 'v', 'c', 'd':
|
||||
// binary, produced by cmd/compile till go1.10
|
||||
return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0])
|
||||
|
||||
case 'i':
|
||||
// indexed, produced by cmd/compile till go1.19,
|
||||
// and also by [Write].
|
||||
//
|
||||
// If proposal #69491 is accepted, go/types
|
||||
// serialization will be implemented by
|
||||
// types.Export, to which Write would eventually
|
||||
// delegate (explicitly dropping any pretence at
|
||||
// inter-version Write-Read compatibility).
|
||||
// This [Read] function would delegate to types.Import
|
||||
// when it detects that the file was produced by Export.
|
||||
_, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path)
|
||||
return pkg, err
|
||||
|
||||
case 'v', 'c', 'd':
|
||||
_, pkg, err := gcimporter.BImportData(fset, imports, data, path)
|
||||
return pkg, err
|
||||
|
||||
case 'u':
|
||||
// unified, produced by cmd/compile since go1.20
|
||||
_, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path)
|
||||
return pkg, err
|
||||
|
||||
|
@ -165,7 +223,7 @@ func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
|||
//
|
||||
// Experimental: This API is experimental and may change in the future.
|
||||
func ReadBundle(in io.Reader, fset *token.FileSet, imports map[string]*types.Package) ([]*types.Package, error) {
|
||||
data, err := ioutil.ReadAll(in)
|
||||
data, err := readAll(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading export bundle: %v", err)
|
||||
}
|
||||
|
|
49
vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
generated
vendored
49
vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
generated
vendored
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
// Package packagesdriver fetches type sizes for go/packages and go/analysis.
|
||||
package packagesdriver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
)
|
||||
|
||||
var debug = false
|
||||
|
||||
func GetSizesGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (types.Sizes, error) {
|
||||
inv.Verb = "list"
|
||||
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
|
||||
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
|
||||
var goarch, compiler string
|
||||
if rawErr != nil {
|
||||
if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") {
|
||||
// User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
|
||||
// TODO(matloob): Is this a problem in practice?
|
||||
inv.Verb = "env"
|
||||
inv.Args = []string{"GOARCH"}
|
||||
envout, enverr := gocmdRunner.Run(ctx, inv)
|
||||
if enverr != nil {
|
||||
return nil, enverr
|
||||
}
|
||||
goarch = strings.TrimSpace(envout.String())
|
||||
compiler = "gc"
|
||||
} else {
|
||||
return nil, friendlyErr
|
||||
}
|
||||
} else {
|
||||
fields := strings.Fields(stdout.String())
|
||||
if len(fields) < 2 {
|
||||
return nil, fmt.Errorf("could not parse GOARCH and Go compiler in format \"<GOARCH> <compiler>\":\nstdout: <<%s>>\nstderr: <<%s>>",
|
||||
stdout.String(), stderr.String())
|
||||
}
|
||||
goarch = fields[0]
|
||||
compiler = fields[1]
|
||||
}
|
||||
return types.SizesFor(compiler, goarch), nil
|
||||
}
|
63
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
63
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
|
@ -5,12 +5,20 @@
|
|||
/*
|
||||
Package packages loads Go packages for inspection and analysis.
|
||||
|
||||
The Load function takes as input a list of patterns and return a list of Package
|
||||
structs describing individual packages matched by those patterns.
|
||||
The LoadMode controls the amount of detail in the loaded packages.
|
||||
The [Load] function takes as input a list of patterns and returns a
|
||||
list of [Package] values describing individual packages matched by those
|
||||
patterns.
|
||||
A [Config] specifies configuration options, the most important of which is
|
||||
the [LoadMode], which controls the amount of detail in the loaded packages.
|
||||
|
||||
Load passes most patterns directly to the underlying build tool,
|
||||
but all patterns with the prefix "query=", where query is a
|
||||
Load passes most patterns directly to the underlying build tool.
|
||||
The default build tool is the go command.
|
||||
Its supported patterns are described at
|
||||
https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns.
|
||||
Other build systems may be supported by providing a "driver";
|
||||
see [The driver protocol].
|
||||
|
||||
All patterns with the prefix "query=", where query is a
|
||||
non-empty string of letters from [a-z], are reserved and may be
|
||||
interpreted as query operators.
|
||||
|
||||
|
@ -35,7 +43,7 @@ The Package struct provides basic information about the package, including
|
|||
- Imports, a map from source import strings to the Packages they name;
|
||||
- Types, the type information for the package's exported symbols;
|
||||
- Syntax, the parsed syntax trees for the package's source code; and
|
||||
- TypeInfo, the result of a complete type-check of the package syntax trees.
|
||||
- TypesInfo, the result of a complete type-check of the package syntax trees.
|
||||
|
||||
(See the documentation for type Package for the complete list of fields
|
||||
and more detailed descriptions.)
|
||||
|
@ -56,7 +64,7 @@ graph using the Imports fields.
|
|||
|
||||
The Load function can be configured by passing a pointer to a Config as
|
||||
the first argument. A nil Config is equivalent to the zero Config, which
|
||||
causes Load to run in LoadFiles mode, collecting minimal information.
|
||||
causes Load to run in [LoadFiles] mode, collecting minimal information.
|
||||
See the documentation for type Config for details.
|
||||
|
||||
As noted earlier, the Config.Mode controls the amount of detail
|
||||
|
@ -64,9 +72,40 @@ reported about the loaded packages. See the documentation for type LoadMode
|
|||
for details.
|
||||
|
||||
Most tools should pass their command-line arguments (after any flags)
|
||||
uninterpreted to the loader, so that the loader can interpret them
|
||||
uninterpreted to Load, so that it can interpret them
|
||||
according to the conventions of the underlying build system.
|
||||
|
||||
See the Example function for typical usage.
|
||||
|
||||
# The driver protocol
|
||||
|
||||
Load may be used to load Go packages even in Go projects that use
|
||||
alternative build systems, by installing an appropriate "driver"
|
||||
program for the build system and specifying its location in the
|
||||
GOPACKAGESDRIVER environment variable.
|
||||
For example,
|
||||
https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration
|
||||
explains how to use the driver for Bazel.
|
||||
|
||||
The driver program is responsible for interpreting patterns in its
|
||||
preferred notation and reporting information about the packages that
|
||||
those patterns identify. Drivers must also support the special "file="
|
||||
and "pattern=" patterns described above.
|
||||
|
||||
The patterns are provided as positional command-line arguments. A
|
||||
JSON-encoded [DriverRequest] message providing additional information
|
||||
is written to the driver's standard input. The driver must write a
|
||||
JSON-encoded [DriverResponse] message to its standard output. (This
|
||||
message differs from the JSON schema produced by 'go list'.)
|
||||
|
||||
The value of the PWD environment variable seen by the driver process
|
||||
is the preferred name of its working directory. (The working directory
|
||||
may have other aliases due to symbolic links; see the comment on the
|
||||
Dir field of [exec.Cmd] for related information.)
|
||||
When the driver process emits in its response the name of a file
|
||||
that is a descendant of this directory, it must use an absolute path
|
||||
that has the value of PWD as a prefix, to ensure that the returned
|
||||
filenames satisfy the original query.
|
||||
*/
|
||||
package packages // import "golang.org/x/tools/go/packages"
|
||||
|
||||
|
@ -168,14 +207,6 @@ Instead, ssadump no longer requests the runtime package,
|
|||
but seeks it among the dependencies of the user-specified packages,
|
||||
and emits an error if it is not found.
|
||||
|
||||
Overlays: The Overlay field in the Config allows providing alternate contents
|
||||
for Go source files, by providing a mapping from file path to contents.
|
||||
go/packages will pull in new imports added in overlay files when go/packages
|
||||
is run in LoadImports mode or greater.
|
||||
Overlay support for the go list driver isn't complete yet: if the file doesn't
|
||||
exist on disk, it will only be recognized in an overlay if it is a non-test file
|
||||
and the package would be reported even without the overlay.
|
||||
|
||||
Questions & Tasks
|
||||
|
||||
- Add GOARCH/GOOS?
|
||||
|
|
102
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
102
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
|
@ -2,48 +2,88 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file enables an external tool to intercept package requests.
|
||||
// If the tool is present then its results are used in preference to
|
||||
// the go list command.
|
||||
|
||||
package packages
|
||||
|
||||
// This file defines the protocol that enables an external "driver"
|
||||
// tool to supply package metadata in place of 'go list'.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The Driver Protocol
|
||||
// DriverRequest defines the schema of a request for package metadata
|
||||
// from an external driver program. The JSON-encoded DriverRequest
|
||||
// message is provided to the driver program's standard input. The
|
||||
// query patterns are provided as command-line arguments.
|
||||
//
|
||||
// The driver, given the inputs to a call to Load, returns metadata about the packages specified.
|
||||
// This allows for different build systems to support go/packages by telling go/packages how the
|
||||
// packages' source is organized.
|
||||
// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
|
||||
// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
|
||||
// documentation in doc.go for the full description of the patterns that need to be supported.
|
||||
// A driver receives as a JSON-serialized driverRequest struct in standard input and will
|
||||
// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
|
||||
|
||||
// driverRequest is used to provide the portion of Load's Config that is needed by a driver.
|
||||
type driverRequest struct {
|
||||
// See the package documentation for an overview.
|
||||
type DriverRequest struct {
|
||||
Mode LoadMode `json:"mode"`
|
||||
|
||||
// Env specifies the environment the underlying build system should be run in.
|
||||
Env []string `json:"env"`
|
||||
|
||||
// BuildFlags are flags that should be passed to the underlying build system.
|
||||
BuildFlags []string `json:"build_flags"`
|
||||
|
||||
// Tests specifies whether the patterns should also return test packages.
|
||||
Tests bool `json:"tests"`
|
||||
// Overlay maps file paths (relative to the driver's working directory) to the byte contents
|
||||
// of overlay files.
|
||||
|
||||
// Overlay maps file paths (relative to the driver's working directory)
|
||||
// to the contents of overlay files (see Config.Overlay).
|
||||
Overlay map[string][]byte `json:"overlay"`
|
||||
}
|
||||
|
||||
// DriverResponse defines the schema of a response from an external
|
||||
// driver program, providing the results of a query for package
|
||||
// metadata. The driver program must write a JSON-encoded
|
||||
// DriverResponse message to its standard output.
|
||||
//
|
||||
// See the package documentation for an overview.
|
||||
type DriverResponse struct {
|
||||
// NotHandled is returned if the request can't be handled by the current
|
||||
// driver. If an external driver returns a response with NotHandled, the
|
||||
// rest of the DriverResponse is ignored, and go/packages will fallback
|
||||
// to the next driver. If go/packages is extended in the future to support
|
||||
// lists of multiple drivers, go/packages will fall back to the next driver.
|
||||
NotHandled bool
|
||||
|
||||
// Compiler and Arch are the arguments pass of types.SizesFor
|
||||
// to get a types.Sizes to use when type checking.
|
||||
Compiler string
|
||||
Arch string
|
||||
|
||||
// Roots is the set of package IDs that make up the root packages.
|
||||
// We have to encode this separately because when we encode a single package
|
||||
// we cannot know if it is one of the roots as that requires knowledge of the
|
||||
// graph it is part of.
|
||||
Roots []string `json:",omitempty"`
|
||||
|
||||
// Packages is the full set of packages in the graph.
|
||||
// The packages are not connected into a graph.
|
||||
// The Imports if populated will be stubs that only have their ID set.
|
||||
// Imports will be connected and then type and syntax information added in a
|
||||
// later pass (see refine).
|
||||
Packages []*Package
|
||||
|
||||
// GoVersion is the minor version number used by the driver
|
||||
// (e.g. the go command on the PATH) when selecting .go files.
|
||||
// Zero means unknown.
|
||||
GoVersion int
|
||||
}
|
||||
|
||||
// driver is the type for functions that query the build system for the
|
||||
// packages named by the patterns.
|
||||
type driver func(cfg *Config, patterns []string) (*DriverResponse, error)
|
||||
|
||||
// findExternalDriver returns the file path of a tool that supplies
|
||||
// the build system package structure, or "" if not found."
|
||||
// the build system package structure, or "" if not found.
|
||||
// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
|
||||
// value, otherwise it searches for a binary named gopackagesdriver on the PATH.
|
||||
func findExternalDriver(cfg *Config) driver {
|
||||
|
@ -64,8 +104,8 @@ func findExternalDriver(cfg *Config) driver {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
return func(cfg *Config, words ...string) (*driverResponse, error) {
|
||||
req, err := json.Marshal(driverRequest{
|
||||
return func(cfg *Config, patterns []string) (*DriverResponse, error) {
|
||||
req, err := json.Marshal(DriverRequest{
|
||||
Mode: cfg.Mode,
|
||||
Env: cfg.Env,
|
||||
BuildFlags: cfg.BuildFlags,
|
||||
|
@ -78,9 +118,21 @@ func findExternalDriver(cfg *Config) driver {
|
|||
|
||||
buf := new(bytes.Buffer)
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd := exec.CommandContext(cfg.Context, tool, words...)
|
||||
cmd := exec.CommandContext(cfg.Context, tool, patterns...)
|
||||
cmd.Dir = cfg.Dir
|
||||
cmd.Env = cfg.Env
|
||||
// The cwd gets resolved to the real path. On Darwin, where
|
||||
// /tmp is a symlink, this breaks anything that expects the
|
||||
// working directory to keep the original path, including the
|
||||
// go command when dealing with modules.
|
||||
//
|
||||
// os.Getwd stdlib has a special feature where if the
|
||||
// cwd and the PWD are the same node then it trusts
|
||||
// the PWD, so by setting it in the env for the child
|
||||
// process we fix up all the paths returned by the go
|
||||
// command.
|
||||
//
|
||||
// (See similar trick in Invocation.run in ../../internal/gocommand/invoke.go)
|
||||
cmd.Env = append(slices.Clip(cfg.Env), "PWD="+cfg.Dir)
|
||||
cmd.Stdin = bytes.NewReader(req)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = stderr
|
||||
|
@ -92,7 +144,7 @@ func findExternalDriver(cfg *Config) driver {
|
|||
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)
|
||||
}
|
||||
|
||||
var response driverResponse
|
||||
var response DriverResponse
|
||||
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
324
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
324
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
|
@ -9,10 +9,9 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
@ -22,8 +21,6 @@ import (
|
|||
"sync"
|
||||
"unicode"
|
||||
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"golang.org/x/tools/go/internal/packagesdriver"
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
"golang.org/x/tools/internal/packagesinternal"
|
||||
)
|
||||
|
@ -37,23 +34,23 @@ type goTooOldError struct {
|
|||
error
|
||||
}
|
||||
|
||||
// responseDeduper wraps a driverResponse, deduplicating its contents.
|
||||
// responseDeduper wraps a DriverResponse, deduplicating its contents.
|
||||
type responseDeduper struct {
|
||||
seenRoots map[string]bool
|
||||
seenPackages map[string]*Package
|
||||
dr *driverResponse
|
||||
dr *DriverResponse
|
||||
}
|
||||
|
||||
func newDeduper() *responseDeduper {
|
||||
return &responseDeduper{
|
||||
dr: &driverResponse{},
|
||||
dr: &DriverResponse{},
|
||||
seenRoots: map[string]bool{},
|
||||
seenPackages: map[string]*Package{},
|
||||
}
|
||||
}
|
||||
|
||||
// addAll fills in r with a driverResponse.
|
||||
func (r *responseDeduper) addAll(dr *driverResponse) {
|
||||
// addAll fills in r with a DriverResponse.
|
||||
func (r *responseDeduper) addAll(dr *DriverResponse) {
|
||||
for _, pkg := range dr.Packages {
|
||||
r.addPackage(pkg)
|
||||
}
|
||||
|
@ -83,6 +80,12 @@ type golistState struct {
|
|||
cfg *Config
|
||||
ctx context.Context
|
||||
|
||||
runner *gocommand.Runner
|
||||
|
||||
// overlay is the JSON file that encodes the Config.Overlay
|
||||
// mapping, used by 'go list -overlay=...'.
|
||||
overlay string
|
||||
|
||||
envOnce sync.Once
|
||||
goEnvError error
|
||||
goEnv map[string]string
|
||||
|
@ -130,7 +133,10 @@ func (state *golistState) mustGetEnv() map[string]string {
|
|||
// goListDriver uses the go list command to interpret the patterns and produce
|
||||
// the build system package structure.
|
||||
// See driver for more details.
|
||||
func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
|
||||
//
|
||||
// overlay is the JSON file that encodes the cfg.Overlay
|
||||
// mapping, used by 'go list -overlay=...'
|
||||
func goListDriver(cfg *Config, runner *gocommand.Runner, overlay string, patterns []string) (_ *DriverResponse, err error) {
|
||||
// Make sure that any asynchronous go commands are killed when we return.
|
||||
parentCtx := cfg.Context
|
||||
if parentCtx == nil {
|
||||
|
@ -145,19 +151,23 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
|
|||
cfg: cfg,
|
||||
ctx: ctx,
|
||||
vendorDirs: map[string]bool{},
|
||||
overlay: overlay,
|
||||
runner: runner,
|
||||
}
|
||||
|
||||
// Fill in response.Sizes asynchronously if necessary.
|
||||
var sizeserr error
|
||||
var sizeswg sync.WaitGroup
|
||||
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
|
||||
sizeswg.Add(1)
|
||||
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
var sizes types.Sizes
|
||||
sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner)
|
||||
// types.SizesFor always returns nil or a *types.StdSizes.
|
||||
response.dr.Sizes, _ = sizes.(*types.StdSizes)
|
||||
sizeswg.Done()
|
||||
compiler, arch, err := getSizesForArgs(ctx, state.cfgInvocation(), runner)
|
||||
response.dr.Compiler = compiler
|
||||
response.dr.Arch = arch
|
||||
errCh <- err
|
||||
}()
|
||||
defer func() {
|
||||
if sizesErr := <-errCh; sizesErr != nil {
|
||||
err = sizesErr
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
@ -210,87 +220,10 @@ extractQueries:
|
|||
}
|
||||
}
|
||||
|
||||
// Only use go/packages' overlay processing if we're using a Go version
|
||||
// below 1.16. Otherwise, go list handles it.
|
||||
if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 {
|
||||
modifiedPkgs, needPkgs, err := state.processGolistOverlay(response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var containsCandidates []string
|
||||
if len(containFiles) > 0 {
|
||||
containsCandidates = append(containsCandidates, modifiedPkgs...)
|
||||
containsCandidates = append(containsCandidates, needPkgs...)
|
||||
}
|
||||
if err := state.addNeededOverlayPackages(response, needPkgs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check candidate packages for containFiles.
|
||||
if len(containFiles) > 0 {
|
||||
for _, id := range containsCandidates {
|
||||
pkg, ok := response.seenPackages[id]
|
||||
if !ok {
|
||||
response.addPackage(&Package{
|
||||
ID: id,
|
||||
Errors: []Error{{
|
||||
Kind: ListError,
|
||||
Msg: fmt.Sprintf("package %s expected but not seen", id),
|
||||
}},
|
||||
})
|
||||
continue
|
||||
}
|
||||
for _, f := range containFiles {
|
||||
for _, g := range pkg.GoFiles {
|
||||
if sameFile(f, g) {
|
||||
response.addRoot(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add root for any package that matches a pattern. This applies only to
|
||||
// packages that are modified by overlays, since they are not added as
|
||||
// roots automatically.
|
||||
for _, pattern := range restPatterns {
|
||||
match := matchPattern(pattern)
|
||||
for _, pkgID := range modifiedPkgs {
|
||||
pkg, ok := response.seenPackages[pkgID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if match(pkg.PkgPath) {
|
||||
response.addRoot(pkg.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sizeswg.Wait()
|
||||
if sizeserr != nil {
|
||||
return nil, sizeserr
|
||||
}
|
||||
// (We may yet return an error due to defer.)
|
||||
return response.dr, nil
|
||||
}
|
||||
|
||||
func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error {
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
dr, err := state.createDriverResponse(pkgs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, pkg := range dr.Packages {
|
||||
response.addPackage(pkg)
|
||||
}
|
||||
_, needPkgs, err := state.processGolistOverlay(response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return state.addNeededOverlayPackages(response, needPkgs)
|
||||
}
|
||||
|
||||
func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error {
|
||||
for _, query := range queries {
|
||||
// TODO(matloob): Do only one query per directory.
|
||||
|
@ -342,7 +275,7 @@ func (state *golistState) runContainsQueries(response *responseDeduper, queries
|
|||
|
||||
// adhocPackage attempts to load or construct an ad-hoc package for a given
|
||||
// query, if the original call to the driver produced inadequate results.
|
||||
func (state *golistState) adhocPackage(pattern, query string) (*driverResponse, error) {
|
||||
func (state *golistState) adhocPackage(pattern, query string) (*DriverResponse, error) {
|
||||
response, err := state.createDriverResponse(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -389,6 +322,7 @@ type jsonPackage struct {
|
|||
ImportPath string
|
||||
Dir string
|
||||
Name string
|
||||
Target string
|
||||
Export string
|
||||
GoFiles []string
|
||||
CompiledGoFiles []string
|
||||
|
@ -433,7 +367,7 @@ func otherFiles(p *jsonPackage) [][]string {
|
|||
|
||||
// createDriverResponse uses the "go list" command to expand the pattern
|
||||
// words and return a response for the specified packages.
|
||||
func (state *golistState) createDriverResponse(words ...string) (*driverResponse, error) {
|
||||
func (state *golistState) createDriverResponse(words ...string) (*DriverResponse, error) {
|
||||
// go list uses the following identifiers in ImportPath and Imports:
|
||||
//
|
||||
// "p" -- importable package or main (command)
|
||||
|
@ -460,7 +394,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
pkgs := make(map[string]*Package)
|
||||
additionalErrors := make(map[string][]Error)
|
||||
// Decode the JSON and convert it to Package form.
|
||||
response := &driverResponse{
|
||||
response := &DriverResponse{
|
||||
GoVersion: goVersion,
|
||||
}
|
||||
for dec := json.NewDecoder(buf); dec.More(); {
|
||||
|
@ -572,13 +506,15 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
pkg := &Package{
|
||||
Name: p.Name,
|
||||
ID: p.ImportPath,
|
||||
Dir: p.Dir,
|
||||
Target: p.Target,
|
||||
GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
|
||||
CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles),
|
||||
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
|
||||
EmbedFiles: absJoin(p.Dir, p.EmbedFiles),
|
||||
EmbedPatterns: absJoin(p.Dir, p.EmbedPatterns),
|
||||
IgnoredFiles: absJoin(p.Dir, p.IgnoredGoFiles, p.IgnoredOtherFiles),
|
||||
forTest: p.ForTest,
|
||||
ForTest: p.ForTest,
|
||||
depsErrors: p.DepsErrors,
|
||||
Module: p.Module,
|
||||
}
|
||||
|
@ -604,17 +540,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
|
||||
// Work around https://golang.org/issue/28749:
|
||||
// cmd/go puts assembly, C, and C++ files in CompiledGoFiles.
|
||||
// Filter out any elements of CompiledGoFiles that are also in OtherFiles.
|
||||
// We have to keep this workaround in place until go1.12 is a distant memory.
|
||||
if len(pkg.OtherFiles) > 0 {
|
||||
other := make(map[string]bool, len(pkg.OtherFiles))
|
||||
for _, f := range pkg.OtherFiles {
|
||||
other[f] = true
|
||||
}
|
||||
|
||||
// Remove files from CompiledGoFiles that are non-go files
|
||||
// (or are not files that look like they are from the cache).
|
||||
if len(pkg.CompiledGoFiles) > 0 {
|
||||
out := pkg.CompiledGoFiles[:0]
|
||||
for _, f := range pkg.CompiledGoFiles {
|
||||
if other[f] {
|
||||
if ext := filepath.Ext(f); ext != ".go" && ext != "" { // ext == "" means the file is from the cache, so probably cgo-processed file
|
||||
continue
|
||||
}
|
||||
out = append(out, f)
|
||||
|
@ -630,7 +561,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
}
|
||||
|
||||
if pkg.PkgPath == "unsafe" {
|
||||
pkg.GoFiles = nil // ignore fake unsafe.go file
|
||||
pkg.CompiledGoFiles = nil // ignore fake unsafe.go file (#59929)
|
||||
} else if len(pkg.CompiledGoFiles) == 0 {
|
||||
// Work around for pre-go.1.11 versions of go list.
|
||||
// TODO(matloob): they should be handled by the fallback.
|
||||
// Can we delete this?
|
||||
pkg.CompiledGoFiles = pkg.GoFiles
|
||||
}
|
||||
|
||||
// Assume go list emits only absolute paths for Dir.
|
||||
|
@ -668,16 +604,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
response.Roots = append(response.Roots, pkg.ID)
|
||||
}
|
||||
|
||||
// Work around for pre-go.1.11 versions of go list.
|
||||
// TODO(matloob): they should be handled by the fallback.
|
||||
// Can we delete this?
|
||||
if len(pkg.CompiledGoFiles) == 0 {
|
||||
pkg.CompiledGoFiles = pkg.GoFiles
|
||||
}
|
||||
|
||||
// Temporary work-around for golang/go#39986. Parse filenames out of
|
||||
// error messages. This happens if there are unrecoverable syntax
|
||||
// errors in the source, so we can't match on a specific error message.
|
||||
//
|
||||
// TODO(rfindley): remove this heuristic, in favor of considering
|
||||
// InvalidGoFiles from the list driver.
|
||||
if err := p.Error; err != nil && state.shouldAddFilenameFromError(p) {
|
||||
addFilenameFromPos := func(pos string) bool {
|
||||
split := strings.Split(pos, ":")
|
||||
|
@ -763,7 +695,7 @@ func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
|
|||
// getGoVersion returns the effective minor version of the go command.
|
||||
func (state *golistState) getGoVersion() (int, error) {
|
||||
state.goVersionOnce.Do(func() {
|
||||
state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner)
|
||||
state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.runner)
|
||||
})
|
||||
return state.goVersion, state.goVersionError
|
||||
}
|
||||
|
@ -833,7 +765,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
|||
}
|
||||
}
|
||||
addFields("Name", "ImportPath", "Error") // These fields are always needed
|
||||
if cfg.Mode&NeedFiles != 0 || cfg.Mode&NeedTypes != 0 {
|
||||
if cfg.Mode&NeedFiles != 0 || cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
|
||||
addFields("Dir", "GoFiles", "IgnoredGoFiles", "IgnoredOtherFiles", "CFiles",
|
||||
"CgoFiles", "CXXFiles", "MFiles", "HFiles", "FFiles", "SFiles",
|
||||
"SwigFiles", "SwigCXXFiles", "SysoFiles")
|
||||
|
@ -841,7 +773,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
|||
addFields("TestGoFiles", "XTestGoFiles")
|
||||
}
|
||||
}
|
||||
if cfg.Mode&NeedTypes != 0 {
|
||||
if cfg.Mode&(NeedTypes|NeedTypesInfo) != 0 {
|
||||
// CompiledGoFiles seems to be required for the test case TestCgoNoSyntax,
|
||||
// even when -compiled isn't passed in.
|
||||
// TODO(#52435): Should we make the test ask for -compiled, or automatically
|
||||
|
@ -866,7 +798,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
|||
// Request Dir in the unlikely case Export is not absolute.
|
||||
addFields("Dir", "Export")
|
||||
}
|
||||
if cfg.Mode&needInternalForTest != 0 {
|
||||
if cfg.Mode&NeedForTest != 0 {
|
||||
addFields("ForTest")
|
||||
}
|
||||
if cfg.Mode&needInternalDepsErrors != 0 {
|
||||
|
@ -881,6 +813,9 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
|||
if cfg.Mode&NeedEmbedPatterns != 0 {
|
||||
addFields("EmbedPatterns")
|
||||
}
|
||||
if cfg.Mode&NeedTarget != 0 {
|
||||
addFields("Target")
|
||||
}
|
||||
return "-json=" + strings.Join(fields, ",")
|
||||
}
|
||||
|
||||
|
@ -896,6 +831,15 @@ func golistargs(cfg *Config, words []string, goVersion int) []string {
|
|||
// probably because you'd just get the TestMain.
|
||||
fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0 && !usesExportData(cfg)),
|
||||
}
|
||||
|
||||
// golang/go#60456: with go1.21 and later, go list serves pgo variants, which
|
||||
// can be costly to compute and may result in redundant processing for the
|
||||
// caller. Disable these variants. If someone wants to add e.g. a NeedPGO
|
||||
// mode flag, that should be a separate proposal.
|
||||
if goVersion >= 21 {
|
||||
fullargs = append(fullargs, "-pgo=off")
|
||||
}
|
||||
|
||||
fullargs = append(fullargs, cfg.BuildFlags...)
|
||||
fullargs = append(fullargs, "--")
|
||||
fullargs = append(fullargs, words...)
|
||||
|
@ -913,6 +857,7 @@ func (state *golistState) cfgInvocation() gocommand.Invocation {
|
|||
Env: cfg.Env,
|
||||
Logf: cfg.Logf,
|
||||
WorkingDir: cfg.Dir,
|
||||
Overlay: state.overlay,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,33 +866,10 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
|
|||
cfg := state.cfg
|
||||
|
||||
inv := state.cfgInvocation()
|
||||
|
||||
// For Go versions 1.16 and above, `go list` accepts overlays directly via
|
||||
// the -overlay flag. Set it, if it's available.
|
||||
//
|
||||
// The check for "list" is not necessarily required, but we should avoid
|
||||
// getting the go version if possible.
|
||||
if verb == "list" {
|
||||
goVersion, err := state.getGoVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if goVersion >= 16 {
|
||||
filename, cleanup, err := state.writeOverlays()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cleanup()
|
||||
inv.Overlay = filename
|
||||
}
|
||||
}
|
||||
inv.Verb = verb
|
||||
inv.Args = args
|
||||
gocmdRunner := cfg.gocmdRunner
|
||||
if gocmdRunner == nil {
|
||||
gocmdRunner = &gocommand.Runner{}
|
||||
}
|
||||
stdout, stderr, friendlyErr, err := gocmdRunner.RunRaw(cfg.Context, inv)
|
||||
|
||||
stdout, stderr, friendlyErr, err := state.runner.RunRaw(cfg.Context, inv)
|
||||
if err != nil {
|
||||
// Check for 'go' executable not being found.
|
||||
if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound {
|
||||
|
@ -971,6 +893,12 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
|
|||
return nil, friendlyErr
|
||||
}
|
||||
|
||||
// Return an error if 'go list' failed due to missing tools in
|
||||
// $GOROOT/pkg/tool/$GOOS_$GOARCH (#69606).
|
||||
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), `go: no such tool`) {
|
||||
return nil, friendlyErr
|
||||
}
|
||||
|
||||
// Is there an error running the C compiler in cgo? This will be reported in the "Error" field
|
||||
// and should be suppressed by go list -e.
|
||||
//
|
||||
|
@ -1087,67 +1015,6 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
|
|||
return stdout, nil
|
||||
}
|
||||
|
||||
// OverlayJSON is the format overlay files are expected to be in.
|
||||
// The Replace map maps from overlaid paths to replacement paths:
|
||||
// the Go command will forward all reads trying to open
|
||||
// each overlaid path to its replacement path, or consider the overlaid
|
||||
// path not to exist if the replacement path is empty.
|
||||
//
|
||||
// From golang/go#39958.
|
||||
type OverlayJSON struct {
|
||||
Replace map[string]string `json:"replace,omitempty"`
|
||||
}
|
||||
|
||||
// writeOverlays writes out files for go list's -overlay flag, as described
|
||||
// above.
|
||||
func (state *golistState) writeOverlays() (filename string, cleanup func(), err error) {
|
||||
// Do nothing if there are no overlays in the config.
|
||||
if len(state.cfg.Overlay) == 0 {
|
||||
return "", func() {}, nil
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "gopackages-*")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// The caller must clean up this directory, unless this function returns an
|
||||
// error.
|
||||
cleanup = func() {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
cleanup()
|
||||
}
|
||||
}()
|
||||
overlays := map[string]string{}
|
||||
for k, v := range state.cfg.Overlay {
|
||||
// Create a unique filename for the overlaid files, to avoid
|
||||
// creating nested directories.
|
||||
noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "")
|
||||
f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator))
|
||||
if err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
if _, err := f.Write(v); err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
overlays[k] = f.Name()
|
||||
}
|
||||
b, err := json.Marshal(OverlayJSON{Replace: overlays})
|
||||
if err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
// Write out the overlay file that contains the filepath mappings.
|
||||
filename = filepath.Join(dir, "overlay.json")
|
||||
if err := ioutil.WriteFile(filename, b, 0665); err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
return filename, cleanup, nil
|
||||
}
|
||||
|
||||
func containsGoFile(s []string) bool {
|
||||
for _, f := range s {
|
||||
if strings.HasSuffix(f, ".go") {
|
||||
|
@ -1176,3 +1043,44 @@ func cmdDebugStr(cmd *exec.Cmd) string {
|
|||
}
|
||||
return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], strings.Join(args, " "))
|
||||
}
|
||||
|
||||
// getSizesForArgs queries 'go list' for the appropriate
|
||||
// Compiler and GOARCH arguments to pass to [types.SizesFor].
|
||||
func getSizesForArgs(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) {
|
||||
inv.Verb = "list"
|
||||
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
|
||||
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
|
||||
var goarch, compiler string
|
||||
if rawErr != nil {
|
||||
rawErrMsg := rawErr.Error()
|
||||
if strings.Contains(rawErrMsg, "cannot find main module") ||
|
||||
strings.Contains(rawErrMsg, "go.mod file not found") {
|
||||
// User's running outside of a module.
|
||||
// All bets are off. Get GOARCH and guess compiler is gc.
|
||||
// TODO(matloob): Is this a problem in practice?
|
||||
inv.Verb = "env"
|
||||
inv.Args = []string{"GOARCH"}
|
||||
envout, enverr := gocmdRunner.Run(ctx, inv)
|
||||
if enverr != nil {
|
||||
return "", "", enverr
|
||||
}
|
||||
goarch = strings.TrimSpace(envout.String())
|
||||
compiler = "gc"
|
||||
} else if friendlyErr != nil {
|
||||
return "", "", friendlyErr
|
||||
} else {
|
||||
// This should be unreachable, but be defensive
|
||||
// in case RunRaw's error results are inconsistent.
|
||||
return "", "", rawErr
|
||||
}
|
||||
} else {
|
||||
fields := strings.Fields(stdout.String())
|
||||
if len(fields) < 2 {
|
||||
return "", "", fmt.Errorf("could not parse GOARCH and Go compiler in format \"<GOARCH> <compiler>\":\nstdout: <<%s>>\nstderr: <<%s>>",
|
||||
stdout.String(), stderr.String())
|
||||
}
|
||||
goarch = fields[0]
|
||||
compiler = fields[1]
|
||||
}
|
||||
return compiler, goarch, nil
|
||||
}
|
||||
|
|
492
vendor/golang.org/x/tools/go/packages/golist_overlay.go
generated
vendored
492
vendor/golang.org/x/tools/go/packages/golist_overlay.go
generated
vendored
|
@ -6,314 +6,11 @@ package packages
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
)
|
||||
|
||||
// processGolistOverlay provides rudimentary support for adding
|
||||
// files that don't exist on disk to an overlay. The results can be
|
||||
// sometimes incorrect.
|
||||
// TODO(matloob): Handle unsupported cases, including the following:
|
||||
// - determining the correct package to add given a new import path
|
||||
func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) {
|
||||
havePkgs := make(map[string]string) // importPath -> non-test package ID
|
||||
needPkgsSet := make(map[string]bool)
|
||||
modifiedPkgsSet := make(map[string]bool)
|
||||
|
||||
pkgOfDir := make(map[string][]*Package)
|
||||
for _, pkg := range response.dr.Packages {
|
||||
// This is an approximation of import path to id. This can be
|
||||
// wrong for tests, vendored packages, and a number of other cases.
|
||||
havePkgs[pkg.PkgPath] = pkg.ID
|
||||
dir, err := commonDir(pkg.GoFiles)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if dir != "" {
|
||||
pkgOfDir[dir] = append(pkgOfDir[dir], pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// If no new imports are added, it is safe to avoid loading any needPkgs.
|
||||
// Otherwise, it's hard to tell which package is actually being loaded
|
||||
// (due to vendoring) and whether any modified package will show up
|
||||
// in the transitive set of dependencies (because new imports are added,
|
||||
// potentially modifying the transitive set of dependencies).
|
||||
var overlayAddsImports bool
|
||||
|
||||
// If both a package and its test package are created by the overlay, we
|
||||
// need the real package first. Process all non-test files before test
|
||||
// files, and make the whole process deterministic while we're at it.
|
||||
var overlayFiles []string
|
||||
for opath := range state.cfg.Overlay {
|
||||
overlayFiles = append(overlayFiles, opath)
|
||||
}
|
||||
sort.Slice(overlayFiles, func(i, j int) bool {
|
||||
iTest := strings.HasSuffix(overlayFiles[i], "_test.go")
|
||||
jTest := strings.HasSuffix(overlayFiles[j], "_test.go")
|
||||
if iTest != jTest {
|
||||
return !iTest // non-tests are before tests.
|
||||
}
|
||||
return overlayFiles[i] < overlayFiles[j]
|
||||
})
|
||||
for _, opath := range overlayFiles {
|
||||
contents := state.cfg.Overlay[opath]
|
||||
base := filepath.Base(opath)
|
||||
dir := filepath.Dir(opath)
|
||||
var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant
|
||||
var testVariantOf *Package // if opath is a test file, this is the package it is testing
|
||||
var fileExists bool
|
||||
isTestFile := strings.HasSuffix(opath, "_test.go")
|
||||
pkgName, ok := extractPackageName(opath, contents)
|
||||
if !ok {
|
||||
// Don't bother adding a file that doesn't even have a parsable package statement
|
||||
// to the overlay.
|
||||
continue
|
||||
}
|
||||
// If all the overlay files belong to a different package, change the
|
||||
// package name to that package.
|
||||
maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir])
|
||||
nextPackage:
|
||||
for _, p := range response.dr.Packages {
|
||||
if pkgName != p.Name && p.ID != "command-line-arguments" {
|
||||
continue
|
||||
}
|
||||
for _, f := range p.GoFiles {
|
||||
if !sameFile(filepath.Dir(f), dir) {
|
||||
continue
|
||||
}
|
||||
// Make sure to capture information on the package's test variant, if needed.
|
||||
if isTestFile && !hasTestFiles(p) {
|
||||
// TODO(matloob): Are there packages other than the 'production' variant
|
||||
// of a package that this can match? This shouldn't match the test main package
|
||||
// because the file is generated in another directory.
|
||||
testVariantOf = p
|
||||
continue nextPackage
|
||||
} else if !isTestFile && hasTestFiles(p) {
|
||||
// We're examining a test variant, but the overlaid file is
|
||||
// a non-test file. Because the overlay implementation
|
||||
// (currently) only adds a file to one package, skip this
|
||||
// package, so that we can add the file to the production
|
||||
// variant of the package. (https://golang.org/issue/36857
|
||||
// tracks handling overlays on both the production and test
|
||||
// variant of a package).
|
||||
continue nextPackage
|
||||
}
|
||||
if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath {
|
||||
// We have already seen the production version of the
|
||||
// for which p is a test variant.
|
||||
if hasTestFiles(p) {
|
||||
testVariantOf = pkg
|
||||
}
|
||||
}
|
||||
pkg = p
|
||||
if filepath.Base(f) == base {
|
||||
fileExists = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// The overlay could have included an entirely new package or an
|
||||
// ad-hoc package. An ad-hoc package is one that we have manually
|
||||
// constructed from inadequate `go list` results for a file= query.
|
||||
// It will have the ID command-line-arguments.
|
||||
if pkg == nil || pkg.ID == "command-line-arguments" {
|
||||
// Try to find the module or gopath dir the file is contained in.
|
||||
// Then for modules, add the module opath to the beginning.
|
||||
pkgPath, ok, err := state.getPkgPath(dir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
var forTest string // only set for x tests
|
||||
isXTest := strings.HasSuffix(pkgName, "_test")
|
||||
if isXTest {
|
||||
forTest = pkgPath
|
||||
pkgPath += "_test"
|
||||
}
|
||||
id := pkgPath
|
||||
if isTestFile {
|
||||
if isXTest {
|
||||
id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest)
|
||||
} else {
|
||||
id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
|
||||
}
|
||||
}
|
||||
if pkg != nil {
|
||||
// TODO(rstambler): We should change the package's path and ID
|
||||
// here. The only issue is that this messes with the roots.
|
||||
} else {
|
||||
// Try to reclaim a package with the same ID, if it exists in the response.
|
||||
for _, p := range response.dr.Packages {
|
||||
if reclaimPackage(p, id, opath, contents) {
|
||||
pkg = p
|
||||
break
|
||||
}
|
||||
}
|
||||
// Otherwise, create a new package.
|
||||
if pkg == nil {
|
||||
pkg = &Package{
|
||||
PkgPath: pkgPath,
|
||||
ID: id,
|
||||
Name: pkgName,
|
||||
Imports: make(map[string]*Package),
|
||||
}
|
||||
response.addPackage(pkg)
|
||||
havePkgs[pkg.PkgPath] = id
|
||||
// Add the production package's sources for a test variant.
|
||||
if isTestFile && !isXTest && testVariantOf != nil {
|
||||
pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
|
||||
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
|
||||
// Add the package under test and its imports to the test variant.
|
||||
pkg.forTest = testVariantOf.PkgPath
|
||||
for k, v := range testVariantOf.Imports {
|
||||
pkg.Imports[k] = &Package{ID: v.ID}
|
||||
}
|
||||
}
|
||||
if isXTest {
|
||||
pkg.forTest = forTest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !fileExists {
|
||||
pkg.GoFiles = append(pkg.GoFiles, opath)
|
||||
// TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior
|
||||
// if the file will be ignored due to its build tags.
|
||||
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath)
|
||||
modifiedPkgsSet[pkg.ID] = true
|
||||
}
|
||||
imports, err := extractImports(opath, contents)
|
||||
if err != nil {
|
||||
// Let the parser or type checker report errors later.
|
||||
continue
|
||||
}
|
||||
for _, imp := range imports {
|
||||
// TODO(rstambler): If the package is an x test and the import has
|
||||
// a test variant, make sure to replace it.
|
||||
if _, found := pkg.Imports[imp]; found {
|
||||
continue
|
||||
}
|
||||
overlayAddsImports = true
|
||||
id, ok := havePkgs[imp]
|
||||
if !ok {
|
||||
var err error
|
||||
id, err = state.resolveImport(dir, imp)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
pkg.Imports[imp] = &Package{ID: id}
|
||||
// Add dependencies to the non-test variant version of this package as well.
|
||||
if testVariantOf != nil {
|
||||
testVariantOf.Imports[imp] = &Package{ID: id}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// toPkgPath guesses the package path given the id.
|
||||
toPkgPath := func(sourceDir, id string) (string, error) {
|
||||
if i := strings.IndexByte(id, ' '); i >= 0 {
|
||||
return state.resolveImport(sourceDir, id[:i])
|
||||
}
|
||||
return state.resolveImport(sourceDir, id)
|
||||
}
|
||||
|
||||
// Now that new packages have been created, do another pass to determine
|
||||
// the new set of missing packages.
|
||||
for _, pkg := range response.dr.Packages {
|
||||
for _, imp := range pkg.Imports {
|
||||
if len(pkg.GoFiles) == 0 {
|
||||
return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath)
|
||||
}
|
||||
pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if _, ok := havePkgs[pkgPath]; !ok {
|
||||
needPkgsSet[pkgPath] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if overlayAddsImports {
|
||||
needPkgs = make([]string, 0, len(needPkgsSet))
|
||||
for pkg := range needPkgsSet {
|
||||
needPkgs = append(needPkgs, pkg)
|
||||
}
|
||||
}
|
||||
modifiedPkgs = make([]string, 0, len(modifiedPkgsSet))
|
||||
for pkg := range modifiedPkgsSet {
|
||||
modifiedPkgs = append(modifiedPkgs, pkg)
|
||||
}
|
||||
return modifiedPkgs, needPkgs, err
|
||||
}
|
||||
|
||||
// resolveImport finds the ID of a package given its import path.
|
||||
// In particular, it will find the right vendored copy when in GOPATH mode.
|
||||
func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) {
|
||||
env, err := state.getEnv()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if env["GOMOD"] != "" {
|
||||
return importPath, nil
|
||||
}
|
||||
|
||||
searchDir := sourceDir
|
||||
for {
|
||||
vendorDir := filepath.Join(searchDir, "vendor")
|
||||
exists, ok := state.vendorDirs[vendorDir]
|
||||
if !ok {
|
||||
info, err := os.Stat(vendorDir)
|
||||
exists = err == nil && info.IsDir()
|
||||
state.vendorDirs[vendorDir] = exists
|
||||
}
|
||||
|
||||
if exists {
|
||||
vendoredPath := filepath.Join(vendorDir, importPath)
|
||||
if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() {
|
||||
// We should probably check for .go files here, but shame on anyone who fools us.
|
||||
path, ok, err := state.getPkgPath(vendoredPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ok {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We know we've hit the top of the filesystem when we Dir / and get /,
|
||||
// or C:\ and get C:\, etc.
|
||||
next := filepath.Dir(searchDir)
|
||||
if next == searchDir {
|
||||
break
|
||||
}
|
||||
searchDir = next
|
||||
}
|
||||
return importPath, nil
|
||||
}
|
||||
|
||||
func hasTestFiles(p *Package) bool {
|
||||
for _, f := range p.GoFiles {
|
||||
if strings.HasSuffix(f, "_test.go") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// determineRootDirs returns a mapping from absolute directories that could
|
||||
// contain code to their corresponding import path prefixes.
|
||||
func (state *golistState) determineRootDirs() (map[string]string, error) {
|
||||
|
@ -384,192 +81,3 @@ func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) {
|
|||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func extractImports(filename string, contents []byte) ([]string, error) {
|
||||
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset?
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res []string
|
||||
for _, imp := range f.Imports {
|
||||
quotedPath := imp.Path.Value
|
||||
path, err := strconv.Unquote(quotedPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, path)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// reclaimPackage attempts to reuse a package that failed to load in an overlay.
|
||||
//
|
||||
// If the package has errors and has no Name, GoFiles, or Imports,
|
||||
// then it's possible that it doesn't yet exist on disk.
|
||||
func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool {
|
||||
// TODO(rstambler): Check the message of the actual error?
|
||||
// It differs between $GOPATH and module mode.
|
||||
if pkg.ID != id {
|
||||
return false
|
||||
}
|
||||
if len(pkg.Errors) != 1 {
|
||||
return false
|
||||
}
|
||||
if pkg.Name != "" || pkg.ExportFile != "" {
|
||||
return false
|
||||
}
|
||||
if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 {
|
||||
return false
|
||||
}
|
||||
if len(pkg.Imports) > 0 {
|
||||
return false
|
||||
}
|
||||
pkgName, ok := extractPackageName(filename, contents)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
pkg.Name = pkgName
|
||||
pkg.Errors = nil
|
||||
return true
|
||||
}
|
||||
|
||||
func extractPackageName(filename string, contents []byte) (string, bool) {
|
||||
// TODO(rstambler): Check the message of the actual error?
|
||||
// It differs between $GOPATH and module mode.
|
||||
f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset?
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return f.Name.Name, true
|
||||
}
|
||||
|
||||
// commonDir returns the directory that all files are in, "" if files is empty,
|
||||
// or an error if they aren't in the same directory.
|
||||
func commonDir(files []string) (string, error) {
|
||||
seen := make(map[string]bool)
|
||||
for _, f := range files {
|
||||
seen[filepath.Dir(f)] = true
|
||||
}
|
||||
if len(seen) > 1 {
|
||||
return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen)
|
||||
}
|
||||
for k := range seen {
|
||||
// seen has only one element; return it.
|
||||
return k, nil
|
||||
}
|
||||
return "", nil // no files
|
||||
}
|
||||
|
||||
// It is possible that the files in the disk directory dir have a different package
|
||||
// name from newName, which is deduced from the overlays. If they all have a different
|
||||
// package name, and they all have the same package name, then that name becomes
|
||||
// the package name.
|
||||
// It returns true if it changes the package name, false otherwise.
|
||||
func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) {
|
||||
names := make(map[string]int)
|
||||
for _, p := range pkgsOfDir {
|
||||
names[p.Name]++
|
||||
}
|
||||
if len(names) != 1 {
|
||||
// some files are in different packages
|
||||
return
|
||||
}
|
||||
var oldName string
|
||||
for k := range names {
|
||||
oldName = k
|
||||
}
|
||||
if newName == oldName {
|
||||
return
|
||||
}
|
||||
// We might have a case where all of the package names in the directory are
|
||||
// the same, but the overlay file is for an x test, which belongs to its
|
||||
// own package. If the x test does not yet exist on disk, we may not yet
|
||||
// have its package name on disk, but we should not rename the packages.
|
||||
//
|
||||
// We use a heuristic to determine if this file belongs to an x test:
|
||||
// The test file should have a package name whose package name has a _test
|
||||
// suffix or looks like "newName_test".
|
||||
maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test")
|
||||
if isTestFile && maybeXTest {
|
||||
return
|
||||
}
|
||||
for _, p := range pkgsOfDir {
|
||||
p.Name = newName
|
||||
}
|
||||
}
|
||||
|
||||
// This function is copy-pasted from
|
||||
// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360.
|
||||
// It should be deleted when we remove support for overlays from go/packages.
|
||||
//
|
||||
// NOTE: This does not handle any ./... or ./ style queries, as this function
|
||||
// doesn't know the working directory.
|
||||
//
|
||||
// matchPattern(pattern)(name) reports whether
|
||||
// name matches pattern. Pattern is a limited glob
|
||||
// pattern in which '...' means 'any string' and there
|
||||
// is no other special syntax.
|
||||
// Unfortunately, there are two special cases. Quoting "go help packages":
|
||||
//
|
||||
// First, /... at the end of the pattern can match an empty string,
|
||||
// so that net/... matches both net and packages in its subdirectories, like net/http.
|
||||
// Second, any slash-separated pattern element containing a wildcard never
|
||||
// participates in a match of the "vendor" element in the path of a vendored
|
||||
// package, so that ./... does not match packages in subdirectories of
|
||||
// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
|
||||
// Note, however, that a directory named vendor that itself contains code
|
||||
// is not a vendored package: cmd/vendor would be a command named vendor,
|
||||
// and the pattern cmd/... matches it.
|
||||
func matchPattern(pattern string) func(name string) bool {
|
||||
// Convert pattern to regular expression.
|
||||
// The strategy for the trailing /... is to nest it in an explicit ? expression.
|
||||
// The strategy for the vendor exclusion is to change the unmatchable
|
||||
// vendor strings to a disallowed code point (vendorChar) and to use
|
||||
// "(anything but that codepoint)*" as the implementation of the ... wildcard.
|
||||
// This is a bit complicated but the obvious alternative,
|
||||
// namely a hand-written search like in most shell glob matchers,
|
||||
// is too easy to make accidentally exponential.
|
||||
// Using package regexp guarantees linear-time matching.
|
||||
|
||||
const vendorChar = "\x00"
|
||||
|
||||
if strings.Contains(pattern, vendorChar) {
|
||||
return func(name string) bool { return false }
|
||||
}
|
||||
|
||||
re := regexp.QuoteMeta(pattern)
|
||||
re = replaceVendor(re, vendorChar)
|
||||
switch {
|
||||
case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
|
||||
re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
|
||||
case re == vendorChar+`/\.\.\.`:
|
||||
re = `(/vendor|/` + vendorChar + `/\.\.\.)`
|
||||
case strings.HasSuffix(re, `/\.\.\.`):
|
||||
re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
|
||||
}
|
||||
re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`)
|
||||
|
||||
reg := regexp.MustCompile(`^` + re + `$`)
|
||||
|
||||
return func(name string) bool {
|
||||
if strings.Contains(name, vendorChar) {
|
||||
return false
|
||||
}
|
||||
return reg.MatchString(replaceVendor(name, vendorChar))
|
||||
}
|
||||
}
|
||||
|
||||
// replaceVendor returns the result of replacing
|
||||
// non-trailing vendor path elements in x with repl.
|
||||
func replaceVendor(x, repl string) string {
|
||||
if !strings.Contains(x, "vendor") {
|
||||
return x
|
||||
}
|
||||
elem := strings.Split(x, "/")
|
||||
for i := 0; i < len(elem)-1; i++ {
|
||||
if elem[i] == "vendor" {
|
||||
elem[i] = repl
|
||||
}
|
||||
}
|
||||
return strings.Join(elem, "/")
|
||||
}
|
||||
|
|
73
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
73
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
|
@ -9,49 +9,48 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var allModes = []LoadMode{
|
||||
NeedName,
|
||||
NeedFiles,
|
||||
NeedCompiledGoFiles,
|
||||
NeedImports,
|
||||
NeedDeps,
|
||||
NeedExportFile,
|
||||
NeedTypes,
|
||||
NeedSyntax,
|
||||
NeedTypesInfo,
|
||||
NeedTypesSizes,
|
||||
var modes = [...]struct {
|
||||
mode LoadMode
|
||||
name string
|
||||
}{
|
||||
{NeedName, "NeedName"},
|
||||
{NeedFiles, "NeedFiles"},
|
||||
{NeedCompiledGoFiles, "NeedCompiledGoFiles"},
|
||||
{NeedImports, "NeedImports"},
|
||||
{NeedDeps, "NeedDeps"},
|
||||
{NeedExportFile, "NeedExportFile"},
|
||||
{NeedTypes, "NeedTypes"},
|
||||
{NeedSyntax, "NeedSyntax"},
|
||||
{NeedTypesInfo, "NeedTypesInfo"},
|
||||
{NeedTypesSizes, "NeedTypesSizes"},
|
||||
{NeedForTest, "NeedForTest"},
|
||||
{NeedModule, "NeedModule"},
|
||||
{NeedEmbedFiles, "NeedEmbedFiles"},
|
||||
{NeedEmbedPatterns, "NeedEmbedPatterns"},
|
||||
{NeedTarget, "NeedTarget"},
|
||||
}
|
||||
|
||||
var modeStrings = []string{
|
||||
"NeedName",
|
||||
"NeedFiles",
|
||||
"NeedCompiledGoFiles",
|
||||
"NeedImports",
|
||||
"NeedDeps",
|
||||
"NeedExportFile",
|
||||
"NeedTypes",
|
||||
"NeedSyntax",
|
||||
"NeedTypesInfo",
|
||||
"NeedTypesSizes",
|
||||
}
|
||||
|
||||
func (mod LoadMode) String() string {
|
||||
m := mod
|
||||
if m == 0 {
|
||||
func (mode LoadMode) String() string {
|
||||
if mode == 0 {
|
||||
return "LoadMode(0)"
|
||||
}
|
||||
var out []string
|
||||
for i, x := range allModes {
|
||||
if x > m {
|
||||
break
|
||||
}
|
||||
if (m & x) != 0 {
|
||||
out = append(out, modeStrings[i])
|
||||
m = m ^ x
|
||||
// named bits
|
||||
for _, item := range modes {
|
||||
if (mode & item.mode) != 0 {
|
||||
mode ^= item.mode
|
||||
out = append(out, item.name)
|
||||
}
|
||||
}
|
||||
if m != 0 {
|
||||
out = append(out, "Unknown")
|
||||
// unnamed residue
|
||||
if mode != 0 {
|
||||
if out == nil {
|
||||
return fmt.Sprintf("LoadMode(%#x)", int(mode))
|
||||
}
|
||||
out = append(out, fmt.Sprintf("%#x", int(mode)))
|
||||
}
|
||||
return fmt.Sprintf("LoadMode(%s)", strings.Join(out, "|"))
|
||||
if len(out) == 1 {
|
||||
return out[0]
|
||||
}
|
||||
return "(" + strings.Join(out, "|") + ")"
|
||||
}
|
||||
|
|
830
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
830
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
File diff suppressed because it is too large
Load diff
9
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
9
vendor/golang.org/x/tools/go/packages/visit.go
generated
vendored
|
@ -49,11 +49,20 @@ func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) {
|
|||
// PrintErrors returns the number of errors printed.
|
||||
func PrintErrors(pkgs []*Package) int {
|
||||
var n int
|
||||
errModules := make(map[*Module]bool)
|
||||
Visit(pkgs, nil, func(pkg *Package) {
|
||||
for _, err := range pkg.Errors {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
n++
|
||||
}
|
||||
|
||||
// Print pkg.Module.Error once if present.
|
||||
mod := pkg.Module
|
||||
if mod != nil && mod.Error != nil && !errModules[mod] {
|
||||
errModules[mod] = true
|
||||
fmt.Fprintln(os.Stderr, mod.Error.Err)
|
||||
n++
|
||||
}
|
||||
})
|
||||
return n
|
||||
}
|
||||
|
|
817
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
817
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
|
@ -0,0 +1,817 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
// Package objectpath defines a naming scheme for types.Objects
|
||||
// (that is, named entities in Go programs) relative to their enclosing
|
||||
// package.
|
||||
//
|
||||
// Type-checker objects are canonical, so they are usually identified by
|
||||
// their address in memory (a pointer), but a pointer has meaning only
|
||||
// within one address space. By contrast, objectpath names allow the
|
||||
// identity of an object to be sent from one program to another,
|
||||
// establishing a correspondence between types.Object variables that are
|
||||
// distinct but logically equivalent.
|
||||
//
|
||||
// A single object may have multiple paths. In this example,
|
||||
//
|
||||
// type A struct{ X int }
|
||||
// type B A
|
||||
//
|
||||
// the field X has two paths due to its membership of both A and B.
|
||||
// The For(obj) function always returns one of these paths, arbitrarily
|
||||
// but consistently.
|
||||
package objectpath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
// TODO(adonovan): think about generic aliases.
|
||||
|
||||
// A Path is an opaque name that identifies a types.Object
|
||||
// relative to its package. Conceptually, the name consists of a
|
||||
// sequence of destructuring operations applied to the package scope
|
||||
// to obtain the original object.
|
||||
// The name does not include the package itself.
|
||||
type Path string
|
||||
|
||||
// Encoding
|
||||
//
|
||||
// An object path is a textual and (with training) human-readable encoding
|
||||
// of a sequence of destructuring operators, starting from a types.Package.
|
||||
// The sequences represent a path through the package/object/type graph.
|
||||
// We classify these operators by their type:
|
||||
//
|
||||
// PO package->object Package.Scope.Lookup
|
||||
// OT object->type Object.Type
|
||||
// TT type->type Type.{Elem,Key,{,{,Recv}Type}Params,Results,Underlying,Rhs} [EKPRUTrCa]
|
||||
// TO type->object Type.{At,Field,Method,Obj} [AFMO]
|
||||
//
|
||||
// All valid paths start with a package and end at an object
|
||||
// and thus may be defined by the regular language:
|
||||
//
|
||||
// objectpath = PO (OT TT* TO)*
|
||||
//
|
||||
// The concrete encoding follows directly:
|
||||
// - The only PO operator is Package.Scope.Lookup, which requires an identifier.
|
||||
// - The only OT operator is Object.Type,
|
||||
// which we encode as '.' because dot cannot appear in an identifier.
|
||||
// - The TT operators are encoded as [EKPRUTrCa];
|
||||
// two of these ({,Recv}TypeParams) require an integer operand,
|
||||
// which is encoded as a string of decimal digits.
|
||||
// - The TO operators are encoded as [AFMO];
|
||||
// three of these (At,Field,Method) require an integer operand,
|
||||
// which is encoded as a string of decimal digits.
|
||||
// These indices are stable across different representations
|
||||
// of the same package, even source and export data.
|
||||
// The indices used are implementation specific and may not correspond to
|
||||
// the argument to the go/types function.
|
||||
//
|
||||
// In the example below,
|
||||
//
|
||||
// package p
|
||||
//
|
||||
// type T interface {
|
||||
// f() (a string, b struct{ X int })
|
||||
// }
|
||||
//
|
||||
// field X has the path "T.UM0.RA1.F0",
|
||||
// representing the following sequence of operations:
|
||||
//
|
||||
// p.Lookup("T") T
|
||||
// .Type().Underlying().Method(0). f
|
||||
// .Type().Results().At(1) b
|
||||
// .Type().Field(0) X
|
||||
//
|
||||
// The encoding is not maximally compact---every R or P is
|
||||
// followed by an A, for example---but this simplifies the
|
||||
// encoder and decoder.
|
||||
const (
|
||||
// object->type operators
|
||||
opType = '.' // .Type() (Object)
|
||||
|
||||
// type->type operators
|
||||
opElem = 'E' // .Elem() (Pointer, Slice, Array, Chan, Map)
|
||||
opKey = 'K' // .Key() (Map)
|
||||
opParams = 'P' // .Params() (Signature)
|
||||
opResults = 'R' // .Results() (Signature)
|
||||
opUnderlying = 'U' // .Underlying() (Named)
|
||||
opTypeParam = 'T' // .TypeParams.At(i) (Named, Signature)
|
||||
opRecvTypeParam = 'r' // .RecvTypeParams.At(i) (Signature)
|
||||
opConstraint = 'C' // .Constraint() (TypeParam)
|
||||
opRhs = 'a' // .Rhs() (Alias)
|
||||
|
||||
// type->object operators
|
||||
opAt = 'A' // .At(i) (Tuple)
|
||||
opField = 'F' // .Field(i) (Struct)
|
||||
opMethod = 'M' // .Method(i) (Named or Interface; not Struct: "promoted" names are ignored)
|
||||
opObj = 'O' // .Obj() (Named, TypeParam)
|
||||
)
|
||||
|
||||
// For is equivalent to new(Encoder).For(obj).
|
||||
//
|
||||
// It may be more efficient to reuse a single Encoder across several calls.
|
||||
func For(obj types.Object) (Path, error) {
|
||||
return new(Encoder).For(obj)
|
||||
}
|
||||
|
||||
// An Encoder amortizes the cost of encoding the paths of multiple objects.
|
||||
// The zero value of an Encoder is ready to use.
|
||||
type Encoder struct {
|
||||
scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
|
||||
}
|
||||
|
||||
// For returns the path to an object relative to its package,
|
||||
// or an error if the object is not accessible from the package's Scope.
|
||||
//
|
||||
// The For function guarantees to return a path only for the following objects:
|
||||
// - package-level types
|
||||
// - exported package-level non-types
|
||||
// - methods
|
||||
// - parameter and result variables
|
||||
// - struct fields
|
||||
// These objects are sufficient to define the API of their package.
|
||||
// The objects described by a package's export data are drawn from this set.
|
||||
//
|
||||
// The set of objects accessible from a package's Scope depends on
|
||||
// whether the package was produced by type-checking syntax, or
|
||||
// reading export data; the latter may have a smaller Scope since
|
||||
// export data trims objects that are not reachable from an exported
|
||||
// declaration. For example, the For function will return a path for
|
||||
// an exported method of an unexported type that is not reachable
|
||||
// from any public declaration; this path will cause the Object
|
||||
// function to fail if called on a package loaded from export data.
|
||||
// TODO(adonovan): is this a bug or feature? Should this package
|
||||
// compute accessibility in the same way?
|
||||
//
|
||||
// For does not return a path for predeclared names, imported package
|
||||
// names, local names, and unexported package-level names (except
|
||||
// types).
|
||||
//
|
||||
// Example: given this definition,
|
||||
//
|
||||
// package p
|
||||
//
|
||||
// type T interface {
|
||||
// f() (a string, b struct{ X int })
|
||||
// }
|
||||
//
|
||||
// For(X) would return a path that denotes the following sequence of operations:
|
||||
//
|
||||
// p.Scope().Lookup("T") (TypeName T)
|
||||
// .Type().Underlying().Method(0). (method Func f)
|
||||
// .Type().Results().At(1) (field Var b)
|
||||
// .Type().Field(0) (field Var X)
|
||||
//
|
||||
// where p is the package (*types.Package) to which X belongs.
|
||||
func (enc *Encoder) For(obj types.Object) (Path, error) {
|
||||
pkg := obj.Pkg()
|
||||
|
||||
// This table lists the cases of interest.
|
||||
//
|
||||
// Object Action
|
||||
// ------ ------
|
||||
// nil reject
|
||||
// builtin reject
|
||||
// pkgname reject
|
||||
// label reject
|
||||
// var
|
||||
// package-level accept
|
||||
// func param/result accept
|
||||
// local reject
|
||||
// struct field accept
|
||||
// const
|
||||
// package-level accept
|
||||
// local reject
|
||||
// func
|
||||
// package-level accept
|
||||
// init functions reject
|
||||
// concrete method accept
|
||||
// interface method accept
|
||||
// type
|
||||
// package-level accept
|
||||
// local reject
|
||||
//
|
||||
// The only accessible package-level objects are members of pkg itself.
|
||||
//
|
||||
// The cases are handled in four steps:
|
||||
//
|
||||
// 1. reject nil and builtin
|
||||
// 2. accept package-level objects
|
||||
// 3. reject obviously invalid objects
|
||||
// 4. search the API for the path to the param/result/field/method.
|
||||
|
||||
// 1. reference to nil or builtin?
|
||||
if pkg == nil {
|
||||
return "", fmt.Errorf("predeclared %s has no path", obj)
|
||||
}
|
||||
scope := pkg.Scope()
|
||||
|
||||
// 2. package-level object?
|
||||
if scope.Lookup(obj.Name()) == obj {
|
||||
// Only exported objects (and non-exported types) have a path.
|
||||
// Non-exported types may be referenced by other objects.
|
||||
if _, ok := obj.(*types.TypeName); !ok && !obj.Exported() {
|
||||
return "", fmt.Errorf("no path for non-exported %v", obj)
|
||||
}
|
||||
return Path(obj.Name()), nil
|
||||
}
|
||||
|
||||
// 3. Not a package-level object.
|
||||
// Reject obviously non-viable cases.
|
||||
switch obj := obj.(type) {
|
||||
case *types.TypeName:
|
||||
if _, ok := types.Unalias(obj.Type()).(*types.TypeParam); !ok {
|
||||
// With the exception of type parameters, only package-level type names
|
||||
// have a path.
|
||||
return "", fmt.Errorf("no path for %v", obj)
|
||||
}
|
||||
case *types.Const, // Only package-level constants have a path.
|
||||
*types.Label, // Labels are function-local.
|
||||
*types.PkgName: // PkgNames are file-local.
|
||||
return "", fmt.Errorf("no path for %v", obj)
|
||||
|
||||
case *types.Var:
|
||||
// Could be:
|
||||
// - a field (obj.IsField())
|
||||
// - a func parameter or result
|
||||
// - a local var.
|
||||
// Sadly there is no way to distinguish
|
||||
// a param/result from a local
|
||||
// so we must proceed to the find.
|
||||
|
||||
case *types.Func:
|
||||
// A func, if not package-level, must be a method.
|
||||
if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
|
||||
return "", fmt.Errorf("func is not a method: %v", obj)
|
||||
}
|
||||
|
||||
if path, ok := enc.concreteMethod(obj); ok {
|
||||
// Fast path for concrete methods that avoids looping over scope.
|
||||
return path, nil
|
||||
}
|
||||
|
||||
default:
|
||||
panic(obj)
|
||||
}
|
||||
|
||||
// 4. Search the API for the path to the var (field/param/result) or method.
|
||||
|
||||
// First inspect package-level named types.
|
||||
// In the presence of path aliases, these give
|
||||
// the best paths because non-types may
|
||||
// refer to types, but not the reverse.
|
||||
empty := make([]byte, 0, 48) // initial space
|
||||
objs := enc.scopeObjects(scope)
|
||||
for _, o := range objs {
|
||||
tname, ok := o.(*types.TypeName)
|
||||
if !ok {
|
||||
continue // handle non-types in second pass
|
||||
}
|
||||
|
||||
path := append(empty, o.Name()...)
|
||||
path = append(path, opType)
|
||||
|
||||
T := o.Type()
|
||||
if alias, ok := T.(*types.Alias); ok {
|
||||
if r := findTypeParam(obj, aliases.TypeParams(alias), path, opTypeParam); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
if r := find(obj, aliases.Rhs(alias), append(path, opRhs)); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
|
||||
} else if tname.IsAlias() {
|
||||
// legacy alias
|
||||
if r := find(obj, T, path); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
|
||||
} else if named, ok := T.(*types.Named); ok {
|
||||
// defined (named) type
|
||||
if r := findTypeParam(obj, named.TypeParams(), path, opTypeParam); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
if r := find(obj, named.Underlying(), append(path, opUnderlying)); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then inspect everything else:
|
||||
// non-types, and declared methods of defined types.
|
||||
for _, o := range objs {
|
||||
path := append(empty, o.Name()...)
|
||||
if _, ok := o.(*types.TypeName); !ok {
|
||||
if o.Exported() {
|
||||
// exported non-type (const, var, func)
|
||||
if r := find(obj, o.Type(), append(path, opType)); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Inspect declared methods of defined types.
|
||||
if T, ok := types.Unalias(o.Type()).(*types.Named); ok {
|
||||
path = append(path, opType)
|
||||
// The method index here is always with respect
|
||||
// to the underlying go/types data structures,
|
||||
// which ultimately derives from source order
|
||||
// and must be preserved by export data.
|
||||
for i := 0; i < T.NumMethods(); i++ {
|
||||
m := T.Method(i)
|
||||
path2 := appendOpArg(path, opMethod, i)
|
||||
if m == obj {
|
||||
return Path(path2), nil // found declared method
|
||||
}
|
||||
if r := find(obj, m.Type(), append(path2, opType)); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("can't find path for %v in %s", obj, pkg.Path())
|
||||
}
|
||||
|
||||
func appendOpArg(path []byte, op byte, arg int) []byte {
|
||||
path = append(path, op)
|
||||
path = strconv.AppendInt(path, int64(arg), 10)
|
||||
return path
|
||||
}
|
||||
|
||||
// concreteMethod returns the path for meth, which must have a non-nil receiver.
|
||||
// The second return value indicates success and may be false if the method is
|
||||
// an interface method or if it is an instantiated method.
|
||||
//
|
||||
// This function is just an optimization that avoids the general scope walking
|
||||
// approach. You are expected to fall back to the general approach if this
|
||||
// function fails.
|
||||
func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
|
||||
// Concrete methods can only be declared on package-scoped named types. For
|
||||
// that reason we can skip the expensive walk over the package scope: the
|
||||
// path will always be package -> named type -> method. We can trivially get
|
||||
// the type name from the receiver, and only have to look over the type's
|
||||
// methods to find the method index.
|
||||
//
|
||||
// Methods on generic types require special consideration, however. Consider
|
||||
// the following package:
|
||||
//
|
||||
// L1: type S[T any] struct{}
|
||||
// L2: func (recv S[A]) Foo() { recv.Bar() }
|
||||
// L3: func (recv S[B]) Bar() { }
|
||||
// L4: type Alias = S[int]
|
||||
// L5: func _[T any]() { var s S[int]; s.Foo() }
|
||||
//
|
||||
// The receivers of methods on generic types are instantiations. L2 and L3
|
||||
// instantiate S with the type-parameters A and B, which are scoped to the
|
||||
// respective methods. L4 and L5 each instantiate S with int. Each of these
|
||||
// instantiations has its own method set, full of methods (and thus objects)
|
||||
// with receivers whose types are the respective instantiations. In other
|
||||
// words, we have
|
||||
//
|
||||
// S[A].Foo, S[A].Bar
|
||||
// S[B].Foo, S[B].Bar
|
||||
// S[int].Foo, S[int].Bar
|
||||
//
|
||||
// We may thus be trying to produce object paths for any of these objects.
|
||||
//
|
||||
// S[A].Foo and S[B].Bar are the origin methods, and their paths are S.Foo
|
||||
// and S.Bar, which are the paths that this function naturally produces.
|
||||
//
|
||||
// S[A].Bar, S[B].Foo, and both methods on S[int] are instantiations that
|
||||
// don't correspond to the origin methods. For S[int], this is significant.
|
||||
// The most precise object path for S[int].Foo, for example, is Alias.Foo,
|
||||
// not S.Foo. Our function, however, would produce S.Foo, which would
|
||||
// resolve to a different object.
|
||||
//
|
||||
// For S[A].Bar and S[B].Foo it could be argued that S.Bar and S.Foo are
|
||||
// still the correct paths, since only the origin methods have meaningful
|
||||
// paths. But this is likely only true for trivial cases and has edge cases.
|
||||
// Since this function is only an optimization, we err on the side of giving
|
||||
// up, deferring to the slower but definitely correct algorithm. Most users
|
||||
// of objectpath will only be giving us origin methods, anyway, as referring
|
||||
// to instantiated methods is usually not useful.
|
||||
|
||||
if meth.Origin() != meth {
|
||||
return "", false
|
||||
}
|
||||
|
||||
_, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv())
|
||||
if named == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if types.IsInterface(named) {
|
||||
// Named interfaces don't have to be package-scoped
|
||||
//
|
||||
// TODO(dominikh): opt: if scope.Lookup(name) == named, then we can apply this optimization to interface
|
||||
// methods, too, I think.
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Preallocate space for the name, opType, opMethod, and some digits.
|
||||
name := named.Obj().Name()
|
||||
path := make([]byte, 0, len(name)+8)
|
||||
path = append(path, name...)
|
||||
path = append(path, opType)
|
||||
|
||||
// Method indices are w.r.t. the go/types data structures,
|
||||
// ultimately deriving from source order,
|
||||
// which is preserved by export data.
|
||||
for i := 0; i < named.NumMethods(); i++ {
|
||||
if named.Method(i) == meth {
|
||||
path = appendOpArg(path, opMethod, i)
|
||||
return Path(path), true
|
||||
}
|
||||
}
|
||||
|
||||
// Due to golang/go#59944, go/types fails to associate the receiver with
|
||||
// certain methods on cgo types.
|
||||
//
|
||||
// TODO(rfindley): replace this panic once golang/go#59944 is fixed in all Go
|
||||
// versions gopls supports.
|
||||
return "", false
|
||||
// panic(fmt.Sprintf("couldn't find method %s on type %s; methods: %#v", meth, named, enc.namedMethods(named)))
|
||||
}
|
||||
|
||||
// find finds obj within type T, returning the path to it, or nil if not found.
|
||||
//
|
||||
// The seen map is used to short circuit cycles through type parameters. If
|
||||
// nil, it will be allocated as necessary.
|
||||
//
|
||||
// The seenMethods map is used internally to short circuit cycles through
|
||||
// interface methods, such as occur in the following example:
|
||||
//
|
||||
// type I interface { f() interface{I} }
|
||||
//
|
||||
// See golang/go#68046 for details.
|
||||
func find(obj types.Object, T types.Type, path []byte) []byte {
|
||||
return (&finder{obj: obj}).find(T, path)
|
||||
}
|
||||
|
||||
// finder closes over search state for a call to find.
|
||||
type finder struct {
|
||||
obj types.Object // the sought object
|
||||
seenTParamNames map[*types.TypeName]bool // for cycle breaking through type parameters
|
||||
seenMethods map[*types.Func]bool // for cycle breaking through recursive interfaces
|
||||
}
|
||||
|
||||
func (f *finder) find(T types.Type, path []byte) []byte {
|
||||
switch T := T.(type) {
|
||||
case *types.Alias:
|
||||
return f.find(types.Unalias(T), path)
|
||||
case *types.Basic, *types.Named:
|
||||
// Named types belonging to pkg were handled already,
|
||||
// so T must belong to another package. No path.
|
||||
return nil
|
||||
case *types.Pointer:
|
||||
return f.find(T.Elem(), append(path, opElem))
|
||||
case *types.Slice:
|
||||
return f.find(T.Elem(), append(path, opElem))
|
||||
case *types.Array:
|
||||
return f.find(T.Elem(), append(path, opElem))
|
||||
case *types.Chan:
|
||||
return f.find(T.Elem(), append(path, opElem))
|
||||
case *types.Map:
|
||||
if r := f.find(T.Key(), append(path, opKey)); r != nil {
|
||||
return r
|
||||
}
|
||||
return f.find(T.Elem(), append(path, opElem))
|
||||
case *types.Signature:
|
||||
if r := f.findTypeParam(T.RecvTypeParams(), path, opRecvTypeParam); r != nil {
|
||||
return r
|
||||
}
|
||||
if r := f.findTypeParam(T.TypeParams(), path, opTypeParam); r != nil {
|
||||
return r
|
||||
}
|
||||
if r := f.find(T.Params(), append(path, opParams)); r != nil {
|
||||
return r
|
||||
}
|
||||
return f.find(T.Results(), append(path, opResults))
|
||||
case *types.Struct:
|
||||
for i := 0; i < T.NumFields(); i++ {
|
||||
fld := T.Field(i)
|
||||
path2 := appendOpArg(path, opField, i)
|
||||
if fld == f.obj {
|
||||
return path2 // found field var
|
||||
}
|
||||
if r := f.find(fld.Type(), append(path2, opType)); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *types.Tuple:
|
||||
for i := 0; i < T.Len(); i++ {
|
||||
v := T.At(i)
|
||||
path2 := appendOpArg(path, opAt, i)
|
||||
if v == f.obj {
|
||||
return path2 // found param/result var
|
||||
}
|
||||
if r := f.find(v.Type(), append(path2, opType)); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *types.Interface:
|
||||
for i := 0; i < T.NumMethods(); i++ {
|
||||
m := T.Method(i)
|
||||
if f.seenMethods[m] {
|
||||
return nil
|
||||
}
|
||||
path2 := appendOpArg(path, opMethod, i)
|
||||
if m == f.obj {
|
||||
return path2 // found interface method
|
||||
}
|
||||
if f.seenMethods == nil {
|
||||
f.seenMethods = make(map[*types.Func]bool)
|
||||
}
|
||||
f.seenMethods[m] = true
|
||||
if r := f.find(m.Type(), append(path2, opType)); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *types.TypeParam:
|
||||
name := T.Obj()
|
||||
if f.seenTParamNames[name] {
|
||||
return nil
|
||||
}
|
||||
if name == f.obj {
|
||||
return append(path, opObj)
|
||||
}
|
||||
if f.seenTParamNames == nil {
|
||||
f.seenTParamNames = make(map[*types.TypeName]bool)
|
||||
}
|
||||
f.seenTParamNames[name] = true
|
||||
if r := f.find(T.Constraint(), append(path, opConstraint)); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
}
|
||||
panic(T)
|
||||
}
|
||||
|
||||
func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, op byte) []byte {
|
||||
return (&finder{obj: obj}).findTypeParam(list, path, op)
|
||||
}
|
||||
|
||||
func (f *finder) findTypeParam(list *types.TypeParamList, path []byte, op byte) []byte {
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
tparam := list.At(i)
|
||||
path2 := appendOpArg(path, op, i)
|
||||
if r := f.find(tparam, path2); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Object returns the object denoted by path p within the package pkg.
|
||||
func Object(pkg *types.Package, p Path) (types.Object, error) {
|
||||
pathstr := string(p)
|
||||
if pathstr == "" {
|
||||
return nil, fmt.Errorf("empty path")
|
||||
}
|
||||
|
||||
var pkgobj, suffix string
|
||||
if dot := strings.IndexByte(pathstr, opType); dot < 0 {
|
||||
pkgobj = pathstr
|
||||
} else {
|
||||
pkgobj = pathstr[:dot]
|
||||
suffix = pathstr[dot:] // suffix starts with "."
|
||||
}
|
||||
|
||||
obj := pkg.Scope().Lookup(pkgobj)
|
||||
if obj == nil {
|
||||
return nil, fmt.Errorf("package %s does not contain %q", pkg.Path(), pkgobj)
|
||||
}
|
||||
|
||||
// abstraction of *types.{Pointer,Slice,Array,Chan,Map}
|
||||
type hasElem interface {
|
||||
Elem() types.Type
|
||||
}
|
||||
// abstraction of *types.{Named,Signature}
|
||||
type hasTypeParams interface {
|
||||
TypeParams() *types.TypeParamList
|
||||
}
|
||||
// abstraction of *types.{Named,TypeParam}
|
||||
type hasObj interface {
|
||||
Obj() *types.TypeName
|
||||
}
|
||||
|
||||
// The loop state is the pair (t, obj),
|
||||
// exactly one of which is non-nil, initially obj.
|
||||
// All suffixes start with '.' (the only object->type operation),
|
||||
// followed by optional type->type operations,
|
||||
// then a type->object operation.
|
||||
// The cycle then repeats.
|
||||
var t types.Type
|
||||
for suffix != "" {
|
||||
code := suffix[0]
|
||||
suffix = suffix[1:]
|
||||
|
||||
// Codes [AFMTr] have an integer operand.
|
||||
var index int
|
||||
switch code {
|
||||
case opAt, opField, opMethod, opTypeParam, opRecvTypeParam:
|
||||
rest := strings.TrimLeft(suffix, "0123456789")
|
||||
numerals := suffix[:len(suffix)-len(rest)]
|
||||
suffix = rest
|
||||
i, err := strconv.Atoi(numerals)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid path: bad numeric operand %q for code %q", numerals, code)
|
||||
}
|
||||
index = int(i)
|
||||
case opObj:
|
||||
// no operand
|
||||
default:
|
||||
// The suffix must end with a type->object operation.
|
||||
if suffix == "" {
|
||||
return nil, fmt.Errorf("invalid path: ends with %q, want [AFMO]", code)
|
||||
}
|
||||
}
|
||||
|
||||
if code == opType {
|
||||
if t != nil {
|
||||
return nil, fmt.Errorf("invalid path: unexpected %q in type context", opType)
|
||||
}
|
||||
t = obj.Type()
|
||||
obj = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("invalid path: code %q in object context", code)
|
||||
}
|
||||
|
||||
// Inv: t != nil, obj == nil
|
||||
|
||||
t = types.Unalias(t)
|
||||
switch code {
|
||||
case opElem:
|
||||
hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want pointer, slice, array, chan or map)", code, t, t)
|
||||
}
|
||||
t = hasElem.Elem()
|
||||
|
||||
case opKey:
|
||||
mapType, ok := t.(*types.Map)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want map)", code, t, t)
|
||||
}
|
||||
t = mapType.Key()
|
||||
|
||||
case opParams:
|
||||
sig, ok := t.(*types.Signature)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
|
||||
}
|
||||
t = sig.Params()
|
||||
|
||||
case opResults:
|
||||
sig, ok := t.(*types.Signature)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
|
||||
}
|
||||
t = sig.Results()
|
||||
|
||||
case opUnderlying:
|
||||
named, ok := t.(*types.Named)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named)", code, t, t)
|
||||
}
|
||||
t = named.Underlying()
|
||||
|
||||
case opRhs:
|
||||
if alias, ok := t.(*types.Alias); ok {
|
||||
t = aliases.Rhs(alias)
|
||||
} else if false && aliases.Enabled() {
|
||||
// The Enabled check is too expensive, so for now we
|
||||
// simply assume that aliases are not enabled.
|
||||
// TODO(adonovan): replace with "if true {" when go1.24 is assured.
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want alias)", code, t, t)
|
||||
}
|
||||
|
||||
case opTypeParam:
|
||||
hasTypeParams, ok := t.(hasTypeParams) // Named, Signature
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or signature)", code, t, t)
|
||||
}
|
||||
tparams := hasTypeParams.TypeParams()
|
||||
if n := tparams.Len(); index >= n {
|
||||
return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
|
||||
}
|
||||
t = tparams.At(index)
|
||||
|
||||
case opRecvTypeParam:
|
||||
sig, ok := t.(*types.Signature) // Signature
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want signature)", code, t, t)
|
||||
}
|
||||
rtparams := sig.RecvTypeParams()
|
||||
if n := rtparams.Len(); index >= n {
|
||||
return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
|
||||
}
|
||||
t = rtparams.At(index)
|
||||
|
||||
case opConstraint:
|
||||
tparam, ok := t.(*types.TypeParam)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t)
|
||||
}
|
||||
t = tparam.Constraint()
|
||||
|
||||
case opAt:
|
||||
tuple, ok := t.(*types.Tuple)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want tuple)", code, t, t)
|
||||
}
|
||||
if n := tuple.Len(); index >= n {
|
||||
return nil, fmt.Errorf("tuple index %d out of range [0-%d)", index, n)
|
||||
}
|
||||
obj = tuple.At(index)
|
||||
t = nil
|
||||
|
||||
case opField:
|
||||
structType, ok := t.(*types.Struct)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want struct)", code, t, t)
|
||||
}
|
||||
if n := structType.NumFields(); index >= n {
|
||||
return nil, fmt.Errorf("field index %d out of range [0-%d)", index, n)
|
||||
}
|
||||
obj = structType.Field(index)
|
||||
t = nil
|
||||
|
||||
case opMethod:
|
||||
switch t := t.(type) {
|
||||
case *types.Interface:
|
||||
if index >= t.NumMethods() {
|
||||
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
|
||||
}
|
||||
obj = t.Method(index) // Id-ordered
|
||||
|
||||
case *types.Named:
|
||||
if index >= t.NumMethods() {
|
||||
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
|
||||
}
|
||||
obj = t.Method(index)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
|
||||
}
|
||||
t = nil
|
||||
|
||||
case opObj:
|
||||
hasObj, ok := t.(hasObj)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want named or type param)", code, t, t)
|
||||
}
|
||||
obj = hasObj.Obj()
|
||||
t = nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid path: unknown code %q", code)
|
||||
}
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
panic(p) // path does not end in an object-valued operator
|
||||
}
|
||||
|
||||
if obj.Pkg() != pkg {
|
||||
return nil, fmt.Errorf("path denotes %s, which belongs to a different package", obj)
|
||||
}
|
||||
|
||||
return obj, nil // success
|
||||
}
|
||||
|
||||
// scopeObjects is a memoization of scope objects.
|
||||
// Callers must not modify the result.
|
||||
func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object {
|
||||
m := enc.scopeMemo
|
||||
if m == nil {
|
||||
m = make(map[*types.Scope][]types.Object)
|
||||
enc.scopeMemo = m
|
||||
}
|
||||
objs, ok := m[scope]
|
||||
if !ok {
|
||||
names := scope.Names() // allocates and sorts
|
||||
objs = make([]types.Object, len(names))
|
||||
for i, name := range names {
|
||||
objs[i] = scope.Lookup(name)
|
||||
}
|
||||
m[scope] = objs
|
||||
}
|
||||
return objs
|
||||
}
|
68
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
Normal file
68
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// Callee returns the named target of a function call, if any:
|
||||
// a function, method, builtin, or variable.
|
||||
//
|
||||
// Functions and methods may potentially have type parameters.
|
||||
func Callee(info *types.Info, call *ast.CallExpr) types.Object {
|
||||
fun := ast.Unparen(call.Fun)
|
||||
|
||||
// Look through type instantiation if necessary.
|
||||
isInstance := false
|
||||
switch fun.(type) {
|
||||
case *ast.IndexExpr, *ast.IndexListExpr:
|
||||
// When extracting the callee from an *IndexExpr, we need to check that
|
||||
// it is a *types.Func and not a *types.Var.
|
||||
// Example: Don't match a slice m within the expression `m[0]()`.
|
||||
isInstance = true
|
||||
fun, _, _, _ = typeparams.UnpackIndexExpr(fun)
|
||||
}
|
||||
|
||||
var obj types.Object
|
||||
switch fun := fun.(type) {
|
||||
case *ast.Ident:
|
||||
obj = info.Uses[fun] // type, var, builtin, or declared func
|
||||
case *ast.SelectorExpr:
|
||||
if sel, ok := info.Selections[fun]; ok {
|
||||
obj = sel.Obj() // method or field
|
||||
} else {
|
||||
obj = info.Uses[fun.Sel] // qualified identifier?
|
||||
}
|
||||
}
|
||||
if _, ok := obj.(*types.TypeName); ok {
|
||||
return nil // T(x) is a conversion, not a call
|
||||
}
|
||||
// A Func is required to match instantiations.
|
||||
if _, ok := obj.(*types.Func); isInstance && !ok {
|
||||
return nil // Was not a Func.
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// StaticCallee returns the target (function or method) of a static function
|
||||
// call, if any. It returns nil for calls to builtins.
|
||||
//
|
||||
// Note: for calls of instantiated functions and methods, StaticCallee returns
|
||||
// the corresponding generic function or method on the generic type.
|
||||
func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func {
|
||||
if f, ok := Callee(info, call).(*types.Func); ok && !interfaceMethod(f) {
|
||||
return f
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func interfaceMethod(f *types.Func) bool {
|
||||
recv := f.Type().(*types.Signature).Recv()
|
||||
return recv != nil && types.IsInterface(recv.Type())
|
||||
}
|
30
vendor/golang.org/x/tools/go/types/typeutil/imports.go
generated
vendored
Normal file
30
vendor/golang.org/x/tools/go/types/typeutil/imports.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
package typeutil
|
||||
|
||||
import "go/types"
|
||||
|
||||
// Dependencies returns all dependencies of the specified packages.
|
||||
//
|
||||
// Dependent packages appear in topological order: if package P imports
|
||||
// package Q, Q appears earlier than P in the result.
|
||||
// The algorithm follows import statements in the order they
|
||||
// appear in the source code, so the result is a total order.
|
||||
func Dependencies(pkgs ...*types.Package) []*types.Package {
|
||||
var result []*types.Package
|
||||
seen := make(map[*types.Package]bool)
|
||||
var visit func(pkgs []*types.Package)
|
||||
visit = func(pkgs []*types.Package) {
|
||||
for _, p := range pkgs {
|
||||
if !seen[p] {
|
||||
seen[p] = true
|
||||
visit(p.Imports())
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(pkgs)
|
||||
return result
|
||||
}
|
467
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
Normal file
467
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
Normal file
|
@ -0,0 +1,467 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
// Package typeutil defines various utilities for types, such as [Map],
|
||||
// a hash table that maps [types.Type] to any value.
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"hash/maphash"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// Map is a hash-table-based mapping from types (types.Type) to
|
||||
// arbitrary values. The concrete types that implement
|
||||
// the Type interface are pointers. Since they are not canonicalized,
|
||||
// == cannot be used to check for equivalence, and thus we cannot
|
||||
// simply use a Go map.
|
||||
//
|
||||
// Just as with map[K]V, a nil *Map is a valid empty map.
|
||||
//
|
||||
// Read-only map operations ([Map.At], [Map.Len], and so on) may
|
||||
// safely be called concurrently.
|
||||
//
|
||||
// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420
|
||||
// and 69559, if the latter proposals for a generic hash-map type and
|
||||
// a types.Hash function are accepted.
|
||||
type Map struct {
|
||||
table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
|
||||
length int // number of map entries
|
||||
}
|
||||
|
||||
// entry is an entry (key/value association) in a hash bucket.
|
||||
type entry struct {
|
||||
key types.Type
|
||||
value any
|
||||
}
|
||||
|
||||
// SetHasher has no effect.
|
||||
//
|
||||
// It is a relic of an optimization that is no longer profitable. Do
|
||||
// not use [Hasher], [MakeHasher], or [SetHasher] in new code.
|
||||
func (m *Map) SetHasher(Hasher) {}
|
||||
|
||||
// Delete removes the entry with the given key, if any.
|
||||
// It returns true if the entry was found.
|
||||
func (m *Map) Delete(key types.Type) bool {
|
||||
if m != nil && m.table != nil {
|
||||
hash := hash(key)
|
||||
bucket := m.table[hash]
|
||||
for i, e := range bucket {
|
||||
if e.key != nil && types.Identical(key, e.key) {
|
||||
// We can't compact the bucket as it
|
||||
// would disturb iterators.
|
||||
bucket[i] = entry{}
|
||||
m.length--
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// At returns the map entry for the given key.
|
||||
// The result is nil if the entry is not present.
|
||||
func (m *Map) At(key types.Type) any {
|
||||
if m != nil && m.table != nil {
|
||||
for _, e := range m.table[hash(key)] {
|
||||
if e.key != nil && types.Identical(key, e.key) {
|
||||
return e.value
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets the map entry for key to val,
|
||||
// and returns the previous entry, if any.
|
||||
func (m *Map) Set(key types.Type, value any) (prev any) {
|
||||
if m.table != nil {
|
||||
hash := hash(key)
|
||||
bucket := m.table[hash]
|
||||
var hole *entry
|
||||
for i, e := range bucket {
|
||||
if e.key == nil {
|
||||
hole = &bucket[i]
|
||||
} else if types.Identical(key, e.key) {
|
||||
prev = e.value
|
||||
bucket[i].value = value
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if hole != nil {
|
||||
*hole = entry{key, value} // overwrite deleted entry
|
||||
} else {
|
||||
m.table[hash] = append(bucket, entry{key, value})
|
||||
}
|
||||
} else {
|
||||
hash := hash(key)
|
||||
m.table = map[uint32][]entry{hash: {entry{key, value}}}
|
||||
}
|
||||
|
||||
m.length++
|
||||
return
|
||||
}
|
||||
|
||||
// Len returns the number of map entries.
|
||||
func (m *Map) Len() int {
|
||||
if m != nil {
|
||||
return m.length
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Iterate calls function f on each entry in the map in unspecified order.
|
||||
//
|
||||
// If f should mutate the map, Iterate provides the same guarantees as
|
||||
// Go maps: if f deletes a map entry that Iterate has not yet reached,
|
||||
// f will not be invoked for it, but if f inserts a map entry that
|
||||
// Iterate has not yet reached, whether or not f will be invoked for
|
||||
// it is unspecified.
|
||||
func (m *Map) Iterate(f func(key types.Type, value any)) {
|
||||
if m != nil {
|
||||
for _, bucket := range m.table {
|
||||
for _, e := range bucket {
|
||||
if e.key != nil {
|
||||
f(e.key, e.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keys returns a new slice containing the set of map keys.
|
||||
// The order is unspecified.
|
||||
func (m *Map) Keys() []types.Type {
|
||||
keys := make([]types.Type, 0, m.Len())
|
||||
m.Iterate(func(key types.Type, _ any) {
|
||||
keys = append(keys, key)
|
||||
})
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m *Map) toString(values bool) string {
|
||||
if m == nil {
|
||||
return "{}"
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, "{")
|
||||
sep := ""
|
||||
m.Iterate(func(key types.Type, value any) {
|
||||
fmt.Fprint(&buf, sep)
|
||||
sep = ", "
|
||||
fmt.Fprint(&buf, key)
|
||||
if values {
|
||||
fmt.Fprintf(&buf, ": %q", value)
|
||||
}
|
||||
})
|
||||
fmt.Fprint(&buf, "}")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// String returns a string representation of the map's entries.
|
||||
// Values are printed using fmt.Sprintf("%v", v).
|
||||
// Order is unspecified.
|
||||
func (m *Map) String() string {
|
||||
return m.toString(true)
|
||||
}
|
||||
|
||||
// KeysString returns a string representation of the map's key set.
|
||||
// Order is unspecified.
|
||||
func (m *Map) KeysString() string {
|
||||
return m.toString(false)
|
||||
}
|
||||
|
||||
// -- Hasher --
|
||||
|
||||
// hash returns the hash of type t.
|
||||
// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted.
|
||||
func hash(t types.Type) uint32 {
|
||||
return theHasher.Hash(t)
|
||||
}
|
||||
|
||||
// A Hasher provides a [Hasher.Hash] method to map a type to its hash value.
|
||||
// Hashers are stateless, and all are equivalent.
|
||||
type Hasher struct{}
|
||||
|
||||
var theHasher Hasher
|
||||
|
||||
// MakeHasher returns Hasher{}.
|
||||
// Hashers are stateless; all are equivalent.
|
||||
func MakeHasher() Hasher { return theHasher }
|
||||
|
||||
// Hash computes a hash value for the given type t such that
|
||||
// Identical(t, t') => Hash(t) == Hash(t').
|
||||
func (h Hasher) Hash(t types.Type) uint32 {
|
||||
return hasher{inGenericSig: false}.hash(t)
|
||||
}
|
||||
|
||||
// hasher holds the state of a single Hash traversal: whether we are
|
||||
// inside the signature of a generic function; this is used to
|
||||
// optimize [hasher.hashTypeParam].
|
||||
type hasher struct{ inGenericSig bool }
|
||||
|
||||
// hashString computes the Fowler–Noll–Vo hash of s.
|
||||
func hashString(s string) uint32 {
|
||||
var h uint32
|
||||
for i := 0; i < len(s); i++ {
|
||||
h ^= uint32(s[i])
|
||||
h *= 16777619
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// hash computes the hash of t.
|
||||
func (h hasher) hash(t types.Type) uint32 {
|
||||
// See Identical for rationale.
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
return uint32(t.Kind())
|
||||
|
||||
case *types.Alias:
|
||||
return h.hash(types.Unalias(t))
|
||||
|
||||
case *types.Array:
|
||||
return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Slice:
|
||||
return 9049 + 2*h.hash(t.Elem())
|
||||
|
||||
case *types.Struct:
|
||||
var hash uint32 = 9059
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if f.Anonymous() {
|
||||
hash += 8861
|
||||
}
|
||||
hash += hashString(t.Tag(i))
|
||||
hash += hashString(f.Name()) // (ignore f.Pkg)
|
||||
hash += h.hash(f.Type())
|
||||
}
|
||||
return hash
|
||||
|
||||
case *types.Pointer:
|
||||
return 9067 + 2*h.hash(t.Elem())
|
||||
|
||||
case *types.Signature:
|
||||
var hash uint32 = 9091
|
||||
if t.Variadic() {
|
||||
hash *= 8863
|
||||
}
|
||||
|
||||
tparams := t.TypeParams()
|
||||
for i := range tparams.Len() {
|
||||
h.inGenericSig = true
|
||||
tparam := tparams.At(i)
|
||||
hash += 7 * h.hash(tparam.Constraint())
|
||||
}
|
||||
|
||||
return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
|
||||
|
||||
case *types.Union:
|
||||
return h.hashUnion(t)
|
||||
|
||||
case *types.Interface:
|
||||
// Interfaces are identical if they have the same set of methods, with
|
||||
// identical names and types, and they have the same set of type
|
||||
// restrictions. See go/types.identical for more details.
|
||||
var hash uint32 = 9103
|
||||
|
||||
// Hash methods.
|
||||
for i, n := 0, t.NumMethods(); i < n; i++ {
|
||||
// Method order is not significant.
|
||||
// Ignore m.Pkg().
|
||||
m := t.Method(i)
|
||||
// Use shallow hash on method signature to
|
||||
// avoid anonymous interface cycles.
|
||||
hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type())
|
||||
}
|
||||
|
||||
// Hash type restrictions.
|
||||
terms, err := typeparams.InterfaceTermSet(t)
|
||||
// if err != nil t has invalid type restrictions.
|
||||
if err == nil {
|
||||
hash += h.hashTermSet(terms)
|
||||
}
|
||||
|
||||
return hash
|
||||
|
||||
case *types.Map:
|
||||
return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Chan:
|
||||
return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Named:
|
||||
hash := h.hashTypeName(t.Obj())
|
||||
targs := t.TypeArgs()
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
targ := targs.At(i)
|
||||
hash += 2 * h.hash(targ)
|
||||
}
|
||||
return hash
|
||||
|
||||
case *types.TypeParam:
|
||||
return h.hashTypeParam(t)
|
||||
|
||||
case *types.Tuple:
|
||||
return h.hashTuple(t)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("%T: %v", t, t))
|
||||
}
|
||||
|
||||
func (h hasher) hashTuple(tuple *types.Tuple) uint32 {
|
||||
// See go/types.identicalTypes for rationale.
|
||||
n := tuple.Len()
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := range n {
|
||||
hash += 3 * h.hash(tuple.At(i).Type())
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
func (h hasher) hashUnion(t *types.Union) uint32 {
|
||||
// Hash type restrictions.
|
||||
terms, err := typeparams.UnionTermSet(t)
|
||||
// if err != nil t has invalid type restrictions. Fall back on a non-zero
|
||||
// hash.
|
||||
if err != nil {
|
||||
return 9151
|
||||
}
|
||||
return h.hashTermSet(terms)
|
||||
}
|
||||
|
||||
func (h hasher) hashTermSet(terms []*types.Term) uint32 {
|
||||
hash := 9157 + 2*uint32(len(terms))
|
||||
for _, term := range terms {
|
||||
// term order is not significant.
|
||||
termHash := h.hash(term.Type())
|
||||
if term.Tilde() {
|
||||
termHash *= 9161
|
||||
}
|
||||
hash += 3 * termHash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// hashTypeParam returns the hash of a type parameter.
|
||||
func (h hasher) hashTypeParam(t *types.TypeParam) uint32 {
|
||||
// Within the signature of a generic function, TypeParams are
|
||||
// identical if they have the same index and constraint, so we
|
||||
// hash them based on index.
|
||||
//
|
||||
// When we are outside a generic function, free TypeParams are
|
||||
// identical iff they are the same object, so we can use a
|
||||
// more discriminating hash consistent with object identity.
|
||||
// This optimization saves [Map] about 4% when hashing all the
|
||||
// types.Info.Types in the forward closure of net/http.
|
||||
if !h.inGenericSig {
|
||||
// Optimization: outside a generic function signature,
|
||||
// use a more discrimating hash consistent with object identity.
|
||||
return h.hashTypeName(t.Obj())
|
||||
}
|
||||
return 9173 + 3*uint32(t.Index())
|
||||
}
|
||||
|
||||
var theSeed = maphash.MakeSeed()
|
||||
|
||||
// hashTypeName hashes the pointer of tname.
|
||||
func (hasher) hashTypeName(tname *types.TypeName) uint32 {
|
||||
// Since types.Identical uses == to compare TypeNames,
|
||||
// the Hash function uses maphash.Comparable.
|
||||
// TODO(adonovan): or will, when it becomes available in go1.24.
|
||||
// In the meantime we use the pointer's numeric value.
|
||||
//
|
||||
// hash := maphash.Comparable(theSeed, tname)
|
||||
//
|
||||
// (Another approach would be to hash the name and package
|
||||
// path, and whether or not it is a package-level typename. It
|
||||
// is rare for a package to define multiple local types with
|
||||
// the same name.)
|
||||
hash := uintptr(unsafe.Pointer(tname))
|
||||
return uint32(hash ^ (hash >> 32))
|
||||
}
|
||||
|
||||
// shallowHash computes a hash of t without looking at any of its
|
||||
// element Types, to avoid potential anonymous cycles in the types of
|
||||
// interface methods.
|
||||
//
|
||||
// When an unnamed non-empty interface type appears anywhere among the
|
||||
// arguments or results of an interface method, there is a potential
|
||||
// for endless recursion. Consider:
|
||||
//
|
||||
// type X interface { m() []*interface { X } }
|
||||
//
|
||||
// The problem is that the Methods of the interface in m's result type
|
||||
// include m itself; there is no mention of the named type X that
|
||||
// might help us break the cycle.
|
||||
// (See comment in go/types.identical, case *Interface, for more.)
|
||||
func (h hasher) shallowHash(t types.Type) uint32 {
|
||||
// t is the type of an interface method (Signature),
|
||||
// its params or results (Tuples), or their immediate
|
||||
// elements (mostly Slice, Pointer, Basic, Named),
|
||||
// so there's no need to optimize anything else.
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
return h.shallowHash(types.Unalias(t))
|
||||
|
||||
case *types.Signature:
|
||||
var hash uint32 = 604171
|
||||
if t.Variadic() {
|
||||
hash *= 971767
|
||||
}
|
||||
// The Signature/Tuple recursion is always finite
|
||||
// and invariably shallow.
|
||||
return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results())
|
||||
|
||||
case *types.Tuple:
|
||||
n := t.Len()
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := range n {
|
||||
hash += 53471161 * h.shallowHash(t.At(i).Type())
|
||||
}
|
||||
return hash
|
||||
|
||||
case *types.Basic:
|
||||
return 45212177 * uint32(t.Kind())
|
||||
|
||||
case *types.Array:
|
||||
return 1524181 + 2*uint32(t.Len())
|
||||
|
||||
case *types.Slice:
|
||||
return 2690201
|
||||
|
||||
case *types.Struct:
|
||||
return 3326489
|
||||
|
||||
case *types.Pointer:
|
||||
return 4393139
|
||||
|
||||
case *types.Union:
|
||||
return 562448657
|
||||
|
||||
case *types.Interface:
|
||||
return 2124679 // no recursion here
|
||||
|
||||
case *types.Map:
|
||||
return 9109
|
||||
|
||||
case *types.Chan:
|
||||
return 9127
|
||||
|
||||
case *types.Named:
|
||||
return h.hashTypeName(t.Obj())
|
||||
|
||||
case *types.TypeParam:
|
||||
return h.hashTypeParam(t)
|
||||
}
|
||||
panic(fmt.Sprintf("shallowHash: %T: %v", t, t))
|
||||
}
|
71
vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go
generated
vendored
Normal file
71
vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
// This file implements a cache of method sets.
|
||||
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A MethodSetCache records the method set of each type T for which
|
||||
// MethodSet(T) is called so that repeat queries are fast.
|
||||
// The zero value is a ready-to-use cache instance.
|
||||
type MethodSetCache struct {
|
||||
mu sync.Mutex
|
||||
named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N
|
||||
others map[types.Type]*types.MethodSet // all other types
|
||||
}
|
||||
|
||||
// MethodSet returns the method set of type T. It is thread-safe.
|
||||
//
|
||||
// If cache is nil, this function is equivalent to types.NewMethodSet(T).
|
||||
// Utility functions can thus expose an optional *MethodSetCache
|
||||
// parameter to clients that care about performance.
|
||||
func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet {
|
||||
if cache == nil {
|
||||
return types.NewMethodSet(T)
|
||||
}
|
||||
cache.mu.Lock()
|
||||
defer cache.mu.Unlock()
|
||||
|
||||
switch T := types.Unalias(T).(type) {
|
||||
case *types.Named:
|
||||
return cache.lookupNamed(T).value
|
||||
|
||||
case *types.Pointer:
|
||||
if N, ok := types.Unalias(T.Elem()).(*types.Named); ok {
|
||||
return cache.lookupNamed(N).pointer
|
||||
}
|
||||
}
|
||||
|
||||
// all other types
|
||||
// (The map uses pointer equivalence, not type identity.)
|
||||
mset := cache.others[T]
|
||||
if mset == nil {
|
||||
mset = types.NewMethodSet(T)
|
||||
if cache.others == nil {
|
||||
cache.others = make(map[types.Type]*types.MethodSet)
|
||||
}
|
||||
cache.others[T] = mset
|
||||
}
|
||||
return mset
|
||||
}
|
||||
|
||||
func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } {
|
||||
if cache.named == nil {
|
||||
cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet })
|
||||
}
|
||||
// Avoid recomputing mset(*T) for each distinct Pointer
|
||||
// instance whose underlying type is a named type.
|
||||
msets, ok := cache.named[named]
|
||||
if !ok {
|
||||
msets.value = types.NewMethodSet(named)
|
||||
msets.pointer = types.NewMethodSet(types.NewPointer(named))
|
||||
cache.named[named] = msets
|
||||
}
|
||||
return msets
|
||||
}
|
53
vendor/golang.org/x/tools/go/types/typeutil/ui.go
generated
vendored
Normal file
53
vendor/golang.org/x/tools/go/types/typeutil/ui.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
package typeutil
|
||||
|
||||
// This file defines utilities for user interfaces that display types.
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// IntuitiveMethodSet returns the intuitive method set of a type T,
|
||||
// which is the set of methods you can call on an addressable value of
|
||||
// that type.
|
||||
//
|
||||
// The result always contains MethodSet(T), and is exactly MethodSet(T)
|
||||
// for interface types and for pointer-to-concrete types.
|
||||
// For all other concrete types T, the result additionally
|
||||
// contains each method belonging to *T if there is no identically
|
||||
// named method on T itself.
|
||||
//
|
||||
// This corresponds to user intuition about method sets;
|
||||
// this function is intended only for user interfaces.
|
||||
//
|
||||
// The order of the result is as for types.MethodSet(T).
|
||||
func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection {
|
||||
isPointerToConcrete := func(T types.Type) bool {
|
||||
ptr, ok := types.Unalias(T).(*types.Pointer)
|
||||
return ok && !types.IsInterface(ptr.Elem())
|
||||
}
|
||||
|
||||
var result []*types.Selection
|
||||
mset := msets.MethodSet(T)
|
||||
if types.IsInterface(T) || isPointerToConcrete(T) {
|
||||
for i, n := 0, mset.Len(); i < n; i++ {
|
||||
result = append(result, mset.At(i))
|
||||
}
|
||||
} else {
|
||||
// T is some other concrete type.
|
||||
// Report methods of T and *T, preferring those of T.
|
||||
pmset := msets.MethodSet(types.NewPointer(T))
|
||||
for i, n := 0, pmset.Len(); i < n; i++ {
|
||||
meth := pmset.At(i)
|
||||
if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
|
||||
meth = m
|
||||
}
|
||||
result = append(result, meth)
|
||||
}
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
38
vendor/golang.org/x/tools/internal/aliases/aliases.go
generated
vendored
Normal file
38
vendor/golang.org/x/tools/internal/aliases/aliases.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package aliases
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// Package aliases defines backward compatible shims
|
||||
// for the types.Alias type representation added in 1.22.
|
||||
// This defines placeholders for x/tools until 1.26.
|
||||
|
||||
// NewAlias creates a new TypeName in Package pkg that
|
||||
// is an alias for the type rhs.
|
||||
//
|
||||
// The enabled parameter determines whether the resulting [TypeName]'s
|
||||
// type is an [types.Alias]. Its value must be the result of a call to
|
||||
// [Enabled], which computes the effective value of
|
||||
// GODEBUG=gotypesalias=... by invoking the type checker. The Enabled
|
||||
// function is expensive and should be called once per task (e.g.
|
||||
// package import), not once per call to NewAlias.
|
||||
//
|
||||
// Precondition: enabled || len(tparams)==0.
|
||||
// If materialized aliases are disabled, there must not be any type parameters.
|
||||
func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type, tparams []*types.TypeParam) *types.TypeName {
|
||||
if enabled {
|
||||
tname := types.NewTypeName(pos, pkg, name, nil)
|
||||
SetTypeParams(types.NewAlias(tname, rhs), tparams)
|
||||
return tname
|
||||
}
|
||||
if len(tparams) > 0 {
|
||||
panic("cannot create an alias with type parameters when gotypesalias is not enabled")
|
||||
}
|
||||
return types.NewTypeName(pos, pkg, name, rhs)
|
||||
}
|
80
vendor/golang.org/x/tools/internal/aliases/aliases_go122.go
generated
vendored
Normal file
80
vendor/golang.org/x/tools/internal/aliases/aliases_go122.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package aliases
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// Rhs returns the type on the right-hand side of the alias declaration.
|
||||
func Rhs(alias *types.Alias) types.Type {
|
||||
if alias, ok := any(alias).(interface{ Rhs() types.Type }); ok {
|
||||
return alias.Rhs() // go1.23+
|
||||
}
|
||||
|
||||
// go1.22's Alias didn't have the Rhs method,
|
||||
// so Unalias is the best we can do.
|
||||
return types.Unalias(alias)
|
||||
}
|
||||
|
||||
// TypeParams returns the type parameter list of the alias.
|
||||
func TypeParams(alias *types.Alias) *types.TypeParamList {
|
||||
if alias, ok := any(alias).(interface{ TypeParams() *types.TypeParamList }); ok {
|
||||
return alias.TypeParams() // go1.23+
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTypeParams sets the type parameters of the alias type.
|
||||
func SetTypeParams(alias *types.Alias, tparams []*types.TypeParam) {
|
||||
if alias, ok := any(alias).(interface {
|
||||
SetTypeParams(tparams []*types.TypeParam)
|
||||
}); ok {
|
||||
alias.SetTypeParams(tparams) // go1.23+
|
||||
} else if len(tparams) > 0 {
|
||||
panic("cannot set type parameters of an Alias type in go1.22")
|
||||
}
|
||||
}
|
||||
|
||||
// TypeArgs returns the type arguments used to instantiate the Alias type.
|
||||
func TypeArgs(alias *types.Alias) *types.TypeList {
|
||||
if alias, ok := any(alias).(interface{ TypeArgs() *types.TypeList }); ok {
|
||||
return alias.TypeArgs() // go1.23+
|
||||
}
|
||||
return nil // empty (go1.22)
|
||||
}
|
||||
|
||||
// Origin returns the generic Alias type of which alias is an instance.
|
||||
// If alias is not an instance of a generic alias, Origin returns alias.
|
||||
func Origin(alias *types.Alias) *types.Alias {
|
||||
if alias, ok := any(alias).(interface{ Origin() *types.Alias }); ok {
|
||||
return alias.Origin() // go1.23+
|
||||
}
|
||||
return alias // not an instance of a generic alias (go1.22)
|
||||
}
|
||||
|
||||
// Enabled reports whether [NewAlias] should create [types.Alias] types.
|
||||
//
|
||||
// This function is expensive! Call it sparingly.
|
||||
func Enabled() bool {
|
||||
// The only reliable way to compute the answer is to invoke go/types.
|
||||
// We don't parse the GODEBUG environment variable, because
|
||||
// (a) it's tricky to do so in a manner that is consistent
|
||||
// with the godebug package; in particular, a simple
|
||||
// substring check is not good enough. The value is a
|
||||
// rightmost-wins list of options. But more importantly:
|
||||
// (b) it is impossible to detect changes to the effective
|
||||
// setting caused by os.Setenv("GODEBUG"), as happens in
|
||||
// many tests. Therefore any attempt to cache the result
|
||||
// is just incorrect.
|
||||
fset := token.NewFileSet()
|
||||
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", parser.SkipObjectResolution)
|
||||
pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
|
||||
_, enabled := pkg.Scope().Lookup("A").Type().(*types.Alias)
|
||||
return enabled
|
||||
}
|
21
vendor/golang.org/x/tools/internal/event/keys/util.go
generated
vendored
Normal file
21
vendor/golang.org/x/tools/internal/event/keys/util.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
package keys
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Join returns a canonical join of the keys in S:
|
||||
// a sorted comma-separated string list.
|
||||
func Join[S ~[]T, T ~string](s S) string {
|
||||
strs := make([]string, 0, len(s))
|
||||
for _, v := range s {
|
||||
strs = append(strs, string(v))
|
||||
}
|
||||
sort.Strings(strs)
|
||||
return strings.Join(strs, ",")
|
||||
}
|
852
vendor/golang.org/x/tools/internal/gcimporter/bexport.go
generated
vendored
852
vendor/golang.org/x/tools/internal/gcimporter/bexport.go
generated
vendored
|
@ -1,852 +0,0 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// Binary package export.
|
||||
// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go;
|
||||
// see that file for specification of the format.
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// If debugFormat is set, each integer and string value is preceded by a marker
|
||||
// and position information in the encoding. This mechanism permits an importer
|
||||
// to recognize immediately when it is out of sync. The importer recognizes this
|
||||
// mode automatically (i.e., it can import export data produced with debugging
|
||||
// support even if debugFormat is not set at the time of import). This mode will
|
||||
// lead to massively larger export data (by a factor of 2 to 3) and should only
|
||||
// be enabled during development and debugging.
|
||||
//
|
||||
// NOTE: This flag is the first flag to enable if importing dies because of
|
||||
// (suspected) format errors, and whenever a change is made to the format.
|
||||
const debugFormat = false // default: false
|
||||
|
||||
// Current export format version. Increase with each format change.
|
||||
//
|
||||
// Note: The latest binary (non-indexed) export format is at version 6.
|
||||
// This exporter is still at level 4, but it doesn't matter since
|
||||
// the binary importer can handle older versions just fine.
|
||||
//
|
||||
// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE
|
||||
// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMENTED HERE
|
||||
// 4: type name objects support type aliases, uses aliasTag
|
||||
// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
|
||||
// 2: removed unused bool in ODCL export (compiler only)
|
||||
// 1: header format change (more regular), export package for _ struct fields
|
||||
// 0: Go1.7 encoding
|
||||
const exportVersion = 4
|
||||
|
||||
// trackAllTypes enables cycle tracking for all types, not just named
|
||||
// types. The existing compiler invariants assume that unnamed types
|
||||
// that are not completely set up are not used, or else there are spurious
|
||||
// errors.
|
||||
// If disabled, only named types are tracked, possibly leading to slightly
|
||||
// less efficient encoding in rare cases. It also prevents the export of
|
||||
// some corner-case type declarations (but those are not handled correctly
|
||||
// with with the textual export format either).
|
||||
// TODO(gri) enable and remove once issues caused by it are fixed
|
||||
const trackAllTypes = false
|
||||
|
||||
type exporter struct {
|
||||
fset *token.FileSet
|
||||
out bytes.Buffer
|
||||
|
||||
// object -> index maps, indexed in order of serialization
|
||||
strIndex map[string]int
|
||||
pkgIndex map[*types.Package]int
|
||||
typIndex map[types.Type]int
|
||||
|
||||
// position encoding
|
||||
posInfoFormat bool
|
||||
prevFile string
|
||||
prevLine int
|
||||
|
||||
// debugging support
|
||||
written int // bytes written
|
||||
indent int // for trace
|
||||
}
|
||||
|
||||
// internalError represents an error generated inside this package.
|
||||
type internalError string
|
||||
|
||||
func (e internalError) Error() string { return "gcimporter: " + string(e) }
|
||||
|
||||
func internalErrorf(format string, args ...interface{}) error {
|
||||
return internalError(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// BExportData returns binary export data for pkg.
|
||||
// If no file set is provided, position info will be missing.
|
||||
func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
|
||||
if !debug {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if ierr, ok := e.(internalError); ok {
|
||||
err = ierr
|
||||
return
|
||||
}
|
||||
// Not an internal error; panic again.
|
||||
panic(e)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
p := exporter{
|
||||
fset: fset,
|
||||
strIndex: map[string]int{"": 0}, // empty string is mapped to 0
|
||||
pkgIndex: make(map[*types.Package]int),
|
||||
typIndex: make(map[types.Type]int),
|
||||
posInfoFormat: true, // TODO(gri) might become a flag, eventually
|
||||
}
|
||||
|
||||
// write version info
|
||||
// The version string must start with "version %d" where %d is the version
|
||||
// number. Additional debugging information may follow after a blank; that
|
||||
// text is ignored by the importer.
|
||||
p.rawStringln(fmt.Sprintf("version %d", exportVersion))
|
||||
var debug string
|
||||
if debugFormat {
|
||||
debug = "debug"
|
||||
}
|
||||
p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly
|
||||
p.bool(trackAllTypes)
|
||||
p.bool(p.posInfoFormat)
|
||||
|
||||
// --- generic export data ---
|
||||
|
||||
// populate type map with predeclared "known" types
|
||||
for index, typ := range predeclared() {
|
||||
p.typIndex[typ] = index
|
||||
}
|
||||
if len(p.typIndex) != len(predeclared()) {
|
||||
return nil, internalError("duplicate entries in type map?")
|
||||
}
|
||||
|
||||
// write package data
|
||||
p.pkg(pkg, true)
|
||||
if trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
|
||||
// write objects
|
||||
objcount := 0
|
||||
scope := pkg.Scope()
|
||||
for _, name := range scope.Names() {
|
||||
if !token.IsExported(name) {
|
||||
continue
|
||||
}
|
||||
if trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.obj(scope.Lookup(name))
|
||||
objcount++
|
||||
}
|
||||
|
||||
// indicate end of list
|
||||
if trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.tag(endTag)
|
||||
|
||||
// for self-verification only (redundant)
|
||||
p.int(objcount)
|
||||
|
||||
if trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
|
||||
// --- end of export data ---
|
||||
|
||||
return p.out.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
|
||||
if pkg == nil {
|
||||
panic(internalError("unexpected nil pkg"))
|
||||
}
|
||||
|
||||
// if we saw the package before, write its index (>= 0)
|
||||
if i, ok := p.pkgIndex[pkg]; ok {
|
||||
p.index('P', i)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, remember the package, write the package tag (< 0) and package data
|
||||
if trace {
|
||||
p.tracef("P%d = { ", len(p.pkgIndex))
|
||||
defer p.tracef("} ")
|
||||
}
|
||||
p.pkgIndex[pkg] = len(p.pkgIndex)
|
||||
|
||||
p.tag(packageTag)
|
||||
p.string(pkg.Name())
|
||||
if emptypath {
|
||||
p.string("")
|
||||
} else {
|
||||
p.string(pkg.Path())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) obj(obj types.Object) {
|
||||
switch obj := obj.(type) {
|
||||
case *types.Const:
|
||||
p.tag(constTag)
|
||||
p.pos(obj)
|
||||
p.qualifiedName(obj)
|
||||
p.typ(obj.Type())
|
||||
p.value(obj.Val())
|
||||
|
||||
case *types.TypeName:
|
||||
if obj.IsAlias() {
|
||||
p.tag(aliasTag)
|
||||
p.pos(obj)
|
||||
p.qualifiedName(obj)
|
||||
} else {
|
||||
p.tag(typeTag)
|
||||
}
|
||||
p.typ(obj.Type())
|
||||
|
||||
case *types.Var:
|
||||
p.tag(varTag)
|
||||
p.pos(obj)
|
||||
p.qualifiedName(obj)
|
||||
p.typ(obj.Type())
|
||||
|
||||
case *types.Func:
|
||||
p.tag(funcTag)
|
||||
p.pos(obj)
|
||||
p.qualifiedName(obj)
|
||||
sig := obj.Type().(*types.Signature)
|
||||
p.paramList(sig.Params(), sig.Variadic())
|
||||
p.paramList(sig.Results(), false)
|
||||
|
||||
default:
|
||||
panic(internalErrorf("unexpected object %v (%T)", obj, obj))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) pos(obj types.Object) {
|
||||
if !p.posInfoFormat {
|
||||
return
|
||||
}
|
||||
|
||||
file, line := p.fileLine(obj)
|
||||
if file == p.prevFile {
|
||||
// common case: write line delta
|
||||
// delta == 0 means different file or no line change
|
||||
delta := line - p.prevLine
|
||||
p.int(delta)
|
||||
if delta == 0 {
|
||||
p.int(-1) // -1 means no file change
|
||||
}
|
||||
} else {
|
||||
// different file
|
||||
p.int(0)
|
||||
// Encode filename as length of common prefix with previous
|
||||
// filename, followed by (possibly empty) suffix. Filenames
|
||||
// frequently share path prefixes, so this can save a lot
|
||||
// of space and make export data size less dependent on file
|
||||
// path length. The suffix is unlikely to be empty because
|
||||
// file names tend to end in ".go".
|
||||
n := commonPrefixLen(p.prevFile, file)
|
||||
p.int(n) // n >= 0
|
||||
p.string(file[n:]) // write suffix only
|
||||
p.prevFile = file
|
||||
p.int(line)
|
||||
}
|
||||
p.prevLine = line
|
||||
}
|
||||
|
||||
func (p *exporter) fileLine(obj types.Object) (file string, line int) {
|
||||
if p.fset != nil {
|
||||
pos := p.fset.Position(obj.Pos())
|
||||
file = pos.Filename
|
||||
line = pos.Line
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func commonPrefixLen(a, b string) int {
|
||||
if len(a) > len(b) {
|
||||
a, b = b, a
|
||||
}
|
||||
// len(a) <= len(b)
|
||||
i := 0
|
||||
for i < len(a) && a[i] == b[i] {
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (p *exporter) qualifiedName(obj types.Object) {
|
||||
p.string(obj.Name())
|
||||
p.pkg(obj.Pkg(), false)
|
||||
}
|
||||
|
||||
func (p *exporter) typ(t types.Type) {
|
||||
if t == nil {
|
||||
panic(internalError("nil type"))
|
||||
}
|
||||
|
||||
// Possible optimization: Anonymous pointer types *T where
|
||||
// T is a named type are common. We could canonicalize all
|
||||
// such types *T to a single type PT = *T. This would lead
|
||||
// to at most one *T entry in typIndex, and all future *T's
|
||||
// would be encoded as the respective index directly. Would
|
||||
// save 1 byte (pointerTag) per *T and reduce the typIndex
|
||||
// size (at the cost of a canonicalization map). We can do
|
||||
// this later, without encoding format change.
|
||||
|
||||
// if we saw the type before, write its index (>= 0)
|
||||
if i, ok := p.typIndex[t]; ok {
|
||||
p.index('T', i)
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise, remember the type, write the type tag (< 0) and type data
|
||||
if trackAllTypes {
|
||||
if trace {
|
||||
p.tracef("T%d = {>\n", len(p.typIndex))
|
||||
defer p.tracef("<\n} ")
|
||||
}
|
||||
p.typIndex[t] = len(p.typIndex)
|
||||
}
|
||||
|
||||
switch t := t.(type) {
|
||||
case *types.Named:
|
||||
if !trackAllTypes {
|
||||
// if we don't track all types, track named types now
|
||||
p.typIndex[t] = len(p.typIndex)
|
||||
}
|
||||
|
||||
p.tag(namedTag)
|
||||
p.pos(t.Obj())
|
||||
p.qualifiedName(t.Obj())
|
||||
p.typ(t.Underlying())
|
||||
if !types.IsInterface(t) {
|
||||
p.assocMethods(t)
|
||||
}
|
||||
|
||||
case *types.Array:
|
||||
p.tag(arrayTag)
|
||||
p.int64(t.Len())
|
||||
p.typ(t.Elem())
|
||||
|
||||
case *types.Slice:
|
||||
p.tag(sliceTag)
|
||||
p.typ(t.Elem())
|
||||
|
||||
case *dddSlice:
|
||||
p.tag(dddTag)
|
||||
p.typ(t.elem)
|
||||
|
||||
case *types.Struct:
|
||||
p.tag(structTag)
|
||||
p.fieldList(t)
|
||||
|
||||
case *types.Pointer:
|
||||
p.tag(pointerTag)
|
||||
p.typ(t.Elem())
|
||||
|
||||
case *types.Signature:
|
||||
p.tag(signatureTag)
|
||||
p.paramList(t.Params(), t.Variadic())
|
||||
p.paramList(t.Results(), false)
|
||||
|
||||
case *types.Interface:
|
||||
p.tag(interfaceTag)
|
||||
p.iface(t)
|
||||
|
||||
case *types.Map:
|
||||
p.tag(mapTag)
|
||||
p.typ(t.Key())
|
||||
p.typ(t.Elem())
|
||||
|
||||
case *types.Chan:
|
||||
p.tag(chanTag)
|
||||
p.int(int(3 - t.Dir())) // hack
|
||||
p.typ(t.Elem())
|
||||
|
||||
default:
|
||||
panic(internalErrorf("unexpected type %T: %s", t, t))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) assocMethods(named *types.Named) {
|
||||
// Sort methods (for determinism).
|
||||
var methods []*types.Func
|
||||
for i := 0; i < named.NumMethods(); i++ {
|
||||
methods = append(methods, named.Method(i))
|
||||
}
|
||||
sort.Sort(methodsByName(methods))
|
||||
|
||||
p.int(len(methods))
|
||||
|
||||
if trace && methods != nil {
|
||||
p.tracef("associated methods {>\n")
|
||||
}
|
||||
|
||||
for i, m := range methods {
|
||||
if trace && i > 0 {
|
||||
p.tracef("\n")
|
||||
}
|
||||
|
||||
p.pos(m)
|
||||
name := m.Name()
|
||||
p.string(name)
|
||||
if !exported(name) {
|
||||
p.pkg(m.Pkg(), false)
|
||||
}
|
||||
|
||||
sig := m.Type().(*types.Signature)
|
||||
p.paramList(types.NewTuple(sig.Recv()), false)
|
||||
p.paramList(sig.Params(), sig.Variadic())
|
||||
p.paramList(sig.Results(), false)
|
||||
p.int(0) // dummy value for go:nointerface pragma - ignored by importer
|
||||
}
|
||||
|
||||
if trace && methods != nil {
|
||||
p.tracef("<\n} ")
|
||||
}
|
||||
}
|
||||
|
||||
type methodsByName []*types.Func
|
||||
|
||||
func (x methodsByName) Len() int { return len(x) }
|
||||
func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
|
||||
|
||||
func (p *exporter) fieldList(t *types.Struct) {
|
||||
if trace && t.NumFields() > 0 {
|
||||
p.tracef("fields {>\n")
|
||||
defer p.tracef("<\n} ")
|
||||
}
|
||||
|
||||
p.int(t.NumFields())
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
if trace && i > 0 {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.field(t.Field(i))
|
||||
p.string(t.Tag(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) field(f *types.Var) {
|
||||
if !f.IsField() {
|
||||
panic(internalError("field expected"))
|
||||
}
|
||||
|
||||
p.pos(f)
|
||||
p.fieldName(f)
|
||||
p.typ(f.Type())
|
||||
}
|
||||
|
||||
func (p *exporter) iface(t *types.Interface) {
|
||||
// TODO(gri): enable importer to load embedded interfaces,
|
||||
// then emit Embeddeds and ExplicitMethods separately here.
|
||||
p.int(0)
|
||||
|
||||
n := t.NumMethods()
|
||||
if trace && n > 0 {
|
||||
p.tracef("methods {>\n")
|
||||
defer p.tracef("<\n} ")
|
||||
}
|
||||
p.int(n)
|
||||
for i := 0; i < n; i++ {
|
||||
if trace && i > 0 {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.method(t.Method(i))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) method(m *types.Func) {
|
||||
sig := m.Type().(*types.Signature)
|
||||
if sig.Recv() == nil {
|
||||
panic(internalError("method expected"))
|
||||
}
|
||||
|
||||
p.pos(m)
|
||||
p.string(m.Name())
|
||||
if m.Name() != "_" && !token.IsExported(m.Name()) {
|
||||
p.pkg(m.Pkg(), false)
|
||||
}
|
||||
|
||||
// interface method; no need to encode receiver.
|
||||
p.paramList(sig.Params(), sig.Variadic())
|
||||
p.paramList(sig.Results(), false)
|
||||
}
|
||||
|
||||
func (p *exporter) fieldName(f *types.Var) {
|
||||
name := f.Name()
|
||||
|
||||
if f.Anonymous() {
|
||||
// anonymous field - we distinguish between 3 cases:
|
||||
// 1) field name matches base type name and is exported
|
||||
// 2) field name matches base type name and is not exported
|
||||
// 3) field name doesn't match base type name (alias name)
|
||||
bname := basetypeName(f.Type())
|
||||
if name == bname {
|
||||
if token.IsExported(name) {
|
||||
name = "" // 1) we don't need to know the field name or package
|
||||
} else {
|
||||
name = "?" // 2) use unexported name "?" to force package export
|
||||
}
|
||||
} else {
|
||||
// 3) indicate alias and export name as is
|
||||
// (this requires an extra "@" but this is a rare case)
|
||||
p.string("@")
|
||||
}
|
||||
}
|
||||
|
||||
p.string(name)
|
||||
if name != "" && !token.IsExported(name) {
|
||||
p.pkg(f.Pkg(), false)
|
||||
}
|
||||
}
|
||||
|
||||
func basetypeName(typ types.Type) string {
|
||||
switch typ := deref(typ).(type) {
|
||||
case *types.Basic:
|
||||
return typ.Name()
|
||||
case *types.Named:
|
||||
return typ.Obj().Name()
|
||||
default:
|
||||
return "" // unnamed type
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) paramList(params *types.Tuple, variadic bool) {
|
||||
// use negative length to indicate unnamed parameters
|
||||
// (look at the first parameter only since either all
|
||||
// names are present or all are absent)
|
||||
n := params.Len()
|
||||
if n > 0 && params.At(0).Name() == "" {
|
||||
n = -n
|
||||
}
|
||||
p.int(n)
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
q := params.At(i)
|
||||
t := q.Type()
|
||||
if variadic && i == params.Len()-1 {
|
||||
t = &dddSlice{t.(*types.Slice).Elem()}
|
||||
}
|
||||
p.typ(t)
|
||||
if n > 0 {
|
||||
name := q.Name()
|
||||
p.string(name)
|
||||
if name != "_" {
|
||||
p.pkg(q.Pkg(), false)
|
||||
}
|
||||
}
|
||||
p.string("") // no compiler-specific info
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) value(x constant.Value) {
|
||||
if trace {
|
||||
p.tracef("= ")
|
||||
}
|
||||
|
||||
switch x.Kind() {
|
||||
case constant.Bool:
|
||||
tag := falseTag
|
||||
if constant.BoolVal(x) {
|
||||
tag = trueTag
|
||||
}
|
||||
p.tag(tag)
|
||||
|
||||
case constant.Int:
|
||||
if v, exact := constant.Int64Val(x); exact {
|
||||
// common case: x fits into an int64 - use compact encoding
|
||||
p.tag(int64Tag)
|
||||
p.int64(v)
|
||||
return
|
||||
}
|
||||
// uncommon case: large x - use float encoding
|
||||
// (powers of 2 will be encoded efficiently with exponent)
|
||||
p.tag(floatTag)
|
||||
p.float(constant.ToFloat(x))
|
||||
|
||||
case constant.Float:
|
||||
p.tag(floatTag)
|
||||
p.float(x)
|
||||
|
||||
case constant.Complex:
|
||||
p.tag(complexTag)
|
||||
p.float(constant.Real(x))
|
||||
p.float(constant.Imag(x))
|
||||
|
||||
case constant.String:
|
||||
p.tag(stringTag)
|
||||
p.string(constant.StringVal(x))
|
||||
|
||||
case constant.Unknown:
|
||||
// package contains type errors
|
||||
p.tag(unknownTag)
|
||||
|
||||
default:
|
||||
panic(internalErrorf("unexpected value %v (%T)", x, x))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) float(x constant.Value) {
|
||||
if x.Kind() != constant.Float {
|
||||
panic(internalErrorf("unexpected constant %v, want float", x))
|
||||
}
|
||||
// extract sign (there is no -0)
|
||||
sign := constant.Sign(x)
|
||||
if sign == 0 {
|
||||
// x == 0
|
||||
p.int(0)
|
||||
return
|
||||
}
|
||||
// x != 0
|
||||
|
||||
var f big.Float
|
||||
if v, exact := constant.Float64Val(x); exact {
|
||||
// float64
|
||||
f.SetFloat64(v)
|
||||
} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
|
||||
// TODO(gri): add big.Rat accessor to constant.Value.
|
||||
r := valueToRat(num)
|
||||
f.SetRat(r.Quo(r, valueToRat(denom)))
|
||||
} else {
|
||||
// Value too large to represent as a fraction => inaccessible.
|
||||
// TODO(gri): add big.Float accessor to constant.Value.
|
||||
f.SetFloat64(math.MaxFloat64) // FIXME
|
||||
}
|
||||
|
||||
// extract exponent such that 0.5 <= m < 1.0
|
||||
var m big.Float
|
||||
exp := f.MantExp(&m)
|
||||
|
||||
// extract mantissa as *big.Int
|
||||
// - set exponent large enough so mant satisfies mant.IsInt()
|
||||
// - get *big.Int from mant
|
||||
m.SetMantExp(&m, int(m.MinPrec()))
|
||||
mant, acc := m.Int(nil)
|
||||
if acc != big.Exact {
|
||||
panic(internalError("internal error"))
|
||||
}
|
||||
|
||||
p.int(sign)
|
||||
p.int(exp)
|
||||
p.string(string(mant.Bytes()))
|
||||
}
|
||||
|
||||
func valueToRat(x constant.Value) *big.Rat {
|
||||
// Convert little-endian to big-endian.
|
||||
// I can't believe this is necessary.
|
||||
bytes := constant.Bytes(x)
|
||||
for i := 0; i < len(bytes)/2; i++ {
|
||||
bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
|
||||
}
|
||||
return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
|
||||
}
|
||||
|
||||
func (p *exporter) bool(b bool) bool {
|
||||
if trace {
|
||||
p.tracef("[")
|
||||
defer p.tracef("= %v] ", b)
|
||||
}
|
||||
|
||||
x := 0
|
||||
if b {
|
||||
x = 1
|
||||
}
|
||||
p.int(x)
|
||||
return b
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Low-level encoders
|
||||
|
||||
func (p *exporter) index(marker byte, index int) {
|
||||
if index < 0 {
|
||||
panic(internalError("invalid index < 0"))
|
||||
}
|
||||
if debugFormat {
|
||||
p.marker('t')
|
||||
}
|
||||
if trace {
|
||||
p.tracef("%c%d ", marker, index)
|
||||
}
|
||||
p.rawInt64(int64(index))
|
||||
}
|
||||
|
||||
func (p *exporter) tag(tag int) {
|
||||
if tag >= 0 {
|
||||
panic(internalError("invalid tag >= 0"))
|
||||
}
|
||||
if debugFormat {
|
||||
p.marker('t')
|
||||
}
|
||||
if trace {
|
||||
p.tracef("%s ", tagString[-tag])
|
||||
}
|
||||
p.rawInt64(int64(tag))
|
||||
}
|
||||
|
||||
func (p *exporter) int(x int) {
|
||||
p.int64(int64(x))
|
||||
}
|
||||
|
||||
func (p *exporter) int64(x int64) {
|
||||
if debugFormat {
|
||||
p.marker('i')
|
||||
}
|
||||
if trace {
|
||||
p.tracef("%d ", x)
|
||||
}
|
||||
p.rawInt64(x)
|
||||
}
|
||||
|
||||
func (p *exporter) string(s string) {
|
||||
if debugFormat {
|
||||
p.marker('s')
|
||||
}
|
||||
if trace {
|
||||
p.tracef("%q ", s)
|
||||
}
|
||||
// if we saw the string before, write its index (>= 0)
|
||||
// (the empty string is mapped to 0)
|
||||
if i, ok := p.strIndex[s]; ok {
|
||||
p.rawInt64(int64(i))
|
||||
return
|
||||
}
|
||||
// otherwise, remember string and write its negative length and bytes
|
||||
p.strIndex[s] = len(p.strIndex)
|
||||
p.rawInt64(-int64(len(s)))
|
||||
for i := 0; i < len(s); i++ {
|
||||
p.rawByte(s[i])
|
||||
}
|
||||
}
|
||||
|
||||
// marker emits a marker byte and position information which makes
|
||||
// it easy for a reader to detect if it is "out of sync". Used for
|
||||
// debugFormat format only.
|
||||
func (p *exporter) marker(m byte) {
|
||||
p.rawByte(m)
|
||||
// Enable this for help tracking down the location
|
||||
// of an incorrect marker when running in debugFormat.
|
||||
if false && trace {
|
||||
p.tracef("#%d ", p.written)
|
||||
}
|
||||
p.rawInt64(int64(p.written))
|
||||
}
|
||||
|
||||
// rawInt64 should only be used by low-level encoders.
|
||||
func (p *exporter) rawInt64(x int64) {
|
||||
var tmp [binary.MaxVarintLen64]byte
|
||||
n := binary.PutVarint(tmp[:], x)
|
||||
for i := 0; i < n; i++ {
|
||||
p.rawByte(tmp[i])
|
||||
}
|
||||
}
|
||||
|
||||
// rawStringln should only be used to emit the initial version string.
|
||||
func (p *exporter) rawStringln(s string) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
p.rawByte(s[i])
|
||||
}
|
||||
p.rawByte('\n')
|
||||
}
|
||||
|
||||
// rawByte is the bottleneck interface to write to p.out.
|
||||
// rawByte escapes b as follows (any encoding does that
|
||||
// hides '$'):
|
||||
//
|
||||
// '$' => '|' 'S'
|
||||
// '|' => '|' '|'
|
||||
//
|
||||
// Necessary so other tools can find the end of the
|
||||
// export data by searching for "$$".
|
||||
// rawByte should only be used by low-level encoders.
|
||||
func (p *exporter) rawByte(b byte) {
|
||||
switch b {
|
||||
case '$':
|
||||
// write '$' as '|' 'S'
|
||||
b = 'S'
|
||||
fallthrough
|
||||
case '|':
|
||||
// write '|' as '|' '|'
|
||||
p.out.WriteByte('|')
|
||||
p.written++
|
||||
}
|
||||
p.out.WriteByte(b)
|
||||
p.written++
|
||||
}
|
||||
|
||||
// tracef is like fmt.Printf but it rewrites the format string
|
||||
// to take care of indentation.
|
||||
func (p *exporter) tracef(format string, args ...interface{}) {
|
||||
if strings.ContainsAny(format, "<>\n") {
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < len(format); i++ {
|
||||
// no need to deal with runes
|
||||
ch := format[i]
|
||||
switch ch {
|
||||
case '>':
|
||||
p.indent++
|
||||
continue
|
||||
case '<':
|
||||
p.indent--
|
||||
continue
|
||||
}
|
||||
buf.WriteByte(ch)
|
||||
if ch == '\n' {
|
||||
for j := p.indent; j > 0; j-- {
|
||||
buf.WriteString(". ")
|
||||
}
|
||||
}
|
||||
}
|
||||
format = buf.String()
|
||||
}
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Debugging support.
|
||||
// (tagString is only used when tracing is enabled)
|
||||
var tagString = [...]string{
|
||||
// Packages
|
||||
-packageTag: "package",
|
||||
|
||||
// Types
|
||||
-namedTag: "named type",
|
||||
-arrayTag: "array",
|
||||
-sliceTag: "slice",
|
||||
-dddTag: "ddd",
|
||||
-structTag: "struct",
|
||||
-pointerTag: "pointer",
|
||||
-signatureTag: "signature",
|
||||
-interfaceTag: "interface",
|
||||
-mapTag: "map",
|
||||
-chanTag: "chan",
|
||||
|
||||
// Values
|
||||
-falseTag: "false",
|
||||
-trueTag: "true",
|
||||
-int64Tag: "int64",
|
||||
-floatTag: "float",
|
||||
-fractionTag: "fraction",
|
||||
-complexTag: "complex",
|
||||
-stringTag: "string",
|
||||
-unknownTag: "unknown",
|
||||
|
||||
// Type aliases
|
||||
-aliasTag: "alias",
|
||||
}
|
968
vendor/golang.org/x/tools/internal/gcimporter/bimport.go
generated
vendored
968
vendor/golang.org/x/tools/internal/gcimporter/bimport.go
generated
vendored
|
@ -2,340 +2,24 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go.
|
||||
// This file contains the remaining vestiges of
|
||||
// $GOROOT/src/go/internal/gcimporter/bimport.go.
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type importer struct {
|
||||
imports map[string]*types.Package
|
||||
data []byte
|
||||
importpath string
|
||||
buf []byte // for reading strings
|
||||
version int // export format version
|
||||
|
||||
// object lists
|
||||
strList []string // in order of appearance
|
||||
pathList []string // in order of appearance
|
||||
pkgList []*types.Package // in order of appearance
|
||||
typList []types.Type // in order of appearance
|
||||
interfaceList []*types.Interface // for delayed completion only
|
||||
trackAllTypes bool
|
||||
|
||||
// position encoding
|
||||
posInfoFormat bool
|
||||
prevFile string
|
||||
prevLine int
|
||||
fake fakeFileSet
|
||||
|
||||
// debugging support
|
||||
debugFormat bool
|
||||
read int // bytes read
|
||||
}
|
||||
|
||||
// BImportData imports a package from the serialized package data
|
||||
// and returns the number of bytes consumed and a reference to the package.
|
||||
// If the export data version is not recognized or the format is otherwise
|
||||
// compromised, an error is returned.
|
||||
func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
||||
// catch panics and return them as errors
|
||||
const currentVersion = 6
|
||||
version := -1 // unknown version
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
// Return a (possibly nil or incomplete) package unchanged (see #16088).
|
||||
if version > currentVersion {
|
||||
err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
|
||||
} else {
|
||||
err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
p := importer{
|
||||
imports: imports,
|
||||
data: data,
|
||||
importpath: path,
|
||||
version: version,
|
||||
strList: []string{""}, // empty string is mapped to 0
|
||||
pathList: []string{""}, // empty string is mapped to 0
|
||||
fake: fakeFileSet{
|
||||
fset: fset,
|
||||
files: make(map[string]*fileInfo),
|
||||
},
|
||||
}
|
||||
defer p.fake.setLines() // set lines for files in fset
|
||||
|
||||
// read version info
|
||||
var versionstr string
|
||||
if b := p.rawByte(); b == 'c' || b == 'd' {
|
||||
// Go1.7 encoding; first byte encodes low-level
|
||||
// encoding format (compact vs debug).
|
||||
// For backward-compatibility only (avoid problems with
|
||||
// old installed packages). Newly compiled packages use
|
||||
// the extensible format string.
|
||||
// TODO(gri) Remove this support eventually; after Go1.8.
|
||||
if b == 'd' {
|
||||
p.debugFormat = true
|
||||
}
|
||||
p.trackAllTypes = p.rawByte() == 'a'
|
||||
p.posInfoFormat = p.int() != 0
|
||||
versionstr = p.string()
|
||||
if versionstr == "v1" {
|
||||
version = 0
|
||||
}
|
||||
} else {
|
||||
// Go1.8 extensible encoding
|
||||
// read version string and extract version number (ignore anything after the version number)
|
||||
versionstr = p.rawStringln(b)
|
||||
if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
|
||||
if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
|
||||
version = v
|
||||
}
|
||||
}
|
||||
}
|
||||
p.version = version
|
||||
|
||||
// read version specific flags - extend as necessary
|
||||
switch p.version {
|
||||
// case currentVersion:
|
||||
// ...
|
||||
// fallthrough
|
||||
case currentVersion, 5, 4, 3, 2, 1:
|
||||
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
||||
p.trackAllTypes = p.int() != 0
|
||||
p.posInfoFormat = p.int() != 0
|
||||
case 0:
|
||||
// Go1.7 encoding format - nothing to do here
|
||||
default:
|
||||
errorf("unknown bexport format version %d (%q)", p.version, versionstr)
|
||||
}
|
||||
|
||||
// --- generic export data ---
|
||||
|
||||
// populate typList with predeclared "known" types
|
||||
p.typList = append(p.typList, predeclared()...)
|
||||
|
||||
// read package data
|
||||
pkg = p.pkg()
|
||||
|
||||
// read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go)
|
||||
objcount := 0
|
||||
for {
|
||||
tag := p.tagOrIndex()
|
||||
if tag == endTag {
|
||||
break
|
||||
}
|
||||
p.obj(tag)
|
||||
objcount++
|
||||
}
|
||||
|
||||
// self-verification
|
||||
if count := p.int(); count != objcount {
|
||||
errorf("got %d objects; want %d", objcount, count)
|
||||
}
|
||||
|
||||
// ignore compiler-specific import data
|
||||
|
||||
// complete interfaces
|
||||
// TODO(gri) re-investigate if we still need to do this in a delayed fashion
|
||||
for _, typ := range p.interfaceList {
|
||||
typ.Complete()
|
||||
}
|
||||
|
||||
// record all referenced packages as imports
|
||||
list := append(([]*types.Package)(nil), p.pkgList[1:]...)
|
||||
sort.Sort(byPath(list))
|
||||
pkg.SetImports(list)
|
||||
|
||||
// package was imported completely and without errors
|
||||
pkg.MarkComplete()
|
||||
|
||||
return p.read, pkg, nil
|
||||
}
|
||||
|
||||
func errorf(format string, args ...interface{}) {
|
||||
panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (p *importer) pkg() *types.Package {
|
||||
// if the package was seen before, i is its index (>= 0)
|
||||
i := p.tagOrIndex()
|
||||
if i >= 0 {
|
||||
return p.pkgList[i]
|
||||
}
|
||||
|
||||
// otherwise, i is the package tag (< 0)
|
||||
if i != packageTag {
|
||||
errorf("unexpected package tag %d version %d", i, p.version)
|
||||
}
|
||||
|
||||
// read package data
|
||||
name := p.string()
|
||||
var path string
|
||||
if p.version >= 5 {
|
||||
path = p.path()
|
||||
} else {
|
||||
path = p.string()
|
||||
}
|
||||
if p.version >= 6 {
|
||||
p.int() // package height; unused by go/types
|
||||
}
|
||||
|
||||
// we should never see an empty package name
|
||||
if name == "" {
|
||||
errorf("empty package name in import")
|
||||
}
|
||||
|
||||
// an empty path denotes the package we are currently importing;
|
||||
// it must be the first package we see
|
||||
if (path == "") != (len(p.pkgList) == 0) {
|
||||
errorf("package path %q for pkg index %d", path, len(p.pkgList))
|
||||
}
|
||||
|
||||
// if the package was imported before, use that one; otherwise create a new one
|
||||
if path == "" {
|
||||
path = p.importpath
|
||||
}
|
||||
pkg := p.imports[path]
|
||||
if pkg == nil {
|
||||
pkg = types.NewPackage(path, name)
|
||||
p.imports[path] = pkg
|
||||
} else if pkg.Name() != name {
|
||||
errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path)
|
||||
}
|
||||
p.pkgList = append(p.pkgList, pkg)
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
// objTag returns the tag value for each object kind.
|
||||
func objTag(obj types.Object) int {
|
||||
switch obj.(type) {
|
||||
case *types.Const:
|
||||
return constTag
|
||||
case *types.TypeName:
|
||||
return typeTag
|
||||
case *types.Var:
|
||||
return varTag
|
||||
case *types.Func:
|
||||
return funcTag
|
||||
default:
|
||||
errorf("unexpected object: %v (%T)", obj, obj) // panics
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func sameObj(a, b types.Object) bool {
|
||||
// Because unnamed types are not canonicalized, we cannot simply compare types for
|
||||
// (pointer) identity.
|
||||
// Ideally we'd check equality of constant values as well, but this is good enough.
|
||||
return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
|
||||
}
|
||||
|
||||
func (p *importer) declare(obj types.Object) {
|
||||
pkg := obj.Pkg()
|
||||
if alt := pkg.Scope().Insert(obj); alt != nil {
|
||||
// This can only trigger if we import a (non-type) object a second time.
|
||||
// Excluding type aliases, this cannot happen because 1) we only import a package
|
||||
// once; and b) we ignore compiler-specific export data which may contain
|
||||
// functions whose inlined function bodies refer to other functions that
|
||||
// were already imported.
|
||||
// However, type aliases require reexporting the original type, so we need
|
||||
// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
|
||||
// method importer.obj, switch case importing functions).
|
||||
// TODO(gri) review/update this comment once the gc compiler handles type aliases.
|
||||
if !sameObj(obj, alt) {
|
||||
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *importer) obj(tag int) {
|
||||
switch tag {
|
||||
case constTag:
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil, nil)
|
||||
val := p.value()
|
||||
p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||
|
||||
case aliasTag:
|
||||
// TODO(gri) verify type alias hookup is correct
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil, nil)
|
||||
p.declare(types.NewTypeName(pos, pkg, name, typ))
|
||||
|
||||
case typeTag:
|
||||
p.typ(nil, nil)
|
||||
|
||||
case varTag:
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil, nil)
|
||||
p.declare(types.NewVar(pos, pkg, name, typ))
|
||||
|
||||
case funcTag:
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
sig := types.NewSignature(nil, params, result, isddd)
|
||||
p.declare(types.NewFunc(pos, pkg, name, sig))
|
||||
|
||||
default:
|
||||
errorf("unexpected object tag %d", tag)
|
||||
}
|
||||
}
|
||||
|
||||
const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
|
||||
|
||||
func (p *importer) pos() token.Pos {
|
||||
if !p.posInfoFormat {
|
||||
return token.NoPos
|
||||
}
|
||||
|
||||
file := p.prevFile
|
||||
line := p.prevLine
|
||||
delta := p.int()
|
||||
line += delta
|
||||
if p.version >= 5 {
|
||||
if delta == deltaNewFile {
|
||||
if n := p.int(); n >= 0 {
|
||||
// file changed
|
||||
file = p.path()
|
||||
line = n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if delta == 0 {
|
||||
if n := p.int(); n >= 0 {
|
||||
// file changed
|
||||
file = p.prevFile[:n] + p.string()
|
||||
line = p.int()
|
||||
}
|
||||
}
|
||||
}
|
||||
p.prevFile = file
|
||||
p.prevLine = line
|
||||
|
||||
return p.fake.pos(file, line, 0)
|
||||
}
|
||||
|
||||
// Synthesize a token.Pos
|
||||
type fakeFileSet struct {
|
||||
fset *token.FileSet
|
||||
|
@ -389,205 +73,6 @@ var (
|
|||
fakeLinesOnce sync.Once
|
||||
)
|
||||
|
||||
func (p *importer) qualifiedName() (pkg *types.Package, name string) {
|
||||
name = p.string()
|
||||
pkg = p.pkg()
|
||||
return
|
||||
}
|
||||
|
||||
func (p *importer) record(t types.Type) {
|
||||
p.typList = append(p.typList, t)
|
||||
}
|
||||
|
||||
// A dddSlice is a types.Type representing ...T parameters.
|
||||
// It only appears for parameter types and does not escape
|
||||
// the importer.
|
||||
type dddSlice struct {
|
||||
elem types.Type
|
||||
}
|
||||
|
||||
func (t *dddSlice) Underlying() types.Type { return t }
|
||||
func (t *dddSlice) String() string { return "..." + t.elem.String() }
|
||||
|
||||
// parent is the package which declared the type; parent == nil means
|
||||
// the package currently imported. The parent package is needed for
|
||||
// exported struct fields and interface methods which don't contain
|
||||
// explicit package information in the export data.
|
||||
//
|
||||
// A non-nil tname is used as the "owner" of the result type; i.e.,
|
||||
// the result type is the underlying type of tname. tname is used
|
||||
// to give interface methods a named receiver type where possible.
|
||||
func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type {
|
||||
// if the type was seen before, i is its index (>= 0)
|
||||
i := p.tagOrIndex()
|
||||
if i >= 0 {
|
||||
return p.typList[i]
|
||||
}
|
||||
|
||||
// otherwise, i is the type tag (< 0)
|
||||
switch i {
|
||||
case namedTag:
|
||||
// read type object
|
||||
pos := p.pos()
|
||||
parent, name := p.qualifiedName()
|
||||
scope := parent.Scope()
|
||||
obj := scope.Lookup(name)
|
||||
|
||||
// if the object doesn't exist yet, create and insert it
|
||||
if obj == nil {
|
||||
obj = types.NewTypeName(pos, parent, name, nil)
|
||||
scope.Insert(obj)
|
||||
}
|
||||
|
||||
if _, ok := obj.(*types.TypeName); !ok {
|
||||
errorf("pkg = %s, name = %s => %s", parent, name, obj)
|
||||
}
|
||||
|
||||
// associate new named type with obj if it doesn't exist yet
|
||||
t0 := types.NewNamed(obj.(*types.TypeName), nil, nil)
|
||||
|
||||
// but record the existing type, if any
|
||||
tname := obj.Type().(*types.Named) // tname is either t0 or the existing type
|
||||
p.record(tname)
|
||||
|
||||
// read underlying type
|
||||
t0.SetUnderlying(p.typ(parent, t0))
|
||||
|
||||
// interfaces don't have associated methods
|
||||
if types.IsInterface(t0) {
|
||||
return tname
|
||||
}
|
||||
|
||||
// read associated methods
|
||||
for i := p.int(); i > 0; i-- {
|
||||
// TODO(gri) replace this with something closer to fieldName
|
||||
pos := p.pos()
|
||||
name := p.string()
|
||||
if !exported(name) {
|
||||
p.pkg()
|
||||
}
|
||||
|
||||
recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
p.int() // go:nointerface pragma - discarded
|
||||
|
||||
sig := types.NewSignature(recv.At(0), params, result, isddd)
|
||||
t0.AddMethod(types.NewFunc(pos, parent, name, sig))
|
||||
}
|
||||
|
||||
return tname
|
||||
|
||||
case arrayTag:
|
||||
t := new(types.Array)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
n := p.int64()
|
||||
*t = *types.NewArray(p.typ(parent, nil), n)
|
||||
return t
|
||||
|
||||
case sliceTag:
|
||||
t := new(types.Slice)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
*t = *types.NewSlice(p.typ(parent, nil))
|
||||
return t
|
||||
|
||||
case dddTag:
|
||||
t := new(dddSlice)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
t.elem = p.typ(parent, nil)
|
||||
return t
|
||||
|
||||
case structTag:
|
||||
t := new(types.Struct)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
*t = *types.NewStruct(p.fieldList(parent))
|
||||
return t
|
||||
|
||||
case pointerTag:
|
||||
t := new(types.Pointer)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
*t = *types.NewPointer(p.typ(parent, nil))
|
||||
return t
|
||||
|
||||
case signatureTag:
|
||||
t := new(types.Signature)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
*t = *types.NewSignature(nil, params, result, isddd)
|
||||
return t
|
||||
|
||||
case interfaceTag:
|
||||
// Create a dummy entry in the type list. This is safe because we
|
||||
// cannot expect the interface type to appear in a cycle, as any
|
||||
// such cycle must contain a named type which would have been
|
||||
// first defined earlier.
|
||||
// TODO(gri) Is this still true now that we have type aliases?
|
||||
// See issue #23225.
|
||||
n := len(p.typList)
|
||||
if p.trackAllTypes {
|
||||
p.record(nil)
|
||||
}
|
||||
|
||||
var embeddeds []types.Type
|
||||
for n := p.int(); n > 0; n-- {
|
||||
p.pos()
|
||||
embeddeds = append(embeddeds, p.typ(parent, nil))
|
||||
}
|
||||
|
||||
t := newInterface(p.methodList(parent, tname), embeddeds)
|
||||
p.interfaceList = append(p.interfaceList, t)
|
||||
if p.trackAllTypes {
|
||||
p.typList[n] = t
|
||||
}
|
||||
return t
|
||||
|
||||
case mapTag:
|
||||
t := new(types.Map)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
key := p.typ(parent, nil)
|
||||
val := p.typ(parent, nil)
|
||||
*t = *types.NewMap(key, val)
|
||||
return t
|
||||
|
||||
case chanTag:
|
||||
t := new(types.Chan)
|
||||
if p.trackAllTypes {
|
||||
p.record(t)
|
||||
}
|
||||
|
||||
dir := chanDir(p.int())
|
||||
val := p.typ(parent, nil)
|
||||
*t = *types.NewChan(dir, val)
|
||||
return t
|
||||
|
||||
default:
|
||||
errorf("unexpected type tag %d", i) // panics
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func chanDir(d int) types.ChanDir {
|
||||
// tag values must match the constants in cmd/compile/internal/gc/go.go
|
||||
switch d {
|
||||
|
@ -602,452 +87,3 @@ func chanDir(d int) types.ChanDir {
|
|||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) {
|
||||
if n := p.int(); n > 0 {
|
||||
fields = make([]*types.Var, n)
|
||||
tags = make([]string, n)
|
||||
for i := range fields {
|
||||
fields[i], tags[i] = p.field(parent)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *importer) field(parent *types.Package) (*types.Var, string) {
|
||||
pos := p.pos()
|
||||
pkg, name, alias := p.fieldName(parent)
|
||||
typ := p.typ(parent, nil)
|
||||
tag := p.string()
|
||||
|
||||
anonymous := false
|
||||
if name == "" {
|
||||
// anonymous field - typ must be T or *T and T must be a type name
|
||||
switch typ := deref(typ).(type) {
|
||||
case *types.Basic: // basic types are named types
|
||||
pkg = nil // // objects defined in Universe scope have no package
|
||||
name = typ.Name()
|
||||
case *types.Named:
|
||||
name = typ.Obj().Name()
|
||||
default:
|
||||
errorf("named base type expected")
|
||||
}
|
||||
anonymous = true
|
||||
} else if alias {
|
||||
// anonymous field: we have an explicit name because it's an alias
|
||||
anonymous = true
|
||||
}
|
||||
|
||||
return types.NewField(pos, pkg, name, typ, anonymous), tag
|
||||
}
|
||||
|
||||
func (p *importer) methodList(parent *types.Package, baseType *types.Named) (methods []*types.Func) {
|
||||
if n := p.int(); n > 0 {
|
||||
methods = make([]*types.Func, n)
|
||||
for i := range methods {
|
||||
methods[i] = p.method(parent, baseType)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *importer) method(parent *types.Package, baseType *types.Named) *types.Func {
|
||||
pos := p.pos()
|
||||
pkg, name, _ := p.fieldName(parent)
|
||||
// If we don't have a baseType, use a nil receiver.
|
||||
// A receiver using the actual interface type (which
|
||||
// we don't know yet) will be filled in when we call
|
||||
// types.Interface.Complete.
|
||||
var recv *types.Var
|
||||
if baseType != nil {
|
||||
recv = types.NewVar(token.NoPos, parent, "", baseType)
|
||||
}
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
sig := types.NewSignature(recv, params, result, isddd)
|
||||
return types.NewFunc(pos, pkg, name, sig)
|
||||
}
|
||||
|
||||
func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) {
|
||||
name = p.string()
|
||||
pkg = parent
|
||||
if pkg == nil {
|
||||
// use the imported package instead
|
||||
pkg = p.pkgList[0]
|
||||
}
|
||||
if p.version == 0 && name == "_" {
|
||||
// version 0 didn't export a package for _ fields
|
||||
return
|
||||
}
|
||||
switch name {
|
||||
case "":
|
||||
// 1) field name matches base type name and is exported: nothing to do
|
||||
case "?":
|
||||
// 2) field name matches base type name and is not exported: need package
|
||||
name = ""
|
||||
pkg = p.pkg()
|
||||
case "@":
|
||||
// 3) field name doesn't match type name (alias)
|
||||
name = p.string()
|
||||
alias = true
|
||||
fallthrough
|
||||
default:
|
||||
if !exported(name) {
|
||||
pkg = p.pkg()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *importer) paramList() (*types.Tuple, bool) {
|
||||
n := p.int()
|
||||
if n == 0 {
|
||||
return nil, false
|
||||
}
|
||||
// negative length indicates unnamed parameters
|
||||
named := true
|
||||
if n < 0 {
|
||||
n = -n
|
||||
named = false
|
||||
}
|
||||
// n > 0
|
||||
params := make([]*types.Var, n)
|
||||
isddd := false
|
||||
for i := range params {
|
||||
params[i], isddd = p.param(named)
|
||||
}
|
||||
return types.NewTuple(params...), isddd
|
||||
}
|
||||
|
||||
func (p *importer) param(named bool) (*types.Var, bool) {
|
||||
t := p.typ(nil, nil)
|
||||
td, isddd := t.(*dddSlice)
|
||||
if isddd {
|
||||
t = types.NewSlice(td.elem)
|
||||
}
|
||||
|
||||
var pkg *types.Package
|
||||
var name string
|
||||
if named {
|
||||
name = p.string()
|
||||
if name == "" {
|
||||
errorf("expected named parameter")
|
||||
}
|
||||
if name != "_" {
|
||||
pkg = p.pkg()
|
||||
}
|
||||
if i := strings.Index(name, "·"); i > 0 {
|
||||
name = name[:i] // cut off gc-specific parameter numbering
|
||||
}
|
||||
}
|
||||
|
||||
// read and discard compiler-specific info
|
||||
p.string()
|
||||
|
||||
return types.NewVar(token.NoPos, pkg, name, t), isddd
|
||||
}
|
||||
|
||||
func exported(name string) bool {
|
||||
ch, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(ch)
|
||||
}
|
||||
|
||||
func (p *importer) value() constant.Value {
|
||||
switch tag := p.tagOrIndex(); tag {
|
||||
case falseTag:
|
||||
return constant.MakeBool(false)
|
||||
case trueTag:
|
||||
return constant.MakeBool(true)
|
||||
case int64Tag:
|
||||
return constant.MakeInt64(p.int64())
|
||||
case floatTag:
|
||||
return p.float()
|
||||
case complexTag:
|
||||
re := p.float()
|
||||
im := p.float()
|
||||
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
|
||||
case stringTag:
|
||||
return constant.MakeString(p.string())
|
||||
case unknownTag:
|
||||
return constant.MakeUnknown()
|
||||
default:
|
||||
errorf("unexpected value tag %d", tag) // panics
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *importer) float() constant.Value {
|
||||
sign := p.int()
|
||||
if sign == 0 {
|
||||
return constant.MakeInt64(0)
|
||||
}
|
||||
|
||||
exp := p.int()
|
||||
mant := []byte(p.string()) // big endian
|
||||
|
||||
// remove leading 0's if any
|
||||
for len(mant) > 0 && mant[0] == 0 {
|
||||
mant = mant[1:]
|
||||
}
|
||||
|
||||
// convert to little endian
|
||||
// TODO(gri) go/constant should have a more direct conversion function
|
||||
// (e.g., once it supports a big.Float based implementation)
|
||||
for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 {
|
||||
mant[i], mant[j] = mant[j], mant[i]
|
||||
}
|
||||
|
||||
// adjust exponent (constant.MakeFromBytes creates an integer value,
|
||||
// but mant represents the mantissa bits such that 0.5 <= mant < 1.0)
|
||||
exp -= len(mant) << 3
|
||||
if len(mant) > 0 {
|
||||
for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 {
|
||||
exp++
|
||||
}
|
||||
}
|
||||
|
||||
x := constant.MakeFromBytes(mant)
|
||||
switch {
|
||||
case exp < 0:
|
||||
d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
|
||||
x = constant.BinaryOp(x, token.QUO, d)
|
||||
case exp > 0:
|
||||
x = constant.Shift(x, token.SHL, uint(exp))
|
||||
}
|
||||
|
||||
if sign < 0 {
|
||||
x = constant.UnaryOp(token.SUB, x, 0)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Low-level decoders
|
||||
|
||||
func (p *importer) tagOrIndex() int {
|
||||
if p.debugFormat {
|
||||
p.marker('t')
|
||||
}
|
||||
|
||||
return int(p.rawInt64())
|
||||
}
|
||||
|
||||
func (p *importer) int() int {
|
||||
x := p.int64()
|
||||
if int64(int(x)) != x {
|
||||
errorf("exported integer too large")
|
||||
}
|
||||
return int(x)
|
||||
}
|
||||
|
||||
func (p *importer) int64() int64 {
|
||||
if p.debugFormat {
|
||||
p.marker('i')
|
||||
}
|
||||
|
||||
return p.rawInt64()
|
||||
}
|
||||
|
||||
func (p *importer) path() string {
|
||||
if p.debugFormat {
|
||||
p.marker('p')
|
||||
}
|
||||
// if the path was seen before, i is its index (>= 0)
|
||||
// (the empty string is at index 0)
|
||||
i := p.rawInt64()
|
||||
if i >= 0 {
|
||||
return p.pathList[i]
|
||||
}
|
||||
// otherwise, i is the negative path length (< 0)
|
||||
a := make([]string, -i)
|
||||
for n := range a {
|
||||
a[n] = p.string()
|
||||
}
|
||||
s := strings.Join(a, "/")
|
||||
p.pathList = append(p.pathList, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *importer) string() string {
|
||||
if p.debugFormat {
|
||||
p.marker('s')
|
||||
}
|
||||
// if the string was seen before, i is its index (>= 0)
|
||||
// (the empty string is at index 0)
|
||||
i := p.rawInt64()
|
||||
if i >= 0 {
|
||||
return p.strList[i]
|
||||
}
|
||||
// otherwise, i is the negative string length (< 0)
|
||||
if n := int(-i); n <= cap(p.buf) {
|
||||
p.buf = p.buf[:n]
|
||||
} else {
|
||||
p.buf = make([]byte, n)
|
||||
}
|
||||
for i := range p.buf {
|
||||
p.buf[i] = p.rawByte()
|
||||
}
|
||||
s := string(p.buf)
|
||||
p.strList = append(p.strList, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func (p *importer) marker(want byte) {
|
||||
if got := p.rawByte(); got != want {
|
||||
errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
|
||||
}
|
||||
|
||||
pos := p.read
|
||||
if n := int(p.rawInt64()); n != pos {
|
||||
errorf("incorrect position: got %d; want %d", n, pos)
|
||||
}
|
||||
}
|
||||
|
||||
// rawInt64 should only be used by low-level decoders.
|
||||
func (p *importer) rawInt64() int64 {
|
||||
i, err := binary.ReadVarint(p)
|
||||
if err != nil {
|
||||
errorf("read error: %v", err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// rawStringln should only be used to read the initial version string.
|
||||
func (p *importer) rawStringln(b byte) string {
|
||||
p.buf = p.buf[:0]
|
||||
for b != '\n' {
|
||||
p.buf = append(p.buf, b)
|
||||
b = p.rawByte()
|
||||
}
|
||||
return string(p.buf)
|
||||
}
|
||||
|
||||
// needed for binary.ReadVarint in rawInt64
|
||||
func (p *importer) ReadByte() (byte, error) {
|
||||
return p.rawByte(), nil
|
||||
}
|
||||
|
||||
// byte is the bottleneck interface for reading p.data.
|
||||
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
|
||||
// rawByte should only be used by low-level decoders.
|
||||
func (p *importer) rawByte() byte {
|
||||
b := p.data[0]
|
||||
r := 1
|
||||
if b == '|' {
|
||||
b = p.data[1]
|
||||
r = 2
|
||||
switch b {
|
||||
case 'S':
|
||||
b = '$'
|
||||
case '|':
|
||||
// nothing to do
|
||||
default:
|
||||
errorf("unexpected escape sequence in export data")
|
||||
}
|
||||
}
|
||||
p.data = p.data[r:]
|
||||
p.read += r
|
||||
return b
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Export format
|
||||
|
||||
// Tags. Must be < 0.
|
||||
const (
|
||||
// Objects
|
||||
packageTag = -(iota + 1)
|
||||
constTag
|
||||
typeTag
|
||||
varTag
|
||||
funcTag
|
||||
endTag
|
||||
|
||||
// Types
|
||||
namedTag
|
||||
arrayTag
|
||||
sliceTag
|
||||
dddTag
|
||||
structTag
|
||||
pointerTag
|
||||
signatureTag
|
||||
interfaceTag
|
||||
mapTag
|
||||
chanTag
|
||||
|
||||
// Values
|
||||
falseTag
|
||||
trueTag
|
||||
int64Tag
|
||||
floatTag
|
||||
fractionTag // not used by gc
|
||||
complexTag
|
||||
stringTag
|
||||
nilTag // only used by gc (appears in exported inlined function bodies)
|
||||
unknownTag // not used by gc (only appears in packages with errors)
|
||||
|
||||
// Type aliases
|
||||
aliasTag
|
||||
)
|
||||
|
||||
var predeclOnce sync.Once
|
||||
var predecl []types.Type // initialized lazily
|
||||
|
||||
func predeclared() []types.Type {
|
||||
predeclOnce.Do(func() {
|
||||
// initialize lazily to be sure that all
|
||||
// elements have been initialized before
|
||||
predecl = []types.Type{ // basic types
|
||||
types.Typ[types.Bool],
|
||||
types.Typ[types.Int],
|
||||
types.Typ[types.Int8],
|
||||
types.Typ[types.Int16],
|
||||
types.Typ[types.Int32],
|
||||
types.Typ[types.Int64],
|
||||
types.Typ[types.Uint],
|
||||
types.Typ[types.Uint8],
|
||||
types.Typ[types.Uint16],
|
||||
types.Typ[types.Uint32],
|
||||
types.Typ[types.Uint64],
|
||||
types.Typ[types.Uintptr],
|
||||
types.Typ[types.Float32],
|
||||
types.Typ[types.Float64],
|
||||
types.Typ[types.Complex64],
|
||||
types.Typ[types.Complex128],
|
||||
types.Typ[types.String],
|
||||
|
||||
// basic type aliases
|
||||
types.Universe.Lookup("byte").Type(),
|
||||
types.Universe.Lookup("rune").Type(),
|
||||
|
||||
// error
|
||||
types.Universe.Lookup("error").Type(),
|
||||
|
||||
// untyped types
|
||||
types.Typ[types.UntypedBool],
|
||||
types.Typ[types.UntypedInt],
|
||||
types.Typ[types.UntypedRune],
|
||||
types.Typ[types.UntypedFloat],
|
||||
types.Typ[types.UntypedComplex],
|
||||
types.Typ[types.UntypedString],
|
||||
types.Typ[types.UntypedNil],
|
||||
|
||||
// package unsafe
|
||||
types.Typ[types.UnsafePointer],
|
||||
|
||||
// invalid type
|
||||
types.Typ[types.Invalid], // only appears in packages with errors
|
||||
|
||||
// used internally by gc; never used by this package or in .a files
|
||||
anyType{},
|
||||
}
|
||||
predecl = append(predecl, additionalPredeclared()...)
|
||||
})
|
||||
return predecl
|
||||
}
|
||||
|
||||
type anyType struct{}
|
||||
|
||||
func (t anyType) Underlying() types.Type { return t }
|
||||
func (t anyType) String() string { return "any" }
|
||||
|
|
448
vendor/golang.org/x/tools/internal/gcimporter/exportdata.go
generated
vendored
448
vendor/golang.org/x/tools/internal/gcimporter/exportdata.go
generated
vendored
|
@ -2,49 +2,183 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go.
|
||||
|
||||
// This file implements FindExportData.
|
||||
// This file should be kept in sync with $GOROOT/src/internal/exportdata/exportdata.go.
|
||||
// This file also additionally implements FindExportData for gcexportdata.NewReader.
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"strconv"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func readGopackHeader(r *bufio.Reader) (name string, size int64, err error) {
|
||||
// See $GOROOT/include/ar.h.
|
||||
hdr := make([]byte, 16+12+6+6+8+10+2)
|
||||
_, err = io.ReadFull(r, hdr)
|
||||
// FindExportData positions the reader r at the beginning of the
|
||||
// export data section of an underlying cmd/compile created archive
|
||||
// file by reading from it. The reader must be positioned at the
|
||||
// start of the file before calling this function.
|
||||
// This returns the length of the export data in bytes.
|
||||
//
|
||||
// This function is needed by [gcexportdata.Read], which must
|
||||
// accept inputs produced by the last two releases of cmd/compile,
|
||||
// plus tip.
|
||||
func FindExportData(r *bufio.Reader) (size int64, err error) {
|
||||
arsize, err := FindPackageDefinition(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// leave for debugging
|
||||
if false {
|
||||
fmt.Printf("header: %s", hdr)
|
||||
}
|
||||
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
|
||||
length, err := strconv.Atoi(s)
|
||||
size = int64(length)
|
||||
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
|
||||
err = fmt.Errorf("invalid archive header")
|
||||
size = int64(arsize)
|
||||
|
||||
objapi, headers, err := ReadObjectHeaders(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
name = strings.TrimSpace(string(hdr[:16]))
|
||||
size -= int64(len(objapi))
|
||||
for _, h := range headers {
|
||||
size -= int64(len(h))
|
||||
}
|
||||
|
||||
// Check for the binary export data section header "$$B\n".
|
||||
// TODO(taking): Unify with ReadExportDataHeader so that it stops at the 'u' instead of reading
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hdr := string(line)
|
||||
if hdr != "$$B\n" {
|
||||
err = fmt.Errorf("unknown export data header: %q", hdr)
|
||||
return
|
||||
}
|
||||
size -= int64(len(hdr))
|
||||
|
||||
// For files with a binary export data header "$$B\n",
|
||||
// these are always terminated by an end-of-section marker "\n$$\n".
|
||||
// So the last bytes must always be this constant.
|
||||
//
|
||||
// The end-of-section marker is not a part of the export data itself.
|
||||
// Do not include these in size.
|
||||
//
|
||||
// It would be nice to have sanity check that the final bytes after
|
||||
// the export data are indeed the end-of-section marker. The split
|
||||
// of gcexportdata.NewReader and gcexportdata.Read make checking this
|
||||
// ugly so gcimporter gives up enforcing this. The compiler and go/types
|
||||
// importer do enforce this, which seems good enough.
|
||||
const endofsection = "\n$$\n"
|
||||
size -= int64(len(endofsection))
|
||||
|
||||
if size < 0 {
|
||||
err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", arsize, size)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindExportData positions the reader r at the beginning of the
|
||||
// export data section of an underlying GC-created object/archive
|
||||
// file by reading from it. The reader must be positioned at the
|
||||
// start of the file before calling this function. The hdr result
|
||||
// is the string before the export data, either "$$" or "$$B".
|
||||
// The size result is the length of the export data in bytes, or -1 if not known.
|
||||
func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) {
|
||||
// ReadUnified reads the contents of the unified export data from a reader r
|
||||
// that contains the contents of a GC-created archive file.
|
||||
//
|
||||
// On success, the reader will be positioned after the end-of-section marker "\n$$\n".
|
||||
//
|
||||
// Supported GC-created archive files have 4 layers of nesting:
|
||||
// - An archive file containing a package definition file.
|
||||
// - The package definition file contains headers followed by a data section.
|
||||
// Headers are lines (≤ 4kb) that do not start with "$$".
|
||||
// - The data section starts with "$$B\n" followed by export data followed
|
||||
// by an end of section marker "\n$$\n". (The section start "$$\n" is no
|
||||
// longer supported.)
|
||||
// - The export data starts with a format byte ('u') followed by the <data> in
|
||||
// the given format. (See ReadExportDataHeader for older formats.)
|
||||
//
|
||||
// Putting this together, the bytes in a GC-created archive files are expected
|
||||
// to look like the following.
|
||||
// See cmd/internal/archive for more details on ar file headers.
|
||||
//
|
||||
// | <!arch>\n | ar file signature
|
||||
// | __.PKGDEF...size...\n | ar header for __.PKGDEF including size.
|
||||
// | go object <...>\n | objabi header
|
||||
// | <optional headers>\n | other headers such as build id
|
||||
// | $$B\n | binary format marker
|
||||
// | u<data>\n | unified export <data>
|
||||
// | $$\n | end-of-section marker
|
||||
// | [optional padding] | padding byte (0x0A) if size is odd
|
||||
// | [ar file header] | other ar files
|
||||
// | [ar file data] |
|
||||
func ReadUnified(r *bufio.Reader) (data []byte, err error) {
|
||||
// We historically guaranteed headers at the default buffer size (4096) work.
|
||||
// This ensures we can use ReadSlice throughout.
|
||||
const minBufferSize = 4096
|
||||
r = bufio.NewReaderSize(r, minBufferSize)
|
||||
|
||||
size, err := FindPackageDefinition(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n := size
|
||||
|
||||
objapi, headers, err := ReadObjectHeaders(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n -= len(objapi)
|
||||
for _, h := range headers {
|
||||
n -= len(h)
|
||||
}
|
||||
|
||||
hdrlen, err := ReadExportDataHeader(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n -= hdrlen
|
||||
|
||||
// size also includes the end of section marker. Remove that many bytes from the end.
|
||||
const marker = "\n$$\n"
|
||||
n -= len(marker)
|
||||
|
||||
if n < 0 {
|
||||
err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", size, n)
|
||||
return
|
||||
}
|
||||
|
||||
// Read n bytes from buf.
|
||||
data = make([]byte, n)
|
||||
_, err = io.ReadFull(r, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for marker at the end.
|
||||
var suffix [len(marker)]byte
|
||||
_, err = io.ReadFull(r, suffix[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if s := string(suffix[:]); s != marker {
|
||||
err = fmt.Errorf("read %q instead of end-of-section marker (%q)", s, marker)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindPackageDefinition positions the reader r at the beginning of a package
|
||||
// definition file ("__.PKGDEF") within a GC-created archive by reading
|
||||
// from it, and returns the size of the package definition file in the archive.
|
||||
//
|
||||
// The reader must be positioned at the start of the archive file before calling
|
||||
// this function, and "__.PKGDEF" is assumed to be the first file in the archive.
|
||||
//
|
||||
// See cmd/internal/archive for details on the archive format.
|
||||
func FindPackageDefinition(r *bufio.Reader) (size int, err error) {
|
||||
// Uses ReadSlice to limit risk of malformed inputs.
|
||||
|
||||
// Read first line to make sure this is an object file.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
|
@ -52,48 +186,236 @@ func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
if string(line) == "!<arch>\n" {
|
||||
// Archive file. Scan to __.PKGDEF.
|
||||
var name string
|
||||
if name, size, err = readGopackHeader(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// First entry should be __.PKGDEF.
|
||||
if name != "__.PKGDEF" {
|
||||
err = fmt.Errorf("go archive is missing __.PKGDEF")
|
||||
return
|
||||
}
|
||||
|
||||
// Read first line of __.PKGDEF data, so that line
|
||||
// is once again the first line of the input.
|
||||
if line, err = r.ReadSlice('\n'); err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
size -= int64(len(line))
|
||||
}
|
||||
|
||||
// Now at __.PKGDEF in archive or still at beginning of file.
|
||||
// Either way, line should begin with "go object ".
|
||||
if !strings.HasPrefix(string(line), "go object ") {
|
||||
err = fmt.Errorf("not a Go object file")
|
||||
// Is the first line an archive file signature?
|
||||
if string(line) != "!<arch>\n" {
|
||||
err = fmt.Errorf("not the start of an archive file (%q)", line)
|
||||
return
|
||||
}
|
||||
|
||||
// Skip over object header to export data.
|
||||
// Begins after first line starting with $$.
|
||||
for line[0] != '$' {
|
||||
if line, err = r.ReadSlice('\n'); err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
size -= int64(len(line))
|
||||
}
|
||||
hdr = string(line)
|
||||
if size < 0 {
|
||||
size = -1
|
||||
// package export block should be first
|
||||
size = readArchiveHeader(r, "__.PKGDEF")
|
||||
if size <= 0 {
|
||||
err = fmt.Errorf("not a package file")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadObjectHeaders reads object headers from the reader. Object headers are
|
||||
// lines that do not start with an end-of-section marker "$$". The first header
|
||||
// is the objabi header. On success, the reader will be positioned at the beginning
|
||||
// of the end-of-section marker.
|
||||
//
|
||||
// It returns an error if any header does not fit in r.Size() bytes.
|
||||
func ReadObjectHeaders(r *bufio.Reader) (objapi string, headers []string, err error) {
|
||||
// line is a temporary buffer for headers.
|
||||
// Use bounded reads (ReadSlice, Peek) to limit risk of malformed inputs.
|
||||
var line []byte
|
||||
|
||||
// objapi header should be the first line
|
||||
if line, err = r.ReadSlice('\n'); err != nil {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
objapi = string(line)
|
||||
|
||||
// objapi header begins with "go object ".
|
||||
if !strings.HasPrefix(objapi, "go object ") {
|
||||
err = fmt.Errorf("not a go object file: %s", objapi)
|
||||
return
|
||||
}
|
||||
|
||||
// process remaining object header lines
|
||||
for {
|
||||
// check for an end of section marker "$$"
|
||||
line, err = r.Peek(2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if string(line) == "$$" {
|
||||
return // stop
|
||||
}
|
||||
|
||||
// read next header
|
||||
line, err = r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
headers = append(headers, string(line))
|
||||
}
|
||||
}
|
||||
|
||||
// ReadExportDataHeader reads the export data header and format from r.
|
||||
// It returns the number of bytes read, or an error if the format is no longer
|
||||
// supported or it failed to read.
|
||||
//
|
||||
// The only currently supported format is binary export data in the
|
||||
// unified export format.
|
||||
func ReadExportDataHeader(r *bufio.Reader) (n int, err error) {
|
||||
// Read export data header.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hdr := string(line)
|
||||
switch hdr {
|
||||
case "$$\n":
|
||||
err = fmt.Errorf("old textual export format no longer supported (recompile package)")
|
||||
return
|
||||
|
||||
case "$$B\n":
|
||||
var format byte
|
||||
format, err = r.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// The unified export format starts with a 'u'.
|
||||
switch format {
|
||||
case 'u':
|
||||
default:
|
||||
// Older no longer supported export formats include:
|
||||
// indexed export format which started with an 'i'; and
|
||||
// the older binary export format which started with a 'c',
|
||||
// 'd', or 'v' (from "version").
|
||||
err = fmt.Errorf("binary export format %q is no longer supported (recompile package)", format)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unknown export data header: %q", hdr)
|
||||
return
|
||||
}
|
||||
|
||||
n = len(hdr) + 1 // + 1 is for 'u'
|
||||
return
|
||||
}
|
||||
|
||||
// FindPkg returns the filename and unique package id for an import
|
||||
// path based on package information provided by build.Import (using
|
||||
// the build.Default build.Context). A relative srcDir is interpreted
|
||||
// relative to the current working directory.
|
||||
//
|
||||
// FindPkg is only used in tests within x/tools.
|
||||
func FindPkg(path, srcDir string) (filename, id string, err error) {
|
||||
// TODO(taking): Move internal/exportdata.FindPkg into its own file,
|
||||
// and then this copy into a _test package.
|
||||
if path == "" {
|
||||
return "", "", errors.New("path is empty")
|
||||
}
|
||||
|
||||
var noext string
|
||||
switch {
|
||||
default:
|
||||
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
|
||||
// Don't require the source files to be present.
|
||||
if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
|
||||
srcDir = abs
|
||||
}
|
||||
var bp *build.Package
|
||||
bp, err = build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
|
||||
if bp.PkgObj == "" {
|
||||
if bp.Goroot && bp.Dir != "" {
|
||||
filename, err = lookupGorootExport(bp.Dir)
|
||||
if err == nil {
|
||||
_, err = os.Stat(filename)
|
||||
}
|
||||
if err == nil {
|
||||
return filename, bp.ImportPath, nil
|
||||
}
|
||||
}
|
||||
goto notfound
|
||||
} else {
|
||||
noext = strings.TrimSuffix(bp.PkgObj, ".a")
|
||||
}
|
||||
id = bp.ImportPath
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
|
||||
noext = filepath.Join(srcDir, path)
|
||||
id = noext
|
||||
|
||||
case filepath.IsAbs(path):
|
||||
// for completeness only - go/build.Import
|
||||
// does not support absolute imports
|
||||
// "/x" -> "/x.ext", "/x"
|
||||
noext = path
|
||||
id = path
|
||||
}
|
||||
|
||||
if false { // for debugging
|
||||
if path != id {
|
||||
fmt.Printf("%s -> %s\n", path, id)
|
||||
}
|
||||
}
|
||||
|
||||
// try extensions
|
||||
for _, ext := range pkgExts {
|
||||
filename = noext + ext
|
||||
f, statErr := os.Stat(filename)
|
||||
if statErr == nil && !f.IsDir() {
|
||||
return filename, id, nil
|
||||
}
|
||||
if err == nil {
|
||||
err = statErr
|
||||
}
|
||||
}
|
||||
|
||||
notfound:
|
||||
if err == nil {
|
||||
return "", path, fmt.Errorf("can't find import: %q", path)
|
||||
}
|
||||
return "", path, fmt.Errorf("can't find import: %q: %w", path, err)
|
||||
}
|
||||
|
||||
var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
|
||||
|
||||
var exportMap sync.Map // package dir → func() (string, error)
|
||||
|
||||
// lookupGorootExport returns the location of the export data
|
||||
// (normally found in the build cache, but located in GOROOT/pkg
|
||||
// in prior Go releases) for the package located in pkgDir.
|
||||
//
|
||||
// (We use the package's directory instead of its import path
|
||||
// mainly to simplify handling of the packages in src/vendor
|
||||
// and cmd/vendor.)
|
||||
//
|
||||
// lookupGorootExport is only used in tests within x/tools.
|
||||
func lookupGorootExport(pkgDir string) (string, error) {
|
||||
f, ok := exportMap.Load(pkgDir)
|
||||
if !ok {
|
||||
var (
|
||||
listOnce sync.Once
|
||||
exportPath string
|
||||
err error
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, error) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
|
||||
var output []byte
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
|
||||
err = errors.New(string(ee.Stderr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
exports := strings.Split(string(bytes.TrimSpace(output)), "\n")
|
||||
if len(exports) != 1 {
|
||||
err = fmt.Errorf("go list reported %d exports; expected 1", len(exports))
|
||||
return
|
||||
}
|
||||
|
||||
exportPath = exports[0]
|
||||
})
|
||||
|
||||
return exportPath, err
|
||||
})
|
||||
}
|
||||
|
||||
return f.(func() (string, error))()
|
||||
}
|
||||
|
|
1102
vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
generated
vendored
1102
vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
generated
vendored
File diff suppressed because it is too large
Load diff
654
vendor/golang.org/x/tools/internal/gcimporter/iexport.go
generated
vendored
654
vendor/golang.org/x/tools/internal/gcimporter/iexport.go
generated
vendored
|
@ -2,9 +2,227 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Indexed binary package export.
|
||||
// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go;
|
||||
// see that file for specification of the format.
|
||||
// Indexed package export.
|
||||
//
|
||||
// The indexed export data format is an evolution of the previous
|
||||
// binary export data format. Its chief contribution is introducing an
|
||||
// index table, which allows efficient random access of individual
|
||||
// declarations and inline function bodies. In turn, this allows
|
||||
// avoiding unnecessary work for compilation units that import large
|
||||
// packages.
|
||||
//
|
||||
//
|
||||
// The top-level data format is structured as:
|
||||
//
|
||||
// Header struct {
|
||||
// Tag byte // 'i'
|
||||
// Version uvarint
|
||||
// StringSize uvarint
|
||||
// DataSize uvarint
|
||||
// }
|
||||
//
|
||||
// Strings [StringSize]byte
|
||||
// Data [DataSize]byte
|
||||
//
|
||||
// MainIndex []struct{
|
||||
// PkgPath stringOff
|
||||
// PkgName stringOff
|
||||
// PkgHeight uvarint
|
||||
//
|
||||
// Decls []struct{
|
||||
// Name stringOff
|
||||
// Offset declOff
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Fingerprint [8]byte
|
||||
//
|
||||
// uvarint means a uint64 written out using uvarint encoding.
|
||||
//
|
||||
// []T means a uvarint followed by that many T objects. In other
|
||||
// words:
|
||||
//
|
||||
// Len uvarint
|
||||
// Elems [Len]T
|
||||
//
|
||||
// stringOff means a uvarint that indicates an offset within the
|
||||
// Strings section. At that offset is another uvarint, followed by
|
||||
// that many bytes, which form the string value.
|
||||
//
|
||||
// declOff means a uvarint that indicates an offset within the Data
|
||||
// section where the associated declaration can be found.
|
||||
//
|
||||
//
|
||||
// There are five kinds of declarations, distinguished by their first
|
||||
// byte:
|
||||
//
|
||||
// type Var struct {
|
||||
// Tag byte // 'V'
|
||||
// Pos Pos
|
||||
// Type typeOff
|
||||
// }
|
||||
//
|
||||
// type Func struct {
|
||||
// Tag byte // 'F' or 'G'
|
||||
// Pos Pos
|
||||
// TypeParams []typeOff // only present if Tag == 'G'
|
||||
// Signature Signature
|
||||
// }
|
||||
//
|
||||
// type Const struct {
|
||||
// Tag byte // 'C'
|
||||
// Pos Pos
|
||||
// Value Value
|
||||
// }
|
||||
//
|
||||
// type Type struct {
|
||||
// Tag byte // 'T' or 'U'
|
||||
// Pos Pos
|
||||
// TypeParams []typeOff // only present if Tag == 'U'
|
||||
// Underlying typeOff
|
||||
//
|
||||
// Methods []struct{ // omitted if Underlying is an interface type
|
||||
// Pos Pos
|
||||
// Name stringOff
|
||||
// Recv Param
|
||||
// Signature Signature
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// type Alias struct {
|
||||
// Tag byte // 'A' or 'B'
|
||||
// Pos Pos
|
||||
// TypeParams []typeOff // only present if Tag == 'B'
|
||||
// Type typeOff
|
||||
// }
|
||||
//
|
||||
// // "Automatic" declaration of each typeparam
|
||||
// type TypeParam struct {
|
||||
// Tag byte // 'P'
|
||||
// Pos Pos
|
||||
// Implicit bool
|
||||
// Constraint typeOff
|
||||
// }
|
||||
//
|
||||
// typeOff means a uvarint that either indicates a predeclared type,
|
||||
// or an offset into the Data section. If the uvarint is less than
|
||||
// predeclReserved, then it indicates the index into the predeclared
|
||||
// types list (see predeclared in bexport.go for order). Otherwise,
|
||||
// subtracting predeclReserved yields the offset of a type descriptor.
|
||||
//
|
||||
// Value means a type, kind, and type-specific value. See
|
||||
// (*exportWriter).value for details.
|
||||
//
|
||||
//
|
||||
// There are twelve kinds of type descriptors, distinguished by an itag:
|
||||
//
|
||||
// type DefinedType struct {
|
||||
// Tag itag // definedType
|
||||
// Name stringOff
|
||||
// PkgPath stringOff
|
||||
// }
|
||||
//
|
||||
// type PointerType struct {
|
||||
// Tag itag // pointerType
|
||||
// Elem typeOff
|
||||
// }
|
||||
//
|
||||
// type SliceType struct {
|
||||
// Tag itag // sliceType
|
||||
// Elem typeOff
|
||||
// }
|
||||
//
|
||||
// type ArrayType struct {
|
||||
// Tag itag // arrayType
|
||||
// Len uint64
|
||||
// Elem typeOff
|
||||
// }
|
||||
//
|
||||
// type ChanType struct {
|
||||
// Tag itag // chanType
|
||||
// Dir uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv
|
||||
// Elem typeOff
|
||||
// }
|
||||
//
|
||||
// type MapType struct {
|
||||
// Tag itag // mapType
|
||||
// Key typeOff
|
||||
// Elem typeOff
|
||||
// }
|
||||
//
|
||||
// type FuncType struct {
|
||||
// Tag itag // signatureType
|
||||
// PkgPath stringOff
|
||||
// Signature Signature
|
||||
// }
|
||||
//
|
||||
// type StructType struct {
|
||||
// Tag itag // structType
|
||||
// PkgPath stringOff
|
||||
// Fields []struct {
|
||||
// Pos Pos
|
||||
// Name stringOff
|
||||
// Type typeOff
|
||||
// Embedded bool
|
||||
// Note stringOff
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// type InterfaceType struct {
|
||||
// Tag itag // interfaceType
|
||||
// PkgPath stringOff
|
||||
// Embeddeds []struct {
|
||||
// Pos Pos
|
||||
// Type typeOff
|
||||
// }
|
||||
// Methods []struct {
|
||||
// Pos Pos
|
||||
// Name stringOff
|
||||
// Signature Signature
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Reference to a type param declaration
|
||||
// type TypeParamType struct {
|
||||
// Tag itag // typeParamType
|
||||
// Name stringOff
|
||||
// PkgPath stringOff
|
||||
// }
|
||||
//
|
||||
// // Instantiation of a generic type (like List[T2] or List[int])
|
||||
// type InstanceType struct {
|
||||
// Tag itag // instanceType
|
||||
// Pos pos
|
||||
// TypeArgs []typeOff
|
||||
// BaseType typeOff
|
||||
// }
|
||||
//
|
||||
// type UnionType struct {
|
||||
// Tag itag // interfaceType
|
||||
// Terms []struct {
|
||||
// tilde bool
|
||||
// Type typeOff
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// type Signature struct {
|
||||
// Params []Param
|
||||
// Results []Param
|
||||
// Variadic bool // omitted if Results is empty
|
||||
// }
|
||||
//
|
||||
// type Param struct {
|
||||
// Pos Pos
|
||||
// Name stringOff
|
||||
// Type typOff
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Pos encodes a file:line:column triple, incorporating a simple delta
|
||||
// encoding scheme within a data object. See exportWriter.pos for
|
||||
// details.
|
||||
|
||||
package gcimporter
|
||||
|
||||
|
@ -22,16 +240,42 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/go/types/objectpath"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// IExportShallow encodes "shallow" export data for the specified package.
|
||||
//
|
||||
// No promises are made about the encoding other than that it can be
|
||||
// decoded by the same version of IIExportShallow. If you plan to save
|
||||
// export data in the file system, be sure to include a cryptographic
|
||||
// digest of the executable in the key to avoid version skew.
|
||||
func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) {
|
||||
// For types, we use "shallow" export data. Historically, the Go
|
||||
// compiler always produced a summary of the types for a given package
|
||||
// that included types from other packages that it indirectly
|
||||
// referenced: "deep" export data. This had the advantage that the
|
||||
// compiler (and analogous tools such as gopls) need only load one
|
||||
// file per direct import. However, it meant that the files tended to
|
||||
// get larger based on the level of the package in the import
|
||||
// graph. For example, higher-level packages in the kubernetes module
|
||||
// have over 1MB of "deep" export data, even when they have almost no
|
||||
// content of their own, merely because they mention a major type that
|
||||
// references many others. In pathological cases the export data was
|
||||
// 300x larger than the source for a package due to this quadratic
|
||||
// growth.
|
||||
//
|
||||
// "Shallow" export data means that the serialized types describe only
|
||||
// a single package. If those types mention types from other packages,
|
||||
// the type checker may need to request additional packages beyond
|
||||
// just the direct imports. Type information for the entire transitive
|
||||
// closure of imports is provided (lazily) by the DAG.
|
||||
//
|
||||
// No promises are made about the encoding other than that it can be decoded by
|
||||
// the same version of IIExportShallow. If you plan to save export data in the
|
||||
// file system, be sure to include a cryptographic digest of the executable in
|
||||
// the key to avoid version skew.
|
||||
//
|
||||
// If the provided reportf func is non-nil, it will be used for reporting bugs
|
||||
// encountered during export.
|
||||
// TODO(rfindley): remove reportf when we are confident enough in the new
|
||||
// objectpath encoding.
|
||||
func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) ([]byte, error) {
|
||||
// In principle this operation can only fail if out.Write fails,
|
||||
// but that's impossible for bytes.Buffer---and as a matter of
|
||||
// fact iexportCommon doesn't even check for I/O errors.
|
||||
|
@ -43,22 +287,30 @@ func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) {
|
|||
return out.Bytes(), err
|
||||
}
|
||||
|
||||
// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow
|
||||
// in the same executable. This function cannot import data from
|
||||
// cmd/compile or gcexportdata.Write.
|
||||
func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) {
|
||||
// IImportShallow decodes "shallow" types.Package data encoded by
|
||||
// [IExportShallow] in the same executable. This function cannot import data
|
||||
// from cmd/compile or gcexportdata.Write.
|
||||
//
|
||||
// The importer calls getPackages to obtain package symbols for all
|
||||
// packages mentioned in the export data, including the one being
|
||||
// decoded.
|
||||
//
|
||||
// If the provided reportf func is non-nil, it will be used for reporting bugs
|
||||
// encountered during import.
|
||||
// TODO(rfindley): remove reportf when we are confident enough in the new
|
||||
// objectpath encoding.
|
||||
func IImportShallow(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, path string, reportf ReportFunc) (*types.Package, error) {
|
||||
const bundle = false
|
||||
pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert)
|
||||
const shallow = true
|
||||
pkgs, err := iimportCommon(fset, getPackages, data, bundle, path, shallow, reportf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pkgs[0], nil
|
||||
}
|
||||
|
||||
// InsertType is the type of a function that creates a types.TypeName
|
||||
// object for a named type and inserts it into the scope of the
|
||||
// specified Package.
|
||||
type InsertType = func(pkg *types.Package, name string)
|
||||
// ReportFunc is the type of a function used to report formatted bugs.
|
||||
type ReportFunc = func(string, ...interface{})
|
||||
|
||||
// Current bundled export format version. Increase with each format change.
|
||||
// 0: initial implementation
|
||||
|
@ -138,6 +390,17 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, ver
|
|||
p.doDecl(p.declTodo.popHead())
|
||||
}
|
||||
|
||||
// Produce index of offset of each file record in files.
|
||||
var files intWriter
|
||||
var fileOffset []uint64 // fileOffset[i] is offset in files of file encoded as i
|
||||
if p.shallow {
|
||||
fileOffset = make([]uint64, len(p.fileInfos))
|
||||
for i, info := range p.fileInfos {
|
||||
fileOffset[i] = uint64(files.Len())
|
||||
p.encodeFile(&files, info.file, info.needed)
|
||||
}
|
||||
}
|
||||
|
||||
// Append indices to data0 section.
|
||||
dataLen := uint64(p.data0.Len())
|
||||
w := p.newWriter()
|
||||
|
@ -163,16 +426,75 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, ver
|
|||
}
|
||||
hdr.uint64(uint64(p.version))
|
||||
hdr.uint64(uint64(p.strings.Len()))
|
||||
if p.shallow {
|
||||
hdr.uint64(uint64(files.Len()))
|
||||
hdr.uint64(uint64(len(fileOffset)))
|
||||
for _, offset := range fileOffset {
|
||||
hdr.uint64(offset)
|
||||
}
|
||||
}
|
||||
hdr.uint64(dataLen)
|
||||
|
||||
// Flush output.
|
||||
io.Copy(out, &hdr)
|
||||
io.Copy(out, &p.strings)
|
||||
if p.shallow {
|
||||
io.Copy(out, &files)
|
||||
}
|
||||
io.Copy(out, &p.data0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// encodeFile writes to w a representation of the file sufficient to
|
||||
// faithfully restore position information about all needed offsets.
|
||||
// Mutates the needed array.
|
||||
func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) {
|
||||
_ = needed[0] // precondition: needed is non-empty
|
||||
|
||||
w.uint64(p.stringOff(file.Name()))
|
||||
|
||||
size := uint64(file.Size())
|
||||
w.uint64(size)
|
||||
|
||||
// Sort the set of needed offsets. Duplicates are harmless.
|
||||
sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] })
|
||||
|
||||
lines := file.Lines() // byte offset of each line start
|
||||
w.uint64(uint64(len(lines)))
|
||||
|
||||
// Rather than record the entire array of line start offsets,
|
||||
// we save only a sparse list of (index, offset) pairs for
|
||||
// the start of each line that contains a needed position.
|
||||
var sparse [][2]int // (index, offset) pairs
|
||||
outer:
|
||||
for i, lineStart := range lines {
|
||||
lineEnd := size
|
||||
if i < len(lines)-1 {
|
||||
lineEnd = uint64(lines[i+1])
|
||||
}
|
||||
// Does this line contains a needed offset?
|
||||
if needed[0] < lineEnd {
|
||||
sparse = append(sparse, [2]int{i, lineStart})
|
||||
for needed[0] < lineEnd {
|
||||
needed = needed[1:]
|
||||
if len(needed) == 0 {
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delta-encode the columns.
|
||||
w.uint64(uint64(len(sparse)))
|
||||
var prev [2]int
|
||||
for _, pair := range sparse {
|
||||
w.uint64(uint64(pair[0] - prev[0]))
|
||||
w.uint64(uint64(pair[1] - prev[1]))
|
||||
prev = pair
|
||||
}
|
||||
}
|
||||
|
||||
// writeIndex writes out an object index. mainIndex indicates whether
|
||||
// we're writing out the main index, which is also read by
|
||||
// non-compiler tools and includes a complete package description
|
||||
|
@ -242,8 +564,9 @@ type iexporter struct {
|
|||
out *bytes.Buffer
|
||||
version int
|
||||
|
||||
shallow bool // don't put types from other packages in the index
|
||||
localpkg *types.Package // (nil in bundle mode)
|
||||
shallow bool // don't put types from other packages in the index
|
||||
objEncoder *objectpath.Encoder // encodes objects from other packages in shallow mode; lazily allocated
|
||||
localpkg *types.Package // (nil in bundle mode)
|
||||
|
||||
// allPkgs tracks all packages that have been referenced by
|
||||
// the export data, so we can ensure to include them in the
|
||||
|
@ -255,6 +578,12 @@ type iexporter struct {
|
|||
strings intWriter
|
||||
stringIndex map[string]uint64
|
||||
|
||||
// In shallow mode, object positions are encoded as (file, offset).
|
||||
// Each file is recorded as a line-number table.
|
||||
// Only the lines of needed positions are saved faithfully.
|
||||
fileInfo map[*token.File]uint64 // value is index in fileInfos
|
||||
fileInfos []*filePositions
|
||||
|
||||
data0 intWriter
|
||||
declIndex map[types.Object]uint64
|
||||
tparamNames map[types.Object]string // typeparam->exported name
|
||||
|
@ -263,6 +592,11 @@ type iexporter struct {
|
|||
indent int // for tracing support
|
||||
}
|
||||
|
||||
type filePositions struct {
|
||||
file *token.File
|
||||
needed []uint64 // unordered list of needed file offsets
|
||||
}
|
||||
|
||||
func (p *iexporter) trace(format string, args ...interface{}) {
|
||||
if !trace {
|
||||
// Call sites should also be guarded, but having this check here allows
|
||||
|
@ -272,6 +606,17 @@ func (p *iexporter) trace(format string, args ...interface{}) {
|
|||
fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
|
||||
}
|
||||
|
||||
// objectpathEncoder returns the lazily allocated objectpath.Encoder to use
|
||||
// when encoding objects in other packages during shallow export.
|
||||
//
|
||||
// Using a shared Encoder amortizes some of cost of objectpath search.
|
||||
func (p *iexporter) objectpathEncoder() *objectpath.Encoder {
|
||||
if p.objEncoder == nil {
|
||||
p.objEncoder = new(objectpath.Encoder)
|
||||
}
|
||||
return p.objEncoder
|
||||
}
|
||||
|
||||
// stringOff returns the offset of s within the string section.
|
||||
// If not already present, it's added to the end.
|
||||
func (p *iexporter) stringOff(s string) uint64 {
|
||||
|
@ -286,6 +631,25 @@ func (p *iexporter) stringOff(s string) uint64 {
|
|||
return off
|
||||
}
|
||||
|
||||
// fileIndexAndOffset returns the index of the token.File and the byte offset of pos within it.
|
||||
func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) {
|
||||
index, ok := p.fileInfo[file]
|
||||
if !ok {
|
||||
index = uint64(len(p.fileInfo))
|
||||
p.fileInfos = append(p.fileInfos, &filePositions{file: file})
|
||||
if p.fileInfo == nil {
|
||||
p.fileInfo = make(map[*token.File]uint64)
|
||||
}
|
||||
p.fileInfo[file] = index
|
||||
}
|
||||
// Record each needed offset.
|
||||
info := p.fileInfos[index]
|
||||
offset := uint64(file.Offset(pos))
|
||||
info.needed = append(info.needed, offset)
|
||||
|
||||
return index, offset
|
||||
}
|
||||
|
||||
// pushDecl adds n to the declaration work queue, if not already present.
|
||||
func (p *iexporter) pushDecl(obj types.Object) {
|
||||
// Package unsafe is known to the compiler and predeclared.
|
||||
|
@ -312,7 +676,6 @@ type exportWriter struct {
|
|||
p *iexporter
|
||||
|
||||
data intWriter
|
||||
currPkg *types.Package
|
||||
prevFile string
|
||||
prevLine int64
|
||||
prevColumn int64
|
||||
|
@ -335,25 +698,30 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
}()
|
||||
}
|
||||
w := p.newWriter()
|
||||
w.setPkg(obj.Pkg(), false)
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *types.Var:
|
||||
w.tag('V')
|
||||
w.tag(varTag)
|
||||
w.pos(obj.Pos())
|
||||
w.typ(obj.Type(), obj.Pkg())
|
||||
|
||||
case *types.Func:
|
||||
sig, _ := obj.Type().(*types.Signature)
|
||||
if sig.Recv() != nil {
|
||||
panic(internalErrorf("unexpected method: %v", sig))
|
||||
// We shouldn't see methods in the package scope,
|
||||
// but the type checker may repair "func () F() {}"
|
||||
// to "func (Invalid) F()" and then treat it like "func F()",
|
||||
// so allow that. See golang/go#57729.
|
||||
if sig.Recv().Type() != types.Typ[types.Invalid] {
|
||||
panic(internalErrorf("unexpected method: %v", sig))
|
||||
}
|
||||
}
|
||||
|
||||
// Function.
|
||||
if typeparams.ForSignature(sig).Len() == 0 {
|
||||
w.tag('F')
|
||||
if sig.TypeParams().Len() == 0 {
|
||||
w.tag(funcTag)
|
||||
} else {
|
||||
w.tag('G')
|
||||
w.tag(genericFuncTag)
|
||||
}
|
||||
w.pos(obj.Pos())
|
||||
// The tparam list of the function type is the declaration of the type
|
||||
|
@ -363,27 +731,27 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
//
|
||||
// While importing the type parameters, tparamList computes and records
|
||||
// their export name, so that it can be later used when writing the index.
|
||||
if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 {
|
||||
if tparams := sig.TypeParams(); tparams.Len() > 0 {
|
||||
w.tparamList(obj.Name(), tparams, obj.Pkg())
|
||||
}
|
||||
w.signature(sig)
|
||||
|
||||
case *types.Const:
|
||||
w.tag('C')
|
||||
w.tag(constTag)
|
||||
w.pos(obj.Pos())
|
||||
w.value(obj.Type(), obj.Val())
|
||||
|
||||
case *types.TypeName:
|
||||
t := obj.Type()
|
||||
|
||||
if tparam, ok := t.(*typeparams.TypeParam); ok {
|
||||
w.tag('P')
|
||||
if tparam, ok := types.Unalias(t).(*types.TypeParam); ok {
|
||||
w.tag(typeParamTag)
|
||||
w.pos(obj.Pos())
|
||||
constraint := tparam.Constraint()
|
||||
if p.version >= iexportVersionGo1_18 {
|
||||
implicit := false
|
||||
if iface, _ := constraint.(*types.Interface); iface != nil {
|
||||
implicit = typeparams.IsImplicit(iface)
|
||||
if iface, _ := types.Unalias(constraint).(*types.Interface); iface != nil {
|
||||
implicit = iface.IsImplicit()
|
||||
}
|
||||
w.bool(implicit)
|
||||
}
|
||||
|
@ -392,8 +760,26 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
}
|
||||
|
||||
if obj.IsAlias() {
|
||||
w.tag('A')
|
||||
alias, materialized := t.(*types.Alias) // may fail when aliases are not enabled
|
||||
|
||||
var tparams *types.TypeParamList
|
||||
if materialized {
|
||||
tparams = aliases.TypeParams(alias)
|
||||
}
|
||||
if tparams.Len() == 0 {
|
||||
w.tag(aliasTag)
|
||||
} else {
|
||||
w.tag(genericAliasTag)
|
||||
}
|
||||
w.pos(obj.Pos())
|
||||
if tparams.Len() > 0 {
|
||||
w.tparamList(obj.Name(), tparams, obj.Pkg())
|
||||
}
|
||||
if materialized {
|
||||
// Preserve materialized aliases,
|
||||
// even of non-exported types.
|
||||
t = aliases.Rhs(alias)
|
||||
}
|
||||
w.typ(t, obj.Pkg())
|
||||
break
|
||||
}
|
||||
|
@ -404,20 +790,20 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
panic(internalErrorf("%s is not a defined type", t))
|
||||
}
|
||||
|
||||
if typeparams.ForNamed(named).Len() == 0 {
|
||||
w.tag('T')
|
||||
if named.TypeParams().Len() == 0 {
|
||||
w.tag(typeTag)
|
||||
} else {
|
||||
w.tag('U')
|
||||
w.tag(genericTypeTag)
|
||||
}
|
||||
w.pos(obj.Pos())
|
||||
|
||||
if typeparams.ForNamed(named).Len() > 0 {
|
||||
if named.TypeParams().Len() > 0 {
|
||||
// While importing the type parameters, tparamList computes and records
|
||||
// their export name, so that it can be later used when writing the index.
|
||||
w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg())
|
||||
w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg())
|
||||
}
|
||||
|
||||
underlying := obj.Type().Underlying()
|
||||
underlying := named.Underlying()
|
||||
w.typ(underlying, obj.Pkg())
|
||||
|
||||
if types.IsInterface(t) {
|
||||
|
@ -434,7 +820,7 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
|
||||
// Receiver type parameters are type arguments of the receiver type, so
|
||||
// their name must be qualified before exporting recv.
|
||||
if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 {
|
||||
if rparams := sig.RecvTypeParams(); rparams.Len() > 0 {
|
||||
prefix := obj.Name() + "." + m.Name()
|
||||
for i := 0; i < rparams.Len(); i++ {
|
||||
rparam := rparams.At(i)
|
||||
|
@ -458,13 +844,30 @@ func (w *exportWriter) tag(tag byte) {
|
|||
}
|
||||
|
||||
func (w *exportWriter) pos(pos token.Pos) {
|
||||
if w.p.version >= iexportVersionPosCol {
|
||||
if w.p.shallow {
|
||||
w.posV2(pos)
|
||||
} else if w.p.version >= iexportVersionPosCol {
|
||||
w.posV1(pos)
|
||||
} else {
|
||||
w.posV0(pos)
|
||||
}
|
||||
}
|
||||
|
||||
// posV2 encoding (used only in shallow mode) records positions as
|
||||
// (file, offset), where file is the index in the token.File table
|
||||
// (which records the file name and newline offsets) and offset is a
|
||||
// byte offset. It effectively ignores //line directives.
|
||||
func (w *exportWriter) posV2(pos token.Pos) {
|
||||
if pos == token.NoPos {
|
||||
w.uint64(0)
|
||||
return
|
||||
}
|
||||
file := w.p.fset.File(pos) // fset must be non-nil
|
||||
index, offset := w.p.fileIndexAndOffset(file, pos)
|
||||
w.uint64(1 + index)
|
||||
w.uint64(offset)
|
||||
}
|
||||
|
||||
func (w *exportWriter) posV1(pos token.Pos) {
|
||||
if w.p.fset == nil {
|
||||
w.int64(0)
|
||||
|
@ -549,6 +952,9 @@ func (w *exportWriter) qualifiedType(obj *types.TypeName) {
|
|||
w.pkg(obj.Pkg())
|
||||
}
|
||||
|
||||
// TODO(rfindley): what does 'pkg' even mean here? It would be better to pass
|
||||
// it in explicitly into signatures and structs that may use it for
|
||||
// constructing fields.
|
||||
func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
|
||||
w.data.uint64(w.p.typOff(t, pkg))
|
||||
}
|
||||
|
@ -588,20 +994,31 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
}()
|
||||
}
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
if targs := aliases.TypeArgs(t); targs.Len() > 0 {
|
||||
w.startType(instanceType)
|
||||
w.pos(t.Obj().Pos())
|
||||
w.typeList(targs, pkg)
|
||||
w.typ(aliases.Origin(t), pkg)
|
||||
return
|
||||
}
|
||||
w.startType(aliasType)
|
||||
w.qualifiedType(t.Obj())
|
||||
|
||||
case *types.Named:
|
||||
if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 {
|
||||
if targs := t.TypeArgs(); targs.Len() > 0 {
|
||||
w.startType(instanceType)
|
||||
// TODO(rfindley): investigate if this position is correct, and if it
|
||||
// matters.
|
||||
w.pos(t.Obj().Pos())
|
||||
w.typeList(targs, pkg)
|
||||
w.typ(typeparams.NamedTypeOrigin(t), pkg)
|
||||
w.typ(t.Origin(), pkg)
|
||||
return
|
||||
}
|
||||
w.startType(definedType)
|
||||
w.qualifiedType(t.Obj())
|
||||
|
||||
case *typeparams.TypeParam:
|
||||
case *types.TypeParam:
|
||||
w.startType(typeParamType)
|
||||
w.qualifiedType(t.Obj())
|
||||
|
||||
|
@ -640,37 +1057,60 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
|
||||
case *types.Signature:
|
||||
w.startType(signatureType)
|
||||
w.setPkg(pkg, true)
|
||||
w.pkg(pkg)
|
||||
w.signature(t)
|
||||
|
||||
case *types.Struct:
|
||||
w.startType(structType)
|
||||
n := t.NumFields()
|
||||
// Even for struct{} we must emit some qualifying package, because that's
|
||||
// what the compiler does, and thus that's what the importer expects.
|
||||
fieldPkg := pkg
|
||||
if n > 0 {
|
||||
w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects
|
||||
} else {
|
||||
w.setPkg(pkg, true)
|
||||
fieldPkg = t.Field(0).Pkg()
|
||||
}
|
||||
if fieldPkg == nil {
|
||||
// TODO(rfindley): improve this very hacky logic.
|
||||
//
|
||||
// The importer expects a package to be set for all struct types, even
|
||||
// those with no fields. A better encoding might be to set NumFields
|
||||
// before pkg. setPkg panics with a nil package, which may be possible
|
||||
// to reach with invalid packages (and perhaps valid packages, too?), so
|
||||
// (arbitrarily) set the localpkg if available.
|
||||
//
|
||||
// Alternatively, we may be able to simply guarantee that pkg != nil, by
|
||||
// reconsidering the encoding of constant values.
|
||||
if w.p.shallow {
|
||||
fieldPkg = w.p.localpkg
|
||||
} else {
|
||||
panic(internalErrorf("no package to set for empty struct"))
|
||||
}
|
||||
}
|
||||
w.pkg(fieldPkg)
|
||||
w.uint64(uint64(n))
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if w.p.shallow {
|
||||
w.objectPath(f)
|
||||
}
|
||||
w.pos(f.Pos())
|
||||
w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg
|
||||
w.typ(f.Type(), pkg)
|
||||
w.typ(f.Type(), fieldPkg)
|
||||
w.bool(f.Anonymous())
|
||||
w.string(t.Tag(i)) // note (or tag)
|
||||
}
|
||||
|
||||
case *types.Interface:
|
||||
w.startType(interfaceType)
|
||||
w.setPkg(pkg, true)
|
||||
w.pkg(pkg)
|
||||
|
||||
n := t.NumEmbeddeds()
|
||||
w.uint64(uint64(n))
|
||||
for i := 0; i < n; i++ {
|
||||
ft := t.EmbeddedType(i)
|
||||
tPkg := pkg
|
||||
if named, _ := ft.(*types.Named); named != nil {
|
||||
if named, _ := types.Unalias(ft).(*types.Named); named != nil {
|
||||
w.pos(named.Obj().Pos())
|
||||
} else {
|
||||
w.pos(token.NoPos)
|
||||
|
@ -678,17 +1118,23 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
w.typ(ft, tPkg)
|
||||
}
|
||||
|
||||
// See comment for struct fields. In shallow mode we change the encoding
|
||||
// for interface methods that are promoted from other packages.
|
||||
|
||||
n = t.NumExplicitMethods()
|
||||
w.uint64(uint64(n))
|
||||
for i := 0; i < n; i++ {
|
||||
m := t.ExplicitMethod(i)
|
||||
if w.p.shallow {
|
||||
w.objectPath(m)
|
||||
}
|
||||
w.pos(m.Pos())
|
||||
w.string(m.Name())
|
||||
sig, _ := m.Type().(*types.Signature)
|
||||
w.signature(sig)
|
||||
}
|
||||
|
||||
case *typeparams.Union:
|
||||
case *types.Union:
|
||||
w.startType(unionType)
|
||||
nt := t.Len()
|
||||
w.uint64(uint64(nt))
|
||||
|
@ -703,12 +1149,61 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) setPkg(pkg *types.Package, write bool) {
|
||||
if write {
|
||||
w.pkg(pkg)
|
||||
// objectPath writes the package and objectPath to use to look up obj in a
|
||||
// different package, when encoding in "shallow" mode.
|
||||
//
|
||||
// When doing a shallow import, the importer creates only the local package,
|
||||
// and requests package symbols for dependencies from the client.
|
||||
// However, certain types defined in the local package may hold objects defined
|
||||
// (perhaps deeply) within another package.
|
||||
//
|
||||
// For example, consider the following:
|
||||
//
|
||||
// package a
|
||||
// func F() chan * map[string] struct { X int }
|
||||
//
|
||||
// package b
|
||||
// import "a"
|
||||
// var B = a.F()
|
||||
//
|
||||
// In this example, the type of b.B holds fields defined in package a.
|
||||
// In order to have the correct canonical objects for the field defined in the
|
||||
// type of B, they are encoded as objectPaths and later looked up in the
|
||||
// importer. The same problem applies to interface methods.
|
||||
func (w *exportWriter) objectPath(obj types.Object) {
|
||||
if obj.Pkg() == nil || obj.Pkg() == w.p.localpkg {
|
||||
// obj.Pkg() may be nil for the builtin error.Error.
|
||||
// In this case, or if obj is declared in the local package, no need to
|
||||
// encode.
|
||||
w.string("")
|
||||
return
|
||||
}
|
||||
|
||||
w.currPkg = pkg
|
||||
objectPath, err := w.p.objectpathEncoder().For(obj)
|
||||
if err != nil {
|
||||
// Fall back to the empty string, which will cause the importer to create a
|
||||
// new object, which matches earlier behavior. Creating a new object is
|
||||
// sufficient for many purposes (such as type checking), but causes certain
|
||||
// references algorithms to fail (golang/go#60819). However, we didn't
|
||||
// notice this problem during months of gopls@v0.12.0 testing.
|
||||
//
|
||||
// TODO(golang/go#61674): this workaround is insufficient, as in the case
|
||||
// where the field forwarded from an instantiated type that may not appear
|
||||
// in the export data of the original package:
|
||||
//
|
||||
// // package a
|
||||
// type A[P any] struct{ F P }
|
||||
//
|
||||
// // package b
|
||||
// type B a.A[int]
|
||||
//
|
||||
// We need to update references algorithms not to depend on this
|
||||
// de-duplication, at which point we may want to simply remove the
|
||||
// workaround here.
|
||||
w.string("")
|
||||
return
|
||||
}
|
||||
w.string(string(objectPath))
|
||||
w.pkg(obj.Pkg())
|
||||
}
|
||||
|
||||
func (w *exportWriter) signature(sig *types.Signature) {
|
||||
|
@ -719,14 +1214,14 @@ func (w *exportWriter) signature(sig *types.Signature) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) {
|
||||
func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) {
|
||||
w.uint64(uint64(ts.Len()))
|
||||
for i := 0; i < ts.Len(); i++ {
|
||||
w.typ(ts.At(i), pkg)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) {
|
||||
func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) {
|
||||
ll := uint64(list.Len())
|
||||
w.uint64(ll)
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
|
@ -744,7 +1239,7 @@ const blankMarker = "$"
|
|||
// differs from its actual object name: it is prefixed with a qualifier, and
|
||||
// blank type parameter names are disambiguated by their index in the type
|
||||
// parameter list.
|
||||
func tparamExportName(prefix string, tparam *typeparams.TypeParam) string {
|
||||
func tparamExportName(prefix string, tparam *types.TypeParam) string {
|
||||
assert(prefix != "")
|
||||
name := tparam.Obj().Name()
|
||||
if name == "_" {
|
||||
|
@ -789,6 +1284,17 @@ func (w *exportWriter) value(typ types.Type, v constant.Value) {
|
|||
w.int64(int64(v.Kind()))
|
||||
}
|
||||
|
||||
if v.Kind() == constant.Unknown {
|
||||
// golang/go#60605: treat unknown constant values as if they have invalid type
|
||||
//
|
||||
// This loses some fidelity over the package type-checked from source, but that
|
||||
// is acceptable.
|
||||
//
|
||||
// TODO(rfindley): we should switch on the recorded constant kind rather
|
||||
// than the constant type
|
||||
return
|
||||
}
|
||||
|
||||
switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
|
||||
case types.IsBoolean:
|
||||
w.bool(constant.BoolVal(v))
|
||||
|
@ -845,6 +1351,16 @@ func constantToFloat(x constant.Value) *big.Float {
|
|||
return &f
|
||||
}
|
||||
|
||||
func valueToRat(x constant.Value) *big.Rat {
|
||||
// Convert little-endian to big-endian.
|
||||
// I can't believe this is necessary.
|
||||
bytes := constant.Bytes(x)
|
||||
for i := 0; i < len(bytes)/2; i++ {
|
||||
bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
|
||||
}
|
||||
return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
|
||||
}
|
||||
|
||||
// mpint exports a multi-precision integer.
|
||||
//
|
||||
// For unsigned types, small values are written out as a single
|
||||
|
@ -1054,3 +1570,19 @@ func (q *objQueue) popHead() types.Object {
|
|||
q.head++
|
||||
return obj
|
||||
}
|
||||
|
||||
// internalError represents an error generated inside this package.
|
||||
type internalError string
|
||||
|
||||
func (e internalError) Error() string { return "gcimporter: " + string(e) }
|
||||
|
||||
// TODO(adonovan): make this call panic, so that it's symmetric with errorf.
|
||||
// Otherwise it's easy to forget to do anything with the error.
|
||||
//
|
||||
// TODO(adonovan): also, consider switching the names "errorf" and
|
||||
// "internalErrorf" as the former is used for bugs, whose cause is
|
||||
// internal inconsistency, whereas the latter is used for ordinary
|
||||
// situations like bad input, whose cause is external.
|
||||
func internalErrorf(format string, args ...interface{}) error {
|
||||
return internalError(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
|
403
vendor/golang.org/x/tools/internal/gcimporter/iimport.go
generated
vendored
403
vendor/golang.org/x/tools/internal/gcimporter/iimport.go
generated
vendored
|
@ -3,9 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Indexed package import.
|
||||
// See cmd/compile/internal/gc/iexport.go for the export data format.
|
||||
|
||||
// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go.
|
||||
// See iexport.go for the export data format.
|
||||
|
||||
package gcimporter
|
||||
|
||||
|
@ -21,7 +19,9 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/go/types/objectpath"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
type intReader struct {
|
||||
|
@ -51,6 +51,7 @@ const (
|
|||
iexportVersionPosCol = 1
|
||||
iexportVersionGo1_18 = 2
|
||||
iexportVersionGenerics = 2
|
||||
iexportVersion = iexportVersionGenerics
|
||||
|
||||
iexportVersionCurrent = 2
|
||||
)
|
||||
|
@ -78,6 +79,20 @@ const (
|
|||
typeParamType
|
||||
instanceType
|
||||
unionType
|
||||
aliasType
|
||||
)
|
||||
|
||||
// Object tags
|
||||
const (
|
||||
varTag = 'V'
|
||||
funcTag = 'F'
|
||||
genericFuncTag = 'G'
|
||||
constTag = 'C'
|
||||
aliasTag = 'A'
|
||||
genericAliasTag = 'B'
|
||||
typeParamTag = 'P'
|
||||
typeTag = 'T'
|
||||
genericTypeTag = 'U'
|
||||
)
|
||||
|
||||
// IImportData imports a package from the serialized package data
|
||||
|
@ -85,7 +100,7 @@ const (
|
|||
// If the export data version is not recognized or the format is otherwise
|
||||
// compromised, an error is returned.
|
||||
func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
|
||||
pkgs, err := iimportCommon(fset, imports, data, false, path, nil)
|
||||
pkgs, err := iimportCommon(fset, GetPackagesFromMap(imports), data, false, path, false, nil)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
@ -94,10 +109,49 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
|||
|
||||
// IImportBundle imports a set of packages from the serialized package bundle.
|
||||
func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) {
|
||||
return iimportCommon(fset, imports, data, true, "", nil)
|
||||
return iimportCommon(fset, GetPackagesFromMap(imports), data, true, "", false, nil)
|
||||
}
|
||||
|
||||
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) {
|
||||
// A GetPackagesFunc function obtains the non-nil symbols for a set of
|
||||
// packages, creating and recursively importing them as needed. An
|
||||
// implementation should store each package symbol is in the Pkg
|
||||
// field of the items array.
|
||||
//
|
||||
// Any error causes importing to fail. This can be used to quickly read
|
||||
// the import manifest of an export data file without fully decoding it.
|
||||
type GetPackagesFunc = func(items []GetPackagesItem) error
|
||||
|
||||
// A GetPackagesItem is a request from the importer for the package
|
||||
// symbol of the specified name and path.
|
||||
type GetPackagesItem struct {
|
||||
Name, Path string
|
||||
Pkg *types.Package // to be filled in by GetPackagesFunc call
|
||||
|
||||
// private importer state
|
||||
pathOffset uint64
|
||||
nameIndex map[string]uint64
|
||||
}
|
||||
|
||||
// GetPackagesFromMap returns a GetPackagesFunc that retrieves
|
||||
// packages from the given map of package path to package.
|
||||
//
|
||||
// The returned function may mutate m: each requested package that is not
|
||||
// found is created with types.NewPackage and inserted into m.
|
||||
func GetPackagesFromMap(m map[string]*types.Package) GetPackagesFunc {
|
||||
return func(items []GetPackagesItem) error {
|
||||
for i, item := range items {
|
||||
pkg, ok := m[item.Path]
|
||||
if !ok {
|
||||
pkg = types.NewPackage(item.Path, item.Name)
|
||||
m[item.Path] = pkg
|
||||
}
|
||||
items[i].Pkg = pkg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, bundle bool, path string, shallow bool, reportf ReportFunc) (pkgs []*types.Package, err error) {
|
||||
const currentVersion = iexportVersionCurrent
|
||||
version := int64(-1)
|
||||
if !debug {
|
||||
|
@ -108,7 +162,7 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
} else if version > currentVersion {
|
||||
err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
|
||||
} else {
|
||||
err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
|
||||
err = fmt.Errorf("internal error while importing %q (%v); please report an issue", path, e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -117,11 +171,8 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
r := &intReader{bytes.NewReader(data), path}
|
||||
|
||||
if bundle {
|
||||
bundleVersion := r.uint64()
|
||||
switch bundleVersion {
|
||||
case bundleVersion:
|
||||
default:
|
||||
errorf("unknown bundle format version %d", bundleVersion)
|
||||
if v := r.uint64(); v != bundleVersion {
|
||||
errorf("unknown bundle format version %d", v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,20 +188,36 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
}
|
||||
|
||||
sLen := int64(r.uint64())
|
||||
var fLen int64
|
||||
var fileOffset []uint64
|
||||
if shallow {
|
||||
// Shallow mode uses a different position encoding.
|
||||
fLen = int64(r.uint64())
|
||||
fileOffset = make([]uint64, r.uint64())
|
||||
for i := range fileOffset {
|
||||
fileOffset[i] = r.uint64()
|
||||
}
|
||||
}
|
||||
dLen := int64(r.uint64())
|
||||
|
||||
whence, _ := r.Seek(0, io.SeekCurrent)
|
||||
stringData := data[whence : whence+sLen]
|
||||
declData := data[whence+sLen : whence+sLen+dLen]
|
||||
r.Seek(sLen+dLen, io.SeekCurrent)
|
||||
fileData := data[whence+sLen : whence+sLen+fLen]
|
||||
declData := data[whence+sLen+fLen : whence+sLen+fLen+dLen]
|
||||
r.Seek(sLen+fLen+dLen, io.SeekCurrent)
|
||||
|
||||
p := iimporter{
|
||||
version: int(version),
|
||||
ipath: path,
|
||||
insert: insert,
|
||||
aliases: aliases.Enabled(),
|
||||
shallow: shallow,
|
||||
reportf: reportf,
|
||||
|
||||
stringData: stringData,
|
||||
stringCache: make(map[uint64]string),
|
||||
fileOffset: fileOffset,
|
||||
fileData: fileData,
|
||||
fileCache: make([]*token.File, len(fileOffset)),
|
||||
pkgCache: make(map[uint64]*types.Package),
|
||||
|
||||
declData: declData,
|
||||
|
@ -171,8 +238,10 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
p.typCache[uint64(i)] = pt
|
||||
}
|
||||
|
||||
pkgList := make([]*types.Package, r.uint64())
|
||||
for i := range pkgList {
|
||||
// Gather the relevant packages from the manifest.
|
||||
items := make([]GetPackagesItem, r.uint64())
|
||||
uniquePkgPaths := make(map[string]bool)
|
||||
for i := range items {
|
||||
pkgPathOff := r.uint64()
|
||||
pkgPath := p.stringAt(pkgPathOff)
|
||||
pkgName := p.stringAt(r.uint64())
|
||||
|
@ -181,30 +250,48 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
if pkgPath == "" {
|
||||
pkgPath = path
|
||||
}
|
||||
pkg := imports[pkgPath]
|
||||
if pkg == nil {
|
||||
pkg = types.NewPackage(pkgPath, pkgName)
|
||||
imports[pkgPath] = pkg
|
||||
} else if pkg.Name() != pkgName {
|
||||
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
|
||||
}
|
||||
if i == 0 && !bundle {
|
||||
p.localpkg = pkg
|
||||
}
|
||||
|
||||
p.pkgCache[pkgPathOff] = pkg
|
||||
items[i].Name = pkgName
|
||||
items[i].Path = pkgPath
|
||||
items[i].pathOffset = pkgPathOff
|
||||
|
||||
// Read index for package.
|
||||
nameIndex := make(map[string]uint64)
|
||||
nSyms := r.uint64()
|
||||
// In shallow mode we don't expect an index for other packages.
|
||||
assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil)
|
||||
// In shallow mode, only the current package (i=0) has an index.
|
||||
assert(!(shallow && i > 0 && nSyms != 0))
|
||||
for ; nSyms > 0; nSyms-- {
|
||||
name := p.stringAt(r.uint64())
|
||||
nameIndex[name] = r.uint64()
|
||||
}
|
||||
|
||||
p.pkgIndex[pkg] = nameIndex
|
||||
items[i].nameIndex = nameIndex
|
||||
|
||||
uniquePkgPaths[pkgPath] = true
|
||||
}
|
||||
// Debugging #63822; hypothesis: there are duplicate PkgPaths.
|
||||
if len(uniquePkgPaths) != len(items) {
|
||||
reportf("found duplicate PkgPaths while reading export data manifest: %v", items)
|
||||
}
|
||||
|
||||
// Request packages all at once from the client,
|
||||
// enabling a parallel implementation.
|
||||
if err := getPackages(items); err != nil {
|
||||
return nil, err // don't wrap this error
|
||||
}
|
||||
|
||||
// Check the results and complete the index.
|
||||
pkgList := make([]*types.Package, len(items))
|
||||
for i, item := range items {
|
||||
pkg := item.Pkg
|
||||
if pkg == nil {
|
||||
errorf("internal error: getPackages returned nil package for %q", item.Path)
|
||||
} else if pkg.Path() != item.Path {
|
||||
errorf("internal error: getPackages returned wrong path %q, want %q", pkg.Path(), item.Path)
|
||||
} else if pkg.Name() != item.Name {
|
||||
errorf("internal error: getPackages returned wrong name %s for package %q, want %s", pkg.Name(), item.Path, item.Name)
|
||||
}
|
||||
p.pkgCache[item.pathOffset] = pkg
|
||||
p.pkgIndex[pkg] = item.nameIndex
|
||||
pkgList[i] = pkg
|
||||
}
|
||||
|
||||
|
@ -251,23 +338,30 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
}
|
||||
|
||||
// SetConstraint can't be called if the constraint type is not yet complete.
|
||||
// When type params are created in the 'P' case of (*importReader).obj(),
|
||||
// When type params are created in the typeParamTag case of (*importReader).obj(),
|
||||
// the associated constraint type may not be complete due to recursion.
|
||||
// Therefore, we defer calling SetConstraint there, and call it here instead
|
||||
// after all types are complete.
|
||||
for _, d := range p.later {
|
||||
typeparams.SetTypeParamConstraint(d.t, d.constraint)
|
||||
d.t.SetConstraint(d.constraint)
|
||||
}
|
||||
|
||||
for _, typ := range p.interfaceList {
|
||||
typ.Complete()
|
||||
}
|
||||
|
||||
// Workaround for golang/go#61561. See the doc for instanceList for details.
|
||||
for _, typ := range p.instanceList {
|
||||
if iface, _ := typ.Underlying().(*types.Interface); iface != nil {
|
||||
iface.Complete()
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
type setConstraintArgs struct {
|
||||
t *typeparams.TypeParam
|
||||
t *types.TypeParam
|
||||
constraint types.Type
|
||||
}
|
||||
|
||||
|
@ -275,11 +369,15 @@ type iimporter struct {
|
|||
version int
|
||||
ipath string
|
||||
|
||||
localpkg *types.Package
|
||||
insert func(pkg *types.Package, name string) // "shallow" mode only
|
||||
aliases bool
|
||||
shallow bool
|
||||
reportf ReportFunc // if non-nil, used to report bugs
|
||||
|
||||
stringData []byte
|
||||
stringCache map[uint64]string
|
||||
fileOffset []uint64 // fileOffset[i] is offset in fileData for info about file encoded as i
|
||||
fileData []byte
|
||||
fileCache []*token.File // memoized decoding of file encoded as i
|
||||
pkgCache map[uint64]*types.Package
|
||||
|
||||
declData []byte
|
||||
|
@ -290,6 +388,12 @@ type iimporter struct {
|
|||
fake fakeFileSet
|
||||
interfaceList []*types.Interface
|
||||
|
||||
// Workaround for the go/types bug golang/go#61561: instances produced during
|
||||
// instantiation may contain incomplete interfaces. Here we only complete the
|
||||
// underlying type of the instance, which is the most common case but doesn't
|
||||
// handle parameterized interface literals defined deeper in the type.
|
||||
instanceList []types.Type // instances for later completion (see golang/go#61561)
|
||||
|
||||
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||
later []setConstraintArgs
|
||||
|
||||
|
@ -321,13 +425,9 @@ func (p *iimporter) doDecl(pkg *types.Package, name string) {
|
|||
|
||||
off, ok := p.pkgIndex[pkg][name]
|
||||
if !ok {
|
||||
// In "shallow" mode, call back to the application to
|
||||
// find the object and insert it into the package scope.
|
||||
if p.insert != nil {
|
||||
assert(pkg != p.localpkg)
|
||||
p.insert(pkg, name) // "can't fail"
|
||||
return
|
||||
}
|
||||
// In deep mode, the index should be complete. In shallow
|
||||
// mode, we should have already recursively loaded necessary
|
||||
// dependencies so the above Lookup succeeds.
|
||||
errorf("%v.%v not in index", pkg, name)
|
||||
}
|
||||
|
||||
|
@ -352,6 +452,55 @@ func (p *iimporter) stringAt(off uint64) string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (p *iimporter) fileAt(index uint64) *token.File {
|
||||
file := p.fileCache[index]
|
||||
if file == nil {
|
||||
off := p.fileOffset[index]
|
||||
file = p.decodeFile(intReader{bytes.NewReader(p.fileData[off:]), p.ipath})
|
||||
p.fileCache[index] = file
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func (p *iimporter) decodeFile(rd intReader) *token.File {
|
||||
filename := p.stringAt(rd.uint64())
|
||||
size := int(rd.uint64())
|
||||
file := p.fake.fset.AddFile(filename, -1, size)
|
||||
|
||||
// SetLines requires a nondecreasing sequence.
|
||||
// Because it is common for clients to derive the interval
|
||||
// [start, start+len(name)] from a start position, and we
|
||||
// want to ensure that the end offset is on the same line,
|
||||
// we fill in the gaps of the sparse encoding with values
|
||||
// that strictly increase by the largest possible amount.
|
||||
// This allows us to avoid having to record the actual end
|
||||
// offset of each needed line.
|
||||
|
||||
lines := make([]int, int(rd.uint64()))
|
||||
var index, offset int
|
||||
for i, n := 0, int(rd.uint64()); i < n; i++ {
|
||||
index += int(rd.uint64())
|
||||
offset += int(rd.uint64())
|
||||
lines[index] = offset
|
||||
|
||||
// Ensure monotonicity between points.
|
||||
for j := index - 1; j > 0 && lines[j] == 0; j-- {
|
||||
lines[j] = lines[j+1] - 1
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure monotonicity after last point.
|
||||
for j := len(lines) - 1; j > 0 && lines[j] == 0; j-- {
|
||||
size--
|
||||
lines[j] = size
|
||||
}
|
||||
|
||||
if !file.SetLines(lines) {
|
||||
errorf("SetLines failed: %d", lines) // can't happen
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
func (p *iimporter) pkgAt(off uint64) *types.Package {
|
||||
if pkg, ok := p.pkgCache[off]; ok {
|
||||
return pkg
|
||||
|
@ -390,7 +539,7 @@ func canReuse(def *types.Named, rhs types.Type) bool {
|
|||
if def == nil {
|
||||
return true
|
||||
}
|
||||
iface, _ := rhs.(*types.Interface)
|
||||
iface, _ := types.Unalias(rhs).(*types.Interface)
|
||||
if iface == nil {
|
||||
return true
|
||||
}
|
||||
|
@ -407,40 +556,56 @@ type importReader struct {
|
|||
prevColumn int64
|
||||
}
|
||||
|
||||
// markBlack is redefined in iimport_go123.go, to work around golang/go#69912.
|
||||
//
|
||||
// If TypeNames are not marked black (in the sense of go/types cycle
|
||||
// detection), they may be mutated when dot-imported. Fix this by punching a
|
||||
// hole through the type, when compiling with Go 1.23. (The bug has been fixed
|
||||
// for 1.24, but the fix was not worth back-porting).
|
||||
var markBlack = func(name *types.TypeName) {}
|
||||
|
||||
func (r *importReader) obj(name string) {
|
||||
tag := r.byte()
|
||||
pos := r.pos()
|
||||
|
||||
switch tag {
|
||||
case 'A':
|
||||
case aliasTag, genericAliasTag:
|
||||
var tparams []*types.TypeParam
|
||||
if tag == genericAliasTag {
|
||||
tparams = r.tparamList()
|
||||
}
|
||||
typ := r.typ()
|
||||
obj := aliases.NewAlias(r.p.aliases, pos, r.currPkg, name, typ, tparams)
|
||||
markBlack(obj) // workaround for golang/go#69912
|
||||
r.declare(obj)
|
||||
|
||||
r.declare(types.NewTypeName(pos, r.currPkg, name, typ))
|
||||
|
||||
case 'C':
|
||||
case constTag:
|
||||
typ, val := r.value()
|
||||
|
||||
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
|
||||
|
||||
case 'F', 'G':
|
||||
var tparams []*typeparams.TypeParam
|
||||
if tag == 'G' {
|
||||
case funcTag, genericFuncTag:
|
||||
var tparams []*types.TypeParam
|
||||
if tag == genericFuncTag {
|
||||
tparams = r.tparamList()
|
||||
}
|
||||
sig := r.signature(nil, nil, tparams)
|
||||
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
|
||||
|
||||
case 'T', 'U':
|
||||
case typeTag, genericTypeTag:
|
||||
// Types can be recursive. We need to setup a stub
|
||||
// declaration before recursing.
|
||||
obj := types.NewTypeName(pos, r.currPkg, name, nil)
|
||||
named := types.NewNamed(obj, nil, nil)
|
||||
|
||||
markBlack(obj) // workaround for golang/go#69912
|
||||
|
||||
// Declare obj before calling r.tparamList, so the new type name is recognized
|
||||
// if used in the constraint of one of its own typeparams (see #48280).
|
||||
r.declare(obj)
|
||||
if tag == 'U' {
|
||||
if tag == genericTypeTag {
|
||||
tparams := r.tparamList()
|
||||
typeparams.SetForNamed(named, tparams)
|
||||
named.SetTypeParams(tparams)
|
||||
}
|
||||
|
||||
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
||||
|
@ -455,14 +620,13 @@ func (r *importReader) obj(name string) {
|
|||
// If the receiver has any targs, set those as the
|
||||
// rparams of the method (since those are the
|
||||
// typeparams being used in the method sig/body).
|
||||
base := baseType(recv.Type())
|
||||
assert(base != nil)
|
||||
targs := typeparams.NamedTypeArgs(base)
|
||||
var rparams []*typeparams.TypeParam
|
||||
_, recvNamed := typesinternal.ReceiverNamed(recv)
|
||||
targs := recvNamed.TypeArgs()
|
||||
var rparams []*types.TypeParam
|
||||
if targs.Len() > 0 {
|
||||
rparams = make([]*typeparams.TypeParam, targs.Len())
|
||||
rparams = make([]*types.TypeParam, targs.Len())
|
||||
for i := range rparams {
|
||||
rparams[i] = targs.At(i).(*typeparams.TypeParam)
|
||||
rparams[i] = types.Unalias(targs.At(i)).(*types.TypeParam)
|
||||
}
|
||||
}
|
||||
msig := r.signature(recv, rparams, nil)
|
||||
|
@ -471,7 +635,7 @@ func (r *importReader) obj(name string) {
|
|||
}
|
||||
}
|
||||
|
||||
case 'P':
|
||||
case typeParamTag:
|
||||
// We need to "declare" a typeparam in order to have a name that
|
||||
// can be referenced recursively (if needed) in the type param's
|
||||
// bound.
|
||||
|
@ -480,7 +644,7 @@ func (r *importReader) obj(name string) {
|
|||
}
|
||||
name0 := tparamName(name)
|
||||
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
|
||||
t := typeparams.NewTypeParam(tn, nil)
|
||||
t := types.NewTypeParam(tn, nil)
|
||||
|
||||
// To handle recursive references to the typeparam within its
|
||||
// bound, save the partial type in tparamIndex before reading the bounds.
|
||||
|
@ -492,11 +656,11 @@ func (r *importReader) obj(name string) {
|
|||
}
|
||||
constraint := r.typ()
|
||||
if implicit {
|
||||
iface, _ := constraint.(*types.Interface)
|
||||
iface, _ := types.Unalias(constraint).(*types.Interface)
|
||||
if iface == nil {
|
||||
errorf("non-interface constraint marked implicit")
|
||||
}
|
||||
typeparams.MarkImplicit(iface)
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
// The constraint type may not be complete, if we
|
||||
// are in the middle of a type recursion involving type
|
||||
|
@ -504,7 +668,7 @@ func (r *importReader) obj(name string) {
|
|||
// completely set up all types in ImportData.
|
||||
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||
|
||||
case 'V':
|
||||
case varTag:
|
||||
typ := r.typ()
|
||||
|
||||
r.declare(types.NewVar(pos, r.currPkg, name, typ))
|
||||
|
@ -645,6 +809,10 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) {
|
|||
}
|
||||
|
||||
func (r *importReader) pos() token.Pos {
|
||||
if r.p.shallow {
|
||||
// precise offsets are encoded only in shallow mode
|
||||
return r.posv2()
|
||||
}
|
||||
if r.p.version >= iexportVersionPosCol {
|
||||
r.posv1()
|
||||
} else {
|
||||
|
@ -681,12 +849,21 @@ func (r *importReader) posv1() {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *importReader) posv2() token.Pos {
|
||||
file := r.uint64()
|
||||
if file == 0 {
|
||||
return token.NoPos
|
||||
}
|
||||
tf := r.p.fileAt(file - 1)
|
||||
return tf.Pos(int(r.uint64()))
|
||||
}
|
||||
|
||||
func (r *importReader) typ() types.Type {
|
||||
return r.p.typAt(r.uint64(), nil)
|
||||
}
|
||||
|
||||
func isInterface(t types.Type) bool {
|
||||
_, ok := t.(*types.Interface)
|
||||
_, ok := types.Unalias(t).(*types.Interface)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
@ -696,7 +873,7 @@ func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
|
|||
func (r *importReader) doType(base *types.Named) (res types.Type) {
|
||||
k := r.kind()
|
||||
if debug {
|
||||
r.p.trace("importing type %d (base: %s)", k, base)
|
||||
r.p.trace("importing type %d (base: %v)", k, base)
|
||||
r.p.indent++
|
||||
defer func() {
|
||||
r.p.indent--
|
||||
|
@ -708,7 +885,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
|
|||
errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
|
||||
return nil
|
||||
|
||||
case definedType:
|
||||
case aliasType, definedType:
|
||||
pkg, name := r.qualifiedIdent()
|
||||
r.p.doDecl(pkg, name)
|
||||
return pkg.Scope().Lookup(name).(*types.TypeName).Type()
|
||||
|
@ -734,13 +911,28 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
|
|||
fields := make([]*types.Var, r.uint64())
|
||||
tags := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
var field *types.Var
|
||||
if r.p.shallow {
|
||||
field, _ = r.objectPathObject().(*types.Var)
|
||||
}
|
||||
|
||||
fpos := r.pos()
|
||||
fname := r.ident()
|
||||
ftyp := r.typ()
|
||||
emb := r.bool()
|
||||
tag := r.string()
|
||||
|
||||
fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
|
||||
// Either this is not a shallow import, the field is local, or the
|
||||
// encoded objectPath failed to produce an object (a bug).
|
||||
//
|
||||
// Even in this last, buggy case, fall back on creating a new field. As
|
||||
// discussed in iexport.go, this is not correct, but mostly works and is
|
||||
// preferable to failing (for now at least).
|
||||
if field == nil {
|
||||
field = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
|
||||
}
|
||||
|
||||
fields[i] = field
|
||||
tags[i] = tag
|
||||
}
|
||||
return types.NewStruct(fields, tags)
|
||||
|
@ -756,6 +948,11 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
|
|||
|
||||
methods := make([]*types.Func, r.uint64())
|
||||
for i := range methods {
|
||||
var method *types.Func
|
||||
if r.p.shallow {
|
||||
method, _ = r.objectPathObject().(*types.Func)
|
||||
}
|
||||
|
||||
mpos := r.pos()
|
||||
mname := r.ident()
|
||||
|
||||
|
@ -765,12 +962,15 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
|
|||
if base != nil {
|
||||
recv = types.NewVar(token.NoPos, r.currPkg, "", base)
|
||||
}
|
||||
|
||||
msig := r.signature(recv, nil, nil)
|
||||
methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
|
||||
|
||||
if method == nil {
|
||||
method = types.NewFunc(mpos, r.currPkg, mname, msig)
|
||||
}
|
||||
methods[i] = method
|
||||
}
|
||||
|
||||
typ := newInterface(methods, embeddeds)
|
||||
typ := types.NewInterfaceType(methods, embeddeds)
|
||||
r.p.interfaceList = append(r.p.interfaceList, typ)
|
||||
return typ
|
||||
|
||||
|
@ -804,18 +1004,21 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
|
|||
// The imported instantiated type doesn't include any methods, so
|
||||
// we must always use the methods of the base (orig) type.
|
||||
// TODO provide a non-nil *Environment
|
||||
t, _ := typeparams.Instantiate(nil, baseType, targs, false)
|
||||
t, _ := types.Instantiate(nil, baseType, targs, false)
|
||||
|
||||
// Workaround for golang/go#61561. See the doc for instanceList for details.
|
||||
r.p.instanceList = append(r.p.instanceList, t)
|
||||
return t
|
||||
|
||||
case unionType:
|
||||
if r.p.version < iexportVersionGenerics {
|
||||
errorf("unexpected instantiation type")
|
||||
}
|
||||
terms := make([]*typeparams.Term, r.uint64())
|
||||
terms := make([]*types.Term, r.uint64())
|
||||
for i := range terms {
|
||||
terms[i] = typeparams.NewTerm(r.bool(), r.typ())
|
||||
terms[i] = types.NewTerm(r.bool(), r.typ())
|
||||
}
|
||||
return typeparams.NewUnion(terms)
|
||||
return types.NewUnion(terms)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,23 +1026,43 @@ func (r *importReader) kind() itag {
|
|||
return itag(r.uint64())
|
||||
}
|
||||
|
||||
func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature {
|
||||
// objectPathObject is the inverse of exportWriter.objectPath.
|
||||
//
|
||||
// In shallow mode, certain fields and methods may need to be looked up in an
|
||||
// imported package. See the doc for exportWriter.objectPath for a full
|
||||
// explanation.
|
||||
func (r *importReader) objectPathObject() types.Object {
|
||||
objPath := objectpath.Path(r.string())
|
||||
if objPath == "" {
|
||||
return nil
|
||||
}
|
||||
pkg := r.pkg()
|
||||
obj, err := objectpath.Object(pkg, objPath)
|
||||
if err != nil {
|
||||
if r.p.reportf != nil {
|
||||
r.p.reportf("failed to find object for objectPath %q: %v", objPath, err)
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
func (r *importReader) signature(recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature {
|
||||
params := r.paramList()
|
||||
results := r.paramList()
|
||||
variadic := params.Len() > 0 && r.bool()
|
||||
return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic)
|
||||
return types.NewSignatureType(recv, rparams, tparams, params, results, variadic)
|
||||
}
|
||||
|
||||
func (r *importReader) tparamList() []*typeparams.TypeParam {
|
||||
func (r *importReader) tparamList() []*types.TypeParam {
|
||||
n := r.uint64()
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
xs := make([]*typeparams.TypeParam, n)
|
||||
xs := make([]*types.TypeParam, n)
|
||||
for i := range xs {
|
||||
// Note: the standard library importer is tolerant of nil types here,
|
||||
// though would panic in SetTypeParams.
|
||||
xs[i] = r.typ().(*typeparams.TypeParam)
|
||||
xs[i] = types.Unalias(r.typ()).(*types.TypeParam)
|
||||
}
|
||||
return xs
|
||||
}
|
||||
|
@ -887,12 +1110,8 @@ func (r *importReader) byte() byte {
|
|||
return x
|
||||
}
|
||||
|
||||
func baseType(typ types.Type) *types.Named {
|
||||
// pointer receivers are never types.Named types
|
||||
if p, _ := typ.(*types.Pointer); p != nil {
|
||||
typ = p.Elem()
|
||||
}
|
||||
// receiver base types are always (possibly generic) types.Named types
|
||||
n, _ := typ.(*types.Named)
|
||||
return n
|
||||
}
|
||||
type byPath []*types.Package
|
||||
|
||||
func (a byPath) Len() int { return len(a) }
|
||||
func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
|
||||
|
|
53
vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go
generated
vendored
Normal file
53
vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
//go:build go1.22 && !go1.24
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// TODO(rfindley): delete this workaround once go1.24 is assured.
|
||||
|
||||
func init() {
|
||||
// Update markBlack so that it correctly sets the color
|
||||
// of imported TypeNames.
|
||||
//
|
||||
// See the doc comment for markBlack for details.
|
||||
|
||||
type color uint32
|
||||
const (
|
||||
white color = iota
|
||||
black
|
||||
grey
|
||||
)
|
||||
type object struct {
|
||||
_ *types.Scope
|
||||
_ token.Pos
|
||||
_ *types.Package
|
||||
_ string
|
||||
_ types.Type
|
||||
_ uint32
|
||||
color_ color
|
||||
_ token.Pos
|
||||
}
|
||||
type typeName struct {
|
||||
object
|
||||
}
|
||||
|
||||
// If the size of types.TypeName changes, this will fail to compile.
|
||||
const delta = int64(unsafe.Sizeof(typeName{})) - int64(unsafe.Sizeof(types.TypeName{}))
|
||||
var _ [-delta * delta]int
|
||||
|
||||
markBlack = func(obj *types.TypeName) {
|
||||
type uP = unsafe.Pointer
|
||||
var ptr *typeName
|
||||
*(*uP)(uP(&ptr)) = uP(obj)
|
||||
ptr.color_ = black
|
||||
}
|
||||
}
|
22
vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go
generated
vendored
22
vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go
generated
vendored
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
//go:build !go1.11
|
||||
// +build !go1.11
|
||||
|
||||
package gcimporter
|
||||
|
||||
import "go/types"
|
||||
|
||||
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
|
||||
named := make([]*types.Named, len(embeddeds))
|
||||
for i, e := range embeddeds {
|
||||
var ok bool
|
||||
named[i], ok = e.(*types.Named)
|
||||
if !ok {
|
||||
panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11")
|
||||
}
|
||||
}
|
||||
return types.NewInterface(methods, named)
|
||||
}
|
14
vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go
generated
vendored
14
vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go
generated
vendored
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
//go:build go1.11
|
||||
// +build go1.11
|
||||
|
||||
package gcimporter
|
||||
|
||||
import "go/types"
|
||||
|
||||
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
|
||||
return types.NewInterfaceType(methods, embeddeds)
|
||||
}
|
91
vendor/golang.org/x/tools/internal/gcimporter/predeclared.go
generated
vendored
Normal file
91
vendor/golang.org/x/tools/internal/gcimporter/predeclared.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// predecl is a cache for the predeclared types in types.Universe.
|
||||
//
|
||||
// Cache a distinct result based on the runtime value of any.
|
||||
// The pointer value of the any type varies based on GODEBUG settings.
|
||||
var predeclMu sync.Mutex
|
||||
var predecl map[types.Type][]types.Type
|
||||
|
||||
func predeclared() []types.Type {
|
||||
anyt := types.Universe.Lookup("any").Type()
|
||||
|
||||
predeclMu.Lock()
|
||||
defer predeclMu.Unlock()
|
||||
|
||||
if pre, ok := predecl[anyt]; ok {
|
||||
return pre
|
||||
}
|
||||
|
||||
if predecl == nil {
|
||||
predecl = make(map[types.Type][]types.Type)
|
||||
}
|
||||
|
||||
decls := []types.Type{ // basic types
|
||||
types.Typ[types.Bool],
|
||||
types.Typ[types.Int],
|
||||
types.Typ[types.Int8],
|
||||
types.Typ[types.Int16],
|
||||
types.Typ[types.Int32],
|
||||
types.Typ[types.Int64],
|
||||
types.Typ[types.Uint],
|
||||
types.Typ[types.Uint8],
|
||||
types.Typ[types.Uint16],
|
||||
types.Typ[types.Uint32],
|
||||
types.Typ[types.Uint64],
|
||||
types.Typ[types.Uintptr],
|
||||
types.Typ[types.Float32],
|
||||
types.Typ[types.Float64],
|
||||
types.Typ[types.Complex64],
|
||||
types.Typ[types.Complex128],
|
||||
types.Typ[types.String],
|
||||
|
||||
// basic type aliases
|
||||
types.Universe.Lookup("byte").Type(),
|
||||
types.Universe.Lookup("rune").Type(),
|
||||
|
||||
// error
|
||||
types.Universe.Lookup("error").Type(),
|
||||
|
||||
// untyped types
|
||||
types.Typ[types.UntypedBool],
|
||||
types.Typ[types.UntypedInt],
|
||||
types.Typ[types.UntypedRune],
|
||||
types.Typ[types.UntypedFloat],
|
||||
types.Typ[types.UntypedComplex],
|
||||
types.Typ[types.UntypedString],
|
||||
types.Typ[types.UntypedNil],
|
||||
|
||||
// package unsafe
|
||||
types.Typ[types.UnsafePointer],
|
||||
|
||||
// invalid type
|
||||
types.Typ[types.Invalid], // only appears in packages with errors
|
||||
|
||||
// used internally by gc; never used by this package or in .a files
|
||||
anyType{},
|
||||
|
||||
// comparable
|
||||
types.Universe.Lookup("comparable").Type(),
|
||||
|
||||
// any
|
||||
anyt,
|
||||
}
|
||||
|
||||
predecl[anyt] = decls
|
||||
return decls
|
||||
}
|
||||
|
||||
type anyType struct{}
|
||||
|
||||
func (t anyType) Underlying() types.Type { return t }
|
||||
func (t anyType) String() string { return "any" }
|
30
vendor/golang.org/x/tools/internal/gcimporter/support.go
generated
vendored
Normal file
30
vendor/golang.org/x/tools/internal/gcimporter/support.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Copy of $GOROOT/src/cmd/internal/archive.ReadHeader.
|
||||
func readArchiveHeader(b *bufio.Reader, name string) int {
|
||||
// architecture-independent object file output
|
||||
const HeaderSize = 60
|
||||
|
||||
var buf [HeaderSize]byte
|
||||
if _, err := io.ReadFull(b, buf[:]); err != nil {
|
||||
return -1
|
||||
}
|
||||
aname := strings.Trim(string(buf[0:16]), " ")
|
||||
if !strings.HasPrefix(aname, name) {
|
||||
return -1
|
||||
}
|
||||
asize := strings.Trim(string(buf[48:58]), " ")
|
||||
i, _ := strconv.Atoi(asize)
|
||||
return i
|
||||
}
|
16
vendor/golang.org/x/tools/internal/gcimporter/support_go117.go
generated
vendored
16
vendor/golang.org/x/tools/internal/gcimporter/support_go117.go
generated
vendored
|
@ -1,16 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package gcimporter
|
||||
|
||||
import "go/types"
|
||||
|
||||
const iexportVersion = iexportVersionGo1_11
|
||||
|
||||
func additionalPredeclared() []types.Type {
|
||||
return nil
|
||||
}
|
37
vendor/golang.org/x/tools/internal/gcimporter/support_go118.go
generated
vendored
37
vendor/golang.org/x/tools/internal/gcimporter/support_go118.go
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package gcimporter
|
||||
|
||||
import "go/types"
|
||||
|
||||
const iexportVersion = iexportVersionGenerics
|
||||
|
||||
// additionalPredeclared returns additional predeclared types in go.1.18.
|
||||
func additionalPredeclared() []types.Type {
|
||||
return []types.Type{
|
||||
// comparable
|
||||
types.Universe.Lookup("comparable").Type(),
|
||||
|
||||
// any
|
||||
types.Universe.Lookup("any").Type(),
|
||||
}
|
||||
}
|
||||
|
||||
// See cmd/compile/internal/types.SplitVargenSuffix.
|
||||
func splitVargenSuffix(name string) (base, suffix string) {
|
||||
i := len(name)
|
||||
for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
|
||||
i--
|
||||
}
|
||||
const dot = "·"
|
||||
if i >= len(dot) && name[i-len(dot):i] == dot {
|
||||
i -= len(dot)
|
||||
return name[:i], name[i:]
|
||||
}
|
||||
return name, ""
|
||||
}
|
10
vendor/golang.org/x/tools/internal/gcimporter/unified_no.go
generated
vendored
10
vendor/golang.org/x/tools/internal/gcimporter/unified_no.go
generated
vendored
|
@ -1,10 +0,0 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
//go:build !(go1.18 && goexperiment.unified)
|
||||
// +build !go1.18 !goexperiment.unified
|
||||
|
||||
package gcimporter
|
||||
|
||||
const unifiedIR = false
|
10
vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go
generated
vendored
10
vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go
generated
vendored
|
@ -1,10 +0,0 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
//go:build go1.18 && goexperiment.unified
|
||||
// +build go1.18,goexperiment.unified
|
||||
|
||||
package gcimporter
|
||||
|
||||
const unifiedIR = true
|
19
vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go
generated
vendored
19
vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
||||
err = fmt.Errorf("go/tools compiled with a Go version earlier than 1.18 cannot read unified IR export data")
|
||||
return
|
||||
}
|
247
vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go
generated
vendored
247
vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go
generated
vendored
|
@ -4,16 +4,15 @@
|
|||
|
||||
// Derived from go/internal/gcimporter/ureader.go
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package gcimporter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
"sort"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/pkgbits"
|
||||
)
|
||||
|
||||
|
@ -26,6 +25,7 @@ type pkgReader struct {
|
|||
|
||||
ctxt *types.Context
|
||||
imports map[string]*types.Package // previously imported packages, indexed by path
|
||||
aliases bool // create types.Alias nodes
|
||||
|
||||
// lazily initialized arrays corresponding to the unified IR
|
||||
// PosBase, Pkg, and Type sections, respectively.
|
||||
|
@ -51,8 +51,7 @@ func (pr *pkgReader) later(fn func()) {
|
|||
|
||||
// See cmd/compile/internal/noder.derivedInfo.
|
||||
type derivedInfo struct {
|
||||
idx pkgbits.Index
|
||||
needed bool
|
||||
idx pkgbits.Index
|
||||
}
|
||||
|
||||
// See cmd/compile/internal/noder.typeInfo.
|
||||
|
@ -62,8 +61,15 @@ type typeInfo struct {
|
|||
}
|
||||
|
||||
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
||||
if !debug {
|
||||
defer func() {
|
||||
if x := recover(); x != nil {
|
||||
err = fmt.Errorf("internal error in importing %q (%v); please report an issue", path, x)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
s := string(data)
|
||||
s = s[:strings.LastIndex(s, "\n$$\n")]
|
||||
input := pkgbits.NewPkgDecoder(path, s)
|
||||
pkg = readUnifiedPackage(fset, nil, imports, input)
|
||||
return
|
||||
|
@ -91,6 +97,7 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
|
|||
|
||||
ctxt: ctxt,
|
||||
imports: imports,
|
||||
aliases: aliases.Enabled(),
|
||||
|
||||
posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
|
||||
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
|
||||
|
@ -100,13 +107,17 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
|
|||
|
||||
r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
|
||||
pkg := r.pkg()
|
||||
r.Bool() // has init
|
||||
if r.Version().Has(pkgbits.HasInit) {
|
||||
r.Bool()
|
||||
}
|
||||
|
||||
for i, n := 0, r.Len(); i < n; i++ {
|
||||
// As if r.obj(), but avoiding the Scope.Lookup call,
|
||||
// to avoid eager loading of imports.
|
||||
r.Sync(pkgbits.SyncObject)
|
||||
assert(!r.Bool())
|
||||
if r.Version().Has(pkgbits.DerivedFuncInstance) {
|
||||
assert(!r.Bool())
|
||||
}
|
||||
r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
||||
assert(r.Len() == 0)
|
||||
}
|
||||
|
@ -121,6 +132,16 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
|
|||
iface.Complete()
|
||||
}
|
||||
|
||||
// Imports() of pkg are all of the transitive packages that were loaded.
|
||||
var imps []*types.Package
|
||||
for _, imp := range pr.pkgs {
|
||||
if imp != nil && imp != pkg {
|
||||
imps = append(imps, imp)
|
||||
}
|
||||
}
|
||||
sort.Sort(byPath(imps))
|
||||
pkg.SetImports(imps)
|
||||
|
||||
pkg.MarkComplete()
|
||||
return pkg
|
||||
}
|
||||
|
@ -145,7 +166,7 @@ type readerDict struct {
|
|||
// tparams is a slice of the constructed TypeParams for the element.
|
||||
tparams []*types.TypeParam
|
||||
|
||||
// devived is a slice of types derived from tparams, which may be
|
||||
// derived is a slice of types derived from tparams, which may be
|
||||
// instantiated while reading the current element.
|
||||
derived []derivedInfo
|
||||
derivedTypes []types.Type // lazily instantiated from derived
|
||||
|
@ -158,6 +179,17 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk
|
|||
}
|
||||
}
|
||||
|
||||
func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
|
||||
return &reader{
|
||||
Decoder: pr.TempDecoder(k, idx, marker),
|
||||
p: pr,
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *pkgReader) retireReader(r *reader) {
|
||||
pr.RetireDecoder(&r.Decoder)
|
||||
}
|
||||
|
||||
// @@@ Positions
|
||||
|
||||
func (r *reader) pos() token.Pos {
|
||||
|
@ -182,26 +214,29 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
|
|||
return b
|
||||
}
|
||||
|
||||
r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
||||
var filename string
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
||||
|
||||
// Within types2, position bases have a lot more details (e.g.,
|
||||
// keeping track of where //line directives appeared exactly).
|
||||
//
|
||||
// For go/types, we just track the file name.
|
||||
// Within types2, position bases have a lot more details (e.g.,
|
||||
// keeping track of where //line directives appeared exactly).
|
||||
//
|
||||
// For go/types, we just track the file name.
|
||||
|
||||
filename := r.String()
|
||||
filename = r.String()
|
||||
|
||||
if r.Bool() { // file base
|
||||
// Was: "b = token.NewTrimmedFileBase(filename, true)"
|
||||
} else { // line base
|
||||
pos := r.pos()
|
||||
line := r.Uint()
|
||||
col := r.Uint()
|
||||
if r.Bool() { // file base
|
||||
// Was: "b = token.NewTrimmedFileBase(filename, true)"
|
||||
} else { // line base
|
||||
pos := r.pos()
|
||||
line := r.Uint()
|
||||
col := r.Uint()
|
||||
|
||||
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
|
||||
_, _, _ = pos, line, col
|
||||
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
|
||||
_, _, _ = pos, line, col
|
||||
}
|
||||
pr.retireReader(r)
|
||||
}
|
||||
|
||||
b := filename
|
||||
pr.posBases[idx] = b
|
||||
return b
|
||||
|
@ -229,7 +264,12 @@ func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package {
|
|||
func (r *reader) doPkg() *types.Package {
|
||||
path := r.String()
|
||||
switch path {
|
||||
case "":
|
||||
// cmd/compile emits path="main" for main packages because
|
||||
// that's the linker symbol prefix it used; but we need
|
||||
// the package's path as it would be reported by go list,
|
||||
// hence "main" below.
|
||||
// See test at go/packages.TestMainPackagePathInModeTypes.
|
||||
case "", "main":
|
||||
path = r.p.PkgPath()
|
||||
case "builtin":
|
||||
return nil // universe
|
||||
|
@ -246,39 +286,9 @@ func (r *reader) doPkg() *types.Package {
|
|||
pkg := types.NewPackage(path, name)
|
||||
r.p.imports[path] = pkg
|
||||
|
||||
imports := make([]*types.Package, r.Len())
|
||||
for i := range imports {
|
||||
imports[i] = r.pkg()
|
||||
}
|
||||
pkg.SetImports(flattenImports(imports))
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
// flattenImports returns the transitive closure of all imported
|
||||
// packages rooted from pkgs.
|
||||
func flattenImports(pkgs []*types.Package) []*types.Package {
|
||||
var res []*types.Package
|
||||
|
||||
seen := make(map[*types.Package]bool)
|
||||
var add func(pkg *types.Package)
|
||||
add = func(pkg *types.Package) {
|
||||
if seen[pkg] {
|
||||
return
|
||||
}
|
||||
seen[pkg] = true
|
||||
res = append(res, pkg)
|
||||
for _, imp := range pkg.Imports() {
|
||||
add(imp)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
add(pkg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// @@@ Types
|
||||
|
||||
func (r *reader) typ() types.Type {
|
||||
|
@ -307,12 +317,15 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
||||
r.dict = dict
|
||||
|
||||
typ := r.doTyp()
|
||||
assert(typ != nil)
|
||||
var typ types.Type
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
||||
r.dict = dict
|
||||
|
||||
typ = r.doTyp()
|
||||
assert(typ != nil)
|
||||
pr.retireReader(r)
|
||||
}
|
||||
// See comment in pkgReader.typIdx explaining how this happens.
|
||||
if prev := *where; prev != nil {
|
||||
return prev
|
||||
|
@ -464,7 +477,9 @@ func (r *reader) param() *types.Var {
|
|||
func (r *reader) obj() (types.Object, []types.Type) {
|
||||
r.Sync(pkgbits.SyncObject)
|
||||
|
||||
assert(!r.Bool())
|
||||
if r.Version().Has(pkgbits.DerivedFuncInstance) {
|
||||
assert(!r.Bool())
|
||||
}
|
||||
|
||||
pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
||||
obj := pkgScope(pkg).Lookup(name)
|
||||
|
@ -478,12 +493,19 @@ func (r *reader) obj() (types.Object, []types.Type) {
|
|||
}
|
||||
|
||||
func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
||||
rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||
|
||||
objPkg, objName := rname.qualifiedIdent()
|
||||
assert(objName != "")
|
||||
var objPkg *types.Package
|
||||
var objName string
|
||||
var tag pkgbits.CodeObj
|
||||
{
|
||||
rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||
|
||||
tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||
objPkg, objName = rname.qualifiedIdent()
|
||||
assert(objName != "")
|
||||
|
||||
tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||
pr.retireReader(rname)
|
||||
}
|
||||
|
||||
if tag == pkgbits.ObjStub {
|
||||
assert(objPkg == nil || objPkg == types.Unsafe)
|
||||
|
@ -511,8 +533,12 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
|
||||
case pkgbits.ObjAlias:
|
||||
pos := r.pos()
|
||||
var tparams []*types.TypeParam
|
||||
if r.Version().Has(pkgbits.AliasTypeParamNames) {
|
||||
tparams = r.typeParamNames()
|
||||
}
|
||||
typ := r.typ()
|
||||
declare(types.NewTypeName(pos, objPkg, objName, typ))
|
||||
declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ, tparams))
|
||||
|
||||
case pkgbits.ObjConst:
|
||||
pos := r.pos()
|
||||
|
@ -535,22 +561,11 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
|
||||
named.SetTypeParams(r.typeParamNames())
|
||||
|
||||
rhs := r.typ()
|
||||
pk := r.p
|
||||
pk.laterFor(named, func() {
|
||||
// First be sure that the rhs is initialized, if it needs to be initialized.
|
||||
delete(pk.laterFors, named) // prevent cycles
|
||||
if i, ok := pk.laterFors[rhs]; ok {
|
||||
f := pk.laterFns[i]
|
||||
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
|
||||
f() // initialize RHS
|
||||
}
|
||||
underlying := rhs.Underlying()
|
||||
|
||||
setUnderlying := func(underlying types.Type) {
|
||||
// If the underlying type is an interface, we need to
|
||||
// duplicate its methods so we can replace the receiver
|
||||
// parameter's type (#49906).
|
||||
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
||||
if iface, ok := types.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
||||
methods := make([]*types.Func, iface.NumExplicitMethods())
|
||||
for i := range methods {
|
||||
fn := iface.ExplicitMethod(i)
|
||||
|
@ -571,7 +586,31 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
}
|
||||
|
||||
named.SetUnderlying(underlying)
|
||||
})
|
||||
}
|
||||
|
||||
// Since go.dev/cl/455279, we can assume rhs.Underlying() will
|
||||
// always be non-nil. However, to temporarily support users of
|
||||
// older snapshot releases, we continue to fallback to the old
|
||||
// behavior for now.
|
||||
//
|
||||
// TODO(mdempsky): Remove fallback code and simplify after
|
||||
// allowing time for snapshot users to upgrade.
|
||||
rhs := r.typ()
|
||||
if underlying := rhs.Underlying(); underlying != nil {
|
||||
setUnderlying(underlying)
|
||||
} else {
|
||||
pk := r.p
|
||||
pk.laterFor(named, func() {
|
||||
// First be sure that the rhs is initialized, if it needs to be initialized.
|
||||
delete(pk.laterFors, named) // prevent cycles
|
||||
if i, ok := pk.laterFors[rhs]; ok {
|
||||
f := pk.laterFns[i]
|
||||
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
|
||||
f() // initialize RHS
|
||||
}
|
||||
setUnderlying(rhs.Underlying())
|
||||
})
|
||||
}
|
||||
|
||||
for i, n := 0, r.Len(); i < n; i++ {
|
||||
named.AddMethod(r.method())
|
||||
|
@ -588,25 +627,31 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
}
|
||||
|
||||
func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
|
||||
r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||
|
||||
var dict readerDict
|
||||
|
||||
if implicits := r.Len(); implicits != 0 {
|
||||
errorf("unexpected object with %v implicit type parameter(s)", implicits)
|
||||
}
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||
if implicits := r.Len(); implicits != 0 {
|
||||
errorf("unexpected object with %v implicit type parameter(s)", implicits)
|
||||
}
|
||||
|
||||
dict.bounds = make([]typeInfo, r.Len())
|
||||
for i := range dict.bounds {
|
||||
dict.bounds[i] = r.typInfo()
|
||||
}
|
||||
dict.bounds = make([]typeInfo, r.Len())
|
||||
for i := range dict.bounds {
|
||||
dict.bounds[i] = r.typInfo()
|
||||
}
|
||||
|
||||
dict.derived = make([]derivedInfo, r.Len())
|
||||
dict.derivedTypes = make([]types.Type, len(dict.derived))
|
||||
for i := range dict.derived {
|
||||
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
||||
}
|
||||
dict.derived = make([]derivedInfo, r.Len())
|
||||
dict.derivedTypes = make([]types.Type, len(dict.derived))
|
||||
for i := range dict.derived {
|
||||
dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.RelocType)}
|
||||
if r.Version().Has(pkgbits.DerivedInfoNeeded) {
|
||||
assert(!r.Bool())
|
||||
}
|
||||
}
|
||||
|
||||
pr.retireReader(r)
|
||||
}
|
||||
// function references follow, but reader doesn't need those
|
||||
|
||||
return &dict
|
||||
|
@ -696,3 +741,17 @@ func pkgScope(pkg *types.Package) *types.Scope {
|
|||
}
|
||||
return types.Universe
|
||||
}
|
||||
|
||||
// See cmd/compile/internal/types.SplitVargenSuffix.
|
||||
func splitVargenSuffix(name string) (base, suffix string) {
|
||||
i := len(name)
|
||||
for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
|
||||
i--
|
||||
}
|
||||
const dot = "·"
|
||||
if i >= len(dot) && name[i-len(dot):i] == dot {
|
||||
i -= len(dot)
|
||||
return name[:i], name[i:]
|
||||
}
|
||||
return name, ""
|
||||
}
|
||||
|
|
289
vendor/golang.org/x/tools/internal/gocommand/invoke.go
generated
vendored
289
vendor/golang.org/x/tools/internal/gocommand/invoke.go
generated
vendored
|
@ -8,10 +8,14 @@ package gocommand
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
@ -19,9 +23,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
exec "golang.org/x/sys/execabs"
|
||||
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/event/keys"
|
||||
"golang.org/x/tools/internal/event/label"
|
||||
)
|
||||
|
||||
// An Runner will run go command invocations and serialize
|
||||
|
@ -51,9 +55,22 @@ func (runner *Runner) initialize() {
|
|||
// 1.14: go: updating go.mod: existing contents have changed since last read
|
||||
var modConcurrencyError = regexp.MustCompile(`go:.*go.mod.*contents have changed`)
|
||||
|
||||
// event keys for go command invocations
|
||||
var (
|
||||
verb = keys.NewString("verb", "go command verb")
|
||||
directory = keys.NewString("directory", "")
|
||||
)
|
||||
|
||||
func invLabels(inv Invocation) []label.Label {
|
||||
return []label.Label{verb.Of(inv.Verb), directory.Of(inv.WorkingDir)}
|
||||
}
|
||||
|
||||
// Run is a convenience wrapper around RunRaw.
|
||||
// It returns only stdout and a "friendly" error.
|
||||
func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, error) {
|
||||
ctx, done := event.Start(ctx, "gocommand.Runner.Run", invLabels(inv)...)
|
||||
defer done()
|
||||
|
||||
stdout, _, friendly, _ := runner.RunRaw(ctx, inv)
|
||||
return stdout, friendly
|
||||
}
|
||||
|
@ -61,13 +78,19 @@ func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, e
|
|||
// RunPiped runs the invocation serially, always waiting for any concurrent
|
||||
// invocations to complete first.
|
||||
func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) error {
|
||||
ctx, done := event.Start(ctx, "gocommand.Runner.RunPiped", invLabels(inv)...)
|
||||
defer done()
|
||||
|
||||
_, err := runner.runPiped(ctx, inv, stdout, stderr)
|
||||
return err
|
||||
}
|
||||
|
||||
// RunRaw runs the invocation, serializing requests only if they fight over
|
||||
// go.mod changes.
|
||||
// Postcondition: both error results have same nilness.
|
||||
func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
|
||||
ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...)
|
||||
defer done()
|
||||
// Make sure the runner is always initialized.
|
||||
runner.initialize()
|
||||
|
||||
|
@ -75,23 +98,24 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer
|
|||
stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv)
|
||||
|
||||
// If we encounter a load concurrency error, we need to retry serially.
|
||||
if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) {
|
||||
return stdout, stderr, friendlyErr, err
|
||||
}
|
||||
event.Error(ctx, "Load concurrency error, will retry serially", err)
|
||||
if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) {
|
||||
event.Error(ctx, "Load concurrency error, will retry serially", err)
|
||||
|
||||
// Run serially by calling runPiped.
|
||||
stdout.Reset()
|
||||
stderr.Reset()
|
||||
friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
|
||||
}
|
||||
|
||||
// Run serially by calling runPiped.
|
||||
stdout.Reset()
|
||||
stderr.Reset()
|
||||
friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
|
||||
return stdout, stderr, friendlyErr, err
|
||||
}
|
||||
|
||||
// Postcondition: both error results have same nilness.
|
||||
func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
|
||||
// Wait for 1 worker to become available.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, nil, nil, ctx.Err()
|
||||
return nil, nil, ctx.Err(), ctx.Err()
|
||||
case runner.inFlight <- struct{}{}:
|
||||
defer func() { <-runner.inFlight }()
|
||||
}
|
||||
|
@ -101,6 +125,7 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes
|
|||
return stdout, stderr, friendlyErr, err
|
||||
}
|
||||
|
||||
// Postcondition: both error results have same nilness.
|
||||
func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) {
|
||||
// Make sure the runner is always initialized.
|
||||
runner.initialize()
|
||||
|
@ -109,7 +134,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
|
|||
// runPiped commands.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
return ctx.Err(), ctx.Err()
|
||||
case runner.serialized <- struct{}{}:
|
||||
defer func() { <-runner.serialized }()
|
||||
}
|
||||
|
@ -119,7 +144,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
|
|||
for i := 0; i < maxInFlight; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
return ctx.Err(), ctx.Err()
|
||||
case runner.inFlight <- struct{}{}:
|
||||
// Make sure we always "return" any workers we took.
|
||||
defer func() { <-runner.inFlight }()
|
||||
|
@ -136,12 +161,17 @@ type Invocation struct {
|
|||
BuildFlags []string
|
||||
|
||||
// If ModFlag is set, the go command is invoked with -mod=ModFlag.
|
||||
// TODO(rfindley): remove, in favor of Args.
|
||||
ModFlag string
|
||||
|
||||
// If ModFile is set, the go command is invoked with -modfile=ModFile.
|
||||
// TODO(rfindley): remove, in favor of Args.
|
||||
ModFile string
|
||||
|
||||
// If Overlay is set, the go command is invoked with -overlay=Overlay.
|
||||
// Overlay is the name of the JSON overlay file that describes
|
||||
// unsaved editor buffers; see [WriteOverlays].
|
||||
// If set, the go command is invoked with -overlay=Overlay.
|
||||
// TODO(rfindley): remove, in favor of Args.
|
||||
Overlay string
|
||||
|
||||
// If CleanEnv is set, the invocation will run only with the environment
|
||||
|
@ -152,6 +182,7 @@ type Invocation struct {
|
|||
Logf func(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// Postcondition: both error results have same nilness.
|
||||
func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) {
|
||||
rawError = i.run(ctx, stdout, stderr)
|
||||
if rawError != nil {
|
||||
|
@ -168,12 +199,14 @@ func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io
|
|||
return
|
||||
}
|
||||
|
||||
func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
|
||||
log := i.Logf
|
||||
if log == nil {
|
||||
log = func(string, ...interface{}) {}
|
||||
// logf logs if i.Logf is non-nil.
|
||||
func (i *Invocation) logf(format string, args ...any) {
|
||||
if i.Logf != nil {
|
||||
i.Logf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
|
||||
goArgs := []string{i.Verb}
|
||||
|
||||
appendModFile := func() {
|
||||
|
@ -215,12 +248,24 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
|
|||
cmd := exec.Command("go", goArgs...)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
// On darwin the cwd gets resolved to the real path, which breaks anything that
|
||||
// expects the working directory to keep the original path, including the
|
||||
|
||||
// https://go.dev/issue/59541: don't wait forever copying stderr
|
||||
// after the command has exited.
|
||||
// After CL 484741 we copy stdout manually, so we we'll stop reading that as
|
||||
// soon as ctx is done. However, we also don't want to wait around forever
|
||||
// for stderr. Give a much-longer-than-reasonable delay and then assume that
|
||||
// something has wedged in the kernel or runtime.
|
||||
cmd.WaitDelay = 30 * time.Second
|
||||
|
||||
// The cwd gets resolved to the real path. On Darwin, where
|
||||
// /tmp is a symlink, this breaks anything that expects the
|
||||
// working directory to keep the original path, including the
|
||||
// go command when dealing with modules.
|
||||
// The Go stdlib has a special feature where if the cwd and the PWD are the
|
||||
// same node then it trusts the PWD, so by setting it in the env for the child
|
||||
// process we fix up all the paths returned by the go command.
|
||||
//
|
||||
// os.Getwd has a special feature where if the cwd and the PWD
|
||||
// are the same node then it trusts the PWD, so by setting it
|
||||
// in the env for the child process we fix up all the paths
|
||||
// returned by the go command.
|
||||
if !i.CleanEnv {
|
||||
cmd.Env = os.Environ()
|
||||
}
|
||||
|
@ -229,7 +274,13 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
|
|||
cmd.Env = append(cmd.Env, "PWD="+i.WorkingDir)
|
||||
cmd.Dir = i.WorkingDir
|
||||
}
|
||||
defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
|
||||
|
||||
debugStr := cmdDebugStr(cmd)
|
||||
i.logf("starting %v", debugStr)
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
i.logf("%s for %v", time.Since(start), debugStr)
|
||||
}()
|
||||
|
||||
return runCmdContext(ctx, cmd)
|
||||
}
|
||||
|
@ -242,10 +293,86 @@ var DebugHangingGoCommands = false
|
|||
|
||||
// runCmdContext is like exec.CommandContext except it sends os.Interrupt
|
||||
// before os.Kill.
|
||||
func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
||||
if err := cmd.Start(); err != nil {
|
||||
func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) {
|
||||
// If cmd.Stdout is not an *os.File, the exec package will create a pipe and
|
||||
// copy it to the Writer in a goroutine until the process has finished and
|
||||
// either the pipe reaches EOF or command's WaitDelay expires.
|
||||
//
|
||||
// However, the output from 'go list' can be quite large, and we don't want to
|
||||
// keep reading (and allocating buffers) if we've already decided we don't
|
||||
// care about the output. We don't want to wait for the process to finish, and
|
||||
// we don't wait to wait for the WaitDelay to expire either.
|
||||
//
|
||||
// Instead, if cmd.Stdout requires a copying goroutine we explicitly replace
|
||||
// it with a pipe (which is an *os.File), which we can close in order to stop
|
||||
// copying output as soon as we realize we don't care about it.
|
||||
var stdoutW *os.File
|
||||
if cmd.Stdout != nil {
|
||||
if _, ok := cmd.Stdout.(*os.File); !ok {
|
||||
var stdoutR *os.File
|
||||
stdoutR, stdoutW, err = os.Pipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prevStdout := cmd.Stdout
|
||||
cmd.Stdout = stdoutW
|
||||
|
||||
stdoutErr := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := io.Copy(prevStdout, stdoutR)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("copying stdout: %w", err)
|
||||
}
|
||||
stdoutErr <- err
|
||||
}()
|
||||
defer func() {
|
||||
// We started a goroutine to copy a stdout pipe.
|
||||
// Wait for it to finish, or terminate it if need be.
|
||||
var err2 error
|
||||
select {
|
||||
case err2 = <-stdoutErr:
|
||||
stdoutR.Close()
|
||||
case <-ctx.Done():
|
||||
stdoutR.Close()
|
||||
// Per https://pkg.go.dev/os#File.Close, the call to stdoutR.Close
|
||||
// should cause the Read call in io.Copy to unblock and return
|
||||
// immediately, but we still need to receive from stdoutErr to confirm
|
||||
// that it has happened.
|
||||
<-stdoutErr
|
||||
err2 = ctx.Err()
|
||||
}
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
}()
|
||||
|
||||
// Per https://pkg.go.dev/os/exec#Cmd, “If Stdout and Stderr are the
|
||||
// same writer, and have a type that can be compared with ==, at most
|
||||
// one goroutine at a time will call Write.”
|
||||
//
|
||||
// Since we're starting a goroutine that writes to cmd.Stdout, we must
|
||||
// also update cmd.Stderr so that it still holds.
|
||||
func() {
|
||||
defer func() { recover() }()
|
||||
if cmd.Stderr == prevStdout {
|
||||
cmd.Stderr = cmd.Stdout
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
err = cmd.Start()
|
||||
if stdoutW != nil {
|
||||
// The child process has inherited the pipe file,
|
||||
// so close the copy held in this process.
|
||||
stdoutW.Close()
|
||||
stdoutW = nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resChan := make(chan error, 1)
|
||||
go func() {
|
||||
resChan <- cmd.Wait()
|
||||
|
@ -253,12 +380,15 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
|||
|
||||
// If we're interested in debugging hanging Go commands, stop waiting after a
|
||||
// minute and panic with interesting information.
|
||||
if DebugHangingGoCommands {
|
||||
debug := DebugHangingGoCommands
|
||||
if debug {
|
||||
timer := time.NewTimer(1 * time.Minute)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case err := <-resChan:
|
||||
return err
|
||||
case <-time.After(1 * time.Minute):
|
||||
HandleHangingGoCommand(cmd.Process)
|
||||
case <-timer.C:
|
||||
HandleHangingGoCommand(startTime, cmd)
|
||||
case <-ctx.Done():
|
||||
}
|
||||
} else {
|
||||
|
@ -270,34 +400,29 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
|||
}
|
||||
|
||||
// Cancelled. Interrupt and see if it ends voluntarily.
|
||||
cmd.Process.Signal(os.Interrupt)
|
||||
select {
|
||||
case err := <-resChan:
|
||||
return err
|
||||
case <-time.After(time.Second):
|
||||
if err := cmd.Process.Signal(os.Interrupt); err == nil {
|
||||
// (We used to wait only 1s but this proved
|
||||
// fragile on loaded builder machines.)
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case err := <-resChan:
|
||||
return err
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't shut down in response to interrupt. Kill it hard.
|
||||
// TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT
|
||||
// on certain platforms, such as unix.
|
||||
if err := cmd.Process.Kill(); err != nil && DebugHangingGoCommands {
|
||||
// Don't panic here as this reliably fails on windows with EINVAL.
|
||||
if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) && debug {
|
||||
log.Printf("error killing the Go command: %v", err)
|
||||
}
|
||||
|
||||
// See above: don't wait indefinitely if we're debugging hanging Go commands.
|
||||
if DebugHangingGoCommands {
|
||||
select {
|
||||
case err := <-resChan:
|
||||
return err
|
||||
case <-time.After(10 * time.Second): // a shorter wait as resChan should return quickly following Kill
|
||||
HandleHangingGoCommand(cmd.Process)
|
||||
}
|
||||
}
|
||||
return <-resChan
|
||||
}
|
||||
|
||||
func HandleHangingGoCommand(proc *os.Process) {
|
||||
func HandleHangingGoCommand(start time.Time, cmd *exec.Cmd) {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "darwin", "freebsd", "netbsd":
|
||||
fmt.Fprintln(os.Stderr, `DETECTED A HANGING GO COMMAND
|
||||
|
@ -330,7 +455,7 @@ See golang/go#54461 for more details.`)
|
|||
panic(fmt.Sprintf("running %s: %v", listFiles, err))
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("detected hanging go command (pid %d): see golang/go#54461 for more details", proc.Pid))
|
||||
panic(fmt.Sprintf("detected hanging go command (golang/go#54461); waited %s\n\tcommand:%s\n\tpid:%d", time.Since(start), cmd, cmd.Process.Pid))
|
||||
}
|
||||
|
||||
func cmdDebugStr(cmd *exec.Cmd) string {
|
||||
|
@ -354,3 +479,73 @@ func cmdDebugStr(cmd *exec.Cmd) string {
|
|||
}
|
||||
return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], strings.Join(args, " "))
|
||||
}
|
||||
|
||||
// WriteOverlays writes each value in the overlay (see the Overlay
|
||||
// field of go/packages.Config) to a temporary file and returns the name
|
||||
// of a JSON file describing the mapping that is suitable for the "go
|
||||
// list -overlay" flag.
|
||||
//
|
||||
// On success, the caller must call the cleanup function exactly once
|
||||
// when the files are no longer needed.
|
||||
func WriteOverlays(overlay map[string][]byte) (filename string, cleanup func(), err error) {
|
||||
// Do nothing if there are no overlays in the config.
|
||||
if len(overlay) == 0 {
|
||||
return "", func() {}, nil
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "gocommand-*")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// The caller must clean up this directory,
|
||||
// unless this function returns an error.
|
||||
// (The cleanup operand of each return
|
||||
// statement below is ignored.)
|
||||
defer func() {
|
||||
cleanup = func() {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
if err != nil {
|
||||
cleanup()
|
||||
cleanup = nil
|
||||
}
|
||||
}()
|
||||
|
||||
// Write each map entry to a temporary file.
|
||||
overlays := make(map[string]string)
|
||||
for k, v := range overlay {
|
||||
// Use a unique basename for each file (001-foo.go),
|
||||
// to avoid creating nested directories.
|
||||
base := fmt.Sprintf("%d-%s", 1+len(overlays), filepath.Base(k))
|
||||
filename := filepath.Join(dir, base)
|
||||
err := os.WriteFile(filename, v, 0666)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
overlays[k] = filename
|
||||
}
|
||||
|
||||
// Write the JSON overlay file that maps logical file names to temp files.
|
||||
//
|
||||
// OverlayJSON is the format overlay files are expected to be in.
|
||||
// The Replace map maps from overlaid paths to replacement paths:
|
||||
// the Go command will forward all reads trying to open
|
||||
// each overlaid path to its replacement path, or consider the overlaid
|
||||
// path not to exist if the replacement path is empty.
|
||||
//
|
||||
// From golang/go#39958.
|
||||
type OverlayJSON struct {
|
||||
Replace map[string]string `json:"replace,omitempty"`
|
||||
}
|
||||
b, err := json.Marshal(OverlayJSON{Replace: overlays})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
filename = filepath.Join(dir, "overlay.json")
|
||||
if err := os.WriteFile(filename, b, 0666); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return filename, nil, nil
|
||||
}
|
||||
|
|
54
vendor/golang.org/x/tools/internal/gocommand/vendor.go
generated
vendored
54
vendor/golang.org/x/tools/internal/gocommand/vendor.go
generated
vendored
|
@ -107,3 +107,57 @@ func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*Modul
|
|||
}
|
||||
return mod, lines[4] == "go1.14", nil
|
||||
}
|
||||
|
||||
// WorkspaceVendorEnabled reports whether workspace vendoring is enabled. It takes a *Runner to execute Go commands
|
||||
// with the supplied context.Context and Invocation. The Invocation can contain pre-defined fields,
|
||||
// of which only Verb and Args are modified to run the appropriate Go command.
|
||||
// Inspired by setDefaultBuildMod in modload/init.go
|
||||
func WorkspaceVendorEnabled(ctx context.Context, inv Invocation, r *Runner) (bool, []*ModuleJSON, error) {
|
||||
inv.Verb = "env"
|
||||
inv.Args = []string{"GOWORK"}
|
||||
stdout, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
goWork := string(bytes.TrimSpace(stdout.Bytes()))
|
||||
if fi, err := os.Stat(filepath.Join(filepath.Dir(goWork), "vendor")); err == nil && fi.IsDir() {
|
||||
mainMods, err := getWorkspaceMainModules(ctx, inv, r)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, mainMods, nil
|
||||
}
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
// getWorkspaceMainModules gets the main modules' information.
|
||||
// This is the information needed to figure out if vendoring should be enabled.
|
||||
func getWorkspaceMainModules(ctx context.Context, inv Invocation, r *Runner) ([]*ModuleJSON, error) {
|
||||
const format = `{{.Path}}
|
||||
{{.Dir}}
|
||||
{{.GoMod}}
|
||||
{{.GoVersion}}
|
||||
`
|
||||
inv.Verb = "list"
|
||||
inv.Args = []string{"-m", "-f", format}
|
||||
stdout, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
|
||||
if len(lines) < 4 {
|
||||
return nil, fmt.Errorf("unexpected stdout: %q", stdout.String())
|
||||
}
|
||||
mods := make([]*ModuleJSON, 0, len(lines)/4)
|
||||
for i := 0; i < len(lines); i += 4 {
|
||||
mods = append(mods, &ModuleJSON{
|
||||
Path: lines[i],
|
||||
Dir: lines[i+1],
|
||||
GoMod: lines[i+2],
|
||||
GoVersion: lines[i+3],
|
||||
Main: true,
|
||||
})
|
||||
}
|
||||
return mods, nil
|
||||
}
|
||||
|
|
41
vendor/golang.org/x/tools/internal/gocommand/version.go
generated
vendored
41
vendor/golang.org/x/tools/internal/gocommand/version.go
generated
vendored
|
@ -7,6 +7,7 @@ package gocommand
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -22,21 +23,11 @@ import (
|
|||
func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
||||
inv.Verb = "list"
|
||||
inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`}
|
||||
inv.Env = append(append([]string{}, inv.Env...), "GO111MODULE=off")
|
||||
// Unset any unneeded flags, and remove them from BuildFlags, if they're
|
||||
// present.
|
||||
inv.ModFile = ""
|
||||
inv.BuildFlags = nil // This is not a build command.
|
||||
inv.ModFlag = ""
|
||||
var buildFlags []string
|
||||
for _, flag := range inv.BuildFlags {
|
||||
// Flags can be prefixed by one or two dashes.
|
||||
f := strings.TrimPrefix(strings.TrimPrefix(flag, "-"), "-")
|
||||
if strings.HasPrefix(f, "mod=") || strings.HasPrefix(f, "modfile=") {
|
||||
continue
|
||||
}
|
||||
buildFlags = append(buildFlags, flag)
|
||||
}
|
||||
inv.BuildFlags = buildFlags
|
||||
inv.ModFile = ""
|
||||
inv.Env = append(inv.Env[:len(inv.Env):len(inv.Env)], "GO111MODULE=off")
|
||||
|
||||
stdoutBytes, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -56,3 +47,25 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
|||
}
|
||||
return 0, fmt.Errorf("no parseable ReleaseTags in %v", tags)
|
||||
}
|
||||
|
||||
// GoVersionOutput returns the complete output of the go version command.
|
||||
func GoVersionOutput(ctx context.Context, inv Invocation, r *Runner) (string, error) {
|
||||
inv.Verb = "version"
|
||||
goVersion, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return goVersion.String(), nil
|
||||
}
|
||||
|
||||
// ParseGoVersionOutput extracts the Go version string
|
||||
// from the output of the "go version" command.
|
||||
// Given an unrecognized form, it returns an empty string.
|
||||
func ParseGoVersionOutput(data string) string {
|
||||
re := regexp.MustCompile(`^go version (go\S+|devel \S+)`)
|
||||
m := re.FindStringSubmatch(data)
|
||||
if len(m) != 2 {
|
||||
return "" // unrecognized version
|
||||
}
|
||||
return m[1]
|
||||
}
|
||||
|
|
71
vendor/golang.org/x/tools/internal/goroot/importcfg.go
generated
vendored
71
vendor/golang.org/x/tools/internal/goroot/importcfg.go
generated
vendored
|
@ -1,71 +0,0 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
// Package goroot is a copy of package internal/goroot
|
||||
// in the main GO repot. It provides a utility to produce
|
||||
// an importcfg and import path to package file map mapping
|
||||
// standard library packages to the locations of their export
|
||||
// data files.
|
||||
package goroot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Importcfg returns an importcfg file to be passed to the
|
||||
// Go compiler that contains the cached paths for the .a files for the
|
||||
// standard library.
|
||||
func Importcfg() (string, error) {
|
||||
var icfg bytes.Buffer
|
||||
|
||||
m, err := PkgfileMap()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Fprintf(&icfg, "# import config")
|
||||
for importPath, export := range m {
|
||||
if importPath != "unsafe" && export != "" { // unsafe
|
||||
fmt.Fprintf(&icfg, "\npackagefile %s=%s", importPath, export)
|
||||
}
|
||||
}
|
||||
s := icfg.String()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
var (
|
||||
stdlibPkgfileMap map[string]string
|
||||
stdlibPkgfileErr error
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// PkgfileMap returns a map of package paths to the location on disk
|
||||
// of the .a file for the package.
|
||||
// The caller must not modify the map.
|
||||
func PkgfileMap() (map[string]string, error) {
|
||||
once.Do(func() {
|
||||
m := make(map[string]string)
|
||||
output, err := exec.Command("go", "list", "-export", "-e", "-f", "{{.ImportPath}} {{.Export}}", "std", "cmd").Output()
|
||||
if err != nil {
|
||||
stdlibPkgfileErr = err
|
||||
}
|
||||
for _, line := range strings.Split(string(output), "\n") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
sp := strings.SplitN(line, " ", 2)
|
||||
if len(sp) != 2 {
|
||||
err = fmt.Errorf("determining pkgfile map: invalid line in go list output: %q", line)
|
||||
return
|
||||
}
|
||||
importPath, export := sp[0], sp[1]
|
||||
m[importPath] = export
|
||||
}
|
||||
stdlibPkgfileMap = m
|
||||
})
|
||||
return stdlibPkgfileMap, stdlibPkgfileErr
|
||||
}
|
10
vendor/golang.org/x/tools/internal/packagesinternal/packages.go
generated
vendored
10
vendor/golang.org/x/tools/internal/packagesinternal/packages.go
generated
vendored
|
@ -5,11 +5,6 @@
|
|||
// Package packagesinternal exposes internal-only fields from go/packages.
|
||||
package packagesinternal
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
)
|
||||
|
||||
var GetForTest = func(p interface{}) string { return "" }
|
||||
var GetDepsErrors = func(p interface{}) []*PackageError { return nil }
|
||||
|
||||
type PackageError struct {
|
||||
|
@ -18,13 +13,8 @@ type PackageError struct {
|
|||
Err string // the error itself
|
||||
}
|
||||
|
||||
var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil }
|
||||
|
||||
var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {}
|
||||
|
||||
var TypecheckCgo int
|
||||
var DepsErrors int // must be set as a LoadMode to call GetDepsErrors
|
||||
var ForTest int // must be set as a LoadMode to call GetForTest
|
||||
|
||||
var SetModFlag = func(config interface{}, value string) {}
|
||||
var SetModFile = func(config interface{}, value string) {}
|
||||
|
|
137
vendor/golang.org/x/tools/internal/pkgbits/decoder.go
generated
vendored
137
vendor/golang.org/x/tools/internal/pkgbits/decoder.go
generated
vendored
|
@ -6,6 +6,7 @@ package pkgbits
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
// export data.
|
||||
type PkgDecoder struct {
|
||||
// version is the file format version.
|
||||
version uint32
|
||||
version Version
|
||||
|
||||
// sync indicates whether the file uses sync markers.
|
||||
sync bool
|
||||
|
@ -52,6 +53,8 @@ type PkgDecoder struct {
|
|||
// For example, section K's end positions start at elemEndsEnds[K-1]
|
||||
// (or 0, if K==0) and end at elemEndsEnds[K].
|
||||
elemEndsEnds [numRelocs]uint32
|
||||
|
||||
scratchRelocEnt []RelocEnt
|
||||
}
|
||||
|
||||
// PkgPath returns the package path for the package
|
||||
|
@ -65,8 +68,6 @@ func (pr *PkgDecoder) SyncMarkers() bool { return pr.sync }
|
|||
// NewPkgDecoder returns a PkgDecoder initialized to read the Unified
|
||||
// IR export data from input. pkgPath is the package path for the
|
||||
// compilation unit that produced the export data.
|
||||
//
|
||||
// TODO(mdempsky): Remove pkgPath parameter; unneeded since CL 391014.
|
||||
func NewPkgDecoder(pkgPath, input string) PkgDecoder {
|
||||
pr := PkgDecoder{
|
||||
pkgPath: pkgPath,
|
||||
|
@ -77,14 +78,15 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder {
|
|||
|
||||
r := strings.NewReader(input)
|
||||
|
||||
assert(binary.Read(r, binary.LittleEndian, &pr.version) == nil)
|
||||
var ver uint32
|
||||
assert(binary.Read(r, binary.LittleEndian, &ver) == nil)
|
||||
pr.version = Version(ver)
|
||||
|
||||
switch pr.version {
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported version: %v", pr.version))
|
||||
case 0:
|
||||
// no flags
|
||||
case 1:
|
||||
if pr.version >= numVersions {
|
||||
panic(fmt.Errorf("cannot decode %q, export data version %d is greater than maximum supported version %d", pkgPath, pr.version, numVersions-1))
|
||||
}
|
||||
|
||||
if pr.version.Has(Flags) {
|
||||
var flags uint32
|
||||
assert(binary.Read(r, binary.LittleEndian, &flags) == nil)
|
||||
pr.sync = flags&flagSyncMarkers != 0
|
||||
|
@ -99,7 +101,9 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder {
|
|||
assert(err == nil)
|
||||
|
||||
pr.elemData = input[pos:]
|
||||
assert(len(pr.elemData)-8 == int(pr.elemEnds[len(pr.elemEnds)-1]))
|
||||
|
||||
const fingerprintSize = 8
|
||||
assert(len(pr.elemData)-fingerprintSize == int(pr.elemEnds[len(pr.elemEnds)-1]))
|
||||
|
||||
return pr
|
||||
}
|
||||
|
@ -133,7 +137,7 @@ func (pr *PkgDecoder) AbsIdx(k RelocKind, idx Index) int {
|
|||
absIdx += int(pr.elemEndsEnds[k-1])
|
||||
}
|
||||
if absIdx >= int(pr.elemEndsEnds[k]) {
|
||||
errorf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds)
|
||||
panicf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds)
|
||||
}
|
||||
return absIdx
|
||||
}
|
||||
|
@ -165,6 +169,21 @@ func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Deco
|
|||
return r
|
||||
}
|
||||
|
||||
// TempDecoder returns a Decoder for the given (section, index) pair,
|
||||
// and decodes the given SyncMarker from the element bitstream.
|
||||
// If possible the Decoder should be RetireDecoder'd when it is no longer
|
||||
// needed, this will avoid heap allocations.
|
||||
func (pr *PkgDecoder) TempDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder {
|
||||
r := pr.TempDecoderRaw(k, idx)
|
||||
r.Sync(marker)
|
||||
return r
|
||||
}
|
||||
|
||||
func (pr *PkgDecoder) RetireDecoder(d *Decoder) {
|
||||
pr.scratchRelocEnt = d.Relocs
|
||||
d.Relocs = nil
|
||||
}
|
||||
|
||||
// NewDecoderRaw returns a Decoder for the given (section, index) pair.
|
||||
//
|
||||
// Most callers should use NewDecoder instead.
|
||||
|
@ -175,9 +194,7 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder {
|
|||
Idx: idx,
|
||||
}
|
||||
|
||||
// TODO(mdempsky) r.data.Reset(...) after #44505 is resolved.
|
||||
r.Data = *strings.NewReader(pr.DataIdx(k, idx))
|
||||
|
||||
r.Data.Reset(pr.DataIdx(k, idx))
|
||||
r.Sync(SyncRelocs)
|
||||
r.Relocs = make([]RelocEnt, r.Len())
|
||||
for i := range r.Relocs {
|
||||
|
@ -188,6 +205,30 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder {
|
|||
return r
|
||||
}
|
||||
|
||||
func (pr *PkgDecoder) TempDecoderRaw(k RelocKind, idx Index) Decoder {
|
||||
r := Decoder{
|
||||
common: pr,
|
||||
k: k,
|
||||
Idx: idx,
|
||||
}
|
||||
|
||||
r.Data.Reset(pr.DataIdx(k, idx))
|
||||
r.Sync(SyncRelocs)
|
||||
l := r.Len()
|
||||
if cap(pr.scratchRelocEnt) >= l {
|
||||
r.Relocs = pr.scratchRelocEnt[:l]
|
||||
pr.scratchRelocEnt = nil
|
||||
} else {
|
||||
r.Relocs = make([]RelocEnt, l)
|
||||
}
|
||||
for i := range r.Relocs {
|
||||
r.Sync(SyncReloc)
|
||||
r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// A Decoder provides methods for decoding an individual element's
|
||||
// bitstream data.
|
||||
type Decoder struct {
|
||||
|
@ -202,16 +243,44 @@ type Decoder struct {
|
|||
|
||||
func (r *Decoder) checkErr(err error) {
|
||||
if err != nil {
|
||||
errorf("unexpected decoding error: %w", err)
|
||||
panicf("unexpected decoding error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Decoder) rawUvarint() uint64 {
|
||||
x, err := binary.ReadUvarint(&r.Data)
|
||||
x, err := readUvarint(&r.Data)
|
||||
r.checkErr(err)
|
||||
return x
|
||||
}
|
||||
|
||||
// readUvarint is a type-specialized copy of encoding/binary.ReadUvarint.
|
||||
// This avoids the interface conversion and thus has better escape properties,
|
||||
// which flows up the stack.
|
||||
func readUvarint(r *strings.Reader) (uint64, error) {
|
||||
var x uint64
|
||||
var s uint
|
||||
for i := 0; i < binary.MaxVarintLen64; i++ {
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
if i > 0 && err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return x, err
|
||||
}
|
||||
if b < 0x80 {
|
||||
if i == binary.MaxVarintLen64-1 && b > 1 {
|
||||
return x, overflow
|
||||
}
|
||||
return x | uint64(b)<<s, nil
|
||||
}
|
||||
x |= uint64(b&0x7f) << s
|
||||
s += 7
|
||||
}
|
||||
return x, overflow
|
||||
}
|
||||
|
||||
var overflow = errors.New("pkgbits: readUvarint overflows a 64-bit integer")
|
||||
|
||||
func (r *Decoder) rawVarint() int64 {
|
||||
ux := r.rawUvarint()
|
||||
|
||||
|
@ -303,7 +372,7 @@ func (r *Decoder) Int64() int64 {
|
|||
return r.rawVarint()
|
||||
}
|
||||
|
||||
// Int64 decodes and returns a uint64 value from the element bitstream.
|
||||
// Uint64 decodes and returns a uint64 value from the element bitstream.
|
||||
func (r *Decoder) Uint64() uint64 {
|
||||
r.Sync(SyncUint64)
|
||||
return r.rawUvarint()
|
||||
|
@ -410,8 +479,12 @@ func (r *Decoder) bigFloat() *big.Float {
|
|||
// PeekPkgPath returns the package path for the specified package
|
||||
// index.
|
||||
func (pr *PkgDecoder) PeekPkgPath(idx Index) string {
|
||||
r := pr.NewDecoder(RelocPkg, idx, SyncPkgDef)
|
||||
path := r.String()
|
||||
var path string
|
||||
{
|
||||
r := pr.TempDecoder(RelocPkg, idx, SyncPkgDef)
|
||||
path = r.String()
|
||||
pr.RetireDecoder(&r)
|
||||
}
|
||||
if path == "" {
|
||||
path = pr.pkgPath
|
||||
}
|
||||
|
@ -421,14 +494,26 @@ func (pr *PkgDecoder) PeekPkgPath(idx Index) string {
|
|||
// PeekObj returns the package path, object name, and CodeObj for the
|
||||
// specified object index.
|
||||
func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) {
|
||||
r := pr.NewDecoder(RelocName, idx, SyncObject1)
|
||||
r.Sync(SyncSym)
|
||||
r.Sync(SyncPkg)
|
||||
path := pr.PeekPkgPath(r.Reloc(RelocPkg))
|
||||
name := r.String()
|
||||
var ridx Index
|
||||
var name string
|
||||
var rcode int
|
||||
{
|
||||
r := pr.TempDecoder(RelocName, idx, SyncObject1)
|
||||
r.Sync(SyncSym)
|
||||
r.Sync(SyncPkg)
|
||||
ridx = r.Reloc(RelocPkg)
|
||||
name = r.String()
|
||||
rcode = r.Code(SyncCodeObj)
|
||||
pr.RetireDecoder(&r)
|
||||
}
|
||||
|
||||
path := pr.PeekPkgPath(ridx)
|
||||
assert(name != "")
|
||||
|
||||
tag := CodeObj(r.Code(SyncCodeObj))
|
||||
tag := CodeObj(rcode)
|
||||
|
||||
return path, name, tag
|
||||
}
|
||||
|
||||
// Version reports the version of the bitstream.
|
||||
func (w *Decoder) Version() Version { return w.common.version }
|
||||
|
|
45
vendor/golang.org/x/tools/internal/pkgbits/encoder.go
generated
vendored
45
vendor/golang.org/x/tools/internal/pkgbits/encoder.go
generated
vendored
|
@ -12,18 +12,15 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// currentVersion is the current version number.
|
||||
//
|
||||
// - v0: initial prototype
|
||||
//
|
||||
// - v1: adds the flags uint32 word
|
||||
const currentVersion uint32 = 1
|
||||
|
||||
// A PkgEncoder provides methods for encoding a package's Unified IR
|
||||
// export data.
|
||||
type PkgEncoder struct {
|
||||
// version of the bitstream.
|
||||
version Version
|
||||
|
||||
// elems holds the bitstream for previously encoded elements.
|
||||
elems [numRelocs][]string
|
||||
|
||||
|
@ -47,8 +44,9 @@ func (pw *PkgEncoder) SyncMarkers() bool { return pw.syncFrames >= 0 }
|
|||
// export data files, but can help diagnosing desync errors in
|
||||
// higher-level Unified IR reader/writer code. If syncFrames is
|
||||
// negative, then sync markers are omitted entirely.
|
||||
func NewPkgEncoder(syncFrames int) PkgEncoder {
|
||||
func NewPkgEncoder(version Version, syncFrames int) PkgEncoder {
|
||||
return PkgEncoder{
|
||||
version: version,
|
||||
stringsIdx: make(map[string]Index),
|
||||
syncFrames: syncFrames,
|
||||
}
|
||||
|
@ -64,13 +62,15 @@ func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) {
|
|||
assert(binary.Write(out, binary.LittleEndian, x) == nil)
|
||||
}
|
||||
|
||||
writeUint32(currentVersion)
|
||||
writeUint32(uint32(pw.version))
|
||||
|
||||
var flags uint32
|
||||
if pw.SyncMarkers() {
|
||||
flags |= flagSyncMarkers
|
||||
if pw.version.Has(Flags) {
|
||||
var flags uint32
|
||||
if pw.SyncMarkers() {
|
||||
flags |= flagSyncMarkers
|
||||
}
|
||||
writeUint32(flags)
|
||||
}
|
||||
writeUint32(flags)
|
||||
|
||||
// Write elemEndsEnds.
|
||||
var sum uint32
|
||||
|
@ -159,7 +159,7 @@ type Encoder struct {
|
|||
|
||||
// Flush finalizes the element's bitstream and returns its Index.
|
||||
func (w *Encoder) Flush() Index {
|
||||
var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved
|
||||
var sb strings.Builder
|
||||
|
||||
// Backup the data so we write the relocations at the front.
|
||||
var tmp bytes.Buffer
|
||||
|
@ -189,7 +189,7 @@ func (w *Encoder) Flush() Index {
|
|||
|
||||
func (w *Encoder) checkErr(err error) {
|
||||
if err != nil {
|
||||
errorf("unexpected encoding error: %v", err)
|
||||
panicf("unexpected encoding error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ func (w *Encoder) Len(x int) { assert(x >= 0); w.Uint64(uint64(x)) }
|
|||
// Int encodes and writes an int value into the element bitstream.
|
||||
func (w *Encoder) Int(x int) { w.Int64(int64(x)) }
|
||||
|
||||
// Len encodes and writes a uint value into the element bitstream.
|
||||
// Uint encodes and writes a uint value into the element bitstream.
|
||||
func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) }
|
||||
|
||||
// Reloc encodes and writes a relocation for the given (section,
|
||||
|
@ -320,8 +320,14 @@ func (w *Encoder) Code(c Code) {
|
|||
// section (if not already present), and then writing a relocation
|
||||
// into the element bitstream.
|
||||
func (w *Encoder) String(s string) {
|
||||
w.StringRef(w.p.StringIdx(s))
|
||||
}
|
||||
|
||||
// StringRef writes a reference to the given index, which must be a
|
||||
// previously encoded string value.
|
||||
func (w *Encoder) StringRef(idx Index) {
|
||||
w.Sync(SyncString)
|
||||
w.Reloc(RelocString, w.p.StringIdx(s))
|
||||
w.Reloc(RelocString, idx)
|
||||
}
|
||||
|
||||
// Strings encodes and writes a variable-length slice of strings into
|
||||
|
@ -348,7 +354,7 @@ func (w *Encoder) Value(val constant.Value) {
|
|||
func (w *Encoder) scalar(val constant.Value) {
|
||||
switch v := constant.Val(val).(type) {
|
||||
default:
|
||||
errorf("unhandled %v (%v)", val, val.Kind())
|
||||
panicf("unhandled %v (%v)", val, val.Kind())
|
||||
case bool:
|
||||
w.Code(ValBool)
|
||||
w.Bool(v)
|
||||
|
@ -381,3 +387,6 @@ func (w *Encoder) bigFloat(v *big.Float) {
|
|||
b := v.Append(nil, 'p', -1)
|
||||
w.String(string(b)) // TODO: More efficient encoding.
|
||||
}
|
||||
|
||||
// Version reports the version of the bitstream.
|
||||
func (w *Encoder) Version() Version { return w.p.version }
|
||||
|
|
21
vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go
generated
vendored
21
vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.7
|
||||
// +build !go1.7
|
||||
|
||||
// TODO(mdempsky): Remove after #44505 is resolved
|
||||
|
||||
package pkgbits
|
||||
|
||||
import "runtime"
|
||||
|
||||
func walkFrames(pcs []uintptr, visit frameVisitor) {
|
||||
for _, pc := range pcs {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
file, line := fn.FileLine(pc)
|
||||
|
||||
visit(file, line, fn.Name(), pc-fn.Entry())
|
||||
}
|
||||
}
|
28
vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go
generated
vendored
28
vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go
generated
vendored
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.7
|
||||
// +build go1.7
|
||||
|
||||
package pkgbits
|
||||
|
||||
import "runtime"
|
||||
|
||||
// walkFrames calls visit for each call frame represented by pcs.
|
||||
//
|
||||
// pcs should be a slice of PCs, as returned by runtime.Callers.
|
||||
func walkFrames(pcs []uintptr, visit frameVisitor) {
|
||||
if len(pcs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
frames := runtime.CallersFrames(pcs)
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry)
|
||||
if !more {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
2
vendor/golang.org/x/tools/internal/pkgbits/support.go
generated
vendored
2
vendor/golang.org/x/tools/internal/pkgbits/support.go
generated
vendored
|
@ -12,6 +12,6 @@ func assert(b bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func errorf(format string, args ...interface{}) {
|
||||
func panicf(format string, args ...any) {
|
||||
panic(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
|
23
vendor/golang.org/x/tools/internal/pkgbits/sync.go
generated
vendored
23
vendor/golang.org/x/tools/internal/pkgbits/sync.go
generated
vendored
|
@ -6,6 +6,7 @@ package pkgbits
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -23,6 +24,24 @@ func fmtFrames(pcs ...uintptr) []string {
|
|||
|
||||
type frameVisitor func(file string, line int, name string, offset uintptr)
|
||||
|
||||
// walkFrames calls visit for each call frame represented by pcs.
|
||||
//
|
||||
// pcs should be a slice of PCs, as returned by runtime.Callers.
|
||||
func walkFrames(pcs []uintptr, visit frameVisitor) {
|
||||
if len(pcs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
frames := runtime.CallersFrames(pcs)
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry)
|
||||
if !more {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SyncMarker is an enum type that represents markers that may be
|
||||
// written to export data to ensure the reader and writer stay
|
||||
// synchronized.
|
||||
|
@ -110,4 +129,8 @@ const (
|
|||
SyncStmtsEnd
|
||||
SyncLabel
|
||||
SyncOptLabel
|
||||
|
||||
SyncMultiExpr
|
||||
SyncRType
|
||||
SyncConvRTTI
|
||||
)
|
||||
|
|
7
vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go
generated
vendored
7
vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go
generated
vendored
|
@ -74,11 +74,14 @@ func _() {
|
|||
_ = x[SyncStmtsEnd-64]
|
||||
_ = x[SyncLabel-65]
|
||||
_ = x[SyncOptLabel-66]
|
||||
_ = x[SyncMultiExpr-67]
|
||||
_ = x[SyncRType-68]
|
||||
_ = x[SyncConvRTTI-69]
|
||||
}
|
||||
|
||||
const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel"
|
||||
const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabelMultiExprRTypeConvRTTI"
|
||||
|
||||
var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458}
|
||||
var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458, 467, 472, 480}
|
||||
|
||||
func (i SyncMarker) String() string {
|
||||
i -= 1
|
||||
|
|
85
vendor/golang.org/x/tools/internal/pkgbits/version.go
generated
vendored
Normal file
85
vendor/golang.org/x/tools/internal/pkgbits/version.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package pkgbits
|
||||
|
||||
// Version indicates a version of a unified IR bitstream.
|
||||
// Each Version indicates the addition, removal, or change of
|
||||
// new data in the bitstream.
|
||||
//
|
||||
// These are serialized to disk and the interpretation remains fixed.
|
||||
type Version uint32
|
||||
|
||||
const (
|
||||
// V0: initial prototype.
|
||||
//
|
||||
// All data that is not assigned a Field is in version V0
|
||||
// and has not been deprecated.
|
||||
V0 Version = iota
|
||||
|
||||
// V1: adds the Flags uint32 word
|
||||
V1
|
||||
|
||||
// V2: removes unused legacy fields and supports type parameters for aliases.
|
||||
// - remove the legacy "has init" bool from the public root
|
||||
// - remove obj's "derived func instance" bool
|
||||
// - add a TypeParamNames field to ObjAlias
|
||||
// - remove derived info "needed" bool
|
||||
V2
|
||||
|
||||
numVersions = iota
|
||||
)
|
||||
|
||||
// Field denotes a unit of data in the serialized unified IR bitstream.
|
||||
// It is conceptually a like field in a structure.
|
||||
//
|
||||
// We only really need Fields when the data may or may not be present
|
||||
// in a stream based on the Version of the bitstream.
|
||||
//
|
||||
// Unlike much of pkgbits, Fields are not serialized and
|
||||
// can change values as needed.
|
||||
type Field int
|
||||
|
||||
const (
|
||||
// Flags in a uint32 in the header of a bitstream
|
||||
// that is used to indicate whether optional features are enabled.
|
||||
Flags Field = iota
|
||||
|
||||
// Deprecated: HasInit was a bool indicating whether a package
|
||||
// has any init functions.
|
||||
HasInit
|
||||
|
||||
// Deprecated: DerivedFuncInstance was a bool indicating
|
||||
// whether an object was a function instance.
|
||||
DerivedFuncInstance
|
||||
|
||||
// ObjAlias has a list of TypeParamNames.
|
||||
AliasTypeParamNames
|
||||
|
||||
// Deprecated: DerivedInfoNeeded was a bool indicating
|
||||
// whether a type was a derived type.
|
||||
DerivedInfoNeeded
|
||||
|
||||
numFields = iota
|
||||
)
|
||||
|
||||
// introduced is the version a field was added.
|
||||
var introduced = [numFields]Version{
|
||||
Flags: V1,
|
||||
AliasTypeParamNames: V2,
|
||||
}
|
||||
|
||||
// removed is the version a field was removed in or 0 for fields
|
||||
// that have not yet been deprecated.
|
||||
// (So removed[f]-1 is the last version it is included in.)
|
||||
var removed = [numFields]Version{
|
||||
HasInit: V2,
|
||||
DerivedFuncInstance: V2,
|
||||
DerivedInfoNeeded: V2,
|
||||
}
|
||||
|
||||
// Has reports whether field f is present in a bitstream at version v.
|
||||
func (v Version) Has(f Field) bool {
|
||||
return introduced[f] <= v && (v < removed[f] || removed[f] == V0)
|
||||
}
|
17650
vendor/golang.org/x/tools/internal/stdlib/manifest.go
generated
vendored
Normal file
17650
vendor/golang.org/x/tools/internal/stdlib/manifest.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
97
vendor/golang.org/x/tools/internal/stdlib/stdlib.go
generated
vendored
Normal file
97
vendor/golang.org/x/tools/internal/stdlib/stdlib.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
//go:generate go run generate.go
|
||||
|
||||
// Package stdlib provides a table of all exported symbols in the
|
||||
// standard library, along with the version at which they first
|
||||
// appeared.
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Kind Kind
|
||||
Version Version // Go version that first included the symbol
|
||||
}
|
||||
|
||||
// A Kind indicates the kind of a symbol:
|
||||
// function, variable, constant, type, and so on.
|
||||
type Kind int8
|
||||
|
||||
const (
|
||||
Invalid Kind = iota // Example name:
|
||||
Type // "Buffer"
|
||||
Func // "Println"
|
||||
Var // "EOF"
|
||||
Const // "Pi"
|
||||
Field // "Point.X"
|
||||
Method // "(*Buffer).Grow"
|
||||
)
|
||||
|
||||
func (kind Kind) String() string {
|
||||
return [...]string{
|
||||
Invalid: "invalid",
|
||||
Type: "type",
|
||||
Func: "func",
|
||||
Var: "var",
|
||||
Const: "const",
|
||||
Field: "field",
|
||||
Method: "method",
|
||||
}[kind]
|
||||
}
|
||||
|
||||
// A Version represents a version of Go of the form "go1.%d".
|
||||
type Version int8
|
||||
|
||||
// String returns a version string of the form "go1.23", without allocating.
|
||||
func (v Version) String() string { return versions[v] }
|
||||
|
||||
var versions [30]string // (increase constant as needed)
|
||||
|
||||
func init() {
|
||||
for i := range versions {
|
||||
versions[i] = fmt.Sprintf("go1.%d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// HasPackage reports whether the specified package path is part of
|
||||
// the standard library's public API.
|
||||
func HasPackage(path string) bool {
|
||||
_, ok := PackageSymbols[path]
|
||||
return ok
|
||||
}
|
||||
|
||||
// SplitField splits the field symbol name into type and field
|
||||
// components. It must be called only on Field symbols.
|
||||
//
|
||||
// Example: "File.Package" -> ("File", "Package")
|
||||
func (sym *Symbol) SplitField() (typename, name string) {
|
||||
if sym.Kind != Field {
|
||||
panic("not a field")
|
||||
}
|
||||
typename, name, _ = strings.Cut(sym.Name, ".")
|
||||
return
|
||||
}
|
||||
|
||||
// SplitMethod splits the method symbol name into pointer, receiver,
|
||||
// and method components. It must be called only on Method symbols.
|
||||
//
|
||||
// Example: "(*Buffer).Grow" -> (true, "Buffer", "Grow")
|
||||
func (sym *Symbol) SplitMethod() (ptr bool, recv, name string) {
|
||||
if sym.Kind != Method {
|
||||
panic("not a method")
|
||||
}
|
||||
recv, name, _ = strings.Cut(sym.Name, ".")
|
||||
recv = recv[len("(") : len(recv)-len(")")]
|
||||
ptr = recv[0] == '*'
|
||||
if ptr {
|
||||
recv = recv[len("*"):]
|
||||
}
|
||||
return
|
||||
}
|
127
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
127
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
|
@ -2,20 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package typeparams contains common utilities for writing tools that interact
|
||||
// with generic Go code, as introduced with Go 1.18.
|
||||
//
|
||||
// Many of the types and functions in this package are proxies for the new APIs
|
||||
// introduced in the standard library with Go 1.18. For example, the
|
||||
// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec
|
||||
// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go
|
||||
// versions older than 1.18 these helpers are implemented as stubs, allowing
|
||||
// users of this package to write code that handles generic constructs inline,
|
||||
// even if the Go version being used to compile does not support generics.
|
||||
//
|
||||
// Additionally, this package contains common utilities for working with the
|
||||
// new generic constructs, to supplement the standard library APIs. Notably,
|
||||
// the StructuralTerms API computes a minimal representation of the structural
|
||||
// Package typeparams contains common utilities for writing tools that
|
||||
// interact with generic Go code, as introduced with Go 1.18. It
|
||||
// supplements the standard library APIs. Notably, the StructuralTerms
|
||||
// API computes a minimal representation of the structural
|
||||
// restrictions on a type parameter.
|
||||
//
|
||||
// An external version of these APIs is available in the
|
||||
|
@ -41,7 +31,7 @@ func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Ex
|
|||
switch e := n.(type) {
|
||||
case *ast.IndexExpr:
|
||||
return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
|
||||
case *IndexListExpr:
|
||||
case *ast.IndexListExpr:
|
||||
return e.X, e.Lbrack, e.Indices, e.Rbrack
|
||||
}
|
||||
return nil, token.NoPos, nil, token.NoPos
|
||||
|
@ -62,7 +52,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
|
|||
Rbrack: rbrack,
|
||||
}
|
||||
default:
|
||||
return &IndexListExpr{
|
||||
return &ast.IndexListExpr{
|
||||
X: x,
|
||||
Lbrack: lbrack,
|
||||
Indices: indices,
|
||||
|
@ -71,109 +61,8 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
|
|||
}
|
||||
}
|
||||
|
||||
// IsTypeParam reports whether t is a type parameter.
|
||||
// IsTypeParam reports whether t is a type parameter (or an alias of one).
|
||||
func IsTypeParam(t types.Type) bool {
|
||||
_, ok := t.(*TypeParam)
|
||||
_, ok := types.Unalias(t).(*types.TypeParam)
|
||||
return ok
|
||||
}
|
||||
|
||||
// OriginMethod returns the origin method associated with the method fn.
|
||||
// For methods on a non-generic receiver base type, this is just
|
||||
// fn. However, for methods with a generic receiver, OriginMethod returns the
|
||||
// corresponding method in the method set of the origin type.
|
||||
//
|
||||
// As a special case, if fn is not a method (has no receiver), OriginMethod
|
||||
// returns fn.
|
||||
func OriginMethod(fn *types.Func) *types.Func {
|
||||
recv := fn.Type().(*types.Signature).Recv()
|
||||
if recv == nil {
|
||||
|
||||
return fn
|
||||
}
|
||||
base := recv.Type()
|
||||
p, isPtr := base.(*types.Pointer)
|
||||
if isPtr {
|
||||
base = p.Elem()
|
||||
}
|
||||
named, isNamed := base.(*types.Named)
|
||||
if !isNamed {
|
||||
// Receiver is a *types.Interface.
|
||||
return fn
|
||||
}
|
||||
if ForNamed(named).Len() == 0 {
|
||||
// Receiver base has no type parameters, so we can avoid the lookup below.
|
||||
return fn
|
||||
}
|
||||
orig := NamedTypeOrigin(named)
|
||||
gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name())
|
||||
return gfn.(*types.Func)
|
||||
}
|
||||
|
||||
// GenericAssignableTo is a generalization of types.AssignableTo that
|
||||
// implements the following rule for uninstantiated generic types:
|
||||
//
|
||||
// If V and T are generic named types, then V is considered assignable to T if,
|
||||
// for every possible instantation of V[A_1, ..., A_N], the instantiation
|
||||
// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N].
|
||||
//
|
||||
// If T has structural constraints, they must be satisfied by V.
|
||||
//
|
||||
// For example, consider the following type declarations:
|
||||
//
|
||||
// type Interface[T any] interface {
|
||||
// Accept(T)
|
||||
// }
|
||||
//
|
||||
// type Container[T any] struct {
|
||||
// Element T
|
||||
// }
|
||||
//
|
||||
// func (c Container[T]) Accept(t T) { c.Element = t }
|
||||
//
|
||||
// In this case, GenericAssignableTo reports that instantiations of Container
|
||||
// are assignable to the corresponding instantiation of Interface.
|
||||
func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
|
||||
// If V and T are not both named, or do not have matching non-empty type
|
||||
// parameter lists, fall back on types.AssignableTo.
|
||||
|
||||
VN, Vnamed := V.(*types.Named)
|
||||
TN, Tnamed := T.(*types.Named)
|
||||
if !Vnamed || !Tnamed {
|
||||
return types.AssignableTo(V, T)
|
||||
}
|
||||
|
||||
vtparams := ForNamed(VN)
|
||||
ttparams := ForNamed(TN)
|
||||
if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 {
|
||||
return types.AssignableTo(V, T)
|
||||
}
|
||||
|
||||
// V and T have the same (non-zero) number of type params. Instantiate both
|
||||
// with the type parameters of V. This must always succeed for V, and will
|
||||
// succeed for T if and only if the type set of each type parameter of V is a
|
||||
// subset of the type set of the corresponding type parameter of T, meaning
|
||||
// that every instantiation of V corresponds to a valid instantiation of T.
|
||||
|
||||
// Minor optimization: ensure we share a context across the two
|
||||
// instantiations below.
|
||||
if ctxt == nil {
|
||||
ctxt = NewContext()
|
||||
}
|
||||
|
||||
var targs []types.Type
|
||||
for i := 0; i < vtparams.Len(); i++ {
|
||||
targs = append(targs, vtparams.At(i))
|
||||
}
|
||||
|
||||
vinst, err := Instantiate(ctxt, V, targs, true)
|
||||
if err != nil {
|
||||
panic("type parameters should satisfy their own constraints")
|
||||
}
|
||||
|
||||
tinst, err := Instantiate(ctxt, T, targs, true)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return types.AssignableTo(vinst, tinst)
|
||||
}
|
||||
|
|
58
vendor/golang.org/x/tools/internal/typeparams/coretype.go
generated
vendored
58
vendor/golang.org/x/tools/internal/typeparams/coretype.go
generated
vendored
|
@ -5,6 +5,7 @@
|
|||
package typeparams
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
|
@ -17,7 +18,7 @@ func CoreType(T types.Type) types.Type {
|
|||
return U // for non-interface types,
|
||||
}
|
||||
|
||||
terms, err := _NormalTerms(U)
|
||||
terms, err := NormalTerms(U)
|
||||
if len(terms) == 0 || err != nil {
|
||||
// len(terms) -> empty type set of interface.
|
||||
// err != nil => U is invalid, exceeds complexity bounds, or has an empty type set.
|
||||
|
@ -63,7 +64,7 @@ func CoreType(T types.Type) types.Type {
|
|||
return ch
|
||||
}
|
||||
|
||||
// _NormalTerms returns a slice of terms representing the normalized structural
|
||||
// NormalTerms returns a slice of terms representing the normalized structural
|
||||
// type restrictions of a type, if any.
|
||||
//
|
||||
// For all types other than *types.TypeParam, *types.Interface, and
|
||||
|
@ -81,42 +82,69 @@ func CoreType(T types.Type) types.Type {
|
|||
// restrictions may be arbitrarily complex. For example, consider the
|
||||
// following:
|
||||
//
|
||||
// type A interface{ ~string|~[]byte }
|
||||
// type A interface{ ~string|~[]byte }
|
||||
//
|
||||
// type B interface{ int|string }
|
||||
// type B interface{ int|string }
|
||||
//
|
||||
// type C interface { ~string|~int }
|
||||
// type C interface { ~string|~int }
|
||||
//
|
||||
// type T[P interface{ A|B; C }] int
|
||||
// type T[P interface{ A|B; C }] int
|
||||
//
|
||||
// In this example, the structural type restriction of P is ~string|int: A|B
|
||||
// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
|
||||
// which when intersected with C (~string|~int) yields ~string|int.
|
||||
//
|
||||
// _NormalTerms computes these expansions and reductions, producing a
|
||||
// NormalTerms computes these expansions and reductions, producing a
|
||||
// "normalized" form of the embeddings. A structural restriction is normalized
|
||||
// if it is a single union containing no interface terms, and is minimal in the
|
||||
// sense that removing any term changes the set of types satisfying the
|
||||
// constraint. It is left as a proof for the reader that, modulo sorting, there
|
||||
// is exactly one such normalized form.
|
||||
//
|
||||
// Because the minimal representation always takes this form, _NormalTerms
|
||||
// Because the minimal representation always takes this form, NormalTerms
|
||||
// returns a slice of tilde terms corresponding to the terms of the union in
|
||||
// the normalized structural restriction. An error is returned if the type is
|
||||
// invalid, exceeds complexity bounds, or has an empty type set. In the latter
|
||||
// case, _NormalTerms returns ErrEmptyTypeSet.
|
||||
// case, NormalTerms returns ErrEmptyTypeSet.
|
||||
//
|
||||
// _NormalTerms makes no guarantees about the order of terms, except that it
|
||||
// NormalTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func _NormalTerms(typ types.Type) ([]*Term, error) {
|
||||
switch typ := typ.(type) {
|
||||
case *TypeParam:
|
||||
func NormalTerms(typ types.Type) ([]*types.Term, error) {
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.TypeParam:
|
||||
return StructuralTerms(typ)
|
||||
case *Union:
|
||||
case *types.Union:
|
||||
return UnionTermSet(typ)
|
||||
case *types.Interface:
|
||||
return InterfaceTermSet(typ)
|
||||
default:
|
||||
return []*Term{NewTerm(false, typ)}, nil
|
||||
return []*types.Term{types.NewTerm(false, typ)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Deref returns the type of the variable pointed to by t,
|
||||
// if t's core type is a pointer; otherwise it returns t.
|
||||
//
|
||||
// Do not assume that Deref(T)==T implies T is not a pointer:
|
||||
// consider "type T *T", for example.
|
||||
//
|
||||
// TODO(adonovan): ideally this would live in typesinternal, but that
|
||||
// creates an import cycle. Move there when we melt this package down.
|
||||
func Deref(t types.Type) types.Type {
|
||||
if ptr, ok := CoreType(t).(*types.Pointer); ok {
|
||||
return ptr.Elem()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// MustDeref returns the type of the variable pointed to by t.
|
||||
// It panics if t's core type is not a pointer.
|
||||
//
|
||||
// TODO(adonovan): ideally this would live in typesinternal, but that
|
||||
// creates an import cycle. Move there when we melt this package down.
|
||||
func MustDeref(t types.Type) types.Type {
|
||||
if ptr, ok := CoreType(t).(*types.Pointer); ok {
|
||||
return ptr.Elem()
|
||||
}
|
||||
panic(fmt.Sprintf("%v is not a pointer", t))
|
||||
}
|
||||
|
|
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = false
|
15
vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
generated
vendored
15
vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
generated
vendored
|
@ -1,15 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
// Note: this constant is in a separate file as this is the only acceptable
|
||||
// diff between the <1.18 API of this package and the 1.18 API.
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = true
|
131
vendor/golang.org/x/tools/internal/typeparams/free.go
generated
vendored
Normal file
131
vendor/golang.org/x/tools/internal/typeparams/free.go
generated
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// Free is a memoization of the set of free type parameters within a
|
||||
// type. It makes a sequence of calls to [Free.Has] for overlapping
|
||||
// types more efficient. The zero value is ready for use.
|
||||
//
|
||||
// NOTE: Adapted from go/types/infer.go. If it is later exported, factor.
|
||||
type Free struct {
|
||||
seen map[types.Type]bool
|
||||
}
|
||||
|
||||
// Has reports whether the specified type has a free type parameter.
|
||||
func (w *Free) Has(typ types.Type) (res bool) {
|
||||
// detect cycles
|
||||
if x, ok := w.seen[typ]; ok {
|
||||
return x
|
||||
}
|
||||
if w.seen == nil {
|
||||
w.seen = make(map[types.Type]bool)
|
||||
}
|
||||
w.seen[typ] = false
|
||||
defer func() {
|
||||
w.seen[typ] = res
|
||||
}()
|
||||
|
||||
switch t := typ.(type) {
|
||||
case nil, *types.Basic: // TODO(gri) should nil be handled here?
|
||||
break
|
||||
|
||||
case *types.Alias:
|
||||
if aliases.TypeParams(t).Len() > aliases.TypeArgs(t).Len() {
|
||||
return true // This is an uninstantiated Alias.
|
||||
}
|
||||
// The expansion of an alias can have free type parameters,
|
||||
// whether or not the alias itself has type parameters:
|
||||
//
|
||||
// func _[K comparable]() {
|
||||
// type Set = map[K]bool // free(Set) = {K}
|
||||
// type MapTo[V] = map[K]V // free(Map[foo]) = {V}
|
||||
// }
|
||||
//
|
||||
// So, we must Unalias.
|
||||
return w.Has(types.Unalias(t))
|
||||
|
||||
case *types.Array:
|
||||
return w.Has(t.Elem())
|
||||
|
||||
case *types.Slice:
|
||||
return w.Has(t.Elem())
|
||||
|
||||
case *types.Struct:
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
if w.Has(t.Field(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Pointer:
|
||||
return w.Has(t.Elem())
|
||||
|
||||
case *types.Tuple:
|
||||
n := t.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
if w.Has(t.At(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Signature:
|
||||
// t.tparams may not be nil if we are looking at a signature
|
||||
// of a generic function type (or an interface method) that is
|
||||
// part of the type we're testing. We don't care about these type
|
||||
// parameters.
|
||||
// Similarly, the receiver of a method may declare (rather than
|
||||
// use) type parameters, we don't care about those either.
|
||||
// Thus, we only need to look at the input and result parameters.
|
||||
return w.Has(t.Params()) || w.Has(t.Results())
|
||||
|
||||
case *types.Interface:
|
||||
for i, n := 0, t.NumMethods(); i < n; i++ {
|
||||
if w.Has(t.Method(i).Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
terms, err := InterfaceTermSet(t)
|
||||
if err != nil {
|
||||
return false // ill typed
|
||||
}
|
||||
for _, term := range terms {
|
||||
if w.Has(term.Type()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case *types.Map:
|
||||
return w.Has(t.Key()) || w.Has(t.Elem())
|
||||
|
||||
case *types.Chan:
|
||||
return w.Has(t.Elem())
|
||||
|
||||
case *types.Named:
|
||||
args := t.TypeArgs()
|
||||
if params := t.TypeParams(); params.Len() > args.Len() {
|
||||
return true // this is an uninstantiated named type.
|
||||
}
|
||||
for i, n := 0, args.Len(); i < n; i++ {
|
||||
if w.Has(args.At(i)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return w.Has(t.Underlying()) // recurse for types local to parameterized functions
|
||||
|
||||
case *types.TypeParam:
|
||||
return true
|
||||
|
||||
default:
|
||||
panic(t) // unreachable
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
20
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
20
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
|
@ -60,7 +60,7 @@ var ErrEmptyTypeSet = errors.New("empty type set")
|
|||
//
|
||||
// StructuralTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
|
||||
func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) {
|
||||
constraint := tparam.Constraint()
|
||||
if constraint == nil {
|
||||
return nil, fmt.Errorf("%s has nil constraint", tparam)
|
||||
|
@ -78,7 +78,7 @@ func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
|
|||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
|
||||
func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) {
|
||||
return computeTermSet(iface)
|
||||
}
|
||||
|
||||
|
@ -88,11 +88,11 @@ func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
|
|||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func UnionTermSet(union *Union) ([]*Term, error) {
|
||||
func UnionTermSet(union *types.Union) ([]*types.Term, error) {
|
||||
return computeTermSet(union)
|
||||
}
|
||||
|
||||
func computeTermSet(typ types.Type) ([]*Term, error) {
|
||||
func computeTermSet(typ types.Type) ([]*types.Term, error) {
|
||||
tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -103,9 +103,9 @@ func computeTermSet(typ types.Type) ([]*Term, error) {
|
|||
if tset.terms.isAll() {
|
||||
return nil, nil
|
||||
}
|
||||
var terms []*Term
|
||||
var terms []*types.Term
|
||||
for _, term := range tset.terms {
|
||||
terms = append(terms, NewTerm(term.tilde, term.typ))
|
||||
terms = append(terms, types.NewTerm(term.tilde, term.typ))
|
||||
}
|
||||
return terms, nil
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
|
|||
tset.terms = allTermlist
|
||||
for i := 0; i < u.NumEmbeddeds(); i++ {
|
||||
embedded := u.EmbeddedType(i)
|
||||
if _, ok := embedded.Underlying().(*TypeParam); ok {
|
||||
if _, ok := embedded.Underlying().(*types.TypeParam); ok {
|
||||
return nil, fmt.Errorf("invalid embedded type %T", embedded)
|
||||
}
|
||||
tset2, err := computeTermSetInternal(embedded, seen, depth+1)
|
||||
|
@ -171,7 +171,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
|
|||
}
|
||||
tset.terms = tset.terms.intersect(tset2.terms)
|
||||
}
|
||||
case *Union:
|
||||
case *types.Union:
|
||||
// The term set of a union is the union of term sets of its terms.
|
||||
tset.terms = nil
|
||||
for i := 0; i < u.Len(); i++ {
|
||||
|
@ -184,7 +184,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
|
|||
return nil, err
|
||||
}
|
||||
terms = tset2.terms
|
||||
case *TypeParam, *Union:
|
||||
case *types.TypeParam, *types.Union:
|
||||
// A stand-alone type parameter or union is not permitted as union
|
||||
// term.
|
||||
return nil, fmt.Errorf("invalid union term %T", t)
|
||||
|
@ -199,7 +199,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
|
|||
return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
|
||||
}
|
||||
}
|
||||
case *TypeParam:
|
||||
case *types.TypeParam:
|
||||
panic("unreachable")
|
||||
default:
|
||||
// For all other types, the term set is just a single non-tilde term
|
||||
|
|
2
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
2
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
|
@ -30,7 +30,7 @@ func (xl termlist) String() string {
|
|||
var buf bytes.Buffer
|
||||
for i, x := range xl {
|
||||
if i > 0 {
|
||||
buf.WriteString(" ∪ ")
|
||||
buf.WriteString(" | ")
|
||||
}
|
||||
buf.WriteString(x.String())
|
||||
}
|
||||
|
|
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
|
@ -1,197 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
func unsupported() {
|
||||
panic("type parameters are unsupported at this go version")
|
||||
}
|
||||
|
||||
// IndexListExpr is a placeholder type, as type parameters are not supported at
|
||||
// this Go version. Its methods panic on use.
|
||||
type IndexListExpr struct {
|
||||
ast.Expr
|
||||
X ast.Expr // expression
|
||||
Lbrack token.Pos // position of "["
|
||||
Indices []ast.Expr // index expressions
|
||||
Rbrack token.Pos // position of "]"
|
||||
}
|
||||
|
||||
// ForTypeSpec returns an empty field list, as type parameters on not supported
|
||||
// at this Go version.
|
||||
func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForFuncType returns an empty field list, as type parameters are not
|
||||
// supported at this Go version.
|
||||
func ForFuncType(*ast.FuncType) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TypeParam is a placeholder type, as type parameters are not supported at
|
||||
// this Go version. Its methods panic on use.
|
||||
type TypeParam struct{ types.Type }
|
||||
|
||||
func (*TypeParam) Index() int { unsupported(); return 0 }
|
||||
func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
|
||||
func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil }
|
||||
|
||||
// TypeParamList is a placeholder for an empty type parameter list.
|
||||
type TypeParamList struct{}
|
||||
|
||||
func (*TypeParamList) Len() int { return 0 }
|
||||
func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil }
|
||||
|
||||
// TypeList is a placeholder for an empty type list.
|
||||
type TypeList struct{}
|
||||
|
||||
func (*TypeList) Len() int { return 0 }
|
||||
func (*TypeList) At(int) types.Type { unsupported(); return nil }
|
||||
|
||||
// NewTypeParam is unsupported at this Go version, and panics.
|
||||
func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
|
||||
unsupported()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTypeParamConstraint is unsupported at this Go version, and panics.
|
||||
func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or
|
||||
// typeParams is non-empty.
|
||||
func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
|
||||
if len(recvTypeParams) != 0 || len(typeParams) != 0 {
|
||||
panic("signatures cannot have type parameters at this Go version")
|
||||
}
|
||||
return types.NewSignature(recv, params, results, variadic)
|
||||
}
|
||||
|
||||
// ForSignature returns an empty slice.
|
||||
func ForSignature(*types.Signature) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecvTypeParams returns a nil slice.
|
||||
func RecvTypeParams(sig *types.Signature) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsComparable returns false, as no interfaces are type-restricted at this Go
|
||||
// version.
|
||||
func IsComparable(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMethodSet returns true, as no interfaces are type-restricted at this Go
|
||||
// version.
|
||||
func IsMethodSet(*types.Interface) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsImplicit returns false, as no interfaces are implicit at this Go version.
|
||||
func IsImplicit(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// MarkImplicit does nothing, because this Go version does not have implicit
|
||||
// interfaces.
|
||||
func MarkImplicit(*types.Interface) {}
|
||||
|
||||
// ForNamed returns an empty type parameter list, as type parameters are not
|
||||
// supported at this Go version.
|
||||
func ForNamed(*types.Named) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetForNamed panics if tparams is non-empty.
|
||||
func SetForNamed(_ *types.Named, tparams []*TypeParam) {
|
||||
if len(tparams) > 0 {
|
||||
unsupported()
|
||||
}
|
||||
}
|
||||
|
||||
// NamedTypeArgs returns nil.
|
||||
func NamedTypeArgs(*types.Named) *TypeList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedTypeOrigin is the identity method at this Go version.
|
||||
func NamedTypeOrigin(named *types.Named) types.Type {
|
||||
return named
|
||||
}
|
||||
|
||||
// Term holds information about a structural type restriction.
|
||||
type Term struct {
|
||||
tilde bool
|
||||
typ types.Type
|
||||
}
|
||||
|
||||
func (m *Term) Tilde() bool { return m.tilde }
|
||||
func (m *Term) Type() types.Type { return m.typ }
|
||||
func (m *Term) String() string {
|
||||
pre := ""
|
||||
if m.tilde {
|
||||
pre = "~"
|
||||
}
|
||||
return pre + m.typ.String()
|
||||
}
|
||||
|
||||
// NewTerm is unsupported at this Go version, and panics.
|
||||
func NewTerm(tilde bool, typ types.Type) *Term {
|
||||
return &Term{tilde, typ}
|
||||
}
|
||||
|
||||
// Union is a placeholder type, as type parameters are not supported at this Go
|
||||
// version. Its methods panic on use.
|
||||
type Union struct{ types.Type }
|
||||
|
||||
func (*Union) Len() int { return 0 }
|
||||
func (*Union) Term(i int) *Term { unsupported(); return nil }
|
||||
|
||||
// NewUnion is unsupported at this Go version, and panics.
|
||||
func NewUnion(terms []*Term) *Union {
|
||||
unsupported()
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitInstanceInfo is a noop at this Go version.
|
||||
func InitInstanceInfo(*types.Info) {}
|
||||
|
||||
// Instance is a placeholder type, as type parameters are not supported at this
|
||||
// Go version.
|
||||
type Instance struct {
|
||||
TypeArgs *TypeList
|
||||
Type types.Type
|
||||
}
|
||||
|
||||
// GetInstances returns a nil map, as type parameters are not supported at this
|
||||
// Go version.
|
||||
func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil }
|
||||
|
||||
// Context is a placeholder type, as type parameters are not supported at
|
||||
// this Go version.
|
||||
type Context struct{}
|
||||
|
||||
// NewContext returns a placeholder Context instance.
|
||||
func NewContext() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
||||
// Instantiate is unsupported on this Go version, and panics.
|
||||
func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
|
||||
unsupported()
|
||||
return nil, nil
|
||||
}
|
151
vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
generated
vendored
151
vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
generated
vendored
|
@ -1,151 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// IndexListExpr is an alias for ast.IndexListExpr.
|
||||
type IndexListExpr = ast.IndexListExpr
|
||||
|
||||
// ForTypeSpec returns n.TypeParams.
|
||||
func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return n.TypeParams
|
||||
}
|
||||
|
||||
// ForFuncType returns n.TypeParams.
|
||||
func ForFuncType(n *ast.FuncType) *ast.FieldList {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return n.TypeParams
|
||||
}
|
||||
|
||||
// TypeParam is an alias for types.TypeParam
|
||||
type TypeParam = types.TypeParam
|
||||
|
||||
// TypeParamList is an alias for types.TypeParamList
|
||||
type TypeParamList = types.TypeParamList
|
||||
|
||||
// TypeList is an alias for types.TypeList
|
||||
type TypeList = types.TypeList
|
||||
|
||||
// NewTypeParam calls types.NewTypeParam.
|
||||
func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
|
||||
return types.NewTypeParam(name, constraint)
|
||||
}
|
||||
|
||||
// SetTypeParamConstraint calls tparam.SetConstraint(constraint).
|
||||
func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
|
||||
tparam.SetConstraint(constraint)
|
||||
}
|
||||
|
||||
// NewSignatureType calls types.NewSignatureType.
|
||||
func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
|
||||
return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic)
|
||||
}
|
||||
|
||||
// ForSignature returns sig.TypeParams()
|
||||
func ForSignature(sig *types.Signature) *TypeParamList {
|
||||
return sig.TypeParams()
|
||||
}
|
||||
|
||||
// RecvTypeParams returns sig.RecvTypeParams().
|
||||
func RecvTypeParams(sig *types.Signature) *TypeParamList {
|
||||
return sig.RecvTypeParams()
|
||||
}
|
||||
|
||||
// IsComparable calls iface.IsComparable().
|
||||
func IsComparable(iface *types.Interface) bool {
|
||||
return iface.IsComparable()
|
||||
}
|
||||
|
||||
// IsMethodSet calls iface.IsMethodSet().
|
||||
func IsMethodSet(iface *types.Interface) bool {
|
||||
return iface.IsMethodSet()
|
||||
}
|
||||
|
||||
// IsImplicit calls iface.IsImplicit().
|
||||
func IsImplicit(iface *types.Interface) bool {
|
||||
return iface.IsImplicit()
|
||||
}
|
||||
|
||||
// MarkImplicit calls iface.MarkImplicit().
|
||||
func MarkImplicit(iface *types.Interface) {
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
|
||||
// ForNamed extracts the (possibly empty) type parameter object list from
|
||||
// named.
|
||||
func ForNamed(named *types.Named) *TypeParamList {
|
||||
return named.TypeParams()
|
||||
}
|
||||
|
||||
// SetForNamed sets the type params tparams on n. Each tparam must be of
|
||||
// dynamic type *types.TypeParam.
|
||||
func SetForNamed(n *types.Named, tparams []*TypeParam) {
|
||||
n.SetTypeParams(tparams)
|
||||
}
|
||||
|
||||
// NamedTypeArgs returns named.TypeArgs().
|
||||
func NamedTypeArgs(named *types.Named) *TypeList {
|
||||
return named.TypeArgs()
|
||||
}
|
||||
|
||||
// NamedTypeOrigin returns named.Orig().
|
||||
func NamedTypeOrigin(named *types.Named) types.Type {
|
||||
return named.Origin()
|
||||
}
|
||||
|
||||
// Term is an alias for types.Term.
|
||||
type Term = types.Term
|
||||
|
||||
// NewTerm calls types.NewTerm.
|
||||
func NewTerm(tilde bool, typ types.Type) *Term {
|
||||
return types.NewTerm(tilde, typ)
|
||||
}
|
||||
|
||||
// Union is an alias for types.Union
|
||||
type Union = types.Union
|
||||
|
||||
// NewUnion calls types.NewUnion.
|
||||
func NewUnion(terms []*Term) *Union {
|
||||
return types.NewUnion(terms)
|
||||
}
|
||||
|
||||
// InitInstanceInfo initializes info to record information about type and
|
||||
// function instances.
|
||||
func InitInstanceInfo(info *types.Info) {
|
||||
info.Instances = make(map[*ast.Ident]types.Instance)
|
||||
}
|
||||
|
||||
// Instance is an alias for types.Instance.
|
||||
type Instance = types.Instance
|
||||
|
||||
// GetInstances returns info.Instances.
|
||||
func GetInstances(info *types.Info) map[*ast.Ident]Instance {
|
||||
return info.Instances
|
||||
}
|
||||
|
||||
// Context is an alias for types.Context.
|
||||
type Context = types.Context
|
||||
|
||||
// NewContext calls types.NewContext.
|
||||
func NewContext() *Context {
|
||||
return types.NewContext()
|
||||
}
|
||||
|
||||
// Instantiate calls types.Instantiate.
|
||||
func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
|
||||
return types.Instantiate(ctxt, typ, targs, validate)
|
||||
}
|
9
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
9
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
|
@ -10,11 +10,10 @@ import "go/types"
|
|||
|
||||
// A term describes elementary type sets:
|
||||
//
|
||||
// ∅: (*term)(nil) == ∅ // set of no types (empty set)
|
||||
// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse)
|
||||
// T: &term{false, T} == {T} // set of type T
|
||||
// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t
|
||||
//
|
||||
// ∅: (*term)(nil) == ∅ // set of no types (empty set)
|
||||
// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse)
|
||||
// T: &term{false, T} == {T} // set of type T
|
||||
// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t
|
||||
type term struct {
|
||||
tilde bool // valid if typ != nil
|
||||
typ types.Type
|
||||
|
|
133
vendor/golang.org/x/tools/internal/typesinternal/element.go
generated
vendored
Normal file
133
vendor/golang.org/x/tools/internal/typesinternal/element.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
)
|
||||
|
||||
// ForEachElement calls f for type T and each type reachable from its
|
||||
// type through reflection. It does this by recursively stripping off
|
||||
// type constructors; in addition, for each named type N, the type *N
|
||||
// is added to the result as it may have additional methods.
|
||||
//
|
||||
// The caller must provide an initially empty set used to de-duplicate
|
||||
// identical types, potentially across multiple calls to ForEachElement.
|
||||
// (Its final value holds all the elements seen, matching the arguments
|
||||
// passed to f.)
|
||||
//
|
||||
// TODO(adonovan): share/harmonize with go/callgraph/rta.
|
||||
func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T types.Type, f func(types.Type)) {
|
||||
var visit func(T types.Type, skip bool)
|
||||
visit = func(T types.Type, skip bool) {
|
||||
if !skip {
|
||||
if seen, _ := rtypes.Set(T, true).(bool); seen {
|
||||
return // de-dup
|
||||
}
|
||||
|
||||
f(T) // notify caller of new element type
|
||||
}
|
||||
|
||||
// Recursion over signatures of each method.
|
||||
tmset := msets.MethodSet(T)
|
||||
for i := 0; i < tmset.Len(); i++ {
|
||||
sig := tmset.At(i).Type().(*types.Signature)
|
||||
// It is tempting to call visit(sig, false)
|
||||
// but, as noted in golang.org/cl/65450043,
|
||||
// the Signature.Recv field is ignored by
|
||||
// types.Identical and typeutil.Map, which
|
||||
// is confusing at best.
|
||||
//
|
||||
// More importantly, the true signature rtype
|
||||
// reachable from a method using reflection
|
||||
// has no receiver but an extra ordinary parameter.
|
||||
// For the Read method of io.Reader we want:
|
||||
// func(Reader, []byte) (int, error)
|
||||
// but here sig is:
|
||||
// func([]byte) (int, error)
|
||||
// with .Recv = Reader (though it is hard to
|
||||
// notice because it doesn't affect Signature.String
|
||||
// or types.Identical).
|
||||
//
|
||||
// TODO(adonovan): construct and visit the correct
|
||||
// non-method signature with an extra parameter
|
||||
// (though since unnamed func types have no methods
|
||||
// there is essentially no actual demand for this).
|
||||
//
|
||||
// TODO(adonovan): document whether or not it is
|
||||
// safe to skip non-exported methods (as RTA does).
|
||||
visit(sig.Params(), true) // skip the Tuple
|
||||
visit(sig.Results(), true) // skip the Tuple
|
||||
}
|
||||
|
||||
switch T := T.(type) {
|
||||
case *types.Alias:
|
||||
visit(types.Unalias(T), skip) // emulates the pre-Alias behavior
|
||||
|
||||
case *types.Basic:
|
||||
// nop
|
||||
|
||||
case *types.Interface:
|
||||
// nop---handled by recursion over method set.
|
||||
|
||||
case *types.Pointer:
|
||||
visit(T.Elem(), false)
|
||||
|
||||
case *types.Slice:
|
||||
visit(T.Elem(), false)
|
||||
|
||||
case *types.Chan:
|
||||
visit(T.Elem(), false)
|
||||
|
||||
case *types.Map:
|
||||
visit(T.Key(), false)
|
||||
visit(T.Elem(), false)
|
||||
|
||||
case *types.Signature:
|
||||
if T.Recv() != nil {
|
||||
panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv()))
|
||||
}
|
||||
visit(T.Params(), true) // skip the Tuple
|
||||
visit(T.Results(), true) // skip the Tuple
|
||||
|
||||
case *types.Named:
|
||||
// A pointer-to-named type can be derived from a named
|
||||
// type via reflection. It may have methods too.
|
||||
visit(types.NewPointer(T), false)
|
||||
|
||||
// Consider 'type T struct{S}' where S has methods.
|
||||
// Reflection provides no way to get from T to struct{S},
|
||||
// only to S, so the method set of struct{S} is unwanted,
|
||||
// so set 'skip' flag during recursion.
|
||||
visit(T.Underlying(), true) // skip the unnamed type
|
||||
|
||||
case *types.Array:
|
||||
visit(T.Elem(), false)
|
||||
|
||||
case *types.Struct:
|
||||
for i, n := 0, T.NumFields(); i < n; i++ {
|
||||
// TODO(adonovan): document whether or not
|
||||
// it is safe to skip non-exported fields.
|
||||
visit(T.Field(i).Type(), false)
|
||||
}
|
||||
|
||||
case *types.Tuple:
|
||||
for i, n := 0, T.Len(); i < n; i++ {
|
||||
visit(T.At(i).Type(), false)
|
||||
}
|
||||
|
||||
case *types.TypeParam, *types.Union:
|
||||
// forEachReachable must not be called on parameterized types.
|
||||
panic(T)
|
||||
|
||||
default:
|
||||
panic(T)
|
||||
}
|
||||
}
|
||||
visit(T, false)
|
||||
}
|
52
vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
generated
vendored
52
vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
generated
vendored
|
@ -30,6 +30,12 @@ type ErrorCode int
|
|||
// convention that "bad" implies a problem with syntax, and "invalid" implies a
|
||||
// problem with types.
|
||||
|
||||
const (
|
||||
// InvalidSyntaxTree occurs if an invalid syntax tree is provided
|
||||
// to the type checker. It should never happen.
|
||||
InvalidSyntaxTree ErrorCode = -1
|
||||
)
|
||||
|
||||
const (
|
||||
_ ErrorCode = iota
|
||||
|
||||
|
@ -153,15 +159,15 @@ const (
|
|||
|
||||
/* decls > var (+ other variable assignment codes) */
|
||||
|
||||
// UntypedNil occurs when the predeclared (untyped) value nil is used to
|
||||
// UntypedNilUse occurs when the predeclared (untyped) value nil is used to
|
||||
// initialize a variable declared without an explicit type.
|
||||
//
|
||||
// Example:
|
||||
// var x = nil
|
||||
UntypedNil
|
||||
UntypedNilUse
|
||||
|
||||
// WrongAssignCount occurs when the number of values on the right-hand side
|
||||
// of an assignment or or initialization expression does not match the number
|
||||
// of an assignment or initialization expression does not match the number
|
||||
// of variables on the left-hand side.
|
||||
//
|
||||
// Example:
|
||||
|
@ -832,7 +838,7 @@ const (
|
|||
// InvalidCap occurs when an argument to the cap built-in function is not of
|
||||
// supported type.
|
||||
//
|
||||
// See https://golang.org/ref/spec#Lengthand_capacity for information on
|
||||
// See https://golang.org/ref/spec#Length_and_capacity for information on
|
||||
// which underlying types are supported as arguments to cap and len.
|
||||
//
|
||||
// Example:
|
||||
|
@ -853,7 +859,7 @@ const (
|
|||
// InvalidCopy occurs when the arguments are not of slice type or do not
|
||||
// have compatible type.
|
||||
//
|
||||
// See https://golang.org/ref/spec#Appendingand_copying_slices for more
|
||||
// See https://golang.org/ref/spec#Appending_and_copying_slices for more
|
||||
// information on the type requirements for the copy built-in.
|
||||
//
|
||||
// Example:
|
||||
|
@ -891,7 +897,7 @@ const (
|
|||
// InvalidLen occurs when an argument to the len built-in function is not of
|
||||
// supported type.
|
||||
//
|
||||
// See https://golang.org/ref/spec#Lengthand_capacity for information on
|
||||
// See https://golang.org/ref/spec#Length_and_capacity for information on
|
||||
// which underlying types are supported as arguments to cap and len.
|
||||
//
|
||||
// Example:
|
||||
|
@ -908,7 +914,7 @@ const (
|
|||
|
||||
// InvalidMake occurs when make is called with an unsupported type argument.
|
||||
//
|
||||
// See https://golang.org/ref/spec#Makingslices_maps_and_channels for
|
||||
// See https://golang.org/ref/spec#Making_slices_maps_and_channels for
|
||||
// information on the types that may be created using make.
|
||||
//
|
||||
// Example:
|
||||
|
@ -1443,10 +1449,10 @@ const (
|
|||
NotAGenericType
|
||||
|
||||
// WrongTypeArgCount occurs when a type or function is instantiated with an
|
||||
// incorrent number of type arguments, including when a generic type or
|
||||
// incorrect number of type arguments, including when a generic type or
|
||||
// function is used without instantiation.
|
||||
//
|
||||
// Errors inolving failed type inference are assigned other error codes.
|
||||
// Errors involving failed type inference are assigned other error codes.
|
||||
//
|
||||
// Example:
|
||||
// type T[p any] int
|
||||
|
@ -1523,4 +1529,32 @@ const (
|
|||
// Example:
|
||||
// type T[P any] struct{ *P }
|
||||
MisplacedTypeParam
|
||||
|
||||
// InvalidUnsafeSliceData occurs when unsafe.SliceData is called with
|
||||
// an argument that is not of slice type. It also occurs if it is used
|
||||
// in a package compiled for a language version before go1.20.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.SliceData(x)
|
||||
InvalidUnsafeSliceData
|
||||
|
||||
// InvalidUnsafeString occurs when unsafe.String is called with
|
||||
// a length argument that is not of integer type, negative, or
|
||||
// out of bounds. It also occurs if it is used in a package
|
||||
// compiled for a language version before go1.20.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var b [10]byte
|
||||
// var _ = unsafe.String(&b[0], -1)
|
||||
InvalidUnsafeString
|
||||
|
||||
// InvalidUnsafeStringData occurs if it is used in a package
|
||||
// compiled for a language version before go1.20.
|
||||
_ // not used anymore
|
||||
|
||||
)
|
||||
|
|
26
vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go
generated
vendored
26
vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go
generated
vendored
|
@ -8,6 +8,7 @@ func _() {
|
|||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[InvalidSyntaxTree - -1]
|
||||
_ = x[Test-1]
|
||||
_ = x[BlankPkgName-2]
|
||||
_ = x[MismatchedPkgName-3]
|
||||
|
@ -23,7 +24,7 @@ func _() {
|
|||
_ = x[InvalidConstInit-13]
|
||||
_ = x[InvalidConstVal-14]
|
||||
_ = x[InvalidConstType-15]
|
||||
_ = x[UntypedNil-16]
|
||||
_ = x[UntypedNilUse-16]
|
||||
_ = x[WrongAssignCount-17]
|
||||
_ = x[UnassignableOperand-18]
|
||||
_ = x[NoNewVar-19]
|
||||
|
@ -152,16 +153,27 @@ func _() {
|
|||
_ = x[MisplacedConstraintIface-142]
|
||||
_ = x[InvalidMethodTypeParams-143]
|
||||
_ = x[MisplacedTypeParam-144]
|
||||
_ = x[InvalidUnsafeSliceData-145]
|
||||
_ = x[InvalidUnsafeString-146]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParam"
|
||||
const (
|
||||
_ErrorCode_name_0 = "InvalidSyntaxTree"
|
||||
_ErrorCode_name_1 = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilUseWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
|
||||
)
|
||||
|
||||
var _ErrorCode_index = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 215, 231, 250, 258, 274, 292, 309, 327, 351, 359, 374, 390, 408, 425, 440, 447, 458, 481, 496, 508, 519, 534, 548, 563, 578, 591, 600, 614, 629, 640, 655, 664, 680, 700, 718, 737, 749, 768, 787, 803, 820, 839, 853, 864, 879, 892, 907, 923, 937, 953, 968, 985, 1003, 1018, 1028, 1038, 1055, 1077, 1091, 1105, 1125, 1143, 1163, 1181, 1204, 1220, 1235, 1248, 1258, 1270, 1281, 1295, 1308, 1319, 1329, 1344, 1355, 1366, 1379, 1395, 1412, 1436, 1453, 1468, 1478, 1487, 1500, 1516, 1532, 1543, 1558, 1574, 1588, 1604, 1618, 1635, 1655, 1668, 1684, 1698, 1715, 1732, 1749, 1764, 1778, 1792, 1803, 1815, 1828, 1845, 1858, 1869, 1882, 1894, 1903, 1910, 1922, 1938, 1956, 1974, 1989, 2006, 2025, 2039, 2059, 2071, 2095, 2118, 2136}
|
||||
var (
|
||||
_ErrorCode_index_1 = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 218, 234, 253, 261, 277, 295, 312, 330, 354, 362, 377, 393, 411, 428, 443, 450, 461, 484, 499, 511, 522, 537, 551, 566, 581, 594, 603, 617, 632, 643, 658, 667, 683, 703, 721, 740, 752, 771, 790, 806, 823, 842, 856, 867, 882, 895, 910, 926, 940, 956, 971, 988, 1006, 1021, 1031, 1041, 1058, 1080, 1094, 1108, 1128, 1146, 1166, 1184, 1207, 1223, 1238, 1251, 1261, 1273, 1284, 1298, 1311, 1322, 1332, 1347, 1358, 1369, 1382, 1398, 1415, 1439, 1456, 1471, 1481, 1490, 1503, 1519, 1535, 1546, 1561, 1577, 1591, 1607, 1621, 1638, 1658, 1671, 1687, 1701, 1718, 1735, 1752, 1767, 1781, 1795, 1806, 1818, 1831, 1848, 1861, 1872, 1885, 1897, 1906, 1913, 1925, 1941, 1959, 1977, 1992, 2009, 2028, 2042, 2062, 2074, 2098, 2121, 2139, 2161, 2180}
|
||||
)
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 1
|
||||
if i < 0 || i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
switch {
|
||||
case i == -1:
|
||||
return _ErrorCode_name_0
|
||||
case 1 <= i && i <= 146:
|
||||
i -= 1
|
||||
return _ErrorCode_name_1[_ErrorCode_index_1[i]:_ErrorCode_index_1[i+1]]
|
||||
default:
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
|
|
46
vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
generated
vendored
Normal file
46
vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// FileQualifier returns a [types.Qualifier] function that qualifies
|
||||
// imported symbols appropriately based on the import environment of a given
|
||||
// file.
|
||||
// If the same package is imported multiple times, the last appearance is
|
||||
// recorded.
|
||||
func FileQualifier(f *ast.File, pkg *types.Package) types.Qualifier {
|
||||
// Construct mapping of import paths to their defined names.
|
||||
// It is only necessary to look at renaming imports.
|
||||
imports := make(map[string]string)
|
||||
for _, imp := range f.Imports {
|
||||
if imp.Name != nil && imp.Name.Name != "_" {
|
||||
path, _ := strconv.Unquote(imp.Path.Value)
|
||||
imports[path] = imp.Name.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Define qualifier to replace full package paths with names of the imports.
|
||||
return func(p *types.Package) string {
|
||||
if p == nil || p == pkg {
|
||||
return ""
|
||||
}
|
||||
|
||||
if name, ok := imports[p.Path()]; ok {
|
||||
if name == "." {
|
||||
return ""
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no local renaming, fall back to the package name.
|
||||
return p.Name()
|
||||
}
|
||||
}
|
43
vendor/golang.org/x/tools/internal/typesinternal/recv.go
generated
vendored
Normal file
43
vendor/golang.org/x/tools/internal/typesinternal/recv.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// ReceiverNamed returns the named type (if any) associated with the
|
||||
// type of recv, which may be of the form N or *N, or aliases thereof.
|
||||
// It also reports whether a Pointer was present.
|
||||
//
|
||||
// The named result may be nil in ill-typed code.
|
||||
func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) {
|
||||
t := recv.Type()
|
||||
if ptr, ok := types.Unalias(t).(*types.Pointer); ok {
|
||||
isPtr = true
|
||||
t = ptr.Elem()
|
||||
}
|
||||
named, _ = types.Unalias(t).(*types.Named)
|
||||
return
|
||||
}
|
||||
|
||||
// Unpointer returns T given *T or an alias thereof.
|
||||
// For all other types it is the identity function.
|
||||
// It does not look at underlying types.
|
||||
// The result may be an alias.
|
||||
//
|
||||
// Use this function to strip off the optional pointer on a receiver
|
||||
// in a field or method selection, without losing the named type
|
||||
// (which is needed to compute the method set).
|
||||
//
|
||||
// See also [typeparams.MustDeref], which removes one level of
|
||||
// indirection from the type, regardless of named types (analogous to
|
||||
// a LOAD instruction).
|
||||
func Unpointer(t types.Type) types.Type {
|
||||
if ptr, ok := types.Unalias(t).(*types.Pointer); ok {
|
||||
return ptr.Elem()
|
||||
}
|
||||
return t
|
||||
}
|
89
vendor/golang.org/x/tools/internal/typesinternal/toonew.go
generated
vendored
Normal file
89
vendor/golang.org/x/tools/internal/typesinternal/toonew.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/stdlib"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
// TooNewStdSymbols computes the set of package-level symbols
|
||||
// exported by pkg that are not available at the specified version.
|
||||
// The result maps each symbol to its minimum version.
|
||||
//
|
||||
// The pkg is allowed to contain type errors.
|
||||
func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]string {
|
||||
disallowed := make(map[types.Object]string)
|
||||
|
||||
// Pass 1: package-level symbols.
|
||||
symbols := stdlib.PackageSymbols[pkg.Path()]
|
||||
for _, sym := range symbols {
|
||||
symver := sym.Version.String()
|
||||
if versions.Before(version, symver) {
|
||||
switch sym.Kind {
|
||||
case stdlib.Func, stdlib.Var, stdlib.Const, stdlib.Type:
|
||||
disallowed[pkg.Scope().Lookup(sym.Name)] = symver
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 2: fields and methods.
|
||||
//
|
||||
// We allow fields and methods if their associated type is
|
||||
// disallowed, as otherwise we would report false positives
|
||||
// for compatibility shims. Consider:
|
||||
//
|
||||
// //go:build go1.22
|
||||
// type T struct { F std.Real } // correct new API
|
||||
//
|
||||
// //go:build !go1.22
|
||||
// type T struct { F fake } // shim
|
||||
// type fake struct { ... }
|
||||
// func (fake) M () {}
|
||||
//
|
||||
// These alternative declarations of T use either the std.Real
|
||||
// type, introduced in go1.22, or a fake type, for the field
|
||||
// F. (The fakery could be arbitrarily deep, involving more
|
||||
// nested fields and methods than are shown here.) Clients
|
||||
// that use the compatibility shim T will compile with any
|
||||
// version of go, whether older or newer than go1.22, but only
|
||||
// the newer version will use the std.Real implementation.
|
||||
//
|
||||
// Now consider a reference to method M in new(T).F.M() in a
|
||||
// module that requires a minimum of go1.21. The analysis may
|
||||
// occur using a version of Go higher than 1.21, selecting the
|
||||
// first version of T, so the method M is Real.M. This would
|
||||
// spuriously cause the analyzer to report a reference to a
|
||||
// too-new symbol even though this expression compiles just
|
||||
// fine (with the fake implementation) using go1.21.
|
||||
for _, sym := range symbols {
|
||||
symVersion := sym.Version.String()
|
||||
if !versions.Before(version, symVersion) {
|
||||
continue // allowed
|
||||
}
|
||||
|
||||
var obj types.Object
|
||||
switch sym.Kind {
|
||||
case stdlib.Field:
|
||||
typename, name := sym.SplitField()
|
||||
if t := pkg.Scope().Lookup(typename); t != nil && disallowed[t] == "" {
|
||||
obj, _, _ = types.LookupFieldOrMethod(t.Type(), false, pkg, name)
|
||||
}
|
||||
|
||||
case stdlib.Method:
|
||||
ptr, recvname, name := sym.SplitMethod()
|
||||
if t := pkg.Scope().Lookup(recvname); t != nil && disallowed[t] == "" {
|
||||
obj, _, _ = types.LookupFieldOrMethod(t.Type(), ptr, pkg, name)
|
||||
}
|
||||
}
|
||||
if obj != nil {
|
||||
disallowed[obj] = symVersion
|
||||
}
|
||||
}
|
||||
|
||||
return disallowed
|
||||
}
|
72
vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
72
vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
|
@ -11,6 +11,8 @@ import (
|
|||
"go/types"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
func SetUsesCgo(conf *types.Config) bool {
|
||||
|
@ -49,4 +51,72 @@ func ReadGo116ErrorData(err types.Error) (code ErrorCode, start, end token.Pos,
|
|||
return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true
|
||||
}
|
||||
|
||||
var SetGoVersion = func(conf *types.Config, version string) bool { return false }
|
||||
// NameRelativeTo returns a types.Qualifier that qualifies members of
|
||||
// all packages other than pkg, using only the package name.
|
||||
// (By contrast, [types.RelativeTo] uses the complete package path,
|
||||
// which is often excessive.)
|
||||
//
|
||||
// If pkg is nil, it is equivalent to [*types.Package.Name].
|
||||
func NameRelativeTo(pkg *types.Package) types.Qualifier {
|
||||
return func(other *types.Package) string {
|
||||
if pkg != nil && pkg == other {
|
||||
return "" // same package; unqualified
|
||||
}
|
||||
return other.Name()
|
||||
}
|
||||
}
|
||||
|
||||
// A NamedOrAlias is a [types.Type] that is named (as
|
||||
// defined by the spec) and capable of bearing type parameters: it
|
||||
// abstracts aliases ([types.Alias]) and defined types
|
||||
// ([types.Named]).
|
||||
//
|
||||
// Every type declared by an explicit "type" declaration is a
|
||||
// NamedOrAlias. (Built-in type symbols may additionally
|
||||
// have type [types.Basic], which is not a NamedOrAlias,
|
||||
// though the spec regards them as "named".)
|
||||
//
|
||||
// NamedOrAlias cannot expose the Origin method, because
|
||||
// [types.Alias.Origin] and [types.Named.Origin] have different
|
||||
// (covariant) result types; use [Origin] instead.
|
||||
type NamedOrAlias interface {
|
||||
types.Type
|
||||
Obj() *types.TypeName
|
||||
// TODO(hxjiang): add method TypeArgs() *types.TypeList after stop supporting go1.22.
|
||||
}
|
||||
|
||||
// TypeParams is a light shim around t.TypeParams().
|
||||
// (go/types.Alias).TypeParams requires >= 1.23.
|
||||
func TypeParams(t NamedOrAlias) *types.TypeParamList {
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
return aliases.TypeParams(t)
|
||||
case *types.Named:
|
||||
return t.TypeParams()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TypeArgs is a light shim around t.TypeArgs().
|
||||
// (go/types.Alias).TypeArgs requires >= 1.23.
|
||||
func TypeArgs(t NamedOrAlias) *types.TypeList {
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
return aliases.TypeArgs(t)
|
||||
case *types.Named:
|
||||
return t.TypeArgs()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Origin returns the generic type of the Named or Alias type t if it
|
||||
// is instantiated, otherwise it returns t.
|
||||
func Origin(t NamedOrAlias) NamedOrAlias {
|
||||
switch t := t.(type) {
|
||||
case *types.Alias:
|
||||
return aliases.Origin(t)
|
||||
case *types.Named:
|
||||
return t.Origin()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
|
19
vendor/golang.org/x/tools/internal/typesinternal/types_118.go
generated
vendored
19
vendor/golang.org/x/tools/internal/typesinternal/types_118.go
generated
vendored
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetGoVersion = func(conf *types.Config, version string) bool {
|
||||
conf.GoVersion = version
|
||||
return true
|
||||
}
|
||||
}
|
392
vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
generated
vendored
Normal file
392
vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
generated
vendored
Normal file
|
@ -0,0 +1,392 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ZeroString returns the string representation of the zero value for any type t.
|
||||
// The boolean result indicates whether the type is or contains an invalid type
|
||||
// or a non-basic (constraint) interface type.
|
||||
//
|
||||
// Even for invalid input types, ZeroString may return a partially correct
|
||||
// string representation. The caller should use the returned isValid boolean
|
||||
// to determine the validity of the expression.
|
||||
//
|
||||
// When assigning to a wider type (such as 'any'), it's the caller's
|
||||
// responsibility to handle any necessary type conversions.
|
||||
//
|
||||
// This string can be used on the right-hand side of an assignment where the
|
||||
// left-hand side has that explicit type.
|
||||
// References to named types are qualified by an appropriate (optional)
|
||||
// qualifier function.
|
||||
// Exception: This does not apply to tuples. Their string representation is
|
||||
// informational only and cannot be used in an assignment.
|
||||
//
|
||||
// See [ZeroExpr] for a variant that returns an [ast.Expr].
|
||||
func ZeroString(t types.Type, qual types.Qualifier) (_ string, isValid bool) {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
switch {
|
||||
case t.Info()&types.IsBoolean != 0:
|
||||
return "false", true
|
||||
case t.Info()&types.IsNumeric != 0:
|
||||
return "0", true
|
||||
case t.Info()&types.IsString != 0:
|
||||
return `""`, true
|
||||
case t.Kind() == types.UnsafePointer:
|
||||
fallthrough
|
||||
case t.Kind() == types.UntypedNil:
|
||||
return "nil", true
|
||||
case t.Kind() == types.Invalid:
|
||||
return "invalid", false
|
||||
default:
|
||||
panic(fmt.Sprintf("ZeroString for unexpected type %v", t))
|
||||
}
|
||||
|
||||
case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
|
||||
return "nil", true
|
||||
|
||||
case *types.Interface:
|
||||
if !t.IsMethodSet() {
|
||||
return "invalid", false
|
||||
}
|
||||
return "nil", true
|
||||
|
||||
case *types.Named:
|
||||
switch under := t.Underlying().(type) {
|
||||
case *types.Struct, *types.Array:
|
||||
return types.TypeString(t, qual) + "{}", true
|
||||
default:
|
||||
return ZeroString(under, qual)
|
||||
}
|
||||
|
||||
case *types.Alias:
|
||||
switch t.Underlying().(type) {
|
||||
case *types.Struct, *types.Array:
|
||||
return types.TypeString(t, qual) + "{}", true
|
||||
default:
|
||||
// A type parameter can have alias but alias type's underlying type
|
||||
// can never be a type parameter.
|
||||
// Use types.Unalias to preserve the info of type parameter instead
|
||||
// of call Underlying() going right through and get the underlying
|
||||
// type of the type parameter which is always an interface.
|
||||
return ZeroString(types.Unalias(t), qual)
|
||||
}
|
||||
|
||||
case *types.Array, *types.Struct:
|
||||
return types.TypeString(t, qual) + "{}", true
|
||||
|
||||
case *types.TypeParam:
|
||||
// Assumes func new is not shadowed.
|
||||
return "*new(" + types.TypeString(t, qual) + ")", true
|
||||
|
||||
case *types.Tuple:
|
||||
// Tuples are not normal values.
|
||||
// We are currently format as "(t[0], ..., t[n])". Could be something else.
|
||||
isValid := true
|
||||
components := make([]string, t.Len())
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
comp, ok := ZeroString(t.At(i).Type(), qual)
|
||||
|
||||
components[i] = comp
|
||||
isValid = isValid && ok
|
||||
}
|
||||
return "(" + strings.Join(components, ", ") + ")", isValid
|
||||
|
||||
case *types.Union:
|
||||
// Variables of these types cannot be created, so it makes
|
||||
// no sense to ask for their zero value.
|
||||
panic(fmt.Sprintf("invalid type for a variable: %v", t))
|
||||
|
||||
default:
|
||||
panic(t) // unreachable.
|
||||
}
|
||||
}
|
||||
|
||||
// ZeroExpr returns the ast.Expr representation of the zero value for any type t.
|
||||
// The boolean result indicates whether the type is or contains an invalid type
|
||||
// or a non-basic (constraint) interface type.
|
||||
//
|
||||
// Even for invalid input types, ZeroExpr may return a partially correct ast.Expr
|
||||
// representation. The caller should use the returned isValid boolean to determine
|
||||
// the validity of the expression.
|
||||
//
|
||||
// This function is designed for types suitable for variables and should not be
|
||||
// used with Tuple or Union types.References to named types are qualified by an
|
||||
// appropriate (optional) qualifier function.
|
||||
//
|
||||
// See [ZeroString] for a variant that returns a string.
|
||||
func ZeroExpr(t types.Type, qual types.Qualifier) (_ ast.Expr, isValid bool) {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
switch {
|
||||
case t.Info()&types.IsBoolean != 0:
|
||||
return &ast.Ident{Name: "false"}, true
|
||||
case t.Info()&types.IsNumeric != 0:
|
||||
return &ast.BasicLit{Kind: token.INT, Value: "0"}, true
|
||||
case t.Info()&types.IsString != 0:
|
||||
return &ast.BasicLit{Kind: token.STRING, Value: `""`}, true
|
||||
case t.Kind() == types.UnsafePointer:
|
||||
fallthrough
|
||||
case t.Kind() == types.UntypedNil:
|
||||
return ast.NewIdent("nil"), true
|
||||
case t.Kind() == types.Invalid:
|
||||
return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false
|
||||
default:
|
||||
panic(fmt.Sprintf("ZeroExpr for unexpected type %v", t))
|
||||
}
|
||||
|
||||
case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
|
||||
return ast.NewIdent("nil"), true
|
||||
|
||||
case *types.Interface:
|
||||
if !t.IsMethodSet() {
|
||||
return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false
|
||||
}
|
||||
return ast.NewIdent("nil"), true
|
||||
|
||||
case *types.Named:
|
||||
switch under := t.Underlying().(type) {
|
||||
case *types.Struct, *types.Array:
|
||||
return &ast.CompositeLit{
|
||||
Type: TypeExpr(t, qual),
|
||||
}, true
|
||||
default:
|
||||
return ZeroExpr(under, qual)
|
||||
}
|
||||
|
||||
case *types.Alias:
|
||||
switch t.Underlying().(type) {
|
||||
case *types.Struct, *types.Array:
|
||||
return &ast.CompositeLit{
|
||||
Type: TypeExpr(t, qual),
|
||||
}, true
|
||||
default:
|
||||
return ZeroExpr(types.Unalias(t), qual)
|
||||
}
|
||||
|
||||
case *types.Array, *types.Struct:
|
||||
return &ast.CompositeLit{
|
||||
Type: TypeExpr(t, qual),
|
||||
}, true
|
||||
|
||||
case *types.TypeParam:
|
||||
return &ast.StarExpr{ // *new(T)
|
||||
X: &ast.CallExpr{
|
||||
// Assumes func new is not shadowed.
|
||||
Fun: ast.NewIdent("new"),
|
||||
Args: []ast.Expr{
|
||||
ast.NewIdent(t.Obj().Name()),
|
||||
},
|
||||
},
|
||||
}, true
|
||||
|
||||
case *types.Tuple:
|
||||
// Unlike ZeroString, there is no ast.Expr can express tuple by
|
||||
// "(t[0], ..., t[n])".
|
||||
panic(fmt.Sprintf("invalid type for a variable: %v", t))
|
||||
|
||||
case *types.Union:
|
||||
// Variables of these types cannot be created, so it makes
|
||||
// no sense to ask for their zero value.
|
||||
panic(fmt.Sprintf("invalid type for a variable: %v", t))
|
||||
|
||||
default:
|
||||
panic(t) // unreachable.
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroExpr uses simple syntactic heuristics to report whether expr
|
||||
// is a obvious zero value, such as 0, "", nil, or false.
|
||||
// It cannot do better without type information.
|
||||
func IsZeroExpr(expr ast.Expr) bool {
|
||||
switch e := expr.(type) {
|
||||
case *ast.BasicLit:
|
||||
return e.Value == "0" || e.Value == `""`
|
||||
case *ast.Ident:
|
||||
return e.Name == "nil" || e.Name == "false"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// TypeExpr returns syntax for the specified type. References to named types
|
||||
// are qualified by an appropriate (optional) qualifier function.
|
||||
// It may panic for types such as Tuple or Union.
|
||||
func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.UnsafePointer:
|
||||
return &ast.SelectorExpr{X: ast.NewIdent(qual(types.NewPackage("unsafe", "unsafe"))), Sel: ast.NewIdent("Pointer")}
|
||||
default:
|
||||
return ast.NewIdent(t.Name())
|
||||
}
|
||||
|
||||
case *types.Pointer:
|
||||
return &ast.UnaryExpr{
|
||||
Op: token.MUL,
|
||||
X: TypeExpr(t.Elem(), qual),
|
||||
}
|
||||
|
||||
case *types.Array:
|
||||
return &ast.ArrayType{
|
||||
Len: &ast.BasicLit{
|
||||
Kind: token.INT,
|
||||
Value: fmt.Sprintf("%d", t.Len()),
|
||||
},
|
||||
Elt: TypeExpr(t.Elem(), qual),
|
||||
}
|
||||
|
||||
case *types.Slice:
|
||||
return &ast.ArrayType{
|
||||
Elt: TypeExpr(t.Elem(), qual),
|
||||
}
|
||||
|
||||
case *types.Map:
|
||||
return &ast.MapType{
|
||||
Key: TypeExpr(t.Key(), qual),
|
||||
Value: TypeExpr(t.Elem(), qual),
|
||||
}
|
||||
|
||||
case *types.Chan:
|
||||
dir := ast.ChanDir(t.Dir())
|
||||
if t.Dir() == types.SendRecv {
|
||||
dir = ast.SEND | ast.RECV
|
||||
}
|
||||
return &ast.ChanType{
|
||||
Dir: dir,
|
||||
Value: TypeExpr(t.Elem(), qual),
|
||||
}
|
||||
|
||||
case *types.Signature:
|
||||
var params []*ast.Field
|
||||
for i := 0; i < t.Params().Len(); i++ {
|
||||
params = append(params, &ast.Field{
|
||||
Type: TypeExpr(t.Params().At(i).Type(), qual),
|
||||
Names: []*ast.Ident{
|
||||
{
|
||||
Name: t.Params().At(i).Name(),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if t.Variadic() {
|
||||
last := params[len(params)-1]
|
||||
last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt}
|
||||
}
|
||||
var returns []*ast.Field
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
returns = append(returns, &ast.Field{
|
||||
Type: TypeExpr(t.Results().At(i).Type(), qual),
|
||||
})
|
||||
}
|
||||
return &ast.FuncType{
|
||||
Params: &ast.FieldList{
|
||||
List: params,
|
||||
},
|
||||
Results: &ast.FieldList{
|
||||
List: returns,
|
||||
},
|
||||
}
|
||||
|
||||
case *types.TypeParam:
|
||||
pkgName := qual(t.Obj().Pkg())
|
||||
if pkgName == "" || t.Obj().Pkg() == nil {
|
||||
return ast.NewIdent(t.Obj().Name())
|
||||
}
|
||||
return &ast.SelectorExpr{
|
||||
X: ast.NewIdent(pkgName),
|
||||
Sel: ast.NewIdent(t.Obj().Name()),
|
||||
}
|
||||
|
||||
// types.TypeParam also implements interface NamedOrAlias. To differentiate,
|
||||
// case TypeParam need to be present before case NamedOrAlias.
|
||||
// TODO(hxjiang): remove this comment once TypeArgs() is added to interface
|
||||
// NamedOrAlias.
|
||||
case NamedOrAlias:
|
||||
var expr ast.Expr = ast.NewIdent(t.Obj().Name())
|
||||
if pkgName := qual(t.Obj().Pkg()); pkgName != "." && pkgName != "" {
|
||||
expr = &ast.SelectorExpr{
|
||||
X: ast.NewIdent(pkgName),
|
||||
Sel: expr.(*ast.Ident),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(hxjiang): call t.TypeArgs after adding method TypeArgs() to
|
||||
// typesinternal.NamedOrAlias.
|
||||
if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok {
|
||||
if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 {
|
||||
var indices []ast.Expr
|
||||
for i := range typeArgs.Len() {
|
||||
indices = append(indices, TypeExpr(typeArgs.At(i), qual))
|
||||
}
|
||||
expr = &ast.IndexListExpr{
|
||||
X: expr,
|
||||
Indices: indices,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expr
|
||||
|
||||
case *types.Struct:
|
||||
return ast.NewIdent(t.String())
|
||||
|
||||
case *types.Interface:
|
||||
return ast.NewIdent(t.String())
|
||||
|
||||
case *types.Union:
|
||||
if t.Len() == 0 {
|
||||
panic("Union type should have at least one term")
|
||||
}
|
||||
// Same as go/ast, the return expression will put last term in the
|
||||
// Y field at topmost level of BinaryExpr.
|
||||
// For union of type "float32 | float64 | int64", the structure looks
|
||||
// similar to:
|
||||
// {
|
||||
// X: {
|
||||
// X: float32,
|
||||
// Op: |
|
||||
// Y: float64,
|
||||
// }
|
||||
// Op: |,
|
||||
// Y: int64,
|
||||
// }
|
||||
var union ast.Expr
|
||||
for i := range t.Len() {
|
||||
term := t.Term(i)
|
||||
termExpr := TypeExpr(term.Type(), qual)
|
||||
if term.Tilde() {
|
||||
termExpr = &ast.UnaryExpr{
|
||||
Op: token.TILDE,
|
||||
X: termExpr,
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
union = termExpr
|
||||
} else {
|
||||
union = &ast.BinaryExpr{
|
||||
X: union,
|
||||
Op: token.OR,
|
||||
Y: termExpr,
|
||||
}
|
||||
}
|
||||
}
|
||||
return union
|
||||
|
||||
case *types.Tuple:
|
||||
panic("invalid input type types.Tuple")
|
||||
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
43
vendor/golang.org/x/tools/internal/versions/features.go
generated
vendored
Normal file
43
vendor/golang.org/x/tools/internal/versions/features.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
package versions
|
||||
|
||||
// This file contains predicates for working with file versions to
|
||||
// decide when a tool should consider a language feature enabled.
|
||||
|
||||
// GoVersions that features in x/tools can be gated to.
|
||||
const (
|
||||
Go1_18 = "go1.18"
|
||||
Go1_19 = "go1.19"
|
||||
Go1_20 = "go1.20"
|
||||
Go1_21 = "go1.21"
|
||||
Go1_22 = "go1.22"
|
||||
)
|
||||
|
||||
// Future is an invalid unknown Go version sometime in the future.
|
||||
// Do not use directly with Compare.
|
||||
const Future = ""
|
||||
|
||||
// AtLeast reports whether the file version v comes after a Go release.
|
||||
//
|
||||
// Use this predicate to enable a behavior once a certain Go release
|
||||
// has happened (and stays enabled in the future).
|
||||
func AtLeast(v, release string) bool {
|
||||
if v == Future {
|
||||
return true // an unknown future version is always after y.
|
||||
}
|
||||
return Compare(Lang(v), Lang(release)) >= 0
|
||||
}
|
||||
|
||||
// Before reports whether the file version v is strictly before a Go release.
|
||||
//
|
||||
// Use this predicate to disable a behavior once a certain Go release
|
||||
// has happened (and stays enabled in the future).
|
||||
func Before(v, release string) bool {
|
||||
if v == Future {
|
||||
return false // an unknown future version happens after y.
|
||||
}
|
||||
return Compare(Lang(v), Lang(release)) < 0
|
||||
}
|
172
vendor/golang.org/x/tools/internal/versions/gover.go
generated
vendored
Normal file
172
vendor/golang.org/x/tools/internal/versions/gover.go
generated
vendored
Normal file
|
@ -0,0 +1,172 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
// This is a fork of internal/gover for use by x/tools until
|
||||
// go1.21 and earlier are no longer supported by x/tools.
|
||||
|
||||
package versions
|
||||
|
||||
import "strings"
|
||||
|
||||
// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]]
|
||||
// The numbers are the original decimal strings to avoid integer overflows
|
||||
// and since there is very little actual math. (Probably overflow doesn't matter in practice,
|
||||
// but at the time this code was written, there was an existing test that used
|
||||
// go1.99999999999, which does not fit in an int on 32-bit platforms.
|
||||
// The "big decimal" representation avoids the problem entirely.)
|
||||
type gover struct {
|
||||
major string // decimal
|
||||
minor string // decimal or ""
|
||||
patch string // decimal or ""
|
||||
kind string // "", "alpha", "beta", "rc"
|
||||
pre string // decimal or ""
|
||||
}
|
||||
|
||||
// compare returns -1, 0, or +1 depending on whether
|
||||
// x < y, x == y, or x > y, interpreted as toolchain versions.
|
||||
// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21".
|
||||
// Malformed versions compare less than well-formed versions and equal to each other.
|
||||
// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0".
|
||||
func compare(x, y string) int {
|
||||
vx := parse(x)
|
||||
vy := parse(y)
|
||||
|
||||
if c := cmpInt(vx.major, vy.major); c != 0 {
|
||||
return c
|
||||
}
|
||||
if c := cmpInt(vx.minor, vy.minor); c != 0 {
|
||||
return c
|
||||
}
|
||||
if c := cmpInt(vx.patch, vy.patch); c != 0 {
|
||||
return c
|
||||
}
|
||||
if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc
|
||||
return c
|
||||
}
|
||||
if c := cmpInt(vx.pre, vy.pre); c != 0 {
|
||||
return c
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// lang returns the Go language version. For example, lang("1.2.3") == "1.2".
|
||||
func lang(x string) string {
|
||||
v := parse(x)
|
||||
if v.minor == "" || v.major == "1" && v.minor == "0" {
|
||||
return v.major
|
||||
}
|
||||
return v.major + "." + v.minor
|
||||
}
|
||||
|
||||
// isValid reports whether the version x is valid.
|
||||
func isValid(x string) bool {
|
||||
return parse(x) != gover{}
|
||||
}
|
||||
|
||||
// parse parses the Go version string x into a version.
|
||||
// It returns the zero version if x is malformed.
|
||||
func parse(x string) gover {
|
||||
var v gover
|
||||
|
||||
// Parse major version.
|
||||
var ok bool
|
||||
v.major, x, ok = cutInt(x)
|
||||
if !ok {
|
||||
return gover{}
|
||||
}
|
||||
if x == "" {
|
||||
// Interpret "1" as "1.0.0".
|
||||
v.minor = "0"
|
||||
v.patch = "0"
|
||||
return v
|
||||
}
|
||||
|
||||
// Parse . before minor version.
|
||||
if x[0] != '.' {
|
||||
return gover{}
|
||||
}
|
||||
|
||||
// Parse minor version.
|
||||
v.minor, x, ok = cutInt(x[1:])
|
||||
if !ok {
|
||||
return gover{}
|
||||
}
|
||||
if x == "" {
|
||||
// Patch missing is same as "0" for older versions.
|
||||
// Starting in Go 1.21, patch missing is different from explicit .0.
|
||||
if cmpInt(v.minor, "21") < 0 {
|
||||
v.patch = "0"
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Parse patch if present.
|
||||
if x[0] == '.' {
|
||||
v.patch, x, ok = cutInt(x[1:])
|
||||
if !ok || x != "" {
|
||||
// Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != "").
|
||||
// Allowing them would be a bit confusing because we already have:
|
||||
// 1.21 < 1.21rc1
|
||||
// But a prerelease of a patch would have the opposite effect:
|
||||
// 1.21.3rc1 < 1.21.3
|
||||
// We've never needed them before, so let's not start now.
|
||||
return gover{}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Parse prerelease.
|
||||
i := 0
|
||||
for i < len(x) && (x[i] < '0' || '9' < x[i]) {
|
||||
if x[i] < 'a' || 'z' < x[i] {
|
||||
return gover{}
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i == 0 {
|
||||
return gover{}
|
||||
}
|
||||
v.kind, x = x[:i], x[i:]
|
||||
if x == "" {
|
||||
return v
|
||||
}
|
||||
v.pre, x, ok = cutInt(x)
|
||||
if !ok || x != "" {
|
||||
return gover{}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// cutInt scans the leading decimal number at the start of x to an integer
|
||||
// and returns that value and the rest of the string.
|
||||
func cutInt(x string) (n, rest string, ok bool) {
|
||||
i := 0
|
||||
for i < len(x) && '0' <= x[i] && x[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero
|
||||
return "", "", false
|
||||
}
|
||||
return x[:i], x[i:], true
|
||||
}
|
||||
|
||||
// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers.
|
||||
// (Copied from golang.org/x/mod/semver's compareInt.)
|
||||
func cmpInt(x, y string) int {
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if len(x) < len(y) {
|
||||
return -1
|
||||
}
|
||||
if len(x) > len(y) {
|
||||
return +1
|
||||
}
|
||||
if x < y {
|
||||
return -1
|
||||
} else {
|
||||
return +1
|
||||
}
|
||||
}
|
33
vendor/golang.org/x/tools/internal/versions/types.go
generated
vendored
Normal file
33
vendor/golang.org/x/tools/internal/versions/types.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
package versions
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// FileVersion returns a file's Go version.
|
||||
// The reported version is an unknown Future version if a
|
||||
// version cannot be determined.
|
||||
func FileVersion(info *types.Info, file *ast.File) string {
|
||||
// In tools built with Go >= 1.22, the Go version of a file
|
||||
// follow a cascades of sources:
|
||||
// 1) types.Info.FileVersion, which follows the cascade:
|
||||
// 1.a) file version (ast.File.GoVersion),
|
||||
// 1.b) the package version (types.Config.GoVersion), or
|
||||
// 2) is some unknown Future version.
|
||||
//
|
||||
// File versions require a valid package version to be provided to types
|
||||
// in Config.GoVersion. Config.GoVersion is either from the package's module
|
||||
// or the toolchain (go run). This value should be provided by go/packages
|
||||
// or unitchecker.Config.GoVersion.
|
||||
if v := info.FileVersions[file]; IsValid(v) {
|
||||
return v
|
||||
}
|
||||
// Note: we could instead return runtime.Version() [if valid].
|
||||
// This would act as a max version on what a tool can support.
|
||||
return Future
|
||||
}
|
57
vendor/golang.org/x/tools/internal/versions/versions.go
generated
vendored
Normal file
57
vendor/golang.org/x/tools/internal/versions/versions.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
package versions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Note: If we use build tags to use go/versions when go >=1.22,
|
||||
// we run into go.dev/issue/53737. Under some operations users would see an
|
||||
// import of "go/versions" even if they would not compile the file.
|
||||
// For example, during `go get -u ./...` (go.dev/issue/64490) we do not try to include
|
||||
// For this reason, this library just a clone of go/versions for the moment.
|
||||
|
||||
// Lang returns the Go language version for version x.
|
||||
// If x is not a valid version, Lang returns the empty string.
|
||||
// For example:
|
||||
//
|
||||
// Lang("go1.21rc2") = "go1.21"
|
||||
// Lang("go1.21.2") = "go1.21"
|
||||
// Lang("go1.21") = "go1.21"
|
||||
// Lang("go1") = "go1"
|
||||
// Lang("bad") = ""
|
||||
// Lang("1.21") = ""
|
||||
func Lang(x string) string {
|
||||
v := lang(stripGo(x))
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
return x[:2+len(v)] // "go"+v without allocation
|
||||
}
|
||||
|
||||
// Compare returns -1, 0, or +1 depending on whether
|
||||
// x < y, x == y, or x > y, interpreted as Go versions.
|
||||
// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21".
|
||||
// Invalid versions, including the empty string, compare less than
|
||||
// valid versions and equal to each other.
|
||||
// The language version "go1.21" compares less than the
|
||||
// release candidate and eventual releases "go1.21rc1" and "go1.21.0".
|
||||
// Custom toolchain suffixes are ignored during comparison:
|
||||
// "go1.21.0" and "go1.21.0-bigcorp" are equal.
|
||||
func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) }
|
||||
|
||||
// IsValid reports whether the version x is valid.
|
||||
func IsValid(x string) bool { return isValid(stripGo(x)) }
|
||||
|
||||
// stripGo converts from a "go1.21" version to a "1.21" version.
|
||||
// If v does not start with "go", stripGo returns the empty string (a known invalid version).
|
||||
func stripGo(v string) string {
|
||||
v, _, _ = strings.Cut(v, "-") // strip -bigcorp suffix.
|
||||
if len(v) < 2 || v[:2] != "go" {
|
||||
return ""
|
||||
}
|
||||
return v[2:]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue