staticcheck (#313)
* CI: use staticcheck for linting This commit switches the linter for Go code from golint to staticcheck. Golint has been deprecated since last year and staticcheck is a recommended replacement. Signed-off-by: Lucas Servén Marín <lserven@gmail.com> * revendor Signed-off-by: Lucas Servén Marín <lserven@gmail.com> * cmd,pkg: fix lint warnings Signed-off-by: Lucas Servén Marín <lserven@gmail.com>
This commit is contained in:
committed by
GitHub
parent
93f46e03ea
commit
50fbc2eec2
242
vendor/golang.org/x/tools/go/analysis/analysis.go
generated
vendored
Normal file
242
vendor/golang.org/x/tools/go/analysis/analysis.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
// 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 analysis
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
// An Analyzer describes an analysis function and its options.
|
||||
type Analyzer struct {
|
||||
// The Name of the analyzer must be a valid Go identifier
|
||||
// as it may appear in command-line flags, URLs, and so on.
|
||||
Name string
|
||||
|
||||
// Doc is the documentation for the analyzer.
|
||||
// The part before the first "\n\n" is the title
|
||||
// (no capital or period, max ~60 letters).
|
||||
Doc string
|
||||
|
||||
// Flags defines any flags accepted by the analyzer.
|
||||
// The manner in which these flags are exposed to the user
|
||||
// depends on the driver which runs the analyzer.
|
||||
Flags flag.FlagSet
|
||||
|
||||
// Run applies the analyzer to a package.
|
||||
// It returns an error if the analyzer failed.
|
||||
//
|
||||
// On success, the Run function may return a result
|
||||
// computed by the Analyzer; its type must match ResultType.
|
||||
// The driver makes this result available as an input to
|
||||
// another Analyzer that depends directly on this one (see
|
||||
// Requires) when it analyzes the same package.
|
||||
//
|
||||
// To pass analysis results between packages (and thus
|
||||
// potentially between address spaces), use Facts, which are
|
||||
// serializable.
|
||||
Run func(*Pass) (interface{}, error)
|
||||
|
||||
// RunDespiteErrors allows the driver to invoke
|
||||
// the Run method of this analyzer even on a
|
||||
// package that contains parse or type errors.
|
||||
RunDespiteErrors bool
|
||||
|
||||
// Requires is a set of analyzers that must run successfully
|
||||
// before this one on a given package. This analyzer may inspect
|
||||
// the outputs produced by each analyzer in Requires.
|
||||
// The graph over analyzers implied by Requires edges must be acyclic.
|
||||
//
|
||||
// Requires establishes a "horizontal" dependency between
|
||||
// analysis passes (different analyzers, same package).
|
||||
Requires []*Analyzer
|
||||
|
||||
// ResultType is the type of the optional result of the Run function.
|
||||
ResultType reflect.Type
|
||||
|
||||
// FactTypes indicates that this analyzer imports and exports
|
||||
// Facts of the specified concrete types.
|
||||
// An analyzer that uses facts may assume that its import
|
||||
// dependencies have been similarly analyzed before it runs.
|
||||
// Facts must be pointers.
|
||||
//
|
||||
// FactTypes establishes a "vertical" dependency between
|
||||
// analysis passes (same analyzer, different packages).
|
||||
FactTypes []Fact
|
||||
}
|
||||
|
||||
func (a *Analyzer) String() string { return a.Name }
|
||||
|
||||
func init() {
|
||||
// Set the analysisinternal functions to be able to pass type errors
|
||||
// to the Pass type without modifying the go/analysis API.
|
||||
analysisinternal.SetTypeErrors = func(p interface{}, errors []types.Error) {
|
||||
p.(*Pass).typeErrors = errors
|
||||
}
|
||||
analysisinternal.GetTypeErrors = func(p interface{}) []types.Error {
|
||||
return p.(*Pass).typeErrors
|
||||
}
|
||||
}
|
||||
|
||||
// A Pass provides information to the Run function that
|
||||
// applies a specific analyzer to a single Go package.
|
||||
//
|
||||
// It forms the interface between the analysis logic and the driver
|
||||
// program, and has both input and an output components.
|
||||
//
|
||||
// As in a compiler, one pass may depend on the result computed by another.
|
||||
//
|
||||
// The Run function should not call any of the Pass functions concurrently.
|
||||
type Pass struct {
|
||||
Analyzer *Analyzer // the identity of the current analyzer
|
||||
|
||||
// syntax and type information
|
||||
Fset *token.FileSet // file position information
|
||||
Files []*ast.File // the abstract syntax tree of each file
|
||||
OtherFiles []string // names of non-Go files of this package
|
||||
IgnoredFiles []string // names of ignored source files in this package
|
||||
Pkg *types.Package // type information about the package
|
||||
TypesInfo *types.Info // type information about the syntax trees
|
||||
TypesSizes types.Sizes // function for computing sizes of types
|
||||
|
||||
// Report reports a Diagnostic, a finding about a specific location
|
||||
// in the analyzed source code such as a potential mistake.
|
||||
// It may be called by the Run function.
|
||||
Report func(Diagnostic)
|
||||
|
||||
// ResultOf provides the inputs to this analysis pass, which are
|
||||
// the corresponding results of its prerequisite analyzers.
|
||||
// The map keys are the elements of Analysis.Required,
|
||||
// and the type of each corresponding value is the required
|
||||
// analysis's ResultType.
|
||||
ResultOf map[*Analyzer]interface{}
|
||||
|
||||
// -- facts --
|
||||
|
||||
// ImportObjectFact retrieves a fact associated with obj.
|
||||
// Given a value ptr of type *T, where *T satisfies Fact,
|
||||
// ImportObjectFact copies the value to *ptr.
|
||||
//
|
||||
// ImportObjectFact panics if called after the pass is complete.
|
||||
// ImportObjectFact is not concurrency-safe.
|
||||
ImportObjectFact func(obj types.Object, fact Fact) bool
|
||||
|
||||
// ImportPackageFact retrieves a fact associated with package pkg,
|
||||
// which must be this package or one of its dependencies.
|
||||
// See comments for ImportObjectFact.
|
||||
ImportPackageFact func(pkg *types.Package, fact Fact) bool
|
||||
|
||||
// ExportObjectFact associates a fact of type *T with the obj,
|
||||
// replacing any previous fact of that type.
|
||||
//
|
||||
// ExportObjectFact panics if it is called after the pass is
|
||||
// complete, or if obj does not belong to the package being analyzed.
|
||||
// ExportObjectFact is not concurrency-safe.
|
||||
ExportObjectFact func(obj types.Object, fact Fact)
|
||||
|
||||
// ExportPackageFact associates a fact with the current package.
|
||||
// See comments for ExportObjectFact.
|
||||
ExportPackageFact func(fact Fact)
|
||||
|
||||
// AllPackageFacts returns a new slice containing all package facts of the analysis's FactTypes
|
||||
// in unspecified order.
|
||||
// WARNING: This is an experimental API and may change in the future.
|
||||
AllPackageFacts func() []PackageFact
|
||||
|
||||
// AllObjectFacts returns a new slice containing all object facts of the analysis's FactTypes
|
||||
// in unspecified order.
|
||||
// WARNING: This is an experimental API and may change in the future.
|
||||
AllObjectFacts func() []ObjectFact
|
||||
|
||||
// typeErrors contains types.Errors that are associated with the pkg.
|
||||
typeErrors []types.Error
|
||||
|
||||
/* Further fields may be added in future. */
|
||||
// For example, suggested or applied refactorings.
|
||||
}
|
||||
|
||||
// PackageFact is a package together with an associated fact.
|
||||
// WARNING: This is an experimental API and may change in the future.
|
||||
type PackageFact struct {
|
||||
Package *types.Package
|
||||
Fact Fact
|
||||
}
|
||||
|
||||
// ObjectFact is an object together with an associated fact.
|
||||
// WARNING: This is an experimental API and may change in the future.
|
||||
type ObjectFact struct {
|
||||
Object types.Object
|
||||
Fact Fact
|
||||
}
|
||||
|
||||
// Reportf is a helper function that reports a Diagnostic using the
|
||||
// specified position and formatted error message.
|
||||
func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
pass.Report(Diagnostic{Pos: pos, Message: msg})
|
||||
}
|
||||
|
||||
// The Range interface provides a range. It's equivalent to and satisfied by
|
||||
// ast.Node.
|
||||
type Range interface {
|
||||
Pos() token.Pos // position of first character belonging to the node
|
||||
End() token.Pos // position of first character immediately after the node
|
||||
}
|
||||
|
||||
// ReportRangef is a helper function that reports a Diagnostic using the
|
||||
// range provided. ast.Node values can be passed in as the range because
|
||||
// they satisfy the Range interface.
|
||||
func (pass *Pass) ReportRangef(rng Range, format string, args ...interface{}) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
pass.Report(Diagnostic{Pos: rng.Pos(), End: rng.End(), Message: msg})
|
||||
}
|
||||
|
||||
func (pass *Pass) String() string {
|
||||
return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
|
||||
}
|
||||
|
||||
// A Fact is an intermediate fact produced during analysis.
|
||||
//
|
||||
// Each fact is associated with a named declaration (a types.Object) or
|
||||
// with a package as a whole. A single object or package may have
|
||||
// multiple associated facts, but only one of any particular fact type.
|
||||
//
|
||||
// A Fact represents a predicate such as "never returns", but does not
|
||||
// represent the subject of the predicate such as "function F" or "package P".
|
||||
//
|
||||
// Facts may be produced in one analysis pass and consumed by another
|
||||
// analysis pass even if these are in different address spaces.
|
||||
// If package P imports Q, all facts about Q produced during
|
||||
// analysis of that package will be available during later analysis of P.
|
||||
// Facts are analogous to type export data in a build system:
|
||||
// just as export data enables separate compilation of several passes,
|
||||
// facts enable "separate analysis".
|
||||
//
|
||||
// Each pass (a, p) starts with the set of facts produced by the
|
||||
// same analyzer a applied to the packages directly imported by p.
|
||||
// The analysis may add facts to the set, and they may be exported in turn.
|
||||
// An analysis's Run function may retrieve facts by calling
|
||||
// Pass.Import{Object,Package}Fact and update them using
|
||||
// Pass.Export{Object,Package}Fact.
|
||||
//
|
||||
// A fact is logically private to its Analysis. To pass values
|
||||
// between different analyzers, use the results mechanism;
|
||||
// see Analyzer.Requires, Analyzer.ResultType, and Pass.ResultOf.
|
||||
//
|
||||
// A Fact type must be a pointer.
|
||||
// Facts are encoded and decoded using encoding/gob.
|
||||
// A Fact may implement the GobEncoder/GobDecoder interfaces
|
||||
// to customize its encoding. Fact encoding should not fail.
|
||||
//
|
||||
// A Fact should not be modified once exported.
|
||||
type Fact interface {
|
||||
AFact() // dummy method to avoid type errors
|
||||
}
|
||||
65
vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
Normal file
65
vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2019 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 analysis
|
||||
|
||||
import "go/token"
|
||||
|
||||
// A Diagnostic is a message associated with a source location or range.
|
||||
//
|
||||
// An Analyzer may return a variety of diagnostics; the optional Category,
|
||||
// which should be a constant, may be used to classify them.
|
||||
// It is primarily intended to make it easy to look up documentation.
|
||||
//
|
||||
// If End is provided, the diagnostic is specified to apply to the range between
|
||||
// Pos and End.
|
||||
type Diagnostic struct {
|
||||
Pos token.Pos
|
||||
End token.Pos // optional
|
||||
Category string // optional
|
||||
Message string
|
||||
|
||||
// SuggestedFixes contains suggested fixes for a diagnostic which can be used to perform
|
||||
// edits to a file that address the diagnostic.
|
||||
// TODO(matloob): Should multiple SuggestedFixes be allowed for a diagnostic?
|
||||
// Diagnostics should not contain SuggestedFixes that overlap.
|
||||
// Experimental: This API is experimental and may change in the future.
|
||||
SuggestedFixes []SuggestedFix // optional
|
||||
|
||||
// Experimental: This API is experimental and may change in the future.
|
||||
Related []RelatedInformation // optional
|
||||
}
|
||||
|
||||
// RelatedInformation contains information related to a diagnostic.
|
||||
// For example, a diagnostic that flags duplicated declarations of a
|
||||
// variable may include one RelatedInformation per existing
|
||||
// declaration.
|
||||
type RelatedInformation struct {
|
||||
Pos token.Pos
|
||||
End token.Pos
|
||||
Message string
|
||||
}
|
||||
|
||||
// A SuggestedFix is a code change associated with a Diagnostic that a user can choose
|
||||
// to apply to their code. Usually the SuggestedFix is meant to fix the issue flagged
|
||||
// by the diagnostic.
|
||||
// TextEdits for a SuggestedFix should not overlap. TextEdits for a SuggestedFix
|
||||
// should not contain edits for other packages.
|
||||
// Experimental: This API is experimental and may change in the future.
|
||||
type SuggestedFix struct {
|
||||
// A description for this suggested fix to be shown to a user deciding
|
||||
// whether to accept it.
|
||||
Message string
|
||||
TextEdits []TextEdit
|
||||
}
|
||||
|
||||
// A TextEdit represents the replacement of the code between Pos and End with the new text.
|
||||
// Each TextEdit should apply to a single file. End should not be earlier in the file than Pos.
|
||||
// Experimental: This API is experimental and may change in the future.
|
||||
type TextEdit struct {
|
||||
// For a pure insertion, End can either be set to Pos or token.NoPos.
|
||||
Pos token.Pos
|
||||
End token.Pos
|
||||
NewText []byte
|
||||
}
|
||||
321
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
Normal file
321
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
// 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 analysis defines the interface between a modular static
|
||||
analysis and an analysis driver program.
|
||||
|
||||
|
||||
Background
|
||||
|
||||
A static analysis is a function that inspects a package of Go code and
|
||||
reports a set of diagnostics (typically mistakes in the code), and
|
||||
perhaps produces other results as well, such as suggested refactorings
|
||||
or other facts. An analysis that reports mistakes is informally called a
|
||||
"checker". For example, the printf checker reports mistakes in
|
||||
fmt.Printf format strings.
|
||||
|
||||
A "modular" analysis is one that inspects one package at a time but can
|
||||
save information from a lower-level package and use it when inspecting a
|
||||
higher-level package, analogous to separate compilation in a toolchain.
|
||||
The printf checker is modular: when it discovers that a function such as
|
||||
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
|
||||
calls to that function too, including calls made from another package.
|
||||
|
||||
By implementing a common interface, checkers from a variety of sources
|
||||
can be easily selected, incorporated, and reused in a wide range of
|
||||
driver programs including command-line tools (such as vet), text editors and
|
||||
IDEs, build and test systems (such as go build, Bazel, or Buck), test
|
||||
frameworks, code review tools, code-base indexers (such as SourceGraph),
|
||||
documentation viewers (such as godoc), batch pipelines for large code
|
||||
bases, and so on.
|
||||
|
||||
|
||||
Analyzer
|
||||
|
||||
The primary type in the API is Analyzer. An Analyzer statically
|
||||
describes an analysis function: its name, documentation, flags,
|
||||
relationship to other analyzers, and of course, its logic.
|
||||
|
||||
To define an analysis, a user declares a (logically constant) variable
|
||||
of type Analyzer. Here is a typical example from one of the analyzers in
|
||||
the go/analysis/passes/ subdirectory:
|
||||
|
||||
package unusedresult
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unusedresult",
|
||||
Doc: "check for unused results of calls to some functions",
|
||||
Run: run,
|
||||
...
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (interface{}, error) {
|
||||
...
|
||||
}
|
||||
|
||||
An analysis driver is a program such as vet that runs a set of
|
||||
analyses and prints the diagnostics that they report.
|
||||
The driver program must import the list of Analyzers it needs.
|
||||
Typically each Analyzer resides in a separate package.
|
||||
To add a new Analyzer to an existing driver, add another item to the list:
|
||||
|
||||
import ( "unusedresult"; "nilness"; "printf" )
|
||||
|
||||
var analyses = []*analysis.Analyzer{
|
||||
unusedresult.Analyzer,
|
||||
nilness.Analyzer,
|
||||
printf.Analyzer,
|
||||
}
|
||||
|
||||
A driver may use the name, flags, and documentation to provide on-line
|
||||
help that describes the analyses it performs.
|
||||
The doc comment contains a brief one-line summary,
|
||||
optionally followed by paragraphs of explanation.
|
||||
|
||||
The Analyzer type has more fields besides those shown above:
|
||||
|
||||
type Analyzer struct {
|
||||
Name string
|
||||
Doc string
|
||||
Flags flag.FlagSet
|
||||
Run func(*Pass) (interface{}, error)
|
||||
RunDespiteErrors bool
|
||||
ResultType reflect.Type
|
||||
Requires []*Analyzer
|
||||
FactTypes []Fact
|
||||
}
|
||||
|
||||
The Flags field declares a set of named (global) flag variables that
|
||||
control analysis behavior. Unlike vet, analysis flags are not declared
|
||||
directly in the command line FlagSet; it is up to the driver to set the
|
||||
flag variables. A driver for a single analysis, a, might expose its flag
|
||||
f directly on the command line as -f, whereas a driver for multiple
|
||||
analyses might prefix the flag name by the analysis name (-a.f) to avoid
|
||||
ambiguity. An IDE might expose the flags through a graphical interface,
|
||||
and a batch pipeline might configure them from a config file.
|
||||
See the "findcall" analyzer for an example of flags in action.
|
||||
|
||||
The RunDespiteErrors flag indicates whether the analysis is equipped to
|
||||
handle ill-typed code. If not, the driver will skip the analysis if
|
||||
there were parse or type errors.
|
||||
The optional ResultType field specifies the type of the result value
|
||||
computed by this analysis and made available to other analyses.
|
||||
The Requires field specifies a list of analyses upon which
|
||||
this one depends and whose results it may access, and it constrains the
|
||||
order in which a driver may run analyses.
|
||||
The FactTypes field is discussed in the section on Modularity.
|
||||
The analysis package provides a Validate function to perform basic
|
||||
sanity checks on an Analyzer, such as that its Requires graph is
|
||||
acyclic, its fact and result types are unique, and so on.
|
||||
|
||||
Finally, the Run field contains a function to be called by the driver to
|
||||
execute the analysis on a single package. The driver passes it an
|
||||
instance of the Pass type.
|
||||
|
||||
|
||||
Pass
|
||||
|
||||
A Pass describes a single unit of work: the application of a particular
|
||||
Analyzer to a particular package of Go code.
|
||||
The Pass provides information to the Analyzer's Run function about the
|
||||
package being analyzed, and provides operations to the Run function for
|
||||
reporting diagnostics and other information back to the driver.
|
||||
|
||||
type Pass struct {
|
||||
Fset *token.FileSet
|
||||
Files []*ast.File
|
||||
OtherFiles []string
|
||||
IgnoredFiles []string
|
||||
Pkg *types.Package
|
||||
TypesInfo *types.Info
|
||||
ResultOf map[*Analyzer]interface{}
|
||||
Report func(Diagnostic)
|
||||
...
|
||||
}
|
||||
|
||||
The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
|
||||
type information, and source positions for a single package of Go code.
|
||||
|
||||
The OtherFiles field provides the names, but not the contents, of non-Go
|
||||
files such as assembly that are part of this package. See the "asmdecl"
|
||||
or "buildtags" analyzers for examples of loading non-Go files and reporting
|
||||
diagnostics against them.
|
||||
|
||||
The IgnoredFiles field provides the names, but not the contents,
|
||||
of ignored Go and non-Go source files that are not part of this package
|
||||
with the current build configuration but may be part of other build
|
||||
configurations. See the "buildtags" analyzer for an example of loading
|
||||
and checking IgnoredFiles.
|
||||
|
||||
The ResultOf field provides the results computed by the analyzers
|
||||
required by this one, as expressed in its Analyzer.Requires field. The
|
||||
driver runs the required analyzers first and makes their results
|
||||
available in this map. Each Analyzer must return a value of the type
|
||||
described in its Analyzer.ResultType field.
|
||||
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
|
||||
provides a control-flow graph for each function in the package (see
|
||||
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
|
||||
enables other Analyzers to traverse the syntax trees of the package more
|
||||
efficiently; and the "buildssa" analyzer constructs an SSA-form
|
||||
intermediate representation.
|
||||
Each of these Analyzers extends the capabilities of later Analyzers
|
||||
without adding a dependency to the core API, so an analysis tool pays
|
||||
only for the extensions it needs.
|
||||
|
||||
The Report function emits a diagnostic, a message associated with a
|
||||
source position. For most analyses, diagnostics are their primary
|
||||
result.
|
||||
For convenience, Pass provides a helper method, Reportf, to report a new
|
||||
diagnostic by formatting a string.
|
||||
Diagnostic is defined as:
|
||||
|
||||
type Diagnostic struct {
|
||||
Pos token.Pos
|
||||
Category string // optional
|
||||
Message string
|
||||
}
|
||||
|
||||
The optional Category field is a short identifier that classifies the
|
||||
kind of message when an analysis produces several kinds of diagnostic.
|
||||
|
||||
Many analyses want to associate diagnostics with a severity level.
|
||||
Because Diagnostic does not have a severity level field, an Analyzer's
|
||||
diagnostics effectively all have the same severity level. To separate which
|
||||
diagnostics are high severity and which are low severity, expose multiple
|
||||
Analyzers instead. Analyzers should also be separated when their
|
||||
diagnostics belong in different groups, or could be tagged differently
|
||||
before being shown to the end user. Analyzers should document their severity
|
||||
level to help downstream tools surface diagnostics properly.
|
||||
|
||||
Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
|
||||
and buildtag, inspect the raw text of Go source files or even non-Go
|
||||
files such as assembly. To report a diagnostic against a line of a
|
||||
raw text file, use the following sequence:
|
||||
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil { ... }
|
||||
tf := fset.AddFile(filename, -1, len(content))
|
||||
tf.SetLinesForContent(content)
|
||||
...
|
||||
pass.Reportf(tf.LineStart(line), "oops")
|
||||
|
||||
|
||||
Modular analysis with Facts
|
||||
|
||||
To improve efficiency and scalability, large programs are routinely
|
||||
built using separate compilation: units of the program are compiled
|
||||
separately, and recompiled only when one of their dependencies changes;
|
||||
independent modules may be compiled in parallel. The same technique may
|
||||
be applied to static analyses, for the same benefits. Such analyses are
|
||||
described as "modular".
|
||||
|
||||
A compiler’s type checker is an example of a modular static analysis.
|
||||
Many other checkers we would like to apply to Go programs can be
|
||||
understood as alternative or non-standard type systems. For example,
|
||||
vet's printf checker infers whether a function has the "printf wrapper"
|
||||
type, and it applies stricter checks to calls of such functions. In
|
||||
addition, it records which functions are printf wrappers for use by
|
||||
later analysis passes to identify other printf wrappers by induction.
|
||||
A result such as “f is a printf wrapper” that is not interesting by
|
||||
itself but serves as a stepping stone to an interesting result (such as
|
||||
a diagnostic) is called a "fact".
|
||||
|
||||
The analysis API allows an analysis to define new types of facts, to
|
||||
associate facts of these types with objects (named entities) declared
|
||||
within the current package, or with the package as a whole, and to query
|
||||
for an existing fact of a given type associated with an object or
|
||||
package.
|
||||
|
||||
An Analyzer that uses facts must declare their types:
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "printf",
|
||||
FactTypes: []analysis.Fact{new(isWrapper)},
|
||||
...
|
||||
}
|
||||
|
||||
type isWrapper struct{} // => *types.Func f “is a printf wrapper”
|
||||
|
||||
The driver program ensures that facts for a pass’s dependencies are
|
||||
generated before analyzing the package and is responsible for propagating
|
||||
facts from one package to another, possibly across address spaces.
|
||||
Consequently, Facts must be serializable. The API requires that drivers
|
||||
use the gob encoding, an efficient, robust, self-describing binary
|
||||
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
|
||||
if the default encoding is unsuitable. Facts should be stateless.
|
||||
|
||||
The Pass type has functions to import and export facts,
|
||||
associated either with an object or with a package:
|
||||
|
||||
type Pass struct {
|
||||
...
|
||||
ExportObjectFact func(types.Object, Fact)
|
||||
ImportObjectFact func(types.Object, Fact) bool
|
||||
|
||||
ExportPackageFact func(fact Fact)
|
||||
ImportPackageFact func(*types.Package, Fact) bool
|
||||
}
|
||||
|
||||
An Analyzer may only export facts associated with the current package or
|
||||
its objects, though it may import facts from any package or object that
|
||||
is an import dependency of the current package.
|
||||
|
||||
Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
|
||||
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
|
||||
retrieves the entry from this map and copies its value into the variable
|
||||
pointed to by fact. This scheme assumes that the concrete type of fact
|
||||
is a pointer; this assumption is checked by the Validate function.
|
||||
See the "printf" analyzer for an example of object facts in action.
|
||||
|
||||
Some driver implementations (such as those based on Bazel and Blaze) do
|
||||
not currently apply analyzers to packages of the standard library.
|
||||
Therefore, for best results, analyzer authors should not rely on
|
||||
analysis facts being available for standard packages.
|
||||
For example, although the printf checker is capable of deducing during
|
||||
analysis of the log package that log.Printf is a printf wrapper,
|
||||
this fact is built in to the analyzer so that it correctly checks
|
||||
calls to log.Printf even when run in a driver that does not apply
|
||||
it to standard packages. We would like to remove this limitation in future.
|
||||
|
||||
|
||||
Testing an Analyzer
|
||||
|
||||
The analysistest subpackage provides utilities for testing an Analyzer.
|
||||
In a few lines of code, it is possible to run an analyzer on a package
|
||||
of testdata files and check that it reported all the expected
|
||||
diagnostics and facts (and no more). Expectations are expressed using
|
||||
"// want ..." comments in the input code.
|
||||
|
||||
|
||||
Standalone commands
|
||||
|
||||
Analyzers are provided in the form of packages that a driver program is
|
||||
expected to import. The vet command imports a set of several analyzers,
|
||||
but users may wish to define their own analysis commands that perform
|
||||
additional checks. To simplify the task of creating an analysis command,
|
||||
either for a single analyzer or for a whole suite, we provide the
|
||||
singlechecker and multichecker subpackages.
|
||||
|
||||
The singlechecker package provides the main function for a command that
|
||||
runs one analyzer. By convention, each analyzer such as
|
||||
go/passes/findcall should be accompanied by a singlechecker-based
|
||||
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
|
||||
entirety as:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/analysis/passes/findcall"
|
||||
"golang.org/x/tools/go/analysis/singlechecker"
|
||||
)
|
||||
|
||||
func main() { singlechecker.Main(findcall.Analyzer) }
|
||||
|
||||
A tool that provides multiple analyzers can use multichecker in a
|
||||
similar way, giving it the list of Analyzers.
|
||||
|
||||
*/
|
||||
package analysis
|
||||
49
vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
generated
vendored
Normal file
49
vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 inspect defines an Analyzer that provides an AST inspector
|
||||
// (golang.org/x/tools/go/ast/inspector.Inspector) for the syntax trees
|
||||
// of a package. It is only a building block for other analyzers.
|
||||
//
|
||||
// Example of use in another analysis:
|
||||
//
|
||||
// import (
|
||||
// "golang.org/x/tools/go/analysis"
|
||||
// "golang.org/x/tools/go/analysis/passes/inspect"
|
||||
// "golang.org/x/tools/go/ast/inspector"
|
||||
// )
|
||||
//
|
||||
// var Analyzer = &analysis.Analyzer{
|
||||
// ...
|
||||
// Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
// }
|
||||
//
|
||||
// func run(pass *analysis.Pass) (interface{}, error) {
|
||||
// inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
// inspect.Preorder(nil, func(n ast.Node) {
|
||||
// ...
|
||||
// })
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
)
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "inspect",
|
||||
Doc: "optimize AST traversal for later passes",
|
||||
Run: run,
|
||||
RunDespiteErrors: true,
|
||||
ResultType: reflect.TypeOf(new(inspector.Inspector)),
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (interface{}, error) {
|
||||
return inspector.New(pass.Files), nil
|
||||
}
|
||||
130
vendor/golang.org/x/tools/go/analysis/validate.go
generated
vendored
Normal file
130
vendor/golang.org/x/tools/go/analysis/validate.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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 analysis
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Validate reports an error if any of the analyzers are misconfigured.
|
||||
// Checks include:
|
||||
// that the name is a valid identifier;
|
||||
// that the Requires graph is acyclic;
|
||||
// that analyzer fact types are unique;
|
||||
// that each fact type is a pointer.
|
||||
func Validate(analyzers []*Analyzer) error {
|
||||
// Map each fact type to its sole generating analyzer.
|
||||
factTypes := make(map[reflect.Type]*Analyzer)
|
||||
|
||||
// Traverse the Requires graph, depth first.
|
||||
const (
|
||||
white = iota
|
||||
grey
|
||||
black
|
||||
finished
|
||||
)
|
||||
color := make(map[*Analyzer]uint8)
|
||||
var visit func(a *Analyzer) error
|
||||
visit = func(a *Analyzer) error {
|
||||
if a == nil {
|
||||
return fmt.Errorf("nil *Analyzer")
|
||||
}
|
||||
if color[a] == white {
|
||||
color[a] = grey
|
||||
|
||||
// names
|
||||
if !validIdent(a.Name) {
|
||||
return fmt.Errorf("invalid analyzer name %q", a)
|
||||
}
|
||||
|
||||
if a.Doc == "" {
|
||||
return fmt.Errorf("analyzer %q is undocumented", a)
|
||||
}
|
||||
|
||||
// fact types
|
||||
for _, f := range a.FactTypes {
|
||||
if f == nil {
|
||||
return fmt.Errorf("analyzer %s has nil FactType", a)
|
||||
}
|
||||
t := reflect.TypeOf(f)
|
||||
if prev := factTypes[t]; prev != nil {
|
||||
return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
|
||||
t, a, prev)
|
||||
}
|
||||
if t.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
|
||||
}
|
||||
factTypes[t] = a
|
||||
}
|
||||
|
||||
// recursion
|
||||
for _, req := range a.Requires {
|
||||
if err := visit(req); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
color[a] = black
|
||||
}
|
||||
|
||||
if color[a] == grey {
|
||||
stack := []*Analyzer{a}
|
||||
inCycle := map[string]bool{}
|
||||
for len(stack) > 0 {
|
||||
current := stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
if color[current] == grey && !inCycle[current.Name] {
|
||||
inCycle[current.Name] = true
|
||||
stack = append(stack, current.Requires...)
|
||||
}
|
||||
}
|
||||
return &CycleInRequiresGraphError{AnalyzerNames: inCycle}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
for _, a := range analyzers {
|
||||
if err := visit(a); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Reject duplicates among analyzers.
|
||||
// Precondition: color[a] == black.
|
||||
// Postcondition: color[a] == finished.
|
||||
for _, a := range analyzers {
|
||||
if color[a] == finished {
|
||||
return fmt.Errorf("duplicate analyzer: %s", a.Name)
|
||||
}
|
||||
color[a] = finished
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validIdent(name string) bool {
|
||||
for i, r := range name {
|
||||
if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return name != ""
|
||||
}
|
||||
|
||||
type CycleInRequiresGraphError struct {
|
||||
AnalyzerNames map[string]bool
|
||||
}
|
||||
|
||||
func (e *CycleInRequiresGraphError) Error() string {
|
||||
var b strings.Builder
|
||||
b.WriteString("cycle detected involving the following analyzers:")
|
||||
for n := range e.AnalyzerNames {
|
||||
b.WriteByte(' ')
|
||||
b.WriteString(n)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
20
vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
generated
vendored
20
vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
generated
vendored
@@ -11,6 +11,8 @@ import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"sort"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// PathEnclosingInterval returns the node that encloses the source
|
||||
@@ -294,8 +296,8 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||
|
||||
case *ast.FieldList:
|
||||
children = append(children,
|
||||
tok(n.Opening, len("(")),
|
||||
tok(n.Closing, len(")")))
|
||||
tok(n.Opening, len("(")), // or len("[")
|
||||
tok(n.Closing, len(")"))) // or len("]")
|
||||
|
||||
case *ast.File:
|
||||
// TODO test: Doc
|
||||
@@ -322,6 +324,9 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||
children = append(children, n.Recv)
|
||||
}
|
||||
children = append(children, n.Name)
|
||||
if tparams := typeparams.ForFuncType(n.Type); tparams != nil {
|
||||
children = append(children, tparams)
|
||||
}
|
||||
if n.Type.Params != nil {
|
||||
children = append(children, n.Type.Params)
|
||||
}
|
||||
@@ -371,8 +376,13 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||
|
||||
case *ast.IndexExpr:
|
||||
children = append(children,
|
||||
tok(n.Lbrack, len("{")),
|
||||
tok(n.Rbrack, len("}")))
|
||||
tok(n.Lbrack, len("[")),
|
||||
tok(n.Rbrack, len("]")))
|
||||
|
||||
case *typeparams.IndexListExpr:
|
||||
children = append(children,
|
||||
tok(n.Lbrack, len("[")),
|
||||
tok(n.Rbrack, len("]")))
|
||||
|
||||
case *ast.InterfaceType:
|
||||
children = append(children,
|
||||
@@ -581,6 +591,8 @@ func NodeDescription(n ast.Node) string {
|
||||
return "decrement statement"
|
||||
case *ast.IndexExpr:
|
||||
return "index expression"
|
||||
case *typeparams.IndexListExpr:
|
||||
return "index list expression"
|
||||
case *ast.InterfaceType:
|
||||
return "interface type"
|
||||
case *ast.KeyValueExpr:
|
||||
|
||||
12
vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
generated
vendored
12
vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
generated
vendored
@@ -253,6 +253,10 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
|
||||
a.apply(n, "X", nil, n.X)
|
||||
a.apply(n, "Index", nil, n.Index)
|
||||
|
||||
case *typeparams.IndexListExpr:
|
||||
a.apply(n, "X", nil, n.X)
|
||||
a.applyList(n, "Indices")
|
||||
|
||||
case *ast.SliceExpr:
|
||||
a.apply(n, "X", nil, n.X)
|
||||
a.apply(n, "Low", nil, n.Low)
|
||||
@@ -439,13 +443,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
|
||||
}
|
||||
|
||||
default:
|
||||
if ix := typeparams.GetIndexExprData(n); ix != nil {
|
||||
a.apply(n, "X", nil, ix.X)
|
||||
// *ast.IndexExpr was handled above, so n must be an *ast.MultiIndexExpr.
|
||||
a.applyList(n, "Indices")
|
||||
} else {
|
||||
panic(fmt.Sprintf("Apply: unexpected node type %T", n))
|
||||
}
|
||||
panic(fmt.Sprintf("Apply: unexpected node type %T", n))
|
||||
}
|
||||
|
||||
if a.post != nil && !a.post(&a.cursor) {
|
||||
|
||||
186
vendor/golang.org/x/tools/go/ast/inspector/inspector.go
generated
vendored
Normal file
186
vendor/golang.org/x/tools/go/ast/inspector/inspector.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// 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 inspector provides helper functions for traversal over the
|
||||
// syntax trees of a package, including node filtering by type, and
|
||||
// materialization of the traversal stack.
|
||||
//
|
||||
// During construction, the inspector does a complete traversal and
|
||||
// builds a list of push/pop events and their node type. Subsequent
|
||||
// method calls that request a traversal scan this list, rather than walk
|
||||
// the AST, and perform type filtering using efficient bit sets.
|
||||
//
|
||||
// Experiments suggest the inspector's traversals are about 2.5x faster
|
||||
// than ast.Inspect, but it may take around 5 traversals for this
|
||||
// benefit to amortize the inspector's construction cost.
|
||||
// If efficiency is the primary concern, do not use Inspector for
|
||||
// one-off traversals.
|
||||
package inspector
|
||||
|
||||
// There are four orthogonal features in a traversal:
|
||||
// 1 type filtering
|
||||
// 2 pruning
|
||||
// 3 postorder calls to f
|
||||
// 4 stack
|
||||
// Rather than offer all of them in the API,
|
||||
// only a few combinations are exposed:
|
||||
// - Preorder is the fastest and has fewest features,
|
||||
// but is the most commonly needed traversal.
|
||||
// - Nodes and WithStack both provide pruning and postorder calls,
|
||||
// even though few clients need it, because supporting two versions
|
||||
// is not justified.
|
||||
// More combinations could be supported by expressing them as
|
||||
// wrappers around a more generic traversal, but this was measured
|
||||
// and found to degrade performance significantly (30%).
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
)
|
||||
|
||||
// An Inspector provides methods for inspecting
|
||||
// (traversing) the syntax trees of a package.
|
||||
type Inspector struct {
|
||||
events []event
|
||||
}
|
||||
|
||||
// New returns an Inspector for the specified syntax trees.
|
||||
func New(files []*ast.File) *Inspector {
|
||||
return &Inspector{traverse(files)}
|
||||
}
|
||||
|
||||
// An event represents a push or a pop
|
||||
// of an ast.Node during a traversal.
|
||||
type event struct {
|
||||
node ast.Node
|
||||
typ uint64 // typeOf(node)
|
||||
index int // 1 + index of corresponding pop event, or 0 if this is a pop
|
||||
}
|
||||
|
||||
// Preorder visits all the nodes of the files supplied to New in
|
||||
// depth-first order. It calls f(n) for each node n before it visits
|
||||
// n's children.
|
||||
//
|
||||
// The types argument, if non-empty, enables type-based filtering of
|
||||
// events. The function f if is called only for nodes whose type
|
||||
// matches an element of the types slice.
|
||||
func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) {
|
||||
// Because it avoids postorder calls to f, and the pruning
|
||||
// check, Preorder is almost twice as fast as Nodes. The two
|
||||
// features seem to contribute similar slowdowns (~1.4x each).
|
||||
|
||||
mask := maskOf(types)
|
||||
for i := 0; i < len(in.events); {
|
||||
ev := in.events[i]
|
||||
if ev.typ&mask != 0 {
|
||||
if ev.index > 0 {
|
||||
f(ev.node)
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes visits the nodes of the files supplied to New in depth-first
|
||||
// order. It calls f(n, true) for each node n before it visits n's
|
||||
// children. If f returns true, Nodes invokes f recursively for each
|
||||
// of the non-nil children of the node, followed by a call of
|
||||
// f(n, false).
|
||||
//
|
||||
// The types argument, if non-empty, enables type-based filtering of
|
||||
// events. The function f if is called only for nodes whose type
|
||||
// matches an element of the types slice.
|
||||
func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) {
|
||||
mask := maskOf(types)
|
||||
for i := 0; i < len(in.events); {
|
||||
ev := in.events[i]
|
||||
if ev.typ&mask != 0 {
|
||||
if ev.index > 0 {
|
||||
// push
|
||||
if !f(ev.node, true) {
|
||||
i = ev.index // jump to corresponding pop + 1
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// pop
|
||||
f(ev.node, false)
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack visits nodes in a similar manner to Nodes, but it
|
||||
// supplies each call to f an additional argument, the current
|
||||
// traversal stack. The stack's first element is the outermost node,
|
||||
// an *ast.File; its last is the innermost, n.
|
||||
func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) {
|
||||
mask := maskOf(types)
|
||||
var stack []ast.Node
|
||||
for i := 0; i < len(in.events); {
|
||||
ev := in.events[i]
|
||||
if ev.index > 0 {
|
||||
// push
|
||||
stack = append(stack, ev.node)
|
||||
if ev.typ&mask != 0 {
|
||||
if !f(ev.node, true, stack) {
|
||||
i = ev.index
|
||||
stack = stack[:len(stack)-1]
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// pop
|
||||
if ev.typ&mask != 0 {
|
||||
f(ev.node, false, stack)
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// traverse builds the table of events representing a traversal.
|
||||
func traverse(files []*ast.File) []event {
|
||||
// Preallocate approximate number of events
|
||||
// based on source file extent.
|
||||
// This makes traverse faster by 4x (!).
|
||||
var extent int
|
||||
for _, f := range files {
|
||||
extent += int(f.End() - f.Pos())
|
||||
}
|
||||
// This estimate is based on the net/http package.
|
||||
capacity := extent * 33 / 100
|
||||
if capacity > 1e6 {
|
||||
capacity = 1e6 // impose some reasonable maximum
|
||||
}
|
||||
events := make([]event, 0, capacity)
|
||||
|
||||
var stack []event
|
||||
for _, f := range files {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
if n != nil {
|
||||
// push
|
||||
ev := event{
|
||||
node: n,
|
||||
typ: typeOf(n),
|
||||
index: len(events), // push event temporarily holds own index
|
||||
}
|
||||
stack = append(stack, ev)
|
||||
events = append(events, ev)
|
||||
} else {
|
||||
// pop
|
||||
ev := stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
|
||||
events[ev.index].index = len(events) + 1 // make push refer to pop
|
||||
|
||||
ev.index = 0 // turn ev into a pop event
|
||||
events = append(events, ev)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
227
vendor/golang.org/x/tools/go/ast/inspector/typeof.go
generated
vendored
Normal file
227
vendor/golang.org/x/tools/go/ast/inspector/typeof.go
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
// 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 inspector
|
||||
|
||||
// This file defines func typeOf(ast.Node) uint64.
|
||||
//
|
||||
// The initial map-based implementation was too slow;
|
||||
// see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
const (
|
||||
nArrayType = iota
|
||||
nAssignStmt
|
||||
nBadDecl
|
||||
nBadExpr
|
||||
nBadStmt
|
||||
nBasicLit
|
||||
nBinaryExpr
|
||||
nBlockStmt
|
||||
nBranchStmt
|
||||
nCallExpr
|
||||
nCaseClause
|
||||
nChanType
|
||||
nCommClause
|
||||
nComment
|
||||
nCommentGroup
|
||||
nCompositeLit
|
||||
nDeclStmt
|
||||
nDeferStmt
|
||||
nEllipsis
|
||||
nEmptyStmt
|
||||
nExprStmt
|
||||
nField
|
||||
nFieldList
|
||||
nFile
|
||||
nForStmt
|
||||
nFuncDecl
|
||||
nFuncLit
|
||||
nFuncType
|
||||
nGenDecl
|
||||
nGoStmt
|
||||
nIdent
|
||||
nIfStmt
|
||||
nImportSpec
|
||||
nIncDecStmt
|
||||
nIndexExpr
|
||||
nIndexListExpr
|
||||
nInterfaceType
|
||||
nKeyValueExpr
|
||||
nLabeledStmt
|
||||
nMapType
|
||||
nPackage
|
||||
nParenExpr
|
||||
nRangeStmt
|
||||
nReturnStmt
|
||||
nSelectStmt
|
||||
nSelectorExpr
|
||||
nSendStmt
|
||||
nSliceExpr
|
||||
nStarExpr
|
||||
nStructType
|
||||
nSwitchStmt
|
||||
nTypeAssertExpr
|
||||
nTypeSpec
|
||||
nTypeSwitchStmt
|
||||
nUnaryExpr
|
||||
nValueSpec
|
||||
)
|
||||
|
||||
// typeOf returns a distinct single-bit value that represents the type of n.
|
||||
//
|
||||
// Various implementations were benchmarked with BenchmarkNewInspector:
|
||||
// GOGC=off
|
||||
// - type switch 4.9-5.5ms 2.1ms
|
||||
// - binary search over a sorted list of types 5.5-5.9ms 2.5ms
|
||||
// - linear scan, frequency-ordered list 5.9-6.1ms 2.7ms
|
||||
// - linear scan, unordered list 6.4ms 2.7ms
|
||||
// - hash table 6.5ms 3.1ms
|
||||
// A perfect hash seemed like overkill.
|
||||
//
|
||||
// The compiler's switch statement is the clear winner
|
||||
// as it produces a binary tree in code,
|
||||
// with constant conditions and good branch prediction.
|
||||
// (Sadly it is the most verbose in source code.)
|
||||
// Binary search suffered from poor branch prediction.
|
||||
//
|
||||
func typeOf(n ast.Node) uint64 {
|
||||
// Fast path: nearly half of all nodes are identifiers.
|
||||
if _, ok := n.(*ast.Ident); ok {
|
||||
return 1 << nIdent
|
||||
}
|
||||
|
||||
// These cases include all nodes encountered by ast.Inspect.
|
||||
switch n.(type) {
|
||||
case *ast.ArrayType:
|
||||
return 1 << nArrayType
|
||||
case *ast.AssignStmt:
|
||||
return 1 << nAssignStmt
|
||||
case *ast.BadDecl:
|
||||
return 1 << nBadDecl
|
||||
case *ast.BadExpr:
|
||||
return 1 << nBadExpr
|
||||
case *ast.BadStmt:
|
||||
return 1 << nBadStmt
|
||||
case *ast.BasicLit:
|
||||
return 1 << nBasicLit
|
||||
case *ast.BinaryExpr:
|
||||
return 1 << nBinaryExpr
|
||||
case *ast.BlockStmt:
|
||||
return 1 << nBlockStmt
|
||||
case *ast.BranchStmt:
|
||||
return 1 << nBranchStmt
|
||||
case *ast.CallExpr:
|
||||
return 1 << nCallExpr
|
||||
case *ast.CaseClause:
|
||||
return 1 << nCaseClause
|
||||
case *ast.ChanType:
|
||||
return 1 << nChanType
|
||||
case *ast.CommClause:
|
||||
return 1 << nCommClause
|
||||
case *ast.Comment:
|
||||
return 1 << nComment
|
||||
case *ast.CommentGroup:
|
||||
return 1 << nCommentGroup
|
||||
case *ast.CompositeLit:
|
||||
return 1 << nCompositeLit
|
||||
case *ast.DeclStmt:
|
||||
return 1 << nDeclStmt
|
||||
case *ast.DeferStmt:
|
||||
return 1 << nDeferStmt
|
||||
case *ast.Ellipsis:
|
||||
return 1 << nEllipsis
|
||||
case *ast.EmptyStmt:
|
||||
return 1 << nEmptyStmt
|
||||
case *ast.ExprStmt:
|
||||
return 1 << nExprStmt
|
||||
case *ast.Field:
|
||||
return 1 << nField
|
||||
case *ast.FieldList:
|
||||
return 1 << nFieldList
|
||||
case *ast.File:
|
||||
return 1 << nFile
|
||||
case *ast.ForStmt:
|
||||
return 1 << nForStmt
|
||||
case *ast.FuncDecl:
|
||||
return 1 << nFuncDecl
|
||||
case *ast.FuncLit:
|
||||
return 1 << nFuncLit
|
||||
case *ast.FuncType:
|
||||
return 1 << nFuncType
|
||||
case *ast.GenDecl:
|
||||
return 1 << nGenDecl
|
||||
case *ast.GoStmt:
|
||||
return 1 << nGoStmt
|
||||
case *ast.Ident:
|
||||
return 1 << nIdent
|
||||
case *ast.IfStmt:
|
||||
return 1 << nIfStmt
|
||||
case *ast.ImportSpec:
|
||||
return 1 << nImportSpec
|
||||
case *ast.IncDecStmt:
|
||||
return 1 << nIncDecStmt
|
||||
case *ast.IndexExpr:
|
||||
return 1 << nIndexExpr
|
||||
case *typeparams.IndexListExpr:
|
||||
return 1 << nIndexListExpr
|
||||
case *ast.InterfaceType:
|
||||
return 1 << nInterfaceType
|
||||
case *ast.KeyValueExpr:
|
||||
return 1 << nKeyValueExpr
|
||||
case *ast.LabeledStmt:
|
||||
return 1 << nLabeledStmt
|
||||
case *ast.MapType:
|
||||
return 1 << nMapType
|
||||
case *ast.Package:
|
||||
return 1 << nPackage
|
||||
case *ast.ParenExpr:
|
||||
return 1 << nParenExpr
|
||||
case *ast.RangeStmt:
|
||||
return 1 << nRangeStmt
|
||||
case *ast.ReturnStmt:
|
||||
return 1 << nReturnStmt
|
||||
case *ast.SelectStmt:
|
||||
return 1 << nSelectStmt
|
||||
case *ast.SelectorExpr:
|
||||
return 1 << nSelectorExpr
|
||||
case *ast.SendStmt:
|
||||
return 1 << nSendStmt
|
||||
case *ast.SliceExpr:
|
||||
return 1 << nSliceExpr
|
||||
case *ast.StarExpr:
|
||||
return 1 << nStarExpr
|
||||
case *ast.StructType:
|
||||
return 1 << nStructType
|
||||
case *ast.SwitchStmt:
|
||||
return 1 << nSwitchStmt
|
||||
case *ast.TypeAssertExpr:
|
||||
return 1 << nTypeAssertExpr
|
||||
case *ast.TypeSpec:
|
||||
return 1 << nTypeSpec
|
||||
case *ast.TypeSwitchStmt:
|
||||
return 1 << nTypeSwitchStmt
|
||||
case *ast.UnaryExpr:
|
||||
return 1 << nUnaryExpr
|
||||
case *ast.ValueSpec:
|
||||
return 1 << nValueSpec
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func maskOf(nodes []ast.Node) uint64 {
|
||||
if nodes == nil {
|
||||
return 1<<64 - 1 // match all node types
|
||||
}
|
||||
var mask uint64
|
||||
for _, n := range nodes {
|
||||
mask |= typeOf(n)
|
||||
}
|
||||
return mask
|
||||
}
|
||||
198
vendor/golang.org/x/tools/go/buildutil/allpackages.go
generated
vendored
Normal file
198
vendor/golang.org/x/tools/go/buildutil/allpackages.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// 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 buildutil provides utilities related to the go/build
|
||||
// package in the standard library.
|
||||
//
|
||||
// All I/O is done via the build.Context file system interface, which must
|
||||
// be concurrency-safe.
|
||||
package buildutil // import "golang.org/x/tools/go/buildutil"
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// AllPackages returns the package path of each Go package in any source
|
||||
// directory of the specified build context (e.g. $GOROOT or an element
|
||||
// of $GOPATH). Errors are ignored. The results are sorted.
|
||||
// All package paths are canonical, and thus may contain "/vendor/".
|
||||
//
|
||||
// The result may include import paths for directories that contain no
|
||||
// *.go files, such as "archive" (in $GOROOT/src).
|
||||
//
|
||||
// All I/O is done via the build.Context file system interface,
|
||||
// which must be concurrency-safe.
|
||||
//
|
||||
func AllPackages(ctxt *build.Context) []string {
|
||||
var list []string
|
||||
ForEachPackage(ctxt, func(pkg string, _ error) {
|
||||
list = append(list, pkg)
|
||||
})
|
||||
sort.Strings(list)
|
||||
return list
|
||||
}
|
||||
|
||||
// ForEachPackage calls the found function with the package path of
|
||||
// each Go package it finds in any source directory of the specified
|
||||
// build context (e.g. $GOROOT or an element of $GOPATH).
|
||||
// All package paths are canonical, and thus may contain "/vendor/".
|
||||
//
|
||||
// If the package directory exists but could not be read, the second
|
||||
// argument to the found function provides the error.
|
||||
//
|
||||
// All I/O is done via the build.Context file system interface,
|
||||
// which must be concurrency-safe.
|
||||
//
|
||||
func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
|
||||
ch := make(chan item)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, root := range ctxt.SrcDirs() {
|
||||
root := root
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
allPackages(ctxt, root, ch)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
// All calls to found occur in the caller's goroutine.
|
||||
for i := range ch {
|
||||
found(i.importPath, i.err)
|
||||
}
|
||||
}
|
||||
|
||||
type item struct {
|
||||
importPath string
|
||||
err error // (optional)
|
||||
}
|
||||
|
||||
// We use a process-wide counting semaphore to limit
|
||||
// the number of parallel calls to ReadDir.
|
||||
var ioLimit = make(chan bool, 20)
|
||||
|
||||
func allPackages(ctxt *build.Context, root string, ch chan<- item) {
|
||||
root = filepath.Clean(root) + string(os.PathSeparator)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var walkDir func(dir string)
|
||||
walkDir = func(dir string) {
|
||||
// Avoid .foo, _foo, and testdata directory trees.
|
||||
base := filepath.Base(dir)
|
||||
if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" {
|
||||
return
|
||||
}
|
||||
|
||||
pkg := filepath.ToSlash(strings.TrimPrefix(dir, root))
|
||||
|
||||
// Prune search if we encounter any of these import paths.
|
||||
switch pkg {
|
||||
case "builtin":
|
||||
return
|
||||
}
|
||||
|
||||
ioLimit <- true
|
||||
files, err := ReadDir(ctxt, dir)
|
||||
<-ioLimit
|
||||
if pkg != "" || err != nil {
|
||||
ch <- item{pkg, err}
|
||||
}
|
||||
for _, fi := range files {
|
||||
fi := fi
|
||||
if fi.IsDir() {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
walkDir(filepath.Join(dir, fi.Name()))
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkDir(root)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// ExpandPatterns returns the set of packages matched by patterns,
|
||||
// which may have the following forms:
|
||||
//
|
||||
// golang.org/x/tools/cmd/guru # a single package
|
||||
// golang.org/x/tools/... # all packages beneath dir
|
||||
// ... # the entire workspace.
|
||||
//
|
||||
// Order is significant: a pattern preceded by '-' removes matching
|
||||
// packages from the set. For example, these patterns match all encoding
|
||||
// packages except encoding/xml:
|
||||
//
|
||||
// encoding/... -encoding/xml
|
||||
//
|
||||
// A trailing slash in a pattern is ignored. (Path components of Go
|
||||
// package names are separated by slash, not the platform's path separator.)
|
||||
//
|
||||
func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool {
|
||||
// TODO(adonovan): support other features of 'go list':
|
||||
// - "std"/"cmd"/"all" meta-packages
|
||||
// - "..." not at the end of a pattern
|
||||
// - relative patterns using "./" or "../" prefix
|
||||
|
||||
pkgs := make(map[string]bool)
|
||||
doPkg := func(pkg string, neg bool) {
|
||||
if neg {
|
||||
delete(pkgs, pkg)
|
||||
} else {
|
||||
pkgs[pkg] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Scan entire workspace if wildcards are present.
|
||||
// TODO(adonovan): opt: scan only the necessary subtrees of the workspace.
|
||||
var all []string
|
||||
for _, arg := range patterns {
|
||||
if strings.HasSuffix(arg, "...") {
|
||||
all = AllPackages(ctxt)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, arg := range patterns {
|
||||
if arg == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
neg := arg[0] == '-'
|
||||
if neg {
|
||||
arg = arg[1:]
|
||||
}
|
||||
|
||||
if arg == "..." {
|
||||
// ... matches all packages
|
||||
for _, pkg := range all {
|
||||
doPkg(pkg, neg)
|
||||
}
|
||||
} else if dir := strings.TrimSuffix(arg, "/..."); dir != arg {
|
||||
// dir/... matches all packages beneath dir
|
||||
for _, pkg := range all {
|
||||
if strings.HasPrefix(pkg, dir) &&
|
||||
(len(pkg) == len(dir) || pkg[len(dir)] == '/') {
|
||||
doPkg(pkg, neg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// single package
|
||||
doPkg(strings.TrimSuffix(arg, "/"), neg)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs
|
||||
}
|
||||
113
vendor/golang.org/x/tools/go/buildutil/fakecontext.go
generated
vendored
Normal file
113
vendor/golang.org/x/tools/go/buildutil/fakecontext.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2015 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 buildutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FakeContext returns a build.Context for the fake file tree specified
|
||||
// by pkgs, which maps package import paths to a mapping from file base
|
||||
// names to contents.
|
||||
//
|
||||
// The fake Context has a GOROOT of "/go" and no GOPATH, and overrides
|
||||
// the necessary file access methods to read from memory instead of the
|
||||
// real file system.
|
||||
//
|
||||
// Unlike a real file tree, the fake one has only two levels---packages
|
||||
// and files---so ReadDir("/go/src/") returns all packages under
|
||||
// /go/src/ including, for instance, "math" and "math/big".
|
||||
// ReadDir("/go/src/math/big") would return all the files in the
|
||||
// "math/big" package.
|
||||
//
|
||||
func FakeContext(pkgs map[string]map[string]string) *build.Context {
|
||||
clean := func(filename string) string {
|
||||
f := path.Clean(filepath.ToSlash(filename))
|
||||
// Removing "/go/src" while respecting segment
|
||||
// boundaries has this unfortunate corner case:
|
||||
if f == "/go/src" {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(f, "/go/src/")
|
||||
}
|
||||
|
||||
ctxt := build.Default // copy
|
||||
ctxt.GOROOT = "/go"
|
||||
ctxt.GOPATH = ""
|
||||
ctxt.Compiler = "gc"
|
||||
ctxt.IsDir = func(dir string) bool {
|
||||
dir = clean(dir)
|
||||
if dir == "" {
|
||||
return true // needed by (*build.Context).SrcDirs
|
||||
}
|
||||
return pkgs[dir] != nil
|
||||
}
|
||||
ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
|
||||
dir = clean(dir)
|
||||
var fis []os.FileInfo
|
||||
if dir == "" {
|
||||
// enumerate packages
|
||||
for importPath := range pkgs {
|
||||
fis = append(fis, fakeDirInfo(importPath))
|
||||
}
|
||||
} else {
|
||||
// enumerate files of package
|
||||
for basename := range pkgs[dir] {
|
||||
fis = append(fis, fakeFileInfo(basename))
|
||||
}
|
||||
}
|
||||
sort.Sort(byName(fis))
|
||||
return fis, nil
|
||||
}
|
||||
ctxt.OpenFile = func(filename string) (io.ReadCloser, error) {
|
||||
filename = clean(filename)
|
||||
dir, base := path.Split(filename)
|
||||
content, ok := pkgs[path.Clean(dir)][base]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("file not found: %s", filename)
|
||||
}
|
||||
return ioutil.NopCloser(strings.NewReader(content)), nil
|
||||
}
|
||||
ctxt.IsAbsPath = func(path string) bool {
|
||||
path = filepath.ToSlash(path)
|
||||
// Don't rely on the default (filepath.Path) since on
|
||||
// Windows, it reports virtual paths as non-absolute.
|
||||
return strings.HasPrefix(path, "/")
|
||||
}
|
||||
return &ctxt
|
||||
}
|
||||
|
||||
type byName []os.FileInfo
|
||||
|
||||
func (s byName) Len() int { return len(s) }
|
||||
func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
|
||||
|
||||
type fakeFileInfo string
|
||||
|
||||
func (fi fakeFileInfo) Name() string { return string(fi) }
|
||||
func (fakeFileInfo) Sys() interface{} { return nil }
|
||||
func (fakeFileInfo) ModTime() time.Time { return time.Time{} }
|
||||
func (fakeFileInfo) IsDir() bool { return false }
|
||||
func (fakeFileInfo) Size() int64 { return 0 }
|
||||
func (fakeFileInfo) Mode() os.FileMode { return 0644 }
|
||||
|
||||
type fakeDirInfo string
|
||||
|
||||
func (fd fakeDirInfo) Name() string { return string(fd) }
|
||||
func (fakeDirInfo) Sys() interface{} { return nil }
|
||||
func (fakeDirInfo) ModTime() time.Time { return time.Time{} }
|
||||
func (fakeDirInfo) IsDir() bool { return true }
|
||||
func (fakeDirInfo) Size() int64 { return 0 }
|
||||
func (fakeDirInfo) Mode() os.FileMode { return 0755 }
|
||||
103
vendor/golang.org/x/tools/go/buildutil/overlay.go
generated
vendored
Normal file
103
vendor/golang.org/x/tools/go/buildutil/overlay.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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.
|
||||
|
||||
package buildutil
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OverlayContext overlays a build.Context with additional files from
|
||||
// a map. Files in the map take precedence over other files.
|
||||
//
|
||||
// In addition to plain string comparison, two file names are
|
||||
// considered equal if their base names match and their directory
|
||||
// components point at the same directory on the file system. That is,
|
||||
// symbolic links are followed for directories, but not files.
|
||||
//
|
||||
// A common use case for OverlayContext is to allow editors to pass in
|
||||
// a set of unsaved, modified files.
|
||||
//
|
||||
// Currently, only the Context.OpenFile function will respect the
|
||||
// overlay. This may change in the future.
|
||||
func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Context {
|
||||
// TODO(dominikh): Implement IsDir, HasSubdir and ReadDir
|
||||
|
||||
rc := func(data []byte) (io.ReadCloser, error) {
|
||||
return ioutil.NopCloser(bytes.NewBuffer(data)), nil
|
||||
}
|
||||
|
||||
copy := *orig // make a copy
|
||||
ctxt := ©
|
||||
ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
|
||||
// Fast path: names match exactly.
|
||||
if content, ok := overlay[path]; ok {
|
||||
return rc(content)
|
||||
}
|
||||
|
||||
// Slow path: check for same file under a different
|
||||
// alias, perhaps due to a symbolic link.
|
||||
for filename, content := range overlay {
|
||||
if sameFile(path, filename) {
|
||||
return rc(content)
|
||||
}
|
||||
}
|
||||
|
||||
return OpenFile(orig, path)
|
||||
}
|
||||
return ctxt
|
||||
}
|
||||
|
||||
// ParseOverlayArchive parses an archive containing Go files and their
|
||||
// contents. The result is intended to be used with OverlayContext.
|
||||
//
|
||||
//
|
||||
// Archive format
|
||||
//
|
||||
// The archive consists of a series of files. Each file consists of a
|
||||
// name, a decimal file size and the file contents, separated by
|
||||
// newlines. No newline follows after the file contents.
|
||||
func ParseOverlayArchive(archive io.Reader) (map[string][]byte, error) {
|
||||
overlay := make(map[string][]byte)
|
||||
r := bufio.NewReader(archive)
|
||||
for {
|
||||
// Read file name.
|
||||
filename, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break // OK
|
||||
}
|
||||
return nil, fmt.Errorf("reading archive file name: %v", err)
|
||||
}
|
||||
filename = filepath.Clean(strings.TrimSpace(filename))
|
||||
|
||||
// Read file size.
|
||||
sz, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading size of archive file %s: %v", filename, err)
|
||||
}
|
||||
sz = strings.TrimSpace(sz)
|
||||
size, err := strconv.ParseUint(sz, 10, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing size of archive file %s: %v", filename, err)
|
||||
}
|
||||
|
||||
// Read file content.
|
||||
content := make([]byte, size)
|
||||
if _, err := io.ReadFull(r, content); err != nil {
|
||||
return nil, fmt.Errorf("reading archive file %s: %v", filename, err)
|
||||
}
|
||||
overlay[filename] = content
|
||||
}
|
||||
|
||||
return overlay, nil
|
||||
}
|
||||
79
vendor/golang.org/x/tools/go/buildutil/tags.go
generated
vendored
Normal file
79
vendor/golang.org/x/tools/go/buildutil/tags.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2015 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 buildutil
|
||||
|
||||
// This logic was copied from stringsFlag from $GOROOT/src/cmd/go/build.go.
|
||||
|
||||
import "fmt"
|
||||
|
||||
const TagsFlagDoc = "a list of `build tags` to consider satisfied during the build. " +
|
||||
"For more information about build tags, see the description of " +
|
||||
"build constraints in the documentation for the go/build package"
|
||||
|
||||
// TagsFlag is an implementation of the flag.Value and flag.Getter interfaces that parses
|
||||
// a flag value in the same manner as go build's -tags flag and
|
||||
// populates a []string slice.
|
||||
//
|
||||
// See $GOROOT/src/go/build/doc.go for description of build tags.
|
||||
// See $GOROOT/src/cmd/go/doc.go for description of 'go build -tags' flag.
|
||||
//
|
||||
// Example:
|
||||
// flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
|
||||
type TagsFlag []string
|
||||
|
||||
func (v *TagsFlag) Set(s string) error {
|
||||
var err error
|
||||
*v, err = splitQuotedFields(s)
|
||||
if *v == nil {
|
||||
*v = []string{}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *TagsFlag) Get() interface{} { return *v }
|
||||
|
||||
func splitQuotedFields(s string) ([]string, error) {
|
||||
// Split fields allowing '' or "" around elements.
|
||||
// Quotes further inside the string do not count.
|
||||
var f []string
|
||||
for len(s) > 0 {
|
||||
for len(s) > 0 && isSpaceByte(s[0]) {
|
||||
s = s[1:]
|
||||
}
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
// Accepted quoted string. No unescaping inside.
|
||||
if s[0] == '"' || s[0] == '\'' {
|
||||
quote := s[0]
|
||||
s = s[1:]
|
||||
i := 0
|
||||
for i < len(s) && s[i] != quote {
|
||||
i++
|
||||
}
|
||||
if i >= len(s) {
|
||||
return nil, fmt.Errorf("unterminated %c string", quote)
|
||||
}
|
||||
f = append(f, s[:i])
|
||||
s = s[i+1:]
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for i < len(s) && !isSpaceByte(s[i]) {
|
||||
i++
|
||||
}
|
||||
f = append(f, s[:i])
|
||||
s = s[i:]
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (v *TagsFlag) String() string {
|
||||
return "<tagsFlag>"
|
||||
}
|
||||
|
||||
func isSpaceByte(c byte) bool {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
212
vendor/golang.org/x/tools/go/buildutil/util.go
generated
vendored
Normal file
212
vendor/golang.org/x/tools/go/buildutil/util.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
// 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 buildutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseFile behaves like parser.ParseFile,
|
||||
// but uses the build context's file system interface, if any.
|
||||
//
|
||||
// If file is not absolute (as defined by IsAbsPath), the (dir, file)
|
||||
// components are joined using JoinPath; dir must be absolute.
|
||||
//
|
||||
// The displayPath function, if provided, is used to transform the
|
||||
// filename that will be attached to the ASTs.
|
||||
//
|
||||
// TODO(adonovan): call this from go/loader.parseFiles when the tree thaws.
|
||||
//
|
||||
func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) {
|
||||
if !IsAbsPath(ctxt, file) {
|
||||
file = JoinPath(ctxt, dir, file)
|
||||
}
|
||||
rd, err := OpenFile(ctxt, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rd.Close() // ignore error
|
||||
if displayPath != nil {
|
||||
file = displayPath(file)
|
||||
}
|
||||
return parser.ParseFile(fset, file, rd, mode)
|
||||
}
|
||||
|
||||
// ContainingPackage returns the package containing filename.
|
||||
//
|
||||
// If filename is not absolute, it is interpreted relative to working directory dir.
|
||||
// All I/O is via the build context's file system interface, if any.
|
||||
//
|
||||
// The '...Files []string' fields of the resulting build.Package are not
|
||||
// populated (build.FindOnly mode).
|
||||
//
|
||||
func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) {
|
||||
if !IsAbsPath(ctxt, filename) {
|
||||
filename = JoinPath(ctxt, dir, filename)
|
||||
}
|
||||
|
||||
// We must not assume the file tree uses
|
||||
// "/" always,
|
||||
// `\` always,
|
||||
// or os.PathSeparator (which varies by platform),
|
||||
// but to make any progress, we are forced to assume that
|
||||
// paths will not use `\` unless the PathSeparator
|
||||
// is also `\`, thus we can rely on filepath.ToSlash for some sanity.
|
||||
|
||||
dirSlash := path.Dir(filepath.ToSlash(filename)) + "/"
|
||||
|
||||
// We assume that no source root (GOPATH[i] or GOROOT) contains any other.
|
||||
for _, srcdir := range ctxt.SrcDirs() {
|
||||
srcdirSlash := filepath.ToSlash(srcdir) + "/"
|
||||
if importPath, ok := HasSubdir(ctxt, srcdirSlash, dirSlash); ok {
|
||||
return ctxt.Import(importPath, dir, build.FindOnly)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("can't find package containing %s", filename)
|
||||
}
|
||||
|
||||
// -- Effective methods of file system interface -------------------------
|
||||
|
||||
// (go/build.Context defines these as methods, but does not export them.)
|
||||
|
||||
// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
|
||||
// the local file system to answer the question.
|
||||
func HasSubdir(ctxt *build.Context, root, dir string) (rel string, ok bool) {
|
||||
if f := ctxt.HasSubdir; f != nil {
|
||||
return f(root, dir)
|
||||
}
|
||||
|
||||
// Try using paths we received.
|
||||
if rel, ok = hasSubdir(root, dir); ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Try expanding symlinks and comparing
|
||||
// expanded against unexpanded and
|
||||
// expanded against expanded.
|
||||
rootSym, _ := filepath.EvalSymlinks(root)
|
||||
dirSym, _ := filepath.EvalSymlinks(dir)
|
||||
|
||||
if rel, ok = hasSubdir(rootSym, dir); ok {
|
||||
return
|
||||
}
|
||||
if rel, ok = hasSubdir(root, dirSym); ok {
|
||||
return
|
||||
}
|
||||
return hasSubdir(rootSym, dirSym)
|
||||
}
|
||||
|
||||
func hasSubdir(root, dir string) (rel string, ok bool) {
|
||||
const sep = string(filepath.Separator)
|
||||
root = filepath.Clean(root)
|
||||
if !strings.HasSuffix(root, sep) {
|
||||
root += sep
|
||||
}
|
||||
|
||||
dir = filepath.Clean(dir)
|
||||
if !strings.HasPrefix(dir, root) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return filepath.ToSlash(dir[len(root):]), true
|
||||
}
|
||||
|
||||
// FileExists returns true if the specified file exists,
|
||||
// using the build context's file system interface.
|
||||
func FileExists(ctxt *build.Context, path string) bool {
|
||||
if ctxt.OpenFile != nil {
|
||||
r, err := ctxt.OpenFile(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
r.Close() // ignore error
|
||||
return true
|
||||
}
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// OpenFile behaves like os.Open,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) {
|
||||
if ctxt.OpenFile != nil {
|
||||
return ctxt.OpenFile(path)
|
||||
}
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
// IsAbsPath behaves like filepath.IsAbs,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func IsAbsPath(ctxt *build.Context, path string) bool {
|
||||
if ctxt.IsAbsPath != nil {
|
||||
return ctxt.IsAbsPath(path)
|
||||
}
|
||||
return filepath.IsAbs(path)
|
||||
}
|
||||
|
||||
// JoinPath behaves like filepath.Join,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func JoinPath(ctxt *build.Context, path ...string) string {
|
||||
if ctxt.JoinPath != nil {
|
||||
return ctxt.JoinPath(path...)
|
||||
}
|
||||
return filepath.Join(path...)
|
||||
}
|
||||
|
||||
// IsDir behaves like os.Stat plus IsDir,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func IsDir(ctxt *build.Context, path string) bool {
|
||||
if ctxt.IsDir != nil {
|
||||
return ctxt.IsDir(path)
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
// ReadDir behaves like ioutil.ReadDir,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) {
|
||||
if ctxt.ReadDir != nil {
|
||||
return ctxt.ReadDir(path)
|
||||
}
|
||||
return ioutil.ReadDir(path)
|
||||
}
|
||||
|
||||
// SplitPathList behaves like filepath.SplitList,
|
||||
// but uses the build context's file system interface, if any.
|
||||
func SplitPathList(ctxt *build.Context, s string) []string {
|
||||
if ctxt.SplitPathList != nil {
|
||||
return ctxt.SplitPathList(s)
|
||||
}
|
||||
return filepath.SplitList(s)
|
||||
}
|
||||
|
||||
// sameFile returns true if x and y have the same basename and denote
|
||||
// the same file.
|
||||
//
|
||||
func sameFile(x, y string) bool {
|
||||
if path.Clean(x) == path.Clean(y) {
|
||||
return true
|
||||
}
|
||||
if filepath.Base(x) == filepath.Base(y) { // (optimisation)
|
||||
if xi, err := os.Stat(x); err == nil {
|
||||
if yi, err := os.Stat(y); err == nil {
|
||||
return os.SameFile(xi, yi)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
23
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
23
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
@@ -50,11 +50,24 @@ 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)
|
||||
_, err := gcimporter.FindExportData(buf)
|
||||
// If we ever switch to a zip-like archive format with the ToC
|
||||
// at the end, we can return the correct portion of export data,
|
||||
// but for now we must return the entire rest of the file.
|
||||
return buf, err
|
||||
_, 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
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads export data from in, decodes it, and returns type
|
||||
|
||||
222
vendor/golang.org/x/tools/go/internal/cgo/cgo.go
generated
vendored
Normal file
222
vendor/golang.org/x/tools/go/internal/cgo/cgo.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cgo handles cgo preprocessing of files containing `import "C"`.
|
||||
//
|
||||
// DESIGN
|
||||
//
|
||||
// The approach taken is to run the cgo processor on the package's
|
||||
// CgoFiles and parse the output, faking the filenames of the
|
||||
// resulting ASTs so that the synthetic file containing the C types is
|
||||
// called "C" (e.g. "~/go/src/net/C") and the preprocessed files
|
||||
// have their original names (e.g. "~/go/src/net/cgo_unix.go"),
|
||||
// not the names of the actual temporary files.
|
||||
//
|
||||
// The advantage of this approach is its fidelity to 'go build'. The
|
||||
// downside is that the token.Position.Offset for each AST node is
|
||||
// incorrect, being an offset within the temporary file. Line numbers
|
||||
// should still be correct because of the //line comments.
|
||||
//
|
||||
// The logic of this file is mostly plundered from the 'go build'
|
||||
// tool, which also invokes the cgo preprocessor.
|
||||
//
|
||||
//
|
||||
// REJECTED ALTERNATIVE
|
||||
//
|
||||
// An alternative approach that we explored is to extend go/types'
|
||||
// Importer mechanism to provide the identity of the importing package
|
||||
// so that each time `import "C"` appears it resolves to a different
|
||||
// synthetic package containing just the objects needed in that case.
|
||||
// The loader would invoke cgo but parse only the cgo_types.go file
|
||||
// defining the package-level objects, discarding the other files
|
||||
// resulting from preprocessing.
|
||||
//
|
||||
// The benefit of this approach would have been that source-level
|
||||
// syntax information would correspond exactly to the original cgo
|
||||
// file, with no preprocessing involved, making source tools like
|
||||
// godoc, guru, and eg happy. However, the approach was rejected
|
||||
// due to the additional complexity it would impose on go/types. (It
|
||||
// made for a beautiful demo, though.)
|
||||
//
|
||||
// cgo files, despite their *.go extension, are not legal Go source
|
||||
// files per the specification since they may refer to unexported
|
||||
// members of package "C" such as C.int. Also, a function such as
|
||||
// C.getpwent has in effect two types, one matching its C type and one
|
||||
// which additionally returns (errno C.int). The cgo preprocessor
|
||||
// uses name mangling to distinguish these two functions in the
|
||||
// processed code, but go/types would need to duplicate this logic in
|
||||
// its handling of function calls, analogous to the treatment of map
|
||||
// lookups in which y=m[k] and y,ok=m[k] are both legal.
|
||||
|
||||
package cgo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
exec "golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses
|
||||
// the output and returns the resulting ASTs.
|
||||
//
|
||||
func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) {
|
||||
tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
pkgdir := bp.Dir
|
||||
if DisplayPath != nil {
|
||||
pkgdir = DisplayPath(pkgdir)
|
||||
}
|
||||
|
||||
cgoFiles, cgoDisplayFiles, err := Run(bp, pkgdir, tmpdir, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var files []*ast.File
|
||||
for i := range cgoFiles {
|
||||
rd, err := os.Open(cgoFiles[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
display := filepath.Join(bp.Dir, cgoDisplayFiles[i])
|
||||
f, err := parser.ParseFile(fset, display, rd, mode)
|
||||
rd.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
var cgoRe = regexp.MustCompile(`[/\\:]`)
|
||||
|
||||
// Run invokes the cgo preprocessor on bp.CgoFiles and returns two
|
||||
// lists of files: the resulting processed files (in temporary
|
||||
// directory tmpdir) and the corresponding names of the unprocessed files.
|
||||
//
|
||||
// Run is adapted from (*builder).cgo in
|
||||
// $GOROOT/src/cmd/go/build.go, but these features are unsupported:
|
||||
// Objective C, CGOPKGPATH, CGO_FLAGS.
|
||||
//
|
||||
// If useabs is set to true, absolute paths of the bp.CgoFiles will be passed in
|
||||
// to the cgo preprocessor. This in turn will set the // line comments
|
||||
// referring to those files to use absolute paths. This is needed for
|
||||
// go/packages using the legacy go list support so it is able to find
|
||||
// the original files.
|
||||
func Run(bp *build.Package, pkgdir, tmpdir string, useabs bool) (files, displayFiles []string, err error) {
|
||||
cgoCPPFLAGS, _, _, _ := cflags(bp, true)
|
||||
_, cgoexeCFLAGS, _, _ := cflags(bp, false)
|
||||
|
||||
if len(bp.CgoPkgConfig) > 0 {
|
||||
pcCFLAGS, err := pkgConfigFlags(bp)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
|
||||
}
|
||||
|
||||
// Allows including _cgo_export.h from .[ch] files in the package.
|
||||
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir)
|
||||
|
||||
// _cgo_gotypes.go (displayed "C") contains the type definitions.
|
||||
files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go"))
|
||||
displayFiles = append(displayFiles, "C")
|
||||
for _, fn := range bp.CgoFiles {
|
||||
// "foo.cgo1.go" (displayed "foo.go") is the processed Go source.
|
||||
f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_")
|
||||
files = append(files, filepath.Join(tmpdir, f+"cgo1.go"))
|
||||
displayFiles = append(displayFiles, fn)
|
||||
}
|
||||
|
||||
var cgoflags []string
|
||||
if bp.Goroot && bp.ImportPath == "runtime/cgo" {
|
||||
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
|
||||
}
|
||||
if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" {
|
||||
cgoflags = append(cgoflags, "-import_syscall=false")
|
||||
}
|
||||
|
||||
var cgoFiles []string = bp.CgoFiles
|
||||
if useabs {
|
||||
cgoFiles = make([]string, len(bp.CgoFiles))
|
||||
for i := range cgoFiles {
|
||||
cgoFiles[i] = filepath.Join(pkgdir, bp.CgoFiles[i])
|
||||
}
|
||||
}
|
||||
|
||||
args := stringList(
|
||||
"go", "tool", "cgo", "-objdir", tmpdir, cgoflags, "--",
|
||||
cgoCPPFLAGS, cgoexeCFLAGS, cgoFiles,
|
||||
)
|
||||
if false {
|
||||
log.Printf("Running cgo for package %q: %s (dir=%s)", bp.ImportPath, args, pkgdir)
|
||||
}
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
cmd.Dir = pkgdir
|
||||
cmd.Env = append(os.Environ(), "PWD="+pkgdir)
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err)
|
||||
}
|
||||
|
||||
return files, displayFiles, nil
|
||||
}
|
||||
|
||||
// -- unmodified from 'go build' ---------------------------------------
|
||||
|
||||
// Return the flags to use when invoking the C or C++ compilers, or cgo.
|
||||
func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
|
||||
var defaults string
|
||||
if def {
|
||||
defaults = "-g -O2"
|
||||
}
|
||||
|
||||
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
|
||||
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
|
||||
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
|
||||
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
|
||||
return
|
||||
}
|
||||
|
||||
// envList returns the value of the given environment variable broken
|
||||
// into fields, using the default value when the variable is empty.
|
||||
func envList(key, def string) []string {
|
||||
v := os.Getenv(key)
|
||||
if v == "" {
|
||||
v = def
|
||||
}
|
||||
return strings.Fields(v)
|
||||
}
|
||||
|
||||
// stringList's arguments should be a sequence of string or []string values.
|
||||
// stringList flattens them into a single []string.
|
||||
func stringList(args ...interface{}) []string {
|
||||
var x []string
|
||||
for _, arg := range args {
|
||||
switch arg := arg.(type) {
|
||||
case []string:
|
||||
x = append(x, arg...)
|
||||
case string:
|
||||
x = append(x, arg)
|
||||
default:
|
||||
panic("stringList: invalid argument")
|
||||
}
|
||||
}
|
||||
return x
|
||||
}
|
||||
39
vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go
generated
vendored
Normal file
39
vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// pkgConfig runs pkg-config with the specified arguments and returns the flags it prints.
|
||||
func pkgConfig(mode string, pkgs []string) (flags []string, err error) {
|
||||
cmd := exec.Command("pkg-config", append([]string{mode}, pkgs...)...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("%s failed: %v", strings.Join(cmd.Args, " "), err)
|
||||
if len(out) > 0 {
|
||||
s = fmt.Sprintf("%s: %s", s, out)
|
||||
}
|
||||
return nil, errors.New(s)
|
||||
}
|
||||
if len(out) > 0 {
|
||||
flags = strings.Fields(string(out))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// pkgConfigFlags calls pkg-config if needed and returns the cflags
|
||||
// needed to build the package.
|
||||
func pkgConfigFlags(p *build.Package) (cflags []string, err error) {
|
||||
if len(p.CgoPkgConfig) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return pkgConfig("--cflags", p.CgoPkgConfig)
|
||||
}
|
||||
23
vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go
generated
vendored
23
vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go
generated
vendored
@@ -34,9 +34,6 @@ import (
|
||||
// (suspected) format errors, and whenever a change is made to the format.
|
||||
const debugFormat = false // default: false
|
||||
|
||||
// If trace is set, debugging output is printed to std out.
|
||||
const trace = 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
|
||||
@@ -92,16 +89,18 @@ func internalErrorf(format string, args ...interface{}) error {
|
||||
// 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) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if ierr, ok := e.(internalError); ok {
|
||||
err = ierr
|
||||
return
|
||||
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)
|
||||
}
|
||||
// Not an internal error; panic again.
|
||||
panic(e)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}
|
||||
|
||||
p := exporter{
|
||||
fset: fset,
|
||||
|
||||
52
vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go
generated
vendored
52
vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go
generated
vendored
@@ -74,9 +74,10 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
||||
pathList: []string{""}, // empty string is mapped to 0
|
||||
fake: fakeFileSet{
|
||||
fset: fset,
|
||||
files: make(map[string]*token.File),
|
||||
files: make(map[string]*fileInfo),
|
||||
},
|
||||
}
|
||||
defer p.fake.setLines() // set lines for files in fset
|
||||
|
||||
// read version info
|
||||
var versionstr string
|
||||
@@ -338,37 +339,49 @@ func (p *importer) pos() token.Pos {
|
||||
// Synthesize a token.Pos
|
||||
type fakeFileSet struct {
|
||||
fset *token.FileSet
|
||||
files map[string]*token.File
|
||||
files map[string]*fileInfo
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
file *token.File
|
||||
lastline int
|
||||
}
|
||||
|
||||
const maxlines = 64 * 1024
|
||||
|
||||
func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
|
||||
// TODO(mdempsky): Make use of column.
|
||||
|
||||
// Since we don't know the set of needed file positions, we
|
||||
// reserve maxlines positions per file.
|
||||
const maxlines = 64 * 1024
|
||||
// Since we don't know the set of needed file positions, we reserve maxlines
|
||||
// positions per file. We delay calling token.File.SetLines until all
|
||||
// positions have been calculated (by way of fakeFileSet.setLines), so that
|
||||
// we can avoid setting unnecessary lines. See also golang/go#46586.
|
||||
f := s.files[file]
|
||||
if f == nil {
|
||||
f = s.fset.AddFile(file, -1, maxlines)
|
||||
f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)}
|
||||
s.files[file] = f
|
||||
// Allocate the fake linebreak indices on first use.
|
||||
// TODO(adonovan): opt: save ~512KB using a more complex scheme?
|
||||
fakeLinesOnce.Do(func() {
|
||||
fakeLines = make([]int, maxlines)
|
||||
for i := range fakeLines {
|
||||
fakeLines[i] = i
|
||||
}
|
||||
})
|
||||
f.SetLines(fakeLines)
|
||||
}
|
||||
|
||||
if line > maxlines {
|
||||
line = 1
|
||||
}
|
||||
if line > f.lastline {
|
||||
f.lastline = line
|
||||
}
|
||||
|
||||
// Treat the file as if it contained only newlines
|
||||
// and column=1: use the line number as the offset.
|
||||
return f.Pos(line - 1)
|
||||
// Return a fake position assuming that f.file consists only of newlines.
|
||||
return token.Pos(f.file.Base() + line - 1)
|
||||
}
|
||||
|
||||
func (s *fakeFileSet) setLines() {
|
||||
fakeLinesOnce.Do(func() {
|
||||
fakeLines = make([]int, maxlines)
|
||||
for i := range fakeLines {
|
||||
fakeLines[i] = i
|
||||
}
|
||||
})
|
||||
for _, f := range s.files {
|
||||
f.file.SetLines(fakeLines[:f.lastline])
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1029,6 +1042,7 @@ func predeclared() []types.Type {
|
||||
// used internally by gc; never used by this package or in .a files
|
||||
anyType{},
|
||||
}
|
||||
predecl = append(predecl, additionalPredeclared()...)
|
||||
})
|
||||
return predecl
|
||||
}
|
||||
|
||||
16
vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go
generated
vendored
16
vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go
generated
vendored
@@ -16,7 +16,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
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)
|
||||
@@ -28,7 +28,8 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
fmt.Printf("header: %s", hdr)
|
||||
}
|
||||
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
|
||||
size, err = strconv.Atoi(s)
|
||||
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")
|
||||
return
|
||||
@@ -42,8 +43,8 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
// 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".
|
||||
//
|
||||
func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
||||
// 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) {
|
||||
// Read first line to make sure this is an object file.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
@@ -54,7 +55,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
||||
if string(line) == "!<arch>\n" {
|
||||
// Archive file. Scan to __.PKGDEF.
|
||||
var name string
|
||||
if name, _, err = readGopackHeader(r); err != nil {
|
||||
if name, size, err = readGopackHeader(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,6 +71,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
||||
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.
|
||||
@@ -86,8 +88,12 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
||||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
size -= int64(len(line))
|
||||
}
|
||||
hdr = string(line)
|
||||
if size < 0 {
|
||||
size = -1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
12
vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go
generated
vendored
12
vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go
generated
vendored
@@ -29,8 +29,14 @@ import (
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
// debugging/development support
|
||||
const debug = false
|
||||
const (
|
||||
// Enable debug during development: it adds some additional checks, and
|
||||
// prevents errors from being recovered.
|
||||
debug = false
|
||||
|
||||
// If trace is set, debugging output is printed to std out.
|
||||
trace = false
|
||||
)
|
||||
|
||||
var pkgExts = [...]string{".a", ".o"}
|
||||
|
||||
@@ -179,7 +185,7 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func
|
||||
|
||||
var hdr string
|
||||
buf := bufio.NewReader(rc)
|
||||
if hdr, err = FindExportData(buf); err != nil {
|
||||
if hdr, _, err = FindExportData(buf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
318
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
318
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
@@ -11,6 +11,7 @@ package gcimporter
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
@@ -19,11 +20,11 @@ import (
|
||||
"math/big"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// Current indexed export format version. Increase with each format change.
|
||||
// 0: Go1.11 encoding
|
||||
const iexportVersion = 0
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// Current bundled export format version. Increase with each format change.
|
||||
// 0: initial implementation
|
||||
@@ -35,31 +36,35 @@ const bundleVersion = 0
|
||||
// The package path of the top-level package will not be recorded,
|
||||
// so that calls to IImportData can override with a provided package path.
|
||||
func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
return iexportCommon(out, fset, false, []*types.Package{pkg})
|
||||
return iexportCommon(out, fset, false, iexportVersion, []*types.Package{pkg})
|
||||
}
|
||||
|
||||
// IExportBundle writes an indexed export bundle for pkgs to out.
|
||||
func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
|
||||
return iexportCommon(out, fset, true, pkgs)
|
||||
return iexportCommon(out, fset, true, iexportVersion, pkgs)
|
||||
}
|
||||
|
||||
func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, pkgs []*types.Package) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if ierr, ok := e.(internalError); ok {
|
||||
err = ierr
|
||||
return
|
||||
func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, pkgs []*types.Package) (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)
|
||||
}
|
||||
// Not an internal error; panic again.
|
||||
panic(e)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}
|
||||
|
||||
p := iexporter{
|
||||
fset: fset,
|
||||
version: version,
|
||||
allPkgs: map[*types.Package]bool{},
|
||||
stringIndex: map[string]uint64{},
|
||||
declIndex: map[types.Object]uint64{},
|
||||
tparamNames: map[types.Object]string{},
|
||||
typIndex: map[types.Type]uint64{},
|
||||
}
|
||||
if !bundle {
|
||||
@@ -119,7 +124,7 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, pkgs []*type
|
||||
if bundle {
|
||||
hdr.uint64(bundleVersion)
|
||||
}
|
||||
hdr.uint64(iexportVersion)
|
||||
hdr.uint64(uint64(p.version))
|
||||
hdr.uint64(uint64(p.strings.Len()))
|
||||
hdr.uint64(dataLen)
|
||||
|
||||
@@ -136,8 +141,12 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, pkgs []*type
|
||||
// non-compiler tools and includes a complete package description
|
||||
// (i.e., name and height).
|
||||
func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
|
||||
type pkgObj struct {
|
||||
obj types.Object
|
||||
name string // qualified name; differs from obj.Name for type params
|
||||
}
|
||||
// Build a map from packages to objects from that package.
|
||||
pkgObjs := map[*types.Package][]types.Object{}
|
||||
pkgObjs := map[*types.Package][]pkgObj{}
|
||||
|
||||
// For the main index, make sure to include every package that
|
||||
// we reference, even if we're not exporting (or reexporting)
|
||||
@@ -150,7 +159,8 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
|
||||
}
|
||||
|
||||
for obj := range index {
|
||||
pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], obj)
|
||||
name := w.p.exportName(obj)
|
||||
pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
|
||||
}
|
||||
|
||||
var pkgs []*types.Package
|
||||
@@ -158,7 +168,7 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
|
||||
pkgs = append(pkgs, pkg)
|
||||
|
||||
sort.Slice(objs, func(i, j int) bool {
|
||||
return objs[i].Name() < objs[j].Name()
|
||||
return objs[i].name < objs[j].name
|
||||
})
|
||||
}
|
||||
|
||||
@@ -175,15 +185,25 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
|
||||
objs := pkgObjs[pkg]
|
||||
w.uint64(uint64(len(objs)))
|
||||
for _, obj := range objs {
|
||||
w.string(obj.Name())
|
||||
w.uint64(index[obj])
|
||||
w.string(obj.name)
|
||||
w.uint64(index[obj.obj])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exportName returns the 'exported' name of an object. It differs from
|
||||
// obj.Name() only for type parameters (see tparamExportName for details).
|
||||
func (p *iexporter) exportName(obj types.Object) (res string) {
|
||||
if name := p.tparamNames[obj]; name != "" {
|
||||
return name
|
||||
}
|
||||
return obj.Name()
|
||||
}
|
||||
|
||||
type iexporter struct {
|
||||
fset *token.FileSet
|
||||
out *bytes.Buffer
|
||||
fset *token.FileSet
|
||||
out *bytes.Buffer
|
||||
version int
|
||||
|
||||
localpkg *types.Package
|
||||
|
||||
@@ -197,9 +217,21 @@ type iexporter struct {
|
||||
strings intWriter
|
||||
stringIndex map[string]uint64
|
||||
|
||||
data0 intWriter
|
||||
declIndex map[types.Object]uint64
|
||||
typIndex map[types.Type]uint64
|
||||
data0 intWriter
|
||||
declIndex map[types.Object]uint64
|
||||
tparamNames map[types.Object]string // typeparam->exported name
|
||||
typIndex map[types.Type]uint64
|
||||
|
||||
indent int // for tracing support
|
||||
}
|
||||
|
||||
func (p *iexporter) trace(format string, args ...interface{}) {
|
||||
if !trace {
|
||||
// Call sites should also be guarded, but having this check here allows
|
||||
// easily enabling/disabling debug trace statements.
|
||||
return
|
||||
}
|
||||
fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
|
||||
}
|
||||
|
||||
// stringOff returns the offset of s within the string section.
|
||||
@@ -225,7 +257,7 @@ func (p *iexporter) pushDecl(obj types.Object) {
|
||||
return
|
||||
}
|
||||
|
||||
p.declIndex[obj] = ^uint64(0) // mark n present in work queue
|
||||
p.declIndex[obj] = ^uint64(0) // mark obj present in work queue
|
||||
p.declTodo.pushTail(obj)
|
||||
}
|
||||
|
||||
@@ -233,10 +265,11 @@ func (p *iexporter) pushDecl(obj types.Object) {
|
||||
type exportWriter struct {
|
||||
p *iexporter
|
||||
|
||||
data intWriter
|
||||
currPkg *types.Package
|
||||
prevFile string
|
||||
prevLine int64
|
||||
data intWriter
|
||||
currPkg *types.Package
|
||||
prevFile string
|
||||
prevLine int64
|
||||
prevColumn int64
|
||||
}
|
||||
|
||||
func (w *exportWriter) exportPath(pkg *types.Package) string {
|
||||
@@ -247,6 +280,14 @@ func (w *exportWriter) exportPath(pkg *types.Package) string {
|
||||
}
|
||||
|
||||
func (p *iexporter) doDecl(obj types.Object) {
|
||||
if trace {
|
||||
p.trace("exporting decl %v (%T)", obj, obj)
|
||||
p.indent++
|
||||
defer func() {
|
||||
p.indent--
|
||||
p.trace("=> %s", obj)
|
||||
}()
|
||||
}
|
||||
w := p.newWriter()
|
||||
w.setPkg(obj.Pkg(), false)
|
||||
|
||||
@@ -261,8 +302,24 @@ func (p *iexporter) doDecl(obj types.Object) {
|
||||
if sig.Recv() != nil {
|
||||
panic(internalErrorf("unexpected method: %v", sig))
|
||||
}
|
||||
w.tag('F')
|
||||
|
||||
// Function.
|
||||
if typeparams.ForSignature(sig).Len() == 0 {
|
||||
w.tag('F')
|
||||
} else {
|
||||
w.tag('G')
|
||||
}
|
||||
w.pos(obj.Pos())
|
||||
// The tparam list of the function type is the declaration of the type
|
||||
// params. So, write out the type params right now. Then those type params
|
||||
// will be referenced via their type offset (via typOff) in all other
|
||||
// places in the signature and function where they are used.
|
||||
//
|
||||
// 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 {
|
||||
w.tparamList(obj.Name(), tparams, obj.Pkg())
|
||||
}
|
||||
w.signature(sig)
|
||||
|
||||
case *types.Const:
|
||||
@@ -271,30 +328,56 @@ func (p *iexporter) doDecl(obj types.Object) {
|
||||
w.value(obj.Type(), obj.Val())
|
||||
|
||||
case *types.TypeName:
|
||||
t := obj.Type()
|
||||
|
||||
if tparam, ok := t.(*typeparams.TypeParam); ok {
|
||||
w.tag('P')
|
||||
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)
|
||||
}
|
||||
w.bool(implicit)
|
||||
}
|
||||
w.typ(constraint, obj.Pkg())
|
||||
break
|
||||
}
|
||||
|
||||
if obj.IsAlias() {
|
||||
w.tag('A')
|
||||
w.pos(obj.Pos())
|
||||
w.typ(obj.Type(), obj.Pkg())
|
||||
w.typ(t, obj.Pkg())
|
||||
break
|
||||
}
|
||||
|
||||
// Defined type.
|
||||
w.tag('T')
|
||||
named, ok := t.(*types.Named)
|
||||
if !ok {
|
||||
panic(internalErrorf("%s is not a defined type", t))
|
||||
}
|
||||
|
||||
if typeparams.ForNamed(named).Len() == 0 {
|
||||
w.tag('T')
|
||||
} else {
|
||||
w.tag('U')
|
||||
}
|
||||
w.pos(obj.Pos())
|
||||
|
||||
if typeparams.ForNamed(named).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())
|
||||
}
|
||||
|
||||
underlying := obj.Type().Underlying()
|
||||
w.typ(underlying, obj.Pkg())
|
||||
|
||||
t := obj.Type()
|
||||
if types.IsInterface(t) {
|
||||
break
|
||||
}
|
||||
|
||||
named, ok := t.(*types.Named)
|
||||
if !ok {
|
||||
panic(internalErrorf("%s is not a defined type", t))
|
||||
}
|
||||
|
||||
n := named.NumMethods()
|
||||
w.uint64(uint64(n))
|
||||
for i := 0; i < n; i++ {
|
||||
@@ -302,6 +385,17 @@ func (p *iexporter) doDecl(obj types.Object) {
|
||||
w.pos(m.Pos())
|
||||
w.string(m.Name())
|
||||
sig, _ := m.Type().(*types.Signature)
|
||||
|
||||
// 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 {
|
||||
prefix := obj.Name() + "." + m.Name()
|
||||
for i := 0; i < rparams.Len(); i++ {
|
||||
rparam := rparams.At(i)
|
||||
name := tparamExportName(prefix, rparam)
|
||||
w.p.tparamNames[rparam.Obj()] = name
|
||||
}
|
||||
}
|
||||
w.param(sig.Recv())
|
||||
w.signature(sig)
|
||||
}
|
||||
@@ -318,6 +412,48 @@ func (w *exportWriter) tag(tag byte) {
|
||||
}
|
||||
|
||||
func (w *exportWriter) pos(pos token.Pos) {
|
||||
if w.p.version >= iexportVersionPosCol {
|
||||
w.posV1(pos)
|
||||
} else {
|
||||
w.posV0(pos)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) posV1(pos token.Pos) {
|
||||
if w.p.fset == nil {
|
||||
w.int64(0)
|
||||
return
|
||||
}
|
||||
|
||||
p := w.p.fset.Position(pos)
|
||||
file := p.Filename
|
||||
line := int64(p.Line)
|
||||
column := int64(p.Column)
|
||||
|
||||
deltaColumn := (column - w.prevColumn) << 1
|
||||
deltaLine := (line - w.prevLine) << 1
|
||||
|
||||
if file != w.prevFile {
|
||||
deltaLine |= 1
|
||||
}
|
||||
if deltaLine != 0 {
|
||||
deltaColumn |= 1
|
||||
}
|
||||
|
||||
w.int64(deltaColumn)
|
||||
if deltaColumn&1 != 0 {
|
||||
w.int64(deltaLine)
|
||||
if deltaLine&1 != 0 {
|
||||
w.string(file)
|
||||
}
|
||||
}
|
||||
|
||||
w.prevFile = file
|
||||
w.prevLine = line
|
||||
w.prevColumn = column
|
||||
}
|
||||
|
||||
func (w *exportWriter) posV0(pos token.Pos) {
|
||||
if w.p.fset == nil {
|
||||
w.int64(0)
|
||||
return
|
||||
@@ -359,10 +495,11 @@ func (w *exportWriter) pkg(pkg *types.Package) {
|
||||
}
|
||||
|
||||
func (w *exportWriter) qualifiedIdent(obj types.Object) {
|
||||
name := w.p.exportName(obj)
|
||||
|
||||
// Ensure any referenced declarations are written out too.
|
||||
w.p.pushDecl(obj)
|
||||
|
||||
w.string(obj.Name())
|
||||
w.string(name)
|
||||
w.pkg(obj.Pkg())
|
||||
}
|
||||
|
||||
@@ -396,11 +533,32 @@ func (w *exportWriter) startType(k itag) {
|
||||
}
|
||||
|
||||
func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
||||
if trace {
|
||||
w.p.trace("exporting type %s (%T)", t, t)
|
||||
w.p.indent++
|
||||
defer func() {
|
||||
w.p.indent--
|
||||
w.p.trace("=> %s", t)
|
||||
}()
|
||||
}
|
||||
switch t := t.(type) {
|
||||
case *types.Named:
|
||||
if targs := typeparams.NamedTypeArgs(t); 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)
|
||||
return
|
||||
}
|
||||
w.startType(definedType)
|
||||
w.qualifiedIdent(t.Obj())
|
||||
|
||||
case *typeparams.TypeParam:
|
||||
w.startType(typeParamType)
|
||||
w.qualifiedIdent(t.Obj())
|
||||
|
||||
case *types.Pointer:
|
||||
w.startType(pointerType)
|
||||
w.typ(t.Elem(), pkg)
|
||||
@@ -461,9 +619,14 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
||||
n := t.NumEmbeddeds()
|
||||
w.uint64(uint64(n))
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Embedded(i)
|
||||
w.pos(f.Obj().Pos())
|
||||
w.typ(f.Obj().Type(), f.Obj().Pkg())
|
||||
ft := t.EmbeddedType(i)
|
||||
tPkg := pkg
|
||||
if named, _ := ft.(*types.Named); named != nil {
|
||||
w.pos(named.Obj().Pos())
|
||||
} else {
|
||||
w.pos(token.NoPos)
|
||||
}
|
||||
w.typ(ft, tPkg)
|
||||
}
|
||||
|
||||
n = t.NumExplicitMethods()
|
||||
@@ -476,6 +639,16 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
||||
w.signature(sig)
|
||||
}
|
||||
|
||||
case *typeparams.Union:
|
||||
w.startType(unionType)
|
||||
nt := t.Len()
|
||||
w.uint64(uint64(nt))
|
||||
for i := 0; i < nt; i++ {
|
||||
term := t.Term(i)
|
||||
w.bool(term.Tilde())
|
||||
w.typ(term.Type(), pkg)
|
||||
}
|
||||
|
||||
default:
|
||||
panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
|
||||
}
|
||||
@@ -497,6 +670,56 @@ func (w *exportWriter) signature(sig *types.Signature) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *exportWriter) typeList(ts *typeparams.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) {
|
||||
ll := uint64(list.Len())
|
||||
w.uint64(ll)
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
tparam := list.At(i)
|
||||
// Set the type parameter exportName before exporting its type.
|
||||
exportName := tparamExportName(prefix, tparam)
|
||||
w.p.tparamNames[tparam.Obj()] = exportName
|
||||
w.typ(list.At(i), pkg)
|
||||
}
|
||||
}
|
||||
|
||||
const blankMarker = "$"
|
||||
|
||||
// tparamExportName returns the 'exported' name of a type parameter, which
|
||||
// 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 {
|
||||
assert(prefix != "")
|
||||
name := tparam.Obj().Name()
|
||||
if name == "_" {
|
||||
name = blankMarker + strconv.Itoa(tparam.Index())
|
||||
}
|
||||
return prefix + "." + name
|
||||
}
|
||||
|
||||
// tparamName returns the real name of a type parameter, after stripping its
|
||||
// qualifying prefix and reverting blank-name encoding. See tparamExportName
|
||||
// for details.
|
||||
func tparamName(exportName string) string {
|
||||
// Remove the "path" from the type param name that makes it unique.
|
||||
ix := strings.LastIndex(exportName, ".")
|
||||
if ix < 0 {
|
||||
errorf("malformed type parameter export name %s: missing prefix", exportName)
|
||||
}
|
||||
name := exportName[ix+1:]
|
||||
if strings.HasPrefix(name, blankMarker) {
|
||||
return "_"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (w *exportWriter) paramList(tup *types.Tuple) {
|
||||
n := tup.Len()
|
||||
w.uint64(uint64(n))
|
||||
@@ -513,6 +736,9 @@ func (w *exportWriter) param(obj types.Object) {
|
||||
|
||||
func (w *exportWriter) value(typ types.Type, v constant.Value) {
|
||||
w.typ(typ, nil)
|
||||
if w.p.version >= iexportVersionGo1_18 {
|
||||
w.int64(int64(v.Kind()))
|
||||
}
|
||||
|
||||
switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
|
||||
case types.IsBoolean:
|
||||
|
||||
280
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
280
vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go
generated
vendored
@@ -18,6 +18,9 @@ import (
|
||||
"go/types"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
type intReader struct {
|
||||
@@ -41,6 +44,19 @@ func (r *intReader) uint64() uint64 {
|
||||
return i
|
||||
}
|
||||
|
||||
// Keep this in sync with constants in iexport.go.
|
||||
const (
|
||||
iexportVersionGo1_11 = 0
|
||||
iexportVersionPosCol = 1
|
||||
iexportVersionGo1_18 = 2
|
||||
iexportVersionGenerics = 2
|
||||
)
|
||||
|
||||
type ident struct {
|
||||
pkg string
|
||||
name string
|
||||
}
|
||||
|
||||
const predeclReserved = 32
|
||||
|
||||
type itag uint64
|
||||
@@ -56,6 +72,9 @@ const (
|
||||
signatureType
|
||||
structType
|
||||
interfaceType
|
||||
typeParamType
|
||||
instanceType
|
||||
unionType
|
||||
)
|
||||
|
||||
// IImportData imports a package from the serialized package data
|
||||
@@ -78,15 +97,17 @@ func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
|
||||
const currentVersion = 1
|
||||
version := int64(-1)
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
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)
|
||||
if !debug {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}
|
||||
|
||||
r := &intReader{bytes.NewReader(data), path}
|
||||
|
||||
@@ -101,9 +122,13 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
|
||||
version = int64(r.uint64())
|
||||
switch version {
|
||||
case currentVersion, 0:
|
||||
case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
|
||||
default:
|
||||
errorf("unknown iexport format version %d", version)
|
||||
if version > iexportVersionGo1_18 {
|
||||
errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
|
||||
} else {
|
||||
errorf("unknown iexport format version %d", version)
|
||||
}
|
||||
}
|
||||
|
||||
sLen := int64(r.uint64())
|
||||
@@ -115,8 +140,8 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
r.Seek(sLen+dLen, io.SeekCurrent)
|
||||
|
||||
p := iimporter{
|
||||
ipath: path,
|
||||
version: int(version),
|
||||
ipath: path,
|
||||
|
||||
stringData: stringData,
|
||||
stringCache: make(map[uint64]string),
|
||||
@@ -125,12 +150,16 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
declData: declData,
|
||||
pkgIndex: make(map[*types.Package]map[string]uint64),
|
||||
typCache: make(map[uint64]types.Type),
|
||||
// Separate map for typeparams, keyed by their package and unique
|
||||
// name.
|
||||
tparamIndex: make(map[ident]types.Type),
|
||||
|
||||
fake: fakeFileSet{
|
||||
fset: fset,
|
||||
files: make(map[string]*token.File),
|
||||
files: make(map[string]*fileInfo),
|
||||
},
|
||||
}
|
||||
defer p.fake.setLines() // set lines for files in fset
|
||||
|
||||
for i, pt := range predeclared() {
|
||||
p.typCache[uint64(i)] = pt
|
||||
@@ -208,6 +237,15 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
pkg.MarkComplete()
|
||||
}
|
||||
|
||||
// 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(),
|
||||
// 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)
|
||||
}
|
||||
|
||||
for _, typ := range p.interfaceList {
|
||||
typ.Complete()
|
||||
}
|
||||
@@ -215,23 +253,51 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
type setConstraintArgs struct {
|
||||
t *typeparams.TypeParam
|
||||
constraint types.Type
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
ipath string
|
||||
version int
|
||||
ipath string
|
||||
|
||||
stringData []byte
|
||||
stringCache map[uint64]string
|
||||
pkgCache map[uint64]*types.Package
|
||||
|
||||
declData []byte
|
||||
pkgIndex map[*types.Package]map[string]uint64
|
||||
typCache map[uint64]types.Type
|
||||
declData []byte
|
||||
pkgIndex map[*types.Package]map[string]uint64
|
||||
typCache map[uint64]types.Type
|
||||
tparamIndex map[ident]types.Type
|
||||
|
||||
fake fakeFileSet
|
||||
interfaceList []*types.Interface
|
||||
|
||||
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||
later []setConstraintArgs
|
||||
|
||||
indent int // for tracing support
|
||||
}
|
||||
|
||||
func (p *iimporter) trace(format string, args ...interface{}) {
|
||||
if !trace {
|
||||
// Call sites should also be guarded, but having this check here allows
|
||||
// easily enabling/disabling debug trace statements.
|
||||
return
|
||||
}
|
||||
fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
|
||||
}
|
||||
|
||||
func (p *iimporter) doDecl(pkg *types.Package, name string) {
|
||||
if debug {
|
||||
p.trace("import decl %s", name)
|
||||
p.indent++
|
||||
defer func() {
|
||||
p.indent--
|
||||
p.trace("=> %s", name)
|
||||
}()
|
||||
}
|
||||
// See if we've already imported this declaration.
|
||||
if obj := pkg.Scope().Lookup(name); obj != nil {
|
||||
return
|
||||
@@ -273,7 +339,7 @@ func (p *iimporter) pkgAt(off uint64) *types.Package {
|
||||
}
|
||||
|
||||
func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
|
||||
if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) {
|
||||
if t, ok := p.typCache[off]; ok && canReuse(base, t) {
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -285,12 +351,30 @@ func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
|
||||
r.declReader.Reset(p.declData[off-predeclReserved:])
|
||||
t := r.doType(base)
|
||||
|
||||
if base == nil || !isInterface(t) {
|
||||
if canReuse(base, t) {
|
||||
p.typCache[off] = t
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// canReuse reports whether the type rhs on the RHS of the declaration for def
|
||||
// may be re-used.
|
||||
//
|
||||
// Specifically, if def is non-nil and rhs is an interface type with methods, it
|
||||
// may not be re-used because we have a convention of setting the receiver type
|
||||
// for interface methods to def.
|
||||
func canReuse(def *types.Named, rhs types.Type) bool {
|
||||
if def == nil {
|
||||
return true
|
||||
}
|
||||
iface, _ := rhs.(*types.Interface)
|
||||
if iface == nil {
|
||||
return true
|
||||
}
|
||||
// Don't use iface.Empty() here as iface may not be complete.
|
||||
return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0
|
||||
}
|
||||
|
||||
type importReader struct {
|
||||
p *iimporter
|
||||
declReader bytes.Reader
|
||||
@@ -315,17 +399,26 @@ func (r *importReader) obj(name string) {
|
||||
|
||||
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
|
||||
|
||||
case 'F':
|
||||
sig := r.signature(nil)
|
||||
|
||||
case 'F', 'G':
|
||||
var tparams []*typeparams.TypeParam
|
||||
if tag == 'G' {
|
||||
tparams = r.tparamList()
|
||||
}
|
||||
sig := r.signature(nil, nil, tparams)
|
||||
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
|
||||
|
||||
case 'T':
|
||||
case 'T', 'U':
|
||||
// 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)
|
||||
// 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' {
|
||||
tparams := r.tparamList()
|
||||
typeparams.SetForNamed(named, tparams)
|
||||
}
|
||||
|
||||
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
||||
named.SetUnderlying(underlying)
|
||||
@@ -335,12 +428,59 @@ func (r *importReader) obj(name string) {
|
||||
mpos := r.pos()
|
||||
mname := r.ident()
|
||||
recv := r.param()
|
||||
msig := r.signature(recv)
|
||||
|
||||
// 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
|
||||
if targs.Len() > 0 {
|
||||
rparams = make([]*typeparams.TypeParam, targs.Len())
|
||||
for i := range rparams {
|
||||
rparams[i] = targs.At(i).(*typeparams.TypeParam)
|
||||
}
|
||||
}
|
||||
msig := r.signature(recv, rparams, nil)
|
||||
|
||||
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
|
||||
}
|
||||
}
|
||||
|
||||
case 'P':
|
||||
// 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.
|
||||
if r.p.version < iexportVersionGenerics {
|
||||
errorf("unexpected type param type")
|
||||
}
|
||||
name0 := tparamName(name)
|
||||
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
|
||||
t := typeparams.NewTypeParam(tn, nil)
|
||||
|
||||
// To handle recursive references to the typeparam within its
|
||||
// bound, save the partial type in tparamIndex before reading the bounds.
|
||||
id := ident{r.currPkg.Name(), name}
|
||||
r.p.tparamIndex[id] = t
|
||||
var implicit bool
|
||||
if r.p.version >= iexportVersionGo1_18 {
|
||||
implicit = r.bool()
|
||||
}
|
||||
constraint := r.typ()
|
||||
if implicit {
|
||||
iface, _ := constraint.(*types.Interface)
|
||||
if iface == nil {
|
||||
errorf("non-interface constraint marked implicit")
|
||||
}
|
||||
typeparams.MarkImplicit(iface)
|
||||
}
|
||||
// The constraint type may not be complete, if we
|
||||
// are in the middle of a type recursion involving type
|
||||
// constraints. So, we defer SetConstraint until we have
|
||||
// completely set up all types in ImportData.
|
||||
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||
|
||||
case 'V':
|
||||
typ := r.typ()
|
||||
|
||||
@@ -357,6 +497,10 @@ func (r *importReader) declare(obj types.Object) {
|
||||
|
||||
func (r *importReader) value() (typ types.Type, val constant.Value) {
|
||||
typ = r.typ()
|
||||
if r.p.version >= iexportVersionGo1_18 {
|
||||
// TODO: add support for using the kind.
|
||||
_ = constant.Kind(r.int64())
|
||||
}
|
||||
|
||||
switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
|
||||
case types.IsBoolean:
|
||||
@@ -499,7 +643,7 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) {
|
||||
}
|
||||
|
||||
func (r *importReader) pos() token.Pos {
|
||||
if r.p.version >= 1 {
|
||||
if r.p.version >= iexportVersionPosCol {
|
||||
r.posv1()
|
||||
} else {
|
||||
r.posv0()
|
||||
@@ -547,8 +691,17 @@ func isInterface(t types.Type) bool {
|
||||
func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) }
|
||||
func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
|
||||
|
||||
func (r *importReader) doType(base *types.Named) types.Type {
|
||||
switch k := r.kind(); k {
|
||||
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.indent++
|
||||
defer func() {
|
||||
r.p.indent--
|
||||
r.p.trace("=> %s", res)
|
||||
}()
|
||||
}
|
||||
switch k {
|
||||
default:
|
||||
errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
|
||||
return nil
|
||||
@@ -571,7 +724,7 @@ func (r *importReader) doType(base *types.Named) types.Type {
|
||||
return types.NewMap(r.typ(), r.typ())
|
||||
case signatureType:
|
||||
r.currPkg = r.pkg()
|
||||
return r.signature(nil)
|
||||
return r.signature(nil, nil, nil)
|
||||
|
||||
case structType:
|
||||
r.currPkg = r.pkg()
|
||||
@@ -611,13 +764,56 @@ func (r *importReader) doType(base *types.Named) types.Type {
|
||||
recv = types.NewVar(token.NoPos, r.currPkg, "", base)
|
||||
}
|
||||
|
||||
msig := r.signature(recv)
|
||||
msig := r.signature(recv, nil, nil)
|
||||
methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
|
||||
}
|
||||
|
||||
typ := newInterface(methods, embeddeds)
|
||||
r.p.interfaceList = append(r.p.interfaceList, typ)
|
||||
return typ
|
||||
|
||||
case typeParamType:
|
||||
if r.p.version < iexportVersionGenerics {
|
||||
errorf("unexpected type param type")
|
||||
}
|
||||
pkg, name := r.qualifiedIdent()
|
||||
id := ident{pkg.Name(), name}
|
||||
if t, ok := r.p.tparamIndex[id]; ok {
|
||||
// We're already in the process of importing this typeparam.
|
||||
return t
|
||||
}
|
||||
// Otherwise, import the definition of the typeparam now.
|
||||
r.p.doDecl(pkg, name)
|
||||
return r.p.tparamIndex[id]
|
||||
|
||||
case instanceType:
|
||||
if r.p.version < iexportVersionGenerics {
|
||||
errorf("unexpected instantiation type")
|
||||
}
|
||||
// pos does not matter for instances: they are positioned on the original
|
||||
// type.
|
||||
_ = r.pos()
|
||||
len := r.uint64()
|
||||
targs := make([]types.Type, len)
|
||||
for i := range targs {
|
||||
targs[i] = r.typ()
|
||||
}
|
||||
baseType := r.typ()
|
||||
// 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)
|
||||
return t
|
||||
|
||||
case unionType:
|
||||
if r.p.version < iexportVersionGenerics {
|
||||
errorf("unexpected instantiation type")
|
||||
}
|
||||
terms := make([]*typeparams.Term, r.uint64())
|
||||
for i := range terms {
|
||||
terms[i] = typeparams.NewTerm(r.bool(), r.typ())
|
||||
}
|
||||
return typeparams.NewUnion(terms)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,11 +821,25 @@ func (r *importReader) kind() itag {
|
||||
return itag(r.uint64())
|
||||
}
|
||||
|
||||
func (r *importReader) signature(recv *types.Var) *types.Signature {
|
||||
func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature {
|
||||
params := r.paramList()
|
||||
results := r.paramList()
|
||||
variadic := params.Len() > 0 && r.bool()
|
||||
return types.NewSignature(recv, params, results, variadic)
|
||||
return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic)
|
||||
}
|
||||
|
||||
func (r *importReader) tparamList() []*typeparams.TypeParam {
|
||||
n := r.uint64()
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
xs := make([]*typeparams.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)
|
||||
}
|
||||
return xs
|
||||
}
|
||||
|
||||
func (r *importReader) paramList() *types.Tuple {
|
||||
@@ -674,3 +884,13 @@ 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
|
||||
}
|
||||
|
||||
16
vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go
generated
vendored
Normal file
16
vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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
|
||||
}
|
||||
23
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
Normal file
23
vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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(),
|
||||
}
|
||||
}
|
||||
204
vendor/golang.org/x/tools/go/loader/doc.go
generated
vendored
Normal file
204
vendor/golang.org/x/tools/go/loader/doc.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright 2015 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 loader loads a complete Go program from source code, parsing
|
||||
// and type-checking the initial packages plus their transitive closure
|
||||
// of dependencies. The ASTs and the derived facts are retained for
|
||||
// later use.
|
||||
//
|
||||
// Deprecated: This is an older API and does not have support
|
||||
// for modules. Use golang.org/x/tools/go/packages instead.
|
||||
//
|
||||
// The package defines two primary types: Config, which specifies a
|
||||
// set of initial packages to load and various other options; and
|
||||
// Program, which is the result of successfully loading the packages
|
||||
// specified by a configuration.
|
||||
//
|
||||
// The configuration can be set directly, but *Config provides various
|
||||
// convenience methods to simplify the common cases, each of which can
|
||||
// be called any number of times. Finally, these are followed by a
|
||||
// call to Load() to actually load and type-check the program.
|
||||
//
|
||||
// var conf loader.Config
|
||||
//
|
||||
// // Use the command-line arguments to specify
|
||||
// // a set of initial packages to load from source.
|
||||
// // See FromArgsUsage for help.
|
||||
// rest, err := conf.FromArgs(os.Args[1:], wantTests)
|
||||
//
|
||||
// // Parse the specified files and create an ad hoc package with path "foo".
|
||||
// // All files must have the same 'package' declaration.
|
||||
// conf.CreateFromFilenames("foo", "foo.go", "bar.go")
|
||||
//
|
||||
// // Create an ad hoc package with path "foo" from
|
||||
// // the specified already-parsed files.
|
||||
// // All ASTs must have the same 'package' declaration.
|
||||
// conf.CreateFromFiles("foo", parsedFiles)
|
||||
//
|
||||
// // Add "runtime" to the set of packages to be loaded.
|
||||
// conf.Import("runtime")
|
||||
//
|
||||
// // Adds "fmt" and "fmt_test" to the set of packages
|
||||
// // to be loaded. "fmt" will include *_test.go files.
|
||||
// conf.ImportWithTests("fmt")
|
||||
//
|
||||
// // Finally, load all the packages specified by the configuration.
|
||||
// prog, err := conf.Load()
|
||||
//
|
||||
// See examples_test.go for examples of API usage.
|
||||
//
|
||||
//
|
||||
// CONCEPTS AND TERMINOLOGY
|
||||
//
|
||||
// The WORKSPACE is the set of packages accessible to the loader. The
|
||||
// workspace is defined by Config.Build, a *build.Context. The
|
||||
// default context treats subdirectories of $GOROOT and $GOPATH as
|
||||
// packages, but this behavior may be overridden.
|
||||
//
|
||||
// An AD HOC package is one specified as a set of source files on the
|
||||
// command line. In the simplest case, it may consist of a single file
|
||||
// such as $GOROOT/src/net/http/triv.go.
|
||||
//
|
||||
// EXTERNAL TEST packages are those comprised of a set of *_test.go
|
||||
// files all with the same 'package foo_test' declaration, all in the
|
||||
// same directory. (go/build.Package calls these files XTestFiles.)
|
||||
//
|
||||
// An IMPORTABLE package is one that can be referred to by some import
|
||||
// spec. Every importable package is uniquely identified by its
|
||||
// PACKAGE PATH or just PATH, a string such as "fmt", "encoding/json",
|
||||
// or "cmd/vendor/golang.org/x/arch/x86/x86asm". A package path
|
||||
// typically denotes a subdirectory of the workspace.
|
||||
//
|
||||
// An import declaration uses an IMPORT PATH to refer to a package.
|
||||
// Most import declarations use the package path as the import path.
|
||||
//
|
||||
// Due to VENDORING (https://golang.org/s/go15vendor), the
|
||||
// interpretation of an import path may depend on the directory in which
|
||||
// it appears. To resolve an import path to a package path, go/build
|
||||
// must search the enclosing directories for a subdirectory named
|
||||
// "vendor".
|
||||
//
|
||||
// ad hoc packages and external test packages are NON-IMPORTABLE. The
|
||||
// path of an ad hoc package is inferred from the package
|
||||
// declarations of its files and is therefore not a unique package key.
|
||||
// For example, Config.CreatePkgs may specify two initial ad hoc
|
||||
// packages, both with path "main".
|
||||
//
|
||||
// An AUGMENTED package is an importable package P plus all the
|
||||
// *_test.go files with same 'package foo' declaration as P.
|
||||
// (go/build.Package calls these files TestFiles.)
|
||||
//
|
||||
// The INITIAL packages are those specified in the configuration. A
|
||||
// DEPENDENCY is a package loaded to satisfy an import in an initial
|
||||
// package or another dependency.
|
||||
//
|
||||
package loader
|
||||
|
||||
// IMPLEMENTATION NOTES
|
||||
//
|
||||
// 'go test', in-package test files, and import cycles
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
// An external test package may depend upon members of the augmented
|
||||
// package that are not in the unaugmented package, such as functions
|
||||
// that expose internals. (See bufio/export_test.go for an example.)
|
||||
// So, the loader must ensure that for each external test package
|
||||
// it loads, it also augments the corresponding non-test package.
|
||||
//
|
||||
// The import graph over n unaugmented packages must be acyclic; the
|
||||
// import graph over n-1 unaugmented packages plus one augmented
|
||||
// package must also be acyclic. ('go test' relies on this.) But the
|
||||
// import graph over n augmented packages may contain cycles.
|
||||
//
|
||||
// First, all the (unaugmented) non-test packages and their
|
||||
// dependencies are imported in the usual way; the loader reports an
|
||||
// error if it detects an import cycle.
|
||||
//
|
||||
// Then, each package P for which testing is desired is augmented by
|
||||
// the list P' of its in-package test files, by calling
|
||||
// (*types.Checker).Files. This arrangement ensures that P' may
|
||||
// reference definitions within P, but P may not reference definitions
|
||||
// within P'. Furthermore, P' may import any other package, including
|
||||
// ones that depend upon P, without an import cycle error.
|
||||
//
|
||||
// Consider two packages A and B, both of which have lists of
|
||||
// in-package test files we'll call A' and B', and which have the
|
||||
// following import graph edges:
|
||||
// B imports A
|
||||
// B' imports A
|
||||
// A' imports B
|
||||
// This last edge would be expected to create an error were it not
|
||||
// for the special type-checking discipline above.
|
||||
// Cycles of size greater than two are possible. For example:
|
||||
// compress/bzip2/bzip2_test.go (package bzip2) imports "io/ioutil"
|
||||
// io/ioutil/tempfile_test.go (package ioutil) imports "regexp"
|
||||
// regexp/exec_test.go (package regexp) imports "compress/bzip2"
|
||||
//
|
||||
//
|
||||
// Concurrency
|
||||
// -----------
|
||||
//
|
||||
// Let us define the import dependency graph as follows. Each node is a
|
||||
// list of files passed to (Checker).Files at once. Many of these lists
|
||||
// are the production code of an importable Go package, so those nodes
|
||||
// are labelled by the package's path. The remaining nodes are
|
||||
// ad hoc packages and lists of in-package *_test.go files that augment
|
||||
// an importable package; those nodes have no label.
|
||||
//
|
||||
// The edges of the graph represent import statements appearing within a
|
||||
// file. An edge connects a node (a list of files) to the node it
|
||||
// imports, which is importable and thus always labelled.
|
||||
//
|
||||
// Loading is controlled by this dependency graph.
|
||||
//
|
||||
// To reduce I/O latency, we start loading a package's dependencies
|
||||
// asynchronously as soon as we've parsed its files and enumerated its
|
||||
// imports (scanImports). This performs a preorder traversal of the
|
||||
// import dependency graph.
|
||||
//
|
||||
// To exploit hardware parallelism, we type-check unrelated packages in
|
||||
// parallel, where "unrelated" means not ordered by the partial order of
|
||||
// the import dependency graph.
|
||||
//
|
||||
// We use a concurrency-safe non-blocking cache (importer.imported) to
|
||||
// record the results of type-checking, whether success or failure. An
|
||||
// entry is created in this cache by startLoad the first time the
|
||||
// package is imported. The first goroutine to request an entry becomes
|
||||
// responsible for completing the task and broadcasting completion to
|
||||
// subsequent requestors, which block until then.
|
||||
//
|
||||
// Type checking occurs in (parallel) postorder: we cannot type-check a
|
||||
// set of files until we have loaded and type-checked all of their
|
||||
// immediate dependencies (and thus all of their transitive
|
||||
// dependencies). If the input were guaranteed free of import cycles,
|
||||
// this would be trivial: we could simply wait for completion of the
|
||||
// dependencies and then invoke the typechecker.
|
||||
//
|
||||
// But as we saw in the 'go test' section above, some cycles in the
|
||||
// import graph over packages are actually legal, so long as the
|
||||
// cycle-forming edge originates in the in-package test files that
|
||||
// augment the package. This explains why the nodes of the import
|
||||
// dependency graph are not packages, but lists of files: the unlabelled
|
||||
// nodes avoid the cycles. Consider packages A and B where B imports A
|
||||
// and A's in-package tests AT import B. The naively constructed import
|
||||
// graph over packages would contain a cycle (A+AT) --> B --> (A+AT) but
|
||||
// the graph over lists of files is AT --> B --> A, where AT is an
|
||||
// unlabelled node.
|
||||
//
|
||||
// Awaiting completion of the dependencies in a cyclic graph would
|
||||
// deadlock, so we must materialize the import dependency graph (as
|
||||
// importer.graph) and check whether each import edge forms a cycle. If
|
||||
// x imports y, and the graph already contains a path from y to x, then
|
||||
// there is an import cycle, in which case the processing of x must not
|
||||
// wait for the completion of processing of y.
|
||||
//
|
||||
// When the type-checker makes a callback (doImport) to the loader for a
|
||||
// given import edge, there are two possible cases. In the normal case,
|
||||
// the dependency has already been completely type-checked; doImport
|
||||
// does a cache lookup and returns it. In the cyclic case, the entry in
|
||||
// the cache is still necessarily incomplete, indicating a cycle. We
|
||||
// perform the cycle check again to obtain the error message, and return
|
||||
// the error.
|
||||
//
|
||||
// The result of using concurrency is about a 2.5x speedup for stdlib_test.
|
||||
1080
vendor/golang.org/x/tools/go/loader/loader.go
generated
vendored
Normal file
1080
vendor/golang.org/x/tools/go/loader/loader.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
124
vendor/golang.org/x/tools/go/loader/util.go
generated
vendored
Normal file
124
vendor/golang.org/x/tools/go/loader/util.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
)
|
||||
|
||||
// We use a counting semaphore to limit
|
||||
// the number of parallel I/O calls per process.
|
||||
var ioLimit = make(chan bool, 10)
|
||||
|
||||
// parseFiles parses the Go source files within directory dir and
|
||||
// returns the ASTs of the ones that could be at least partially parsed,
|
||||
// along with a list of I/O and parse errors encountered.
|
||||
//
|
||||
// I/O is done via ctxt, which may specify a virtual file system.
|
||||
// displayPath is used to transform the filenames attached to the ASTs.
|
||||
//
|
||||
func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) {
|
||||
if displayPath == nil {
|
||||
displayPath = func(path string) string { return path }
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
n := len(files)
|
||||
parsed := make([]*ast.File, n)
|
||||
errors := make([]error, n)
|
||||
for i, file := range files {
|
||||
if !buildutil.IsAbsPath(ctxt, file) {
|
||||
file = buildutil.JoinPath(ctxt, dir, file)
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(i int, file string) {
|
||||
ioLimit <- true // wait
|
||||
defer func() {
|
||||
wg.Done()
|
||||
<-ioLimit // signal
|
||||
}()
|
||||
var rd io.ReadCloser
|
||||
var err error
|
||||
if ctxt.OpenFile != nil {
|
||||
rd, err = ctxt.OpenFile(file)
|
||||
} else {
|
||||
rd, err = os.Open(file)
|
||||
}
|
||||
if err != nil {
|
||||
errors[i] = err // open failed
|
||||
return
|
||||
}
|
||||
|
||||
// ParseFile may return both an AST and an error.
|
||||
parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode)
|
||||
rd.Close()
|
||||
}(i, file)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// Eliminate nils, preserving order.
|
||||
var o int
|
||||
for _, f := range parsed {
|
||||
if f != nil {
|
||||
parsed[o] = f
|
||||
o++
|
||||
}
|
||||
}
|
||||
parsed = parsed[:o]
|
||||
|
||||
o = 0
|
||||
for _, err := range errors {
|
||||
if err != nil {
|
||||
errors[o] = err
|
||||
o++
|
||||
}
|
||||
}
|
||||
errors = errors[:o]
|
||||
|
||||
return parsed, errors
|
||||
}
|
||||
|
||||
// scanImports returns the set of all import paths from all
|
||||
// import specs in the specified files.
|
||||
func scanImports(files []*ast.File) map[string]bool {
|
||||
imports := make(map[string]bool)
|
||||
for _, f := range files {
|
||||
for _, decl := range f.Decls {
|
||||
if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
|
||||
for _, spec := range decl.Specs {
|
||||
spec := spec.(*ast.ImportSpec)
|
||||
|
||||
// NB: do not assume the program is well-formed!
|
||||
path, err := strconv.Unquote(spec.Path.Value)
|
||||
if err != nil {
|
||||
continue // quietly ignore the error
|
||||
}
|
||||
if path == "C" {
|
||||
continue // skip pseudopackage
|
||||
}
|
||||
imports[path] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return imports
|
||||
}
|
||||
|
||||
// ---------- Internal helpers ----------
|
||||
|
||||
// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
|
||||
func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
|
||||
p := int(pos)
|
||||
base := f.Base()
|
||||
return base <= p && p < base+f.Size()
|
||||
}
|
||||
5
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
5
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
@@ -26,6 +26,7 @@ import (
|
||||
"golang.org/x/tools/go/gcexportdata"
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
"golang.org/x/tools/internal/packagesinternal"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
@@ -327,6 +328,9 @@ type Package struct {
|
||||
// The NeedSyntax LoadMode bit populates this field for packages matching the patterns.
|
||||
// If NeedDeps and NeedImports are also set, this field will also be populated
|
||||
// for dependencies.
|
||||
//
|
||||
// Syntax is kept in the same order as CompiledGoFiles, with the caveat that nils are
|
||||
// removed. If parsing returned nil, Syntax may be shorter than CompiledGoFiles.
|
||||
Syntax []*ast.File
|
||||
|
||||
// TypesInfo provides type information about the package's syntax trees.
|
||||
@@ -910,6 +914,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
}
|
||||
typeparams.InitInstanceInfo(lpkg.TypesInfo)
|
||||
lpkg.TypesSizes = ld.sizes
|
||||
|
||||
importer := importerFunc(func(path string) (*types.Package, error) {
|
||||
|
||||
617
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
617
vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
Normal file
@@ -0,0 +1,617 @@
|
||||
// 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"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// 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,Params,Results,Underlying} [EKPRU]
|
||||
// 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 [EKPRUTC];
|
||||
// one of these (TypeParam) requires 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)
|
||||
opConstraint = 'C' // .Constraint() (TypeParam)
|
||||
|
||||
// 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)
|
||||
)
|
||||
|
||||
// The For function 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.
|
||||
//
|
||||
// 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 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 := obj.Type().(*typeparams.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)
|
||||
}
|
||||
// TODO(adonovan): opt: if the method is concrete,
|
||||
// do a specialized version of the rest of this function so
|
||||
// that it's O(1) not O(|scope|). Basically 'find' is needed
|
||||
// only for struct fields and interface methods.
|
||||
|
||||
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
|
||||
names := scope.Names()
|
||||
for _, name := range names {
|
||||
o := scope.Lookup(name)
|
||||
tname, ok := o.(*types.TypeName)
|
||||
if !ok {
|
||||
continue // handle non-types in second pass
|
||||
}
|
||||
|
||||
path := append(empty, name...)
|
||||
path = append(path, opType)
|
||||
|
||||
T := o.Type()
|
||||
|
||||
if tname.IsAlias() {
|
||||
// type alias
|
||||
if r := find(obj, T, path); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
} else {
|
||||
if named, _ := T.(*types.Named); named != nil {
|
||||
if r := findTypeParam(obj, typeparams.ForNamed(named), path); r != nil {
|
||||
// generic named type
|
||||
return Path(r), nil
|
||||
}
|
||||
}
|
||||
// defined (named) type
|
||||
if r := find(obj, T.Underlying(), append(path, opUnderlying)); r != nil {
|
||||
return Path(r), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then inspect everything else:
|
||||
// non-types, and declared methods of defined types.
|
||||
for _, name := range names {
|
||||
o := scope.Lookup(name)
|
||||
path := append(empty, 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 := o.Type().(*types.Named); ok {
|
||||
path = append(path, opType)
|
||||
// Note that method index here is always with respect
|
||||
// to canonical ordering of methods, regardless of how
|
||||
// they appear in the underlying type.
|
||||
canonical := canonicalize(T)
|
||||
for i := 0; i < len(canonical); i++ {
|
||||
m := canonical[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
|
||||
}
|
||||
|
||||
// find finds obj within type T, returning the path to it, or nil if not found.
|
||||
func find(obj types.Object, T types.Type, path []byte) []byte {
|
||||
switch T := T.(type) {
|
||||
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 find(obj, T.Elem(), append(path, opElem))
|
||||
case *types.Slice:
|
||||
return find(obj, T.Elem(), append(path, opElem))
|
||||
case *types.Array:
|
||||
return find(obj, T.Elem(), append(path, opElem))
|
||||
case *types.Chan:
|
||||
return find(obj, T.Elem(), append(path, opElem))
|
||||
case *types.Map:
|
||||
if r := find(obj, T.Key(), append(path, opKey)); r != nil {
|
||||
return r
|
||||
}
|
||||
return find(obj, T.Elem(), append(path, opElem))
|
||||
case *types.Signature:
|
||||
if r := findTypeParam(obj, typeparams.ForSignature(T), path); r != nil {
|
||||
return r
|
||||
}
|
||||
if r := find(obj, T.Params(), append(path, opParams)); r != nil {
|
||||
return r
|
||||
}
|
||||
return find(obj, T.Results(), append(path, opResults))
|
||||
case *types.Struct:
|
||||
for i := 0; i < T.NumFields(); i++ {
|
||||
f := T.Field(i)
|
||||
path2 := appendOpArg(path, opField, i)
|
||||
if f == obj {
|
||||
return path2 // found field var
|
||||
}
|
||||
if r := find(obj, f.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 == obj {
|
||||
return path2 // found param/result var
|
||||
}
|
||||
if r := find(obj, 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)
|
||||
path2 := appendOpArg(path, opMethod, i)
|
||||
if m == obj {
|
||||
return path2 // found interface method
|
||||
}
|
||||
if r := find(obj, m.Type(), append(path2, opType)); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *typeparams.TypeParam:
|
||||
name := T.Obj()
|
||||
if name == obj {
|
||||
return append(path, opObj)
|
||||
}
|
||||
if r := find(obj, T.Constraint(), append(path, opConstraint)); r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
}
|
||||
panic(T)
|
||||
}
|
||||
|
||||
func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte) []byte {
|
||||
for i := 0; i < list.Len(); i++ {
|
||||
tparam := list.At(i)
|
||||
path2 := appendOpArg(path, opTypeParam, i)
|
||||
if r := find(obj, 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) {
|
||||
if p == "" {
|
||||
return nil, fmt.Errorf("empty path")
|
||||
}
|
||||
|
||||
pathstr := string(p)
|
||||
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() *typeparams.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 [AFM] have an integer operand.
|
||||
var index int
|
||||
switch code {
|
||||
case opAt, opField, opMethod, opTypeParam:
|
||||
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
|
||||
|
||||
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 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 opConstraint:
|
||||
tparam, ok := t.(*typeparams.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:
|
||||
hasMethods, ok := t.(hasMethods) // Interface or Named
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
|
||||
}
|
||||
canonical := canonicalize(hasMethods)
|
||||
if n := len(canonical); index >= n {
|
||||
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, n)
|
||||
}
|
||||
obj = canonical[index]
|
||||
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.Pkg() != pkg {
|
||||
return nil, fmt.Errorf("path denotes %s, which belongs to a different package", obj)
|
||||
}
|
||||
|
||||
return obj, nil // success
|
||||
}
|
||||
|
||||
// hasMethods is an abstraction of *types.{Interface,Named}. This is pulled up
|
||||
// because it is used by methodOrdering, which is in turn used by both encoding
|
||||
// and decoding.
|
||||
type hasMethods interface {
|
||||
Method(int) *types.Func
|
||||
NumMethods() int
|
||||
}
|
||||
|
||||
// canonicalize returns a canonical order for the methods in a hasMethod.
|
||||
func canonicalize(hm hasMethods) []*types.Func {
|
||||
count := hm.NumMethods()
|
||||
if count <= 0 {
|
||||
return nil
|
||||
}
|
||||
canon := make([]*types.Func, count)
|
||||
for i := 0; i < count; i++ {
|
||||
canon[i] = hm.Method(i)
|
||||
}
|
||||
less := func(i, j int) bool {
|
||||
return canon[i].Id() < canon[j].Id()
|
||||
}
|
||||
sort.Slice(canon, less)
|
||||
return canon
|
||||
}
|
||||
69
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
Normal file
69
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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/go/ast/astutil"
|
||||
"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 := astutil.Unparen(call.Fun)
|
||||
|
||||
// Look through type instantiation if necessary.
|
||||
isInstance := false
|
||||
switch fun.(type) {
|
||||
case *ast.IndexExpr, *typeparams.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())
|
||||
}
|
||||
31
vendor/golang.org/x/tools/go/types/typeutil/imports.go
generated
vendored
Normal file
31
vendor/golang.org/x/tools/go/types/typeutil/imports.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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
|
||||
}
|
||||
443
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
Normal file
443
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
Normal file
@@ -0,0 +1,443 @@
|
||||
// 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 mapping from types.Type to interface{} values.
|
||||
package typeutil // import "golang.org/x/tools/go/types/typeutil"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// Map is a hash-table-based mapping from types (types.Type) to
|
||||
// arbitrary interface{} 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.
|
||||
//
|
||||
// Not thread-safe.
|
||||
//
|
||||
type Map struct {
|
||||
hasher Hasher // shared by many Maps
|
||||
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 interface{}
|
||||
}
|
||||
|
||||
// SetHasher sets the hasher used by Map.
|
||||
//
|
||||
// All Hashers are functionally equivalent but contain internal state
|
||||
// used to cache the results of hashing previously seen types.
|
||||
//
|
||||
// A single Hasher created by MakeHasher() may be shared among many
|
||||
// Maps. This is recommended if the instances have many keys in
|
||||
// common, as it will amortize the cost of hash computation.
|
||||
//
|
||||
// A Hasher may grow without bound as new types are seen. Even when a
|
||||
// type is deleted from the map, the Hasher never shrinks, since other
|
||||
// types in the map may reference the deleted type indirectly.
|
||||
//
|
||||
// Hashers are not thread-safe, and read-only operations such as
|
||||
// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
|
||||
// read-lock) is require around all Map operations if a shared
|
||||
// hasher is accessed from multiple threads.
|
||||
//
|
||||
// If SetHasher is not called, the Map will create a private hasher at
|
||||
// the first call to Insert.
|
||||
//
|
||||
func (m *Map) SetHasher(hasher Hasher) {
|
||||
m.hasher = 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 := m.hasher.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) interface{} {
|
||||
if m != nil && m.table != nil {
|
||||
for _, e := range m.table[m.hasher.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 interface{}) (prev interface{}) {
|
||||
if m.table != nil {
|
||||
hash := m.hasher.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 {
|
||||
if m.hasher.memo == nil {
|
||||
m.hasher = MakeHasher()
|
||||
}
|
||||
hash := m.hasher.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 interface{})) {
|
||||
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, _ interface{}) {
|
||||
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 interface{}) {
|
||||
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
|
||||
|
||||
// A Hasher maps each type to its hash value.
|
||||
// For efficiency, a hasher uses memoization; thus its memory
|
||||
// footprint grows monotonically over time.
|
||||
// Hashers are not thread-safe.
|
||||
// Hashers have reference semantics.
|
||||
// Call MakeHasher to create a Hasher.
|
||||
type Hasher struct {
|
||||
memo map[types.Type]uint32
|
||||
|
||||
// ptrMap records pointer identity.
|
||||
ptrMap map[interface{}]uint32
|
||||
|
||||
// sigTParams holds type parameters from the signature being hashed.
|
||||
// Signatures are considered identical modulo renaming of type parameters, so
|
||||
// within the scope of a signature type the identity of the signature's type
|
||||
// parameters is just their index.
|
||||
//
|
||||
// Since the language does not currently support referring to uninstantiated
|
||||
// generic types or functions, and instantiated signatures do not have type
|
||||
// parameter lists, we should never encounter a second non-empty type
|
||||
// parameter list when hashing a generic signature.
|
||||
sigTParams *typeparams.TypeParamList
|
||||
}
|
||||
|
||||
// MakeHasher returns a new Hasher instance.
|
||||
func MakeHasher() Hasher {
|
||||
return Hasher{
|
||||
memo: make(map[types.Type]uint32),
|
||||
ptrMap: make(map[interface{}]uint32),
|
||||
sigTParams: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
hash, ok := h.memo[t]
|
||||
if !ok {
|
||||
hash = h.hashFor(t)
|
||||
h.memo[t] = hash
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// hashFor computes the hash of t.
|
||||
func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
// See Identical for rationale.
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
return uint32(t.Kind())
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Use a separate hasher for types inside of the signature, where type
|
||||
// parameter identity is modified to be (index, constraint). We must use a
|
||||
// new memo for this hasher as type identity may be affected by this
|
||||
// masking. For example, in func[T any](*T), the identity of *T depends on
|
||||
// whether we are mapping the argument in isolation, or recursively as part
|
||||
// of hashing the signature.
|
||||
//
|
||||
// We should never encounter a generic signature while hashing another
|
||||
// generic signature, but defensively set sigTParams only if h.mask is
|
||||
// unset.
|
||||
tparams := typeparams.ForSignature(t)
|
||||
if h.sigTParams == nil && tparams.Len() != 0 {
|
||||
h = Hasher{
|
||||
// There may be something more efficient than discarding the existing
|
||||
// memo, but it would require detecting whether types are 'tainted' by
|
||||
// references to type parameters.
|
||||
memo: make(map[types.Type]uint32),
|
||||
// Re-using ptrMap ensures that pointer identity is preserved in this
|
||||
// hasher.
|
||||
ptrMap: h.ptrMap,
|
||||
sigTParams: tparams,
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < tparams.Len(); i++ {
|
||||
tparam := tparams.At(i)
|
||||
hash += 7 * h.Hash(tparam.Constraint())
|
||||
}
|
||||
|
||||
return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
|
||||
|
||||
case *typeparams.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)
|
||||
hash += 3*hashString(m.Name()) + 5*h.Hash(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.hashPtr(t.Obj())
|
||||
targs := typeparams.NamedTypeArgs(t)
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
targ := targs.At(i)
|
||||
hash += 2 * h.Hash(targ)
|
||||
}
|
||||
return hash
|
||||
|
||||
case *typeparams.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 := 0; i < n; i++ {
|
||||
hash += 3 * h.Hash(tuple.At(i).Type())
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
func (h Hasher) hashUnion(t *typeparams.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 []*typeparams.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 a hash of the type parameter t, with a hash value
|
||||
// depending on whether t is contained in h.sigTParams.
|
||||
//
|
||||
// If h.sigTParams is set and contains t, then we are in the process of hashing
|
||||
// a signature, and the hash value of t must depend only on t's index and
|
||||
// constraint: signatures are considered identical modulo type parameter
|
||||
// renaming. To avoid infinite recursion, we only hash the type parameter
|
||||
// index, and rely on types.Identical to handle signatures where constraints
|
||||
// are not identical.
|
||||
//
|
||||
// Otherwise the hash of t depends only on t's pointer identity.
|
||||
func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 {
|
||||
if h.sigTParams != nil {
|
||||
i := t.Index()
|
||||
if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
|
||||
return 9173 + 3*uint32(i)
|
||||
}
|
||||
}
|
||||
return h.hashPtr(t.Obj())
|
||||
}
|
||||
|
||||
// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that
|
||||
// pointers values are not dependent on the GC.
|
||||
func (h Hasher) hashPtr(ptr interface{}) uint32 {
|
||||
if hash, ok := h.ptrMap[ptr]; ok {
|
||||
return hash
|
||||
}
|
||||
hash := uint32(reflect.ValueOf(ptr).Pointer())
|
||||
h.ptrMap[ptr] = hash
|
||||
return hash
|
||||
}
|
||||
72
vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go
generated
vendored
Normal file
72
vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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 := T.(type) {
|
||||
case *types.Named:
|
||||
return cache.lookupNamed(T).value
|
||||
|
||||
case *types.Pointer:
|
||||
if N, ok := 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
|
||||
}
|
||||
52
vendor/golang.org/x/tools/go/types/typeutil/ui.go
generated
vendored
Normal file
52
vendor/golang.org/x/tools/go/types/typeutil/ui.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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 := 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
|
||||
}
|
||||
428
vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
generated
vendored
Normal file
428
vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
generated
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
// Copyright 2020 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 analysisinternal exposes internal-only fields from go/analysis.
|
||||
package analysisinternal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/lsp/fuzzy"
|
||||
)
|
||||
|
||||
// Flag to gate diagnostics for fuzz tests in 1.18.
|
||||
var DiagnoseFuzzTests bool = false
|
||||
|
||||
var (
|
||||
GetTypeErrors func(p interface{}) []types.Error
|
||||
SetTypeErrors func(p interface{}, errors []types.Error)
|
||||
)
|
||||
|
||||
func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
|
||||
// Get the end position for the type error.
|
||||
offset, end := fset.PositionFor(start, false).Offset, start
|
||||
if offset >= len(src) {
|
||||
return end
|
||||
}
|
||||
if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 {
|
||||
end = start + token.Pos(width)
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
|
||||
under := typ
|
||||
if n, ok := typ.(*types.Named); ok {
|
||||
under = n.Underlying()
|
||||
}
|
||||
switch u := under.(type) {
|
||||
case *types.Basic:
|
||||
switch {
|
||||
case u.Info()&types.IsNumeric != 0:
|
||||
return &ast.BasicLit{Kind: token.INT, Value: "0"}
|
||||
case u.Info()&types.IsBoolean != 0:
|
||||
return &ast.Ident{Name: "false"}
|
||||
case u.Info()&types.IsString != 0:
|
||||
return &ast.BasicLit{Kind: token.STRING, Value: `""`}
|
||||
default:
|
||||
panic("unknown basic type")
|
||||
}
|
||||
case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array:
|
||||
return ast.NewIdent("nil")
|
||||
case *types.Struct:
|
||||
texpr := TypeExpr(fset, f, pkg, typ) // typ because we want the name here.
|
||||
if texpr == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.CompositeLit{
|
||||
Type: texpr,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of
|
||||
// analysisinternal.ZeroValue)
|
||||
func IsZeroValue(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
|
||||
}
|
||||
}
|
||||
|
||||
func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
|
||||
switch t := typ.(type) {
|
||||
case *types.Basic:
|
||||
switch t.Kind() {
|
||||
case types.UnsafePointer:
|
||||
return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
|
||||
default:
|
||||
return ast.NewIdent(t.Name())
|
||||
}
|
||||
case *types.Pointer:
|
||||
x := TypeExpr(fset, f, pkg, t.Elem())
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.UnaryExpr{
|
||||
Op: token.MUL,
|
||||
X: x,
|
||||
}
|
||||
case *types.Array:
|
||||
elt := TypeExpr(fset, f, pkg, t.Elem())
|
||||
if elt == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.ArrayType{
|
||||
Len: &ast.BasicLit{
|
||||
Kind: token.INT,
|
||||
Value: fmt.Sprintf("%d", t.Len()),
|
||||
},
|
||||
Elt: elt,
|
||||
}
|
||||
case *types.Slice:
|
||||
elt := TypeExpr(fset, f, pkg, t.Elem())
|
||||
if elt == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.ArrayType{
|
||||
Elt: elt,
|
||||
}
|
||||
case *types.Map:
|
||||
key := TypeExpr(fset, f, pkg, t.Key())
|
||||
value := TypeExpr(fset, f, pkg, t.Elem())
|
||||
if key == nil || value == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.MapType{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
case *types.Chan:
|
||||
dir := ast.ChanDir(t.Dir())
|
||||
if t.Dir() == types.SendRecv {
|
||||
dir = ast.SEND | ast.RECV
|
||||
}
|
||||
value := TypeExpr(fset, f, pkg, t.Elem())
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return &ast.ChanType{
|
||||
Dir: dir,
|
||||
Value: value,
|
||||
}
|
||||
case *types.Signature:
|
||||
var params []*ast.Field
|
||||
for i := 0; i < t.Params().Len(); i++ {
|
||||
p := TypeExpr(fset, f, pkg, t.Params().At(i).Type())
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
params = append(params, &ast.Field{
|
||||
Type: p,
|
||||
Names: []*ast.Ident{
|
||||
{
|
||||
Name: t.Params().At(i).Name(),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
var returns []*ast.Field
|
||||
for i := 0; i < t.Results().Len(); i++ {
|
||||
r := TypeExpr(fset, f, pkg, t.Results().At(i).Type())
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
returns = append(returns, &ast.Field{
|
||||
Type: r,
|
||||
})
|
||||
}
|
||||
return &ast.FuncType{
|
||||
Params: &ast.FieldList{
|
||||
List: params,
|
||||
},
|
||||
Results: &ast.FieldList{
|
||||
List: returns,
|
||||
},
|
||||
}
|
||||
case *types.Named:
|
||||
if t.Obj().Pkg() == nil {
|
||||
return ast.NewIdent(t.Obj().Name())
|
||||
}
|
||||
if t.Obj().Pkg() == pkg {
|
||||
return ast.NewIdent(t.Obj().Name())
|
||||
}
|
||||
pkgName := t.Obj().Pkg().Name()
|
||||
// If the file already imports the package under another name, use that.
|
||||
for _, group := range astutil.Imports(fset, f) {
|
||||
for _, cand := range group {
|
||||
if strings.Trim(cand.Path.Value, `"`) == t.Obj().Pkg().Path() {
|
||||
if cand.Name != nil && cand.Name.Name != "" {
|
||||
pkgName = cand.Name.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if pkgName == "." {
|
||||
return ast.NewIdent(t.Obj().Name())
|
||||
}
|
||||
return &ast.SelectorExpr{
|
||||
X: ast.NewIdent(pkgName),
|
||||
Sel: ast.NewIdent(t.Obj().Name()),
|
||||
}
|
||||
case *types.Struct:
|
||||
return ast.NewIdent(t.String())
|
||||
case *types.Interface:
|
||||
return ast.NewIdent(t.String())
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type TypeErrorPass string
|
||||
|
||||
const (
|
||||
NoNewVars TypeErrorPass = "nonewvars"
|
||||
NoResultValues TypeErrorPass = "noresultvalues"
|
||||
UndeclaredName TypeErrorPass = "undeclaredname"
|
||||
)
|
||||
|
||||
// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable.
|
||||
// Some examples:
|
||||
//
|
||||
// Basic Example:
|
||||
// z := 1
|
||||
// y := z + x
|
||||
// If x is undeclared, then this function would return `y := z + x`, so that we
|
||||
// can insert `x := ` on the line before `y := z + x`.
|
||||
//
|
||||
// If stmt example:
|
||||
// if z == 1 {
|
||||
// } else if z == y {}
|
||||
// If y is undeclared, then this function would return `if z == 1 {`, because we cannot
|
||||
// insert a statement between an if and an else if statement. As a result, we need to find
|
||||
// the top of the if chain to insert `y := ` before.
|
||||
func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
|
||||
enclosingIndex := -1
|
||||
for i, p := range path {
|
||||
if _, ok := p.(ast.Stmt); ok {
|
||||
enclosingIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if enclosingIndex == -1 {
|
||||
return nil
|
||||
}
|
||||
enclosingStmt := path[enclosingIndex]
|
||||
switch enclosingStmt.(type) {
|
||||
case *ast.IfStmt:
|
||||
// The enclosingStmt is inside of the if declaration,
|
||||
// We need to check if we are in an else-if stmt and
|
||||
// get the base if statement.
|
||||
return baseIfStmt(path, enclosingIndex)
|
||||
case *ast.CaseClause:
|
||||
// Get the enclosing switch stmt if the enclosingStmt is
|
||||
// inside of the case statement.
|
||||
for i := enclosingIndex + 1; i < len(path); i++ {
|
||||
if node, ok := path[i].(*ast.SwitchStmt); ok {
|
||||
return node
|
||||
} else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
|
||||
return node
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(path) <= enclosingIndex+1 {
|
||||
return enclosingStmt.(ast.Stmt)
|
||||
}
|
||||
// Check if the enclosing statement is inside another node.
|
||||
switch expr := path[enclosingIndex+1].(type) {
|
||||
case *ast.IfStmt:
|
||||
// Get the base if statement.
|
||||
return baseIfStmt(path, enclosingIndex+1)
|
||||
case *ast.ForStmt:
|
||||
if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
|
||||
return expr
|
||||
}
|
||||
}
|
||||
return enclosingStmt.(ast.Stmt)
|
||||
}
|
||||
|
||||
// baseIfStmt walks up the if/else-if chain until we get to
|
||||
// the top of the current if chain.
|
||||
func baseIfStmt(path []ast.Node, index int) ast.Stmt {
|
||||
stmt := path[index]
|
||||
for i := index + 1; i < len(path); i++ {
|
||||
if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
|
||||
stmt = node
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return stmt.(ast.Stmt)
|
||||
}
|
||||
|
||||
// WalkASTWithParent walks the AST rooted at n. The semantics are
|
||||
// similar to ast.Inspect except it does not call f(nil).
|
||||
func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
|
||||
var ancestors []ast.Node
|
||||
ast.Inspect(n, func(n ast.Node) (recurse bool) {
|
||||
if n == nil {
|
||||
ancestors = ancestors[:len(ancestors)-1]
|
||||
return false
|
||||
}
|
||||
|
||||
var parent ast.Node
|
||||
if len(ancestors) > 0 {
|
||||
parent = ancestors[len(ancestors)-1]
|
||||
}
|
||||
ancestors = append(ancestors, n)
|
||||
return f(n, parent)
|
||||
})
|
||||
}
|
||||
|
||||
// FindMatchingIdents finds all identifiers in 'node' that match any of the given types.
|
||||
// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within
|
||||
// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that
|
||||
// is unrecognized.
|
||||
func FindMatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]*ast.Ident {
|
||||
matches := map[types.Type][]*ast.Ident{}
|
||||
// Initialize matches to contain the variable types we are searching for.
|
||||
for _, typ := range typs {
|
||||
if typ == nil {
|
||||
continue
|
||||
}
|
||||
matches[typ] = []*ast.Ident{}
|
||||
}
|
||||
seen := map[types.Object]struct{}{}
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
if n == nil {
|
||||
return false
|
||||
}
|
||||
// Prevent circular definitions. If 'pos' is within an assignment statement, do not
|
||||
// allow any identifiers in that assignment statement to be selected. Otherwise,
|
||||
// we could do the following, where 'x' satisfies the type of 'f0':
|
||||
//
|
||||
// x := fakeStruct{f0: x}
|
||||
//
|
||||
assignment, ok := n.(*ast.AssignStmt)
|
||||
if ok && pos > assignment.Pos() && pos <= assignment.End() {
|
||||
return false
|
||||
}
|
||||
if n.End() > pos {
|
||||
return n.Pos() <= pos
|
||||
}
|
||||
ident, ok := n.(*ast.Ident)
|
||||
if !ok || ident.Name == "_" {
|
||||
return true
|
||||
}
|
||||
obj := info.Defs[ident]
|
||||
if obj == nil || obj.Type() == nil {
|
||||
return true
|
||||
}
|
||||
if _, ok := obj.(*types.TypeName); ok {
|
||||
return true
|
||||
}
|
||||
// Prevent duplicates in matches' values.
|
||||
if _, ok = seen[obj]; ok {
|
||||
return true
|
||||
}
|
||||
seen[obj] = struct{}{}
|
||||
// Find the scope for the given position. Then, check whether the object
|
||||
// exists within the scope.
|
||||
innerScope := pkg.Scope().Innermost(pos)
|
||||
if innerScope == nil {
|
||||
return true
|
||||
}
|
||||
_, foundObj := innerScope.LookupParent(ident.Name, pos)
|
||||
if foundObj != obj {
|
||||
return true
|
||||
}
|
||||
// The object must match one of the types that we are searching for.
|
||||
if idents, ok := matches[obj.Type()]; ok {
|
||||
matches[obj.Type()] = append(idents, ast.NewIdent(ident.Name))
|
||||
}
|
||||
// If the object type does not exactly match any of the target types, greedily
|
||||
// find the first target type that the object type can satisfy.
|
||||
for typ := range matches {
|
||||
if obj.Type() == typ {
|
||||
continue
|
||||
}
|
||||
if equivalentTypes(obj.Type(), typ) {
|
||||
matches[typ] = append(matches[typ], ast.NewIdent(ident.Name))
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return matches
|
||||
}
|
||||
|
||||
func equivalentTypes(want, got types.Type) bool {
|
||||
if want == got || types.Identical(want, got) {
|
||||
return true
|
||||
}
|
||||
// Code segment to help check for untyped equality from (golang/go#32146).
|
||||
if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 {
|
||||
if lhs, ok := got.Underlying().(*types.Basic); ok {
|
||||
return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType
|
||||
}
|
||||
}
|
||||
return types.AssignableTo(want, got)
|
||||
}
|
||||
|
||||
// FindBestMatch employs fuzzy matching to evaluate the similarity of each given identifier to the
|
||||
// given pattern. We return the identifier whose name is most similar to the pattern.
|
||||
func FindBestMatch(pattern string, idents []*ast.Ident) ast.Expr {
|
||||
fuzz := fuzzy.NewMatcher(pattern)
|
||||
var bestFuzz ast.Expr
|
||||
highScore := float32(0) // minimum score is 0 (no match)
|
||||
for _, ident := range idents {
|
||||
// TODO: Improve scoring algorithm.
|
||||
score := fuzz.Score(ident.Name)
|
||||
if score > highScore {
|
||||
highScore = score
|
||||
bestFuzz = ident
|
||||
} else if score == 0 {
|
||||
// Order matters in the fuzzy matching algorithm. If we find no match
|
||||
// when matching the target to the identifier, try matching the identifier
|
||||
// to the target.
|
||||
revFuzz := fuzzy.NewMatcher(ident.Name)
|
||||
revScore := revFuzz.Score(pattern)
|
||||
if revScore > highScore {
|
||||
highScore = revScore
|
||||
bestFuzz = ident
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestFuzz
|
||||
}
|
||||
16
vendor/golang.org/x/tools/internal/gocommand/invoke.go
generated
vendored
16
vendor/golang.org/x/tools/internal/gocommand/invoke.go
generated
vendored
@@ -9,7 +9,6 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -18,6 +17,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
exec "golang.org/x/sys/execabs"
|
||||
|
||||
"golang.org/x/tools/internal/event"
|
||||
)
|
||||
|
||||
@@ -131,9 +132,16 @@ type Invocation struct {
|
||||
Verb string
|
||||
Args []string
|
||||
BuildFlags []string
|
||||
ModFlag string
|
||||
ModFile string
|
||||
Overlay string
|
||||
|
||||
// If ModFlag is set, the go command is invoked with -mod=ModFlag.
|
||||
ModFlag string
|
||||
|
||||
// If ModFile is set, the go command is invoked with -modfile=ModFile.
|
||||
ModFile string
|
||||
|
||||
// If Overlay is set, the go command is invoked with -overlay=Overlay.
|
||||
Overlay string
|
||||
|
||||
// If CleanEnv is set, the invocation will run only with the environment
|
||||
// in Env, not starting with os.Environ.
|
||||
CleanEnv bool
|
||||
|
||||
22
vendor/golang.org/x/tools/internal/gocommand/vendor.go
generated
vendored
22
vendor/golang.org/x/tools/internal/gocommand/vendor.go
generated
vendored
@@ -38,10 +38,10 @@ var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`)
|
||||
// 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 VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) {
|
||||
func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (bool, *ModuleJSON, error) {
|
||||
mainMod, go114, err := getMainModuleAnd114(ctx, inv, r)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
// We check the GOFLAGS to see if there is anything overridden or not.
|
||||
@@ -49,7 +49,7 @@ func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON,
|
||||
inv.Args = []string{"GOFLAGS"}
|
||||
stdout, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return false, nil, err
|
||||
}
|
||||
goflags := string(bytes.TrimSpace(stdout.Bytes()))
|
||||
matches := modFlagRegexp.FindStringSubmatch(goflags)
|
||||
@@ -57,25 +57,27 @@ func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON,
|
||||
if len(matches) != 0 {
|
||||
modFlag = matches[1]
|
||||
}
|
||||
if modFlag != "" {
|
||||
// Don't override an explicit '-mod=' argument.
|
||||
return mainMod, modFlag == "vendor", nil
|
||||
// Don't override an explicit '-mod=' argument.
|
||||
if modFlag == "vendor" {
|
||||
return true, mainMod, nil
|
||||
} else if modFlag != "" {
|
||||
return false, nil, nil
|
||||
}
|
||||
if mainMod == nil || !go114 {
|
||||
return mainMod, false, nil
|
||||
return false, nil, nil
|
||||
}
|
||||
// Check 1.14's automatic vendor mode.
|
||||
if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() {
|
||||
if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 {
|
||||
// The Go version is at least 1.14, and a vendor directory exists.
|
||||
// Set -mod=vendor by default.
|
||||
return mainMod, true, nil
|
||||
return true, mainMod, nil
|
||||
}
|
||||
}
|
||||
return mainMod, false, nil
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
// getMainModuleAnd114 gets the main module's information and whether the
|
||||
// getMainModuleAnd114 gets one of the main modules' information and whether the
|
||||
// go command in use is 1.14+. This is the information needed to figure out
|
||||
// if vendoring should be enabled.
|
||||
func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) {
|
||||
|
||||
2
vendor/golang.org/x/tools/internal/imports/imports.go
generated
vendored
2
vendor/golang.org/x/tools/internal/imports/imports.go
generated
vendored
@@ -306,7 +306,7 @@ func matchSpace(orig []byte, src []byte) []byte {
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`)
|
||||
var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+?)"`)
|
||||
|
||||
func addImportSpaces(r io.Reader, breaks []string) ([]byte, error) {
|
||||
var out bytes.Buffer
|
||||
|
||||
25
vendor/golang.org/x/tools/internal/imports/mod.go
generated
vendored
25
vendor/golang.org/x/tools/internal/imports/mod.go
generated
vendored
@@ -34,7 +34,8 @@ type ModuleResolver struct {
|
||||
scannedRoots map[gopathwalk.Root]bool
|
||||
|
||||
initialized bool
|
||||
main *gocommand.ModuleJSON
|
||||
mains []*gocommand.ModuleJSON
|
||||
mainByDir map[string]*gocommand.ModuleJSON
|
||||
modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path...
|
||||
modsByDir []*gocommand.ModuleJSON // ...or Dir.
|
||||
|
||||
@@ -69,21 +70,21 @@ func (r *ModuleResolver) init() error {
|
||||
Logf: r.env.Logf,
|
||||
WorkingDir: r.env.WorkingDir,
|
||||
}
|
||||
mainMod, vendorEnabled, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
|
||||
vendorEnabled, mainModVendor, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mainMod != nil && vendorEnabled {
|
||||
if mainModVendor != nil && vendorEnabled {
|
||||
// Vendor mode is on, so all the non-Main modules are irrelevant,
|
||||
// and we need to search /vendor for everything.
|
||||
r.main = mainMod
|
||||
r.mains = []*gocommand.ModuleJSON{mainModVendor}
|
||||
r.dummyVendorMod = &gocommand.ModuleJSON{
|
||||
Path: "",
|
||||
Dir: filepath.Join(mainMod.Dir, "vendor"),
|
||||
Dir: filepath.Join(mainModVendor.Dir, "vendor"),
|
||||
}
|
||||
r.modsByModPath = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod}
|
||||
r.modsByDir = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod}
|
||||
r.modsByModPath = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
|
||||
r.modsByDir = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod}
|
||||
} else {
|
||||
// Vendor mode is off, so run go list -m ... to find everything.
|
||||
err := r.initAllMods()
|
||||
@@ -122,8 +123,10 @@ func (r *ModuleResolver) init() error {
|
||||
r.roots = []gopathwalk.Root{
|
||||
{filepath.Join(goenv["GOROOT"], "/src"), gopathwalk.RootGOROOT},
|
||||
}
|
||||
if r.main != nil {
|
||||
r.roots = append(r.roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
|
||||
r.mainByDir = make(map[string]*gocommand.ModuleJSON)
|
||||
for _, main := range r.mains {
|
||||
r.roots = append(r.roots, gopathwalk.Root{main.Dir, gopathwalk.RootCurrentModule})
|
||||
r.mainByDir[main.Dir] = main
|
||||
}
|
||||
if vendorEnabled {
|
||||
r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther})
|
||||
@@ -189,7 +192,7 @@ func (r *ModuleResolver) initAllMods() error {
|
||||
r.modsByModPath = append(r.modsByModPath, mod)
|
||||
r.modsByDir = append(r.modsByDir, mod)
|
||||
if mod.Main {
|
||||
r.main = mod
|
||||
r.mains = append(r.mains, mod)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -609,7 +612,7 @@ func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) dir
|
||||
}
|
||||
switch root.Type {
|
||||
case gopathwalk.RootCurrentModule:
|
||||
importPath = path.Join(r.main.Path, filepath.ToSlash(subdir))
|
||||
importPath = path.Join(r.mainByDir[root.Path].Path, filepath.ToSlash(subdir))
|
||||
case gopathwalk.RootModuleCache:
|
||||
matches := modCacheRegexp.FindStringSubmatch(subdir)
|
||||
if len(matches) == 0 {
|
||||
|
||||
15
vendor/golang.org/x/tools/internal/imports/sortimports.go
generated
vendored
15
vendor/golang.org/x/tools/internal/imports/sortimports.go
generated
vendored
@@ -9,6 +9,7 @@ package imports
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
@@ -60,6 +61,7 @@ func sortImports(localPrefix string, fset *token.FileSet, f *ast.File) {
|
||||
|
||||
// mergeImports merges all the import declarations into the first one.
|
||||
// Taken from golang.org/x/tools/ast/astutil.
|
||||
// This does not adjust line numbers properly
|
||||
func mergeImports(fset *token.FileSet, f *ast.File) {
|
||||
if len(f.Decls) <= 1 {
|
||||
return
|
||||
@@ -237,8 +239,17 @@ func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast
|
||||
p := s.Pos()
|
||||
line := fset.File(p).Line(p)
|
||||
for previousLine := line - 1; previousLine >= firstSpecLine; {
|
||||
fset.File(p).MergeLine(previousLine)
|
||||
previousLine--
|
||||
// MergeLine can panic. Avoid the panic at the cost of not removing the blank line
|
||||
// golang/go#50329
|
||||
if previousLine > 0 && previousLine < fset.File(p).LineCount() {
|
||||
fset.File(p).MergeLine(previousLine)
|
||||
previousLine--
|
||||
} else {
|
||||
// try to gather some data to diagnose how this could happen
|
||||
req := "Please report what the imports section of your go file looked like."
|
||||
log.Printf("panic avoided: first:%d line:%d previous:%d max:%d. %s",
|
||||
firstSpecLine, line, previousLine, fset.File(p).LineCount(), req)
|
||||
}
|
||||
}
|
||||
}
|
||||
return specs
|
||||
|
||||
23
vendor/golang.org/x/tools/internal/imports/zstdlib.go
generated
vendored
23
vendor/golang.org/x/tools/internal/imports/zstdlib.go
generated
vendored
@@ -180,6 +180,8 @@ var stdlib = map[string][]string{
|
||||
"NewReader",
|
||||
"NewWriter",
|
||||
"Order",
|
||||
"Reader",
|
||||
"Writer",
|
||||
},
|
||||
"compress/zlib": []string{
|
||||
"BestCompression",
|
||||
@@ -641,7 +643,9 @@ var stdlib = map[string][]string{
|
||||
"Named",
|
||||
"NamedArg",
|
||||
"NullBool",
|
||||
"NullByte",
|
||||
"NullFloat64",
|
||||
"NullInt16",
|
||||
"NullInt32",
|
||||
"NullInt64",
|
||||
"NullString",
|
||||
@@ -2248,6 +2252,7 @@ var stdlib = map[string][]string{
|
||||
"SHT_LOOS",
|
||||
"SHT_LOPROC",
|
||||
"SHT_LOUSER",
|
||||
"SHT_MIPS_ABIFLAGS",
|
||||
"SHT_NOBITS",
|
||||
"SHT_NOTE",
|
||||
"SHT_NULL",
|
||||
@@ -3061,6 +3066,7 @@ var stdlib = map[string][]string{
|
||||
"ParseExpr",
|
||||
"ParseExprFrom",
|
||||
"ParseFile",
|
||||
"SkipObjectResolution",
|
||||
"SpuriousErrors",
|
||||
"Trace",
|
||||
},
|
||||
@@ -3441,6 +3447,7 @@ var stdlib = map[string][]string{
|
||||
"Pt",
|
||||
"RGBA",
|
||||
"RGBA64",
|
||||
"RGBA64Image",
|
||||
"Rect",
|
||||
"Rectangle",
|
||||
"RegisterFormat",
|
||||
@@ -3507,6 +3514,7 @@ var stdlib = map[string][]string{
|
||||
"Op",
|
||||
"Over",
|
||||
"Quantizer",
|
||||
"RGBA64Image",
|
||||
"Src",
|
||||
},
|
||||
"image/gif": []string{
|
||||
@@ -3612,6 +3620,7 @@ var stdlib = map[string][]string{
|
||||
"FS",
|
||||
"File",
|
||||
"FileInfo",
|
||||
"FileInfoToDirEntry",
|
||||
"FileMode",
|
||||
"Glob",
|
||||
"GlobFS",
|
||||
@@ -3772,15 +3781,18 @@ var stdlib = map[string][]string{
|
||||
"Max",
|
||||
"MaxFloat32",
|
||||
"MaxFloat64",
|
||||
"MaxInt",
|
||||
"MaxInt16",
|
||||
"MaxInt32",
|
||||
"MaxInt64",
|
||||
"MaxInt8",
|
||||
"MaxUint",
|
||||
"MaxUint16",
|
||||
"MaxUint32",
|
||||
"MaxUint64",
|
||||
"MaxUint8",
|
||||
"Min",
|
||||
"MinInt",
|
||||
"MinInt16",
|
||||
"MinInt32",
|
||||
"MinInt64",
|
||||
@@ -4078,6 +4090,7 @@ var stdlib = map[string][]string{
|
||||
"UnknownNetworkError",
|
||||
},
|
||||
"net/http": []string{
|
||||
"AllowQuerySemicolons",
|
||||
"CanonicalHeaderKey",
|
||||
"Client",
|
||||
"CloseNotifier",
|
||||
@@ -4660,6 +4673,7 @@ var stdlib = map[string][]string{
|
||||
"Value",
|
||||
"ValueError",
|
||||
"ValueOf",
|
||||
"VisibleFields",
|
||||
"Zero",
|
||||
},
|
||||
"regexp": []string{
|
||||
@@ -4799,6 +4813,10 @@ var stdlib = map[string][]string{
|
||||
"UnlockOSThread",
|
||||
"Version",
|
||||
},
|
||||
"runtime/cgo": []string{
|
||||
"Handle",
|
||||
"NewHandle",
|
||||
},
|
||||
"runtime/debug": []string{
|
||||
"BuildInfo",
|
||||
"FreeOSMemory",
|
||||
@@ -4915,6 +4933,7 @@ var stdlib = map[string][]string{
|
||||
"QuoteRuneToGraphic",
|
||||
"QuoteToASCII",
|
||||
"QuoteToGraphic",
|
||||
"QuotedPrefix",
|
||||
"Unquote",
|
||||
"UnquoteChar",
|
||||
},
|
||||
@@ -10334,6 +10353,7 @@ var stdlib = map[string][]string{
|
||||
"PipeNode",
|
||||
"Pos",
|
||||
"RangeNode",
|
||||
"SkipFuncCheck",
|
||||
"StringNode",
|
||||
"TemplateNode",
|
||||
"TextNode",
|
||||
@@ -10358,6 +10378,7 @@ var stdlib = map[string][]string{
|
||||
"July",
|
||||
"June",
|
||||
"Kitchen",
|
||||
"Layout",
|
||||
"LoadLocation",
|
||||
"LoadLocationFromTZData",
|
||||
"Local",
|
||||
@@ -10406,6 +10427,8 @@ var stdlib = map[string][]string{
|
||||
"UTC",
|
||||
"Unix",
|
||||
"UnixDate",
|
||||
"UnixMicro",
|
||||
"UnixMilli",
|
||||
"Until",
|
||||
"Wednesday",
|
||||
"Weekday",
|
||||
|
||||
183
vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go
generated
vendored
Normal file
183
vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2019 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 fuzzy
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// RuneRole specifies the role of a rune in the context of an input.
|
||||
type RuneRole byte
|
||||
|
||||
const (
|
||||
// RNone specifies a rune without any role in the input (i.e., whitespace/non-ASCII).
|
||||
RNone RuneRole = iota
|
||||
// RSep specifies a rune with the role of segment separator.
|
||||
RSep
|
||||
// RTail specifies a rune which is a lower-case tail in a word in the input.
|
||||
RTail
|
||||
// RUCTail specifies a rune which is an upper-case tail in a word in the input.
|
||||
RUCTail
|
||||
// RHead specifies a rune which is the first character in a word in the input.
|
||||
RHead
|
||||
)
|
||||
|
||||
// RuneRoles detects the roles of each byte rune in an input string and stores it in the output
|
||||
// slice. The rune role depends on the input type. Stops when it parsed all the runes in the string
|
||||
// or when it filled the output. If output is nil, then it gets created.
|
||||
func RuneRoles(candidate []byte, reuse []RuneRole) []RuneRole {
|
||||
var output []RuneRole
|
||||
if cap(reuse) < len(candidate) {
|
||||
output = make([]RuneRole, 0, len(candidate))
|
||||
} else {
|
||||
output = reuse[:0]
|
||||
}
|
||||
|
||||
prev, prev2 := rtNone, rtNone
|
||||
for i := 0; i < len(candidate); i++ {
|
||||
r := rune(candidate[i])
|
||||
|
||||
role := RNone
|
||||
|
||||
curr := rtLower
|
||||
if candidate[i] <= unicode.MaxASCII {
|
||||
curr = runeType(rt[candidate[i]] - '0')
|
||||
}
|
||||
|
||||
if curr == rtLower {
|
||||
if prev == rtNone || prev == rtPunct {
|
||||
role = RHead
|
||||
} else {
|
||||
role = RTail
|
||||
}
|
||||
} else if curr == rtUpper {
|
||||
role = RHead
|
||||
|
||||
if prev == rtUpper {
|
||||
// This and previous characters are both upper case.
|
||||
|
||||
if i+1 == len(candidate) {
|
||||
// This is last character, previous was also uppercase -> this is UCTail
|
||||
// i.e., (current char is C): aBC / BC / ABC
|
||||
role = RUCTail
|
||||
}
|
||||
}
|
||||
} else if curr == rtPunct {
|
||||
switch r {
|
||||
case '.', ':':
|
||||
role = RSep
|
||||
}
|
||||
}
|
||||
if curr != rtLower {
|
||||
if i > 1 && output[i-1] == RHead && prev2 == rtUpper && (output[i-2] == RHead || output[i-2] == RUCTail) {
|
||||
// The previous two characters were uppercase. The current one is not a lower case, so the
|
||||
// previous one can't be a HEAD. Make it a UCTail.
|
||||
// i.e., (last char is current char - B must be a UCTail): ABC / ZABC / AB.
|
||||
output[i-1] = RUCTail
|
||||
}
|
||||
}
|
||||
|
||||
output = append(output, role)
|
||||
prev2 = prev
|
||||
prev = curr
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
type runeType byte
|
||||
|
||||
const (
|
||||
rtNone runeType = iota
|
||||
rtPunct
|
||||
rtLower
|
||||
rtUpper
|
||||
)
|
||||
|
||||
const rt = "00000000000000000000000000000000000000000000001122222222221000000333333333333333333333333330000002222222222222222222222222200000"
|
||||
|
||||
// LastSegment returns the substring representing the last segment from the input, where each
|
||||
// byte has an associated RuneRole in the roles slice. This makes sense only for inputs of Symbol
|
||||
// or Filename type.
|
||||
func LastSegment(input string, roles []RuneRole) string {
|
||||
// Exclude ending separators.
|
||||
end := len(input) - 1
|
||||
for end >= 0 && roles[end] == RSep {
|
||||
end--
|
||||
}
|
||||
if end < 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
start := end - 1
|
||||
for start >= 0 && roles[start] != RSep {
|
||||
start--
|
||||
}
|
||||
|
||||
return input[start+1 : end+1]
|
||||
}
|
||||
|
||||
// fromChunks copies string chunks into the given buffer.
|
||||
func fromChunks(chunks []string, buffer []byte) []byte {
|
||||
ii := 0
|
||||
for _, chunk := range chunks {
|
||||
for i := 0; i < len(chunk); i++ {
|
||||
if ii >= cap(buffer) {
|
||||
break
|
||||
}
|
||||
buffer[ii] = chunk[i]
|
||||
ii++
|
||||
}
|
||||
}
|
||||
return buffer[:ii]
|
||||
}
|
||||
|
||||
// toLower transforms the input string to lower case, which is stored in the output byte slice.
|
||||
// The lower casing considers only ASCII values - non ASCII values are left unmodified.
|
||||
// Stops when parsed all input or when it filled the output slice. If output is nil, then it gets
|
||||
// created.
|
||||
func toLower(input []byte, reuse []byte) []byte {
|
||||
output := reuse
|
||||
if cap(reuse) < len(input) {
|
||||
output = make([]byte, len(input))
|
||||
}
|
||||
|
||||
for i := 0; i < len(input); i++ {
|
||||
r := rune(input[i])
|
||||
if input[i] <= unicode.MaxASCII {
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
r += 'a' - 'A'
|
||||
}
|
||||
}
|
||||
output[i] = byte(r)
|
||||
}
|
||||
return output[:len(input)]
|
||||
}
|
||||
|
||||
// WordConsumer defines a consumer for a word delimited by the [start,end) byte offsets in an input
|
||||
// (start is inclusive, end is exclusive).
|
||||
type WordConsumer func(start, end int)
|
||||
|
||||
// Words find word delimiters in an input based on its bytes' mappings to rune roles. The offset
|
||||
// delimiters for each word are fed to the provided consumer function.
|
||||
func Words(roles []RuneRole, consume WordConsumer) {
|
||||
var wordStart int
|
||||
for i, r := range roles {
|
||||
switch r {
|
||||
case RUCTail, RTail:
|
||||
case RHead, RNone, RSep:
|
||||
if i != wordStart {
|
||||
consume(wordStart, i)
|
||||
}
|
||||
wordStart = i
|
||||
if r != RHead {
|
||||
// Skip this character.
|
||||
wordStart = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if wordStart != len(roles) {
|
||||
consume(wordStart, len(roles))
|
||||
}
|
||||
}
|
||||
407
vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go
generated
vendored
Normal file
407
vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go
generated
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
// Copyright 2019 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 fuzzy implements a fuzzy matching algorithm.
|
||||
package fuzzy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxInputSize is the maximum size of the input scored against the fuzzy matcher. Longer inputs
|
||||
// will be truncated to this size.
|
||||
MaxInputSize = 127
|
||||
// MaxPatternSize is the maximum size of the pattern used to construct the fuzzy matcher. Longer
|
||||
// inputs are truncated to this size.
|
||||
MaxPatternSize = 63
|
||||
)
|
||||
|
||||
type scoreVal int
|
||||
|
||||
func (s scoreVal) val() int {
|
||||
return int(s) >> 1
|
||||
}
|
||||
|
||||
func (s scoreVal) prevK() int {
|
||||
return int(s) & 1
|
||||
}
|
||||
|
||||
func score(val int, prevK int /*0 or 1*/) scoreVal {
|
||||
return scoreVal(val<<1 + prevK)
|
||||
}
|
||||
|
||||
// Matcher implements a fuzzy matching algorithm for scoring candidates against a pattern.
|
||||
// The matcher does not support parallel usage.
|
||||
type Matcher struct {
|
||||
pattern string
|
||||
patternLower []byte // lower-case version of the pattern
|
||||
patternShort []byte // first characters of the pattern
|
||||
caseSensitive bool // set if the pattern is mix-cased
|
||||
|
||||
patternRoles []RuneRole // the role of each character in the pattern
|
||||
roles []RuneRole // the role of each character in the tested string
|
||||
|
||||
scores [MaxInputSize + 1][MaxPatternSize + 1][2]scoreVal
|
||||
|
||||
scoreScale float32
|
||||
|
||||
lastCandidateLen int // in bytes
|
||||
lastCandidateMatched bool
|
||||
|
||||
// Reusable buffers to avoid allocating for every candidate.
|
||||
// - inputBuf stores the concatenated input chunks
|
||||
// - lowerBuf stores the last candidate in lower-case
|
||||
// - rolesBuf stores the calculated roles for each rune in the last
|
||||
// candidate.
|
||||
inputBuf [MaxInputSize]byte
|
||||
lowerBuf [MaxInputSize]byte
|
||||
rolesBuf [MaxInputSize]RuneRole
|
||||
}
|
||||
|
||||
func (m *Matcher) bestK(i, j int) int {
|
||||
if m.scores[i][j][0].val() < m.scores[i][j][1].val() {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// NewMatcher returns a new fuzzy matcher for scoring candidates against the provided pattern.
|
||||
func NewMatcher(pattern string) *Matcher {
|
||||
if len(pattern) > MaxPatternSize {
|
||||
pattern = pattern[:MaxPatternSize]
|
||||
}
|
||||
|
||||
m := &Matcher{
|
||||
pattern: pattern,
|
||||
patternLower: toLower([]byte(pattern), nil),
|
||||
}
|
||||
|
||||
for i, c := range m.patternLower {
|
||||
if pattern[i] != c {
|
||||
m.caseSensitive = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(pattern) > 3 {
|
||||
m.patternShort = m.patternLower[:3]
|
||||
} else {
|
||||
m.patternShort = m.patternLower
|
||||
}
|
||||
|
||||
m.patternRoles = RuneRoles([]byte(pattern), nil)
|
||||
|
||||
if len(pattern) > 0 {
|
||||
maxCharScore := 4
|
||||
m.scoreScale = 1 / float32(maxCharScore*len(pattern))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Score returns the score returned by matching the candidate to the pattern.
|
||||
// This is not designed for parallel use. Multiple candidates must be scored sequentially.
|
||||
// Returns a score between 0 and 1 (0 - no match, 1 - perfect match).
|
||||
func (m *Matcher) Score(candidate string) float32 {
|
||||
return m.ScoreChunks([]string{candidate})
|
||||
}
|
||||
|
||||
func (m *Matcher) ScoreChunks(chunks []string) float32 {
|
||||
candidate := fromChunks(chunks, m.inputBuf[:])
|
||||
if len(candidate) > MaxInputSize {
|
||||
candidate = candidate[:MaxInputSize]
|
||||
}
|
||||
lower := toLower(candidate, m.lowerBuf[:])
|
||||
m.lastCandidateLen = len(candidate)
|
||||
|
||||
if len(m.pattern) == 0 {
|
||||
// Empty patterns perfectly match candidates.
|
||||
return 1
|
||||
}
|
||||
|
||||
if m.match(candidate, lower) {
|
||||
sc := m.computeScore(candidate, lower)
|
||||
if sc > minScore/2 && !m.poorMatch() {
|
||||
m.lastCandidateMatched = true
|
||||
if len(m.pattern) == len(candidate) {
|
||||
// Perfect match.
|
||||
return 1
|
||||
}
|
||||
|
||||
if sc < 0 {
|
||||
sc = 0
|
||||
}
|
||||
normalizedScore := float32(sc) * m.scoreScale
|
||||
if normalizedScore > 1 {
|
||||
normalizedScore = 1
|
||||
}
|
||||
|
||||
return normalizedScore
|
||||
}
|
||||
}
|
||||
|
||||
m.lastCandidateMatched = false
|
||||
return 0
|
||||
}
|
||||
|
||||
const minScore = -10000
|
||||
|
||||
// MatchedRanges returns matches ranges for the last scored string as a flattened array of
|
||||
// [begin, end) byte offset pairs.
|
||||
func (m *Matcher) MatchedRanges() []int {
|
||||
if len(m.pattern) == 0 || !m.lastCandidateMatched {
|
||||
return nil
|
||||
}
|
||||
i, j := m.lastCandidateLen, len(m.pattern)
|
||||
if m.scores[i][j][0].val() < minScore/2 && m.scores[i][j][1].val() < minScore/2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ret []int
|
||||
k := m.bestK(i, j)
|
||||
for i > 0 {
|
||||
take := (k == 1)
|
||||
k = m.scores[i][j][k].prevK()
|
||||
if take {
|
||||
if len(ret) == 0 || ret[len(ret)-1] != i {
|
||||
ret = append(ret, i)
|
||||
ret = append(ret, i-1)
|
||||
} else {
|
||||
ret[len(ret)-1] = i - 1
|
||||
}
|
||||
j--
|
||||
}
|
||||
i--
|
||||
}
|
||||
// Reverse slice.
|
||||
for i := 0; i < len(ret)/2; i++ {
|
||||
ret[i], ret[len(ret)-1-i] = ret[len(ret)-1-i], ret[i]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *Matcher) match(candidate []byte, candidateLower []byte) bool {
|
||||
i, j := 0, 0
|
||||
for ; i < len(candidateLower) && j < len(m.patternLower); i++ {
|
||||
if candidateLower[i] == m.patternLower[j] {
|
||||
j++
|
||||
}
|
||||
}
|
||||
if j != len(m.patternLower) {
|
||||
return false
|
||||
}
|
||||
|
||||
// The input passes the simple test against pattern, so it is time to classify its characters.
|
||||
// Character roles are used below to find the last segment.
|
||||
m.roles = RuneRoles(candidate, m.rolesBuf[:])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *Matcher) computeScore(candidate []byte, candidateLower []byte) int {
|
||||
pattLen, candLen := len(m.pattern), len(candidate)
|
||||
|
||||
for j := 0; j <= len(m.pattern); j++ {
|
||||
m.scores[0][j][0] = minScore << 1
|
||||
m.scores[0][j][1] = minScore << 1
|
||||
}
|
||||
m.scores[0][0][0] = score(0, 0) // Start with 0.
|
||||
|
||||
segmentsLeft, lastSegStart := 1, 0
|
||||
for i := 0; i < candLen; i++ {
|
||||
if m.roles[i] == RSep {
|
||||
segmentsLeft++
|
||||
lastSegStart = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// A per-character bonus for a consecutive match.
|
||||
consecutiveBonus := 2
|
||||
wordIdx := 0 // Word count within segment.
|
||||
for i := 1; i <= candLen; i++ {
|
||||
|
||||
role := m.roles[i-1]
|
||||
isHead := role == RHead
|
||||
|
||||
if isHead {
|
||||
wordIdx++
|
||||
} else if role == RSep && segmentsLeft > 1 {
|
||||
wordIdx = 0
|
||||
segmentsLeft--
|
||||
}
|
||||
|
||||
var skipPenalty int
|
||||
if i == 1 || (i-1) == lastSegStart {
|
||||
// Skipping the start of first or last segment.
|
||||
skipPenalty++
|
||||
}
|
||||
|
||||
for j := 0; j <= pattLen; j++ {
|
||||
// By default, we don't have a match. Fill in the skip data.
|
||||
m.scores[i][j][1] = minScore << 1
|
||||
|
||||
// Compute the skip score.
|
||||
k := 0
|
||||
if m.scores[i-1][j][0].val() < m.scores[i-1][j][1].val() {
|
||||
k = 1
|
||||
}
|
||||
|
||||
skipScore := m.scores[i-1][j][k].val()
|
||||
// Do not penalize missing characters after the last matched segment.
|
||||
if j != pattLen {
|
||||
skipScore -= skipPenalty
|
||||
}
|
||||
m.scores[i][j][0] = score(skipScore, k)
|
||||
|
||||
if j == 0 || candidateLower[i-1] != m.patternLower[j-1] {
|
||||
// Not a match.
|
||||
continue
|
||||
}
|
||||
pRole := m.patternRoles[j-1]
|
||||
|
||||
if role == RTail && pRole == RHead {
|
||||
if j > 1 {
|
||||
// Not a match: a head in the pattern matches a tail character in the candidate.
|
||||
continue
|
||||
}
|
||||
// Special treatment for the first character of the pattern. We allow
|
||||
// matches in the middle of a word if they are long enough, at least
|
||||
// min(3, pattern.length) characters.
|
||||
if !bytes.HasPrefix(candidateLower[i-1:], m.patternShort) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the char score.
|
||||
var charScore int
|
||||
// Bonus 1: the char is in the candidate's last segment.
|
||||
if segmentsLeft <= 1 {
|
||||
charScore++
|
||||
}
|
||||
// Bonus 2: Case match or a Head in the pattern aligns with one in the word.
|
||||
// Single-case patterns lack segmentation signals and we assume any character
|
||||
// can be a head of a segment.
|
||||
if candidate[i-1] == m.pattern[j-1] || role == RHead && (!m.caseSensitive || pRole == RHead) {
|
||||
charScore++
|
||||
}
|
||||
|
||||
// Penalty 1: pattern char is Head, candidate char is Tail.
|
||||
if role == RTail && pRole == RHead {
|
||||
charScore--
|
||||
}
|
||||
// Penalty 2: first pattern character matched in the middle of a word.
|
||||
if j == 1 && role == RTail {
|
||||
charScore -= 4
|
||||
}
|
||||
|
||||
// Third dimension encodes whether there is a gap between the previous match and the current
|
||||
// one.
|
||||
for k := 0; k < 2; k++ {
|
||||
sc := m.scores[i-1][j-1][k].val() + charScore
|
||||
|
||||
isConsecutive := k == 1 || i-1 == 0 || i-1 == lastSegStart
|
||||
if isConsecutive {
|
||||
// Bonus 3: a consecutive match. First character match also gets a bonus to
|
||||
// ensure prefix final match score normalizes to 1.0.
|
||||
// Logically, this is a part of charScore, but we have to compute it here because it
|
||||
// only applies for consecutive matches (k == 1).
|
||||
sc += consecutiveBonus
|
||||
}
|
||||
if k == 0 {
|
||||
// Penalty 3: Matching inside a segment (and previous char wasn't matched). Penalize for the lack
|
||||
// of alignment.
|
||||
if role == RTail || role == RUCTail {
|
||||
sc -= 3
|
||||
}
|
||||
}
|
||||
|
||||
if sc > m.scores[i][j][1].val() {
|
||||
m.scores[i][j][1] = score(sc, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := m.scores[len(candidate)][len(m.pattern)][m.bestK(len(candidate), len(m.pattern))].val()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ScoreTable returns the score table computed for the provided candidate. Used only for debugging.
|
||||
func (m *Matcher) ScoreTable(candidate string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
var line1, line2, separator bytes.Buffer
|
||||
line1.WriteString("\t")
|
||||
line2.WriteString("\t")
|
||||
for j := 0; j < len(m.pattern); j++ {
|
||||
line1.WriteString(fmt.Sprintf("%c\t\t", m.pattern[j]))
|
||||
separator.WriteString("----------------")
|
||||
}
|
||||
|
||||
buf.WriteString(line1.String())
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(separator.String())
|
||||
buf.WriteString("\n")
|
||||
|
||||
for i := 1; i <= len(candidate); i++ {
|
||||
line1.Reset()
|
||||
line2.Reset()
|
||||
|
||||
line1.WriteString(fmt.Sprintf("%c\t", candidate[i-1]))
|
||||
line2.WriteString("\t")
|
||||
|
||||
for j := 1; j <= len(m.pattern); j++ {
|
||||
line1.WriteString(fmt.Sprintf("M%6d(%c)\t", m.scores[i][j][0].val(), dir(m.scores[i][j][0].prevK())))
|
||||
line2.WriteString(fmt.Sprintf("H%6d(%c)\t", m.scores[i][j][1].val(), dir(m.scores[i][j][1].prevK())))
|
||||
}
|
||||
buf.WriteString(line1.String())
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(line2.String())
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(separator.String())
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func dir(prevK int) rune {
|
||||
if prevK == 0 {
|
||||
return 'M'
|
||||
}
|
||||
return 'H'
|
||||
}
|
||||
|
||||
func (m *Matcher) poorMatch() bool {
|
||||
if len(m.pattern) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
i, j := m.lastCandidateLen, len(m.pattern)
|
||||
k := m.bestK(i, j)
|
||||
|
||||
var counter, len int
|
||||
for i > 0 {
|
||||
take := (k == 1)
|
||||
k = m.scores[i][j][k].prevK()
|
||||
if take {
|
||||
len++
|
||||
if k == 0 && len < 3 && m.roles[i-1] == RTail {
|
||||
// Short match in the middle of a word
|
||||
counter++
|
||||
if counter > 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
j--
|
||||
} else {
|
||||
len = 0
|
||||
}
|
||||
i--
|
||||
}
|
||||
return false
|
||||
}
|
||||
236
vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go
generated
vendored
Normal file
236
vendor/golang.org/x/tools/internal/lsp/fuzzy/symbol.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
// 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.
|
||||
|
||||
package fuzzy
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// SymbolMatcher implements a fuzzy matching algorithm optimized for Go symbols
|
||||
// of the form:
|
||||
// example.com/path/to/package.object.field
|
||||
//
|
||||
// Knowing that we are matching symbols like this allows us to make the
|
||||
// following optimizations:
|
||||
// - We can incorporate right-to-left relevance directly into the score
|
||||
// calculation.
|
||||
// - We can match from right to left, discarding leading bytes if the input is
|
||||
// too long.
|
||||
// - We just take the right-most match without losing too much precision. This
|
||||
// allows us to use an O(n) algorithm.
|
||||
// - We can operate directly on chunked strings; in many cases we will
|
||||
// be storing the package path and/or package name separately from the
|
||||
// symbol or identifiers, so doing this avoids allocating strings.
|
||||
// - We can return the index of the right-most match, allowing us to trim
|
||||
// irrelevant qualification.
|
||||
//
|
||||
// This implementation is experimental, serving as a reference fast algorithm
|
||||
// to compare to the fuzzy algorithm implemented by Matcher.
|
||||
type SymbolMatcher struct {
|
||||
// Using buffers of length 256 is both a reasonable size for most qualified
|
||||
// symbols, and makes it easy to avoid bounds checks by using uint8 indexes.
|
||||
pattern [256]rune
|
||||
patternLen uint8
|
||||
inputBuffer [256]rune // avoid allocating when considering chunks
|
||||
roles [256]uint32 // which roles does a rune play (word start, etc.)
|
||||
segments [256]uint8 // how many segments from the right is each rune
|
||||
}
|
||||
|
||||
const (
|
||||
segmentStart uint32 = 1 << iota
|
||||
wordStart
|
||||
separator
|
||||
)
|
||||
|
||||
// NewSymbolMatcher creates a SymbolMatcher that may be used to match the given
|
||||
// search pattern.
|
||||
//
|
||||
// Currently this matcher only accepts case-insensitive fuzzy patterns.
|
||||
//
|
||||
// An empty pattern matches no input.
|
||||
func NewSymbolMatcher(pattern string) *SymbolMatcher {
|
||||
m := &SymbolMatcher{}
|
||||
for _, p := range pattern {
|
||||
m.pattern[m.patternLen] = unicode.ToLower(p)
|
||||
m.patternLen++
|
||||
if m.patternLen == 255 || int(m.patternLen) == len(pattern) {
|
||||
// break at 255 so that we can represent patternLen with a uint8.
|
||||
break
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Match looks for the right-most match of the search pattern within the symbol
|
||||
// represented by concatenating the given chunks, returning its offset and
|
||||
// score.
|
||||
//
|
||||
// If a match is found, the first return value will hold the absolute byte
|
||||
// offset within all chunks for the start of the symbol. In other words, the
|
||||
// index of the match within strings.Join(chunks, ""). If no match is found,
|
||||
// the first return value will be -1.
|
||||
//
|
||||
// The second return value will be the score of the match, which is always
|
||||
// between 0 and 1, inclusive. A score of 0 indicates no match.
|
||||
func (m *SymbolMatcher) Match(chunks []string) (int, float64) {
|
||||
// Explicit behavior for an empty pattern.
|
||||
//
|
||||
// As a minor optimization, this also avoids nilness checks later on, since
|
||||
// the compiler can prove that m != nil.
|
||||
if m.patternLen == 0 {
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
// First phase: populate the input buffer with lower-cased runes.
|
||||
//
|
||||
// We could also check for a forward match here, but since we'd have to write
|
||||
// the entire input anyway this has negligible impact on performance.
|
||||
|
||||
var (
|
||||
inputLen = uint8(0)
|
||||
modifiers = wordStart | segmentStart
|
||||
)
|
||||
|
||||
input:
|
||||
for _, chunk := range chunks {
|
||||
for _, r := range chunk {
|
||||
if r == '.' || r == '/' {
|
||||
modifiers |= separator
|
||||
}
|
||||
// optimization: avoid calls to unicode.ToLower, which can't be inlined.
|
||||
l := r
|
||||
if r <= unicode.MaxASCII {
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
l = r + 'a' - 'A'
|
||||
}
|
||||
} else {
|
||||
l = unicode.ToLower(r)
|
||||
}
|
||||
if l != r {
|
||||
modifiers |= wordStart
|
||||
}
|
||||
m.inputBuffer[inputLen] = l
|
||||
m.roles[inputLen] = modifiers
|
||||
inputLen++
|
||||
if m.roles[inputLen-1]&separator != 0 {
|
||||
modifiers = wordStart | segmentStart
|
||||
} else {
|
||||
modifiers = 0
|
||||
}
|
||||
// TODO: we should prefer the right-most input if it overflows, rather
|
||||
// than the left-most as we're doing here.
|
||||
if inputLen == 255 {
|
||||
break input
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second phase: find the right-most match, and count segments from the
|
||||
// right.
|
||||
|
||||
var (
|
||||
pi = uint8(m.patternLen - 1) // pattern index
|
||||
p = m.pattern[pi] // pattern rune
|
||||
start = -1 // start offset of match
|
||||
rseg = uint8(0)
|
||||
)
|
||||
const maxSeg = 3 // maximum number of segments from the right to count, for scoring purposes.
|
||||
|
||||
for ii := inputLen - 1; ; ii-- {
|
||||
r := m.inputBuffer[ii]
|
||||
if rseg < maxSeg && m.roles[ii]&separator != 0 {
|
||||
rseg++
|
||||
}
|
||||
m.segments[ii] = rseg
|
||||
if p == r {
|
||||
if pi == 0 {
|
||||
start = int(ii)
|
||||
break
|
||||
}
|
||||
pi--
|
||||
p = m.pattern[pi]
|
||||
}
|
||||
// Don't check ii >= 0 in the loop condition: ii is a uint8.
|
||||
if ii == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if start < 0 {
|
||||
// no match: skip scoring
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
// Third phase: find the shortest match, and compute the score.
|
||||
|
||||
// Score is the average score for each character.
|
||||
//
|
||||
// A character score is the multiple of:
|
||||
// 1. 1.0 if the character starts a segment, .8 if the character start a
|
||||
// mid-segment word, otherwise 0.6. This carries over to immediately
|
||||
// following characters.
|
||||
// 2. For the final character match, the multiplier from (1) is reduced to
|
||||
// .8 if the next character in the input is a mid-segment word, or 0.6 if
|
||||
// the next character in the input is not a word or segment start. This
|
||||
// ensures that we favor whole-word or whole-segment matches over prefix
|
||||
// matches.
|
||||
// 3. 1.0 if the character is part of the last segment, otherwise
|
||||
// 1.0-.2*<segments from the right>, with a max segment count of 3.
|
||||
//
|
||||
// This is a very naive algorithm, but it is fast. There's lots of prior art
|
||||
// here, and we should leverage it. For example, we could explicitly consider
|
||||
// character distance, and exact matches of words or segments.
|
||||
//
|
||||
// Also note that this might not actually find the highest scoring match, as
|
||||
// doing so could require a non-linear algorithm, depending on how the score
|
||||
// is calculated.
|
||||
|
||||
pi = 0
|
||||
p = m.pattern[pi]
|
||||
|
||||
const (
|
||||
segStreak = 1.0
|
||||
wordStreak = 0.8
|
||||
noStreak = 0.6
|
||||
perSegment = 0.2 // we count at most 3 segments above
|
||||
)
|
||||
|
||||
streakBonus := noStreak
|
||||
totScore := 0.0
|
||||
for ii := uint8(start); ii < inputLen; ii++ {
|
||||
r := m.inputBuffer[ii]
|
||||
if r == p {
|
||||
pi++
|
||||
p = m.pattern[pi]
|
||||
// Note: this could be optimized with some bit operations.
|
||||
switch {
|
||||
case m.roles[ii]&segmentStart != 0 && segStreak > streakBonus:
|
||||
streakBonus = segStreak
|
||||
case m.roles[ii]&wordStart != 0 && wordStreak > streakBonus:
|
||||
streakBonus = wordStreak
|
||||
}
|
||||
finalChar := pi >= m.patternLen
|
||||
// finalCost := 1.0
|
||||
if finalChar && streakBonus > noStreak {
|
||||
switch {
|
||||
case ii == inputLen-1 || m.roles[ii+1]&segmentStart != 0:
|
||||
// Full segment: no reduction
|
||||
case m.roles[ii+1]&wordStart != 0:
|
||||
streakBonus = wordStreak
|
||||
default:
|
||||
streakBonus = noStreak
|
||||
}
|
||||
}
|
||||
totScore += streakBonus * (1.0 - float64(m.segments[ii])*perSegment)
|
||||
if finalChar {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
streakBonus = noStreak
|
||||
}
|
||||
}
|
||||
|
||||
return start, totScore / float64(m.patternLen)
|
||||
}
|
||||
179
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
179
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
@@ -2,24 +2,179 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package typeparams provides functions to work indirectly with type parameter
|
||||
// data stored in go/ast and go/types objects, while these API are guarded by a
|
||||
// build constraint.
|
||||
// Package typeparams contains common utilities for writing tools that interact
|
||||
// with generic Go code, as introduced with Go 1.18.
|
||||
//
|
||||
// This package exists to make it easier for tools to work with generic code,
|
||||
// while also compiling against older Go versions.
|
||||
// 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
|
||||
// restrictions on a type parameter. In the future, this API may be available
|
||||
// from go/types.
|
||||
//
|
||||
// See the example/README.md for a more detailed guide on how to update tools
|
||||
// to support generics.
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// A IndexExprData holds data from both ast.IndexExpr and the new
|
||||
// ast.MultiIndexExpr, which was introduced in Go 1.18.
|
||||
type IndexExprData struct {
|
||||
X ast.Expr // expression
|
||||
Lbrack token.Pos // position of "["
|
||||
Indices []ast.Expr // index expressions
|
||||
Rbrack token.Pos // position of "]"
|
||||
// UnpackIndexExpr extracts data from AST nodes that represent index
|
||||
// expressions.
|
||||
//
|
||||
// For an ast.IndexExpr, the resulting indices slice will contain exactly one
|
||||
// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable
|
||||
// number of index expressions.
|
||||
//
|
||||
// For nodes that don't represent index expressions, the first return value of
|
||||
// UnpackIndexExpr will be nil.
|
||||
func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) {
|
||||
switch e := n.(type) {
|
||||
case *ast.IndexExpr:
|
||||
return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
|
||||
case *IndexListExpr:
|
||||
return e.X, e.Lbrack, e.Indices, e.Rbrack
|
||||
}
|
||||
return nil, token.NoPos, nil, token.NoPos
|
||||
}
|
||||
|
||||
// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
|
||||
// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
|
||||
// will panic.
|
||||
func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
|
||||
switch len(indices) {
|
||||
case 0:
|
||||
panic("empty indices")
|
||||
case 1:
|
||||
return &ast.IndexExpr{
|
||||
X: x,
|
||||
Lbrack: lbrack,
|
||||
Index: indices[0],
|
||||
Rbrack: rbrack,
|
||||
}
|
||||
default:
|
||||
return &IndexListExpr{
|
||||
X: x,
|
||||
Lbrack: lbrack,
|
||||
Indices: indices,
|
||||
Rbrack: rbrack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsTypeParam reports whether t is a type parameter.
|
||||
func IsTypeParam(t types.Type) bool {
|
||||
_, ok := t.(*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)
|
||||
}
|
||||
|
||||
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
Normal file
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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
Normal file
15
vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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
|
||||
216
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
Normal file
216
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
// 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.
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:generate go run copytermlist.go
|
||||
|
||||
const debug = false
|
||||
|
||||
var ErrEmptyTypeSet = errors.New("empty type set")
|
||||
|
||||
// StructuralTerms returns a slice of terms representing the normalized
|
||||
// structural type restrictions of a type parameter, if any.
|
||||
//
|
||||
// Structural type restrictions of a type parameter are created via
|
||||
// non-interface types embedded in its constraint interface (directly, or via a
|
||||
// chain of interface embeddings). For example, in the declaration
|
||||
// type T[P interface{~int; m()}] int
|
||||
// the structural restriction of the type parameter P is ~int.
|
||||
//
|
||||
// With interface embedding and unions, the specification of structural type
|
||||
// restrictions may be arbitrarily complex. For example, consider the
|
||||
// following:
|
||||
//
|
||||
// type A interface{ ~string|~[]byte }
|
||||
//
|
||||
// type B interface{ int|string }
|
||||
//
|
||||
// type C interface { ~string|~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.
|
||||
//
|
||||
// StructuralTerms 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, StructuralTerms
|
||||
// returns a slice of tilde terms corresponding to the terms of the union in
|
||||
// the normalized structural restriction. An error is returned if the
|
||||
// constraint interface is invalid, exceeds complexity bounds, or has an empty
|
||||
// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet.
|
||||
//
|
||||
// StructuralTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
|
||||
constraint := tparam.Constraint()
|
||||
if constraint == nil {
|
||||
return nil, fmt.Errorf("%s has nil constraint", tparam)
|
||||
}
|
||||
iface, _ := constraint.Underlying().(*types.Interface)
|
||||
if iface == nil {
|
||||
return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying())
|
||||
}
|
||||
return InterfaceTermSet(iface)
|
||||
}
|
||||
|
||||
// InterfaceTermSet computes the normalized terms for a constraint interface,
|
||||
// returning an error if the term set cannot be computed or is empty. In the
|
||||
// latter case, the error will be ErrEmptyTypeSet.
|
||||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
|
||||
return computeTermSet(iface)
|
||||
}
|
||||
|
||||
// UnionTermSet computes the normalized terms for a union, returning an error
|
||||
// if the term set cannot be computed or is empty. In the latter case, the
|
||||
// error will be ErrEmptyTypeSet.
|
||||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func UnionTermSet(union *Union) ([]*Term, error) {
|
||||
return computeTermSet(union)
|
||||
}
|
||||
|
||||
func computeTermSet(typ types.Type) ([]*Term, error) {
|
||||
tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tset.terms.isEmpty() {
|
||||
return nil, ErrEmptyTypeSet
|
||||
}
|
||||
if tset.terms.isAll() {
|
||||
return nil, nil
|
||||
}
|
||||
var terms []*Term
|
||||
for _, term := range tset.terms {
|
||||
terms = append(terms, NewTerm(term.tilde, term.typ))
|
||||
}
|
||||
return terms, nil
|
||||
}
|
||||
|
||||
// A termSet holds the normalized set of terms for a given type.
|
||||
//
|
||||
// The name termSet is intentionally distinct from 'type set': a type set is
|
||||
// all types that implement a type (and includes method restrictions), whereas
|
||||
// a term set just represents the structural restrictions on a type.
|
||||
type termSet struct {
|
||||
complete bool
|
||||
terms termlist
|
||||
}
|
||||
|
||||
func indentf(depth int, format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...)
|
||||
}
|
||||
|
||||
func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) {
|
||||
if t == nil {
|
||||
panic("nil type")
|
||||
}
|
||||
|
||||
if debug {
|
||||
indentf(depth, "%s", t.String())
|
||||
defer func() {
|
||||
if err != nil {
|
||||
indentf(depth, "=> %s", err)
|
||||
} else {
|
||||
indentf(depth, "=> %s", res.terms.String())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const maxTermCount = 100
|
||||
if tset, ok := seen[t]; ok {
|
||||
if !tset.complete {
|
||||
return nil, fmt.Errorf("cycle detected in the declaration of %s", t)
|
||||
}
|
||||
return tset, nil
|
||||
}
|
||||
|
||||
// Mark the current type as seen to avoid infinite recursion.
|
||||
tset := new(termSet)
|
||||
defer func() {
|
||||
tset.complete = true
|
||||
}()
|
||||
seen[t] = tset
|
||||
|
||||
switch u := t.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
// The term set of an interface is the intersection of the term sets of its
|
||||
// embedded types.
|
||||
tset.terms = allTermlist
|
||||
for i := 0; i < u.NumEmbeddeds(); i++ {
|
||||
embedded := u.EmbeddedType(i)
|
||||
if _, ok := embedded.Underlying().(*TypeParam); ok {
|
||||
return nil, fmt.Errorf("invalid embedded type %T", embedded)
|
||||
}
|
||||
tset2, err := computeTermSetInternal(embedded, seen, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tset.terms = tset.terms.intersect(tset2.terms)
|
||||
}
|
||||
case *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++ {
|
||||
t := u.Term(i)
|
||||
var terms termlist
|
||||
switch t.Type().Underlying().(type) {
|
||||
case *types.Interface:
|
||||
tset2, err := computeTermSetInternal(t.Type(), seen, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
terms = tset2.terms
|
||||
case *TypeParam, *Union:
|
||||
// A stand-alone type parameter or union is not permitted as union
|
||||
// term.
|
||||
return nil, fmt.Errorf("invalid union term %T", t)
|
||||
default:
|
||||
if t.Type() == types.Typ[types.Invalid] {
|
||||
continue
|
||||
}
|
||||
terms = termlist{{t.Tilde(), t.Type()}}
|
||||
}
|
||||
tset.terms = tset.terms.union(terms)
|
||||
if len(tset.terms) > maxTermCount {
|
||||
return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
|
||||
}
|
||||
}
|
||||
case *TypeParam:
|
||||
panic("unreachable")
|
||||
default:
|
||||
// For all other types, the term set is just a single non-tilde term
|
||||
// holding the type itself.
|
||||
if u != types.Typ[types.Invalid] {
|
||||
tset.terms = termlist{{false, t}}
|
||||
}
|
||||
}
|
||||
return tset, nil
|
||||
}
|
||||
|
||||
// under is a facade for the go/types internal function of the same name. It is
|
||||
// used by typeterm.go.
|
||||
func under(t types.Type) types.Type {
|
||||
return t.Underlying()
|
||||
}
|
||||
93
vendor/golang.org/x/tools/internal/typeparams/notypeparams.go
generated
vendored
93
vendor/golang.org/x/tools/internal/typeparams/notypeparams.go
generated
vendored
@@ -1,93 +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 !typeparams || !go1.18
|
||||
// +build !typeparams !go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// NOTE: doc comments must be kept in sync with typeparams.go.
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = false
|
||||
|
||||
// GetIndexExprData extracts data from AST nodes that represent index
|
||||
// expressions.
|
||||
//
|
||||
// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
|
||||
// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a
|
||||
// variable number of index expressions.
|
||||
//
|
||||
// For nodes that don't represent index expressions, GetIndexExprData returns
|
||||
// nil.
|
||||
func GetIndexExprData(n ast.Node) *IndexExprData {
|
||||
if e, _ := n.(*ast.IndexExpr); e != nil {
|
||||
return &IndexExprData{
|
||||
X: e.X,
|
||||
Lbrack: e.Lbrack,
|
||||
Indices: []ast.Expr{e.Index},
|
||||
Rbrack: e.Rbrack,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
|
||||
func ForTypeDecl(*ast.TypeSpec) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
|
||||
func ForFuncDecl(*ast.FuncDecl) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForSignature extracts the (possibly empty) type parameter object list from
|
||||
// sig.
|
||||
func ForSignature(*types.Signature) []*types.TypeName {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsComparable reports if iface is the comparable interface.
|
||||
func IsComparable(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsConstraint reports whether iface may only be used as a type parameter
|
||||
// constraint (i.e. has a type set or is the comparable interface).
|
||||
func IsConstraint(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ForNamed extracts the (possibly empty) type parameter object list from
|
||||
// named.
|
||||
func ForNamed(*types.Named) []*types.TypeName {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedTArgs extracts the (possibly empty) type argument list from named.
|
||||
func NamedTArgs(*types.Named) []types.Type {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitInferred initializes info to record inferred type information.
|
||||
func InitInferred(*types.Info) {
|
||||
}
|
||||
|
||||
// GetInferred extracts inferred type information from info for e.
|
||||
//
|
||||
// The expression e may have an inferred type if it is an *ast.IndexExpr
|
||||
// representing partial instantiation of a generic function type for which type
|
||||
// arguments have been inferred using constraint type inference, or if it is an
|
||||
// *ast.CallExpr for which type type arguments have be inferred using both
|
||||
// constraint type inference and function argument inference.
|
||||
func GetInferred(*types.Info, ast.Expr) ([]types.Type, *types.Signature) {
|
||||
return nil, nil
|
||||
}
|
||||
172
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
Normal file
172
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
// 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.
|
||||
|
||||
// Code generated by copytermlist.go DO NOT EDIT.
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// A termlist represents the type set represented by the union
|
||||
// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn.
|
||||
// A termlist is in normal form if all terms are disjoint.
|
||||
// termlist operations don't require the operands to be in
|
||||
// normal form.
|
||||
type termlist []*term
|
||||
|
||||
// allTermlist represents the set of all types.
|
||||
// It is in normal form.
|
||||
var allTermlist = termlist{new(term)}
|
||||
|
||||
// String prints the termlist exactly (without normalization).
|
||||
func (xl termlist) String() string {
|
||||
if len(xl) == 0 {
|
||||
return "∅"
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for i, x := range xl {
|
||||
if i > 0 {
|
||||
buf.WriteString(" ∪ ")
|
||||
}
|
||||
buf.WriteString(x.String())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// isEmpty reports whether the termlist xl represents the empty set of types.
|
||||
func (xl termlist) isEmpty() bool {
|
||||
// If there's a non-nil term, the entire list is not empty.
|
||||
// If the termlist is in normal form, this requires at most
|
||||
// one iteration.
|
||||
for _, x := range xl {
|
||||
if x != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isAll reports whether the termlist xl represents the set of all types.
|
||||
func (xl termlist) isAll() bool {
|
||||
// If there's a 𝓤 term, the entire list is 𝓤.
|
||||
// If the termlist is in normal form, this requires at most
|
||||
// one iteration.
|
||||
for _, x := range xl {
|
||||
if x != nil && x.typ == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// norm returns the normal form of xl.
|
||||
func (xl termlist) norm() termlist {
|
||||
// Quadratic algorithm, but good enough for now.
|
||||
// TODO(gri) fix asymptotic performance
|
||||
used := make([]bool, len(xl))
|
||||
var rl termlist
|
||||
for i, xi := range xl {
|
||||
if xi == nil || used[i] {
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(xl); j++ {
|
||||
xj := xl[j]
|
||||
if xj == nil || used[j] {
|
||||
continue
|
||||
}
|
||||
if u1, u2 := xi.union(xj); u2 == nil {
|
||||
// If we encounter a 𝓤 term, the entire list is 𝓤.
|
||||
// Exit early.
|
||||
// (Note that this is not just an optimization;
|
||||
// if we continue, we may end up with a 𝓤 term
|
||||
// and other terms and the result would not be
|
||||
// in normal form.)
|
||||
if u1.typ == nil {
|
||||
return allTermlist
|
||||
}
|
||||
xi = u1
|
||||
used[j] = true // xj is now unioned into xi - ignore it in future iterations
|
||||
}
|
||||
}
|
||||
rl = append(rl, xi)
|
||||
}
|
||||
return rl
|
||||
}
|
||||
|
||||
// If the type set represented by xl is specified by a single (non-𝓤) term,
|
||||
// structuralType returns that type. Otherwise it returns nil.
|
||||
func (xl termlist) structuralType() types.Type {
|
||||
if nl := xl.norm(); len(nl) == 1 {
|
||||
return nl[0].typ // if nl.isAll() then typ is nil, which is ok
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// union returns the union xl ∪ yl.
|
||||
func (xl termlist) union(yl termlist) termlist {
|
||||
return append(xl, yl...).norm()
|
||||
}
|
||||
|
||||
// intersect returns the intersection xl ∩ yl.
|
||||
func (xl termlist) intersect(yl termlist) termlist {
|
||||
if xl.isEmpty() || yl.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Quadratic algorithm, but good enough for now.
|
||||
// TODO(gri) fix asymptotic performance
|
||||
var rl termlist
|
||||
for _, x := range xl {
|
||||
for _, y := range yl {
|
||||
if r := x.intersect(y); r != nil {
|
||||
rl = append(rl, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rl.norm()
|
||||
}
|
||||
|
||||
// equal reports whether xl and yl represent the same type set.
|
||||
func (xl termlist) equal(yl termlist) bool {
|
||||
// TODO(gri) this should be more efficient
|
||||
return xl.subsetOf(yl) && yl.subsetOf(xl)
|
||||
}
|
||||
|
||||
// includes reports whether t ∈ xl.
|
||||
func (xl termlist) includes(t types.Type) bool {
|
||||
for _, x := range xl {
|
||||
if x.includes(t) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// supersetOf reports whether y ⊆ xl.
|
||||
func (xl termlist) supersetOf(y *term) bool {
|
||||
for _, x := range xl {
|
||||
if y.subsetOf(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// subsetOf reports whether xl ⊆ yl.
|
||||
func (xl termlist) subsetOf(yl termlist) bool {
|
||||
if yl.isEmpty() {
|
||||
return xl.isEmpty()
|
||||
}
|
||||
|
||||
// each term x of xl must be a subset of yl
|
||||
for _, x := range xl {
|
||||
if !yl.supersetOf(x) {
|
||||
return false // x is not a subset yl
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
125
vendor/golang.org/x/tools/internal/typeparams/typeparams.go
generated
vendored
125
vendor/golang.org/x/tools/internal/typeparams/typeparams.go
generated
vendored
@@ -1,125 +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 typeparams && go1.18
|
||||
// +build typeparams,go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// NOTE: doc comments must be kept in sync with notypeparams.go.
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = true
|
||||
|
||||
// GetIndexExprData extracts data from AST nodes that represent index
|
||||
// expressions.
|
||||
//
|
||||
// For an ast.IndexExpr, the resulting IndexExprData will have exactly one
|
||||
// index expression. For an ast.MultiIndexExpr (go1.18+), it may have a
|
||||
// variable number of index expressions.
|
||||
//
|
||||
// For nodes that don't represent index expressions, GetIndexExprData returns
|
||||
// nil.
|
||||
func GetIndexExprData(n ast.Node) *IndexExprData {
|
||||
switch e := n.(type) {
|
||||
case *ast.IndexExpr:
|
||||
return &IndexExprData{
|
||||
X: e.X,
|
||||
Lbrack: e.Lbrack,
|
||||
Indices: []ast.Expr{e.Index},
|
||||
Rbrack: e.Rbrack,
|
||||
}
|
||||
case *ast.MultiIndexExpr:
|
||||
return (*IndexExprData)(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForTypeDecl extracts the (possibly nil) type parameter node list from n.
|
||||
func ForTypeDecl(n *ast.TypeSpec) *ast.FieldList {
|
||||
return n.TParams
|
||||
}
|
||||
|
||||
// ForFuncDecl extracts the (possibly nil) type parameter node list from n.
|
||||
func ForFuncDecl(n *ast.FuncDecl) *ast.FieldList {
|
||||
if n.Type != nil {
|
||||
return n.Type.TParams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForSignature extracts the (possibly empty) type parameter object list from
|
||||
// sig.
|
||||
func ForSignature(sig *types.Signature) []*types.TypeName {
|
||||
return tparamsSlice(sig.TParams())
|
||||
}
|
||||
|
||||
// IsComparable reports if iface is the comparable interface.
|
||||
func IsComparable(iface *types.Interface) bool {
|
||||
return iface.IsComparable()
|
||||
}
|
||||
|
||||
// IsConstraint reports whether iface may only be used as a type parameter
|
||||
// constraint (i.e. has a type set or is the comparable interface).
|
||||
func IsConstraint(iface *types.Interface) bool {
|
||||
return iface.IsConstraint()
|
||||
}
|
||||
|
||||
// ForNamed extracts the (possibly empty) type parameter object list from
|
||||
// named.
|
||||
func ForNamed(named *types.Named) []*types.TypeName {
|
||||
return tparamsSlice(named.TParams())
|
||||
}
|
||||
|
||||
func tparamsSlice(tparams *types.TypeParams) []*types.TypeName {
|
||||
if tparams.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make([]*types.TypeName, tparams.Len())
|
||||
for i := 0; i < tparams.Len(); i++ {
|
||||
result[i] = tparams.At(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NamedTArgs extracts the (possibly empty) type argument list from named.
|
||||
func NamedTArgs(named *types.Named) []types.Type {
|
||||
ntargs := named.NumTArgs()
|
||||
if ntargs == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
targs := make([]types.Type, ntargs)
|
||||
for i := 0; i < ntargs; i++ {
|
||||
targs[i] = named.TArg(i)
|
||||
}
|
||||
|
||||
return targs
|
||||
}
|
||||
|
||||
// InitInferred initializes info to record inferred type information.
|
||||
func InitInferred(info *types.Info) {
|
||||
info.Inferred = make(map[ast.Expr]types.Inferred)
|
||||
}
|
||||
|
||||
// GetInferred extracts inferred type information from info for e.
|
||||
//
|
||||
// The expression e may have an inferred type if it is an *ast.IndexExpr
|
||||
// representing partial instantiation of a generic function type for which type
|
||||
// arguments have been inferred using constraint type inference, or if it is an
|
||||
// *ast.CallExpr for which type type arguments have be inferred using both
|
||||
// constraint type inference and function argument inference.
|
||||
func GetInferred(info *types.Info, e ast.Expr) ([]types.Type, *types.Signature) {
|
||||
if info.Inferred == nil {
|
||||
return nil, nil
|
||||
}
|
||||
inf := info.Inferred[e]
|
||||
return inf.TArgs, inf.Sig
|
||||
}
|
||||
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
Normal file
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// 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
Normal file
151
vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// 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)
|
||||
}
|
||||
170
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
Normal file
170
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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.
|
||||
|
||||
// Code generated by copytermlist.go DO NOT EDIT.
|
||||
|
||||
package typeparams
|
||||
|
||||
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
|
||||
//
|
||||
type term struct {
|
||||
tilde bool // valid if typ != nil
|
||||
typ types.Type
|
||||
}
|
||||
|
||||
func (x *term) String() string {
|
||||
switch {
|
||||
case x == nil:
|
||||
return "∅"
|
||||
case x.typ == nil:
|
||||
return "𝓤"
|
||||
case x.tilde:
|
||||
return "~" + x.typ.String()
|
||||
default:
|
||||
return x.typ.String()
|
||||
}
|
||||
}
|
||||
|
||||
// equal reports whether x and y represent the same type set.
|
||||
func (x *term) equal(y *term) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil || y == nil:
|
||||
return x == y
|
||||
case x.typ == nil || y.typ == nil:
|
||||
return x.typ == y.typ
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
return x.tilde == y.tilde && types.Identical(x.typ, y.typ)
|
||||
}
|
||||
|
||||
// union returns the union x ∪ y: zero, one, or two non-nil terms.
|
||||
func (x *term) union(y *term) (_, _ *term) {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil && y == nil:
|
||||
return nil, nil // ∅ ∪ ∅ == ∅
|
||||
case x == nil:
|
||||
return y, nil // ∅ ∪ y == y
|
||||
case y == nil:
|
||||
return x, nil // x ∪ ∅ == x
|
||||
case x.typ == nil:
|
||||
return x, nil // 𝓤 ∪ y == 𝓤
|
||||
case y.typ == nil:
|
||||
return y, nil // x ∪ 𝓤 == 𝓤
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return x, y // x ∪ y == (x, y) if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ∪ ~t == ~t
|
||||
// ~t ∪ T == ~t
|
||||
// T ∪ ~t == ~t
|
||||
// T ∪ T == T
|
||||
if x.tilde || !y.tilde {
|
||||
return x, nil
|
||||
}
|
||||
return y, nil
|
||||
}
|
||||
|
||||
// intersect returns the intersection x ∩ y.
|
||||
func (x *term) intersect(y *term) *term {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil || y == nil:
|
||||
return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅
|
||||
case x.typ == nil:
|
||||
return y // 𝓤 ∩ y == y
|
||||
case y.typ == nil:
|
||||
return x // x ∩ 𝓤 == x
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return nil // x ∩ y == ∅ if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ∩ ~t == ~t
|
||||
// ~t ∩ T == T
|
||||
// T ∩ ~t == T
|
||||
// T ∩ T == T
|
||||
if !x.tilde || y.tilde {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// includes reports whether t ∈ x.
|
||||
func (x *term) includes(t types.Type) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil:
|
||||
return false // t ∈ ∅ == false
|
||||
case x.typ == nil:
|
||||
return true // t ∈ 𝓤 == true
|
||||
}
|
||||
// ∅ ⊂ x ⊂ 𝓤
|
||||
|
||||
u := t
|
||||
if x.tilde {
|
||||
u = under(u)
|
||||
}
|
||||
return types.Identical(x.typ, u)
|
||||
}
|
||||
|
||||
// subsetOf reports whether x ⊆ y.
|
||||
func (x *term) subsetOf(y *term) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil:
|
||||
return true // ∅ ⊆ y == true
|
||||
case y == nil:
|
||||
return false // x ⊆ ∅ == false since x != ∅
|
||||
case y.typ == nil:
|
||||
return true // x ⊆ 𝓤 == true
|
||||
case x.typ == nil:
|
||||
return false // 𝓤 ⊆ y == false since y != 𝓤
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return false // x ⊆ y == false if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ⊆ ~t == true
|
||||
// ~t ⊆ T == false
|
||||
// T ⊆ ~t == true
|
||||
// T ⊆ T == true
|
||||
return !x.tilde || y.tilde
|
||||
}
|
||||
|
||||
// disjoint reports whether x ∩ y == ∅.
|
||||
// x.typ and y.typ must not be nil.
|
||||
func (x *term) disjoint(y *term) bool {
|
||||
if debug && (x.typ == nil || y.typ == nil) {
|
||||
panic("invalid argument(s)")
|
||||
}
|
||||
ux := x.typ
|
||||
if y.tilde {
|
||||
ux = under(ux)
|
||||
}
|
||||
uy := y.typ
|
||||
if x.tilde {
|
||||
uy = under(uy)
|
||||
}
|
||||
return !types.Identical(ux, uy)
|
||||
}
|
||||
158
vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
generated
vendored
158
vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
generated
vendored
@@ -1365,4 +1365,162 @@ const (
|
||||
// return i
|
||||
// }
|
||||
InvalidGo
|
||||
|
||||
// All codes below were added in Go 1.17.
|
||||
|
||||
/* decl */
|
||||
|
||||
// BadDecl occurs when a declaration has invalid syntax.
|
||||
BadDecl
|
||||
|
||||
// RepeatedDecl occurs when an identifier occurs more than once on the left
|
||||
// hand side of a short variable declaration.
|
||||
//
|
||||
// Example:
|
||||
// func _() {
|
||||
// x, y, y := 1, 2, 3
|
||||
// }
|
||||
RepeatedDecl
|
||||
|
||||
/* unsafe */
|
||||
|
||||
// InvalidUnsafeAdd occurs when unsafe.Add is called with a
|
||||
// length argument that is not of integer type.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var p unsafe.Pointer
|
||||
// var _ = unsafe.Add(p, float64(1))
|
||||
InvalidUnsafeAdd
|
||||
|
||||
// InvalidUnsafeSlice occurs when unsafe.Slice is called with a
|
||||
// pointer argument that is not of pointer type or a length argument
|
||||
// that is not of integer type, negative, or out of bounds.
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.Slice(x, 1)
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.Slice(&x, float64(1))
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.Slice(&x, -1)
|
||||
//
|
||||
// Example:
|
||||
// import "unsafe"
|
||||
//
|
||||
// var x int
|
||||
// var _ = unsafe.Slice(&x, uint64(1) << 63)
|
||||
InvalidUnsafeSlice
|
||||
|
||||
// All codes below were added in Go 1.18.
|
||||
|
||||
/* features */
|
||||
|
||||
// UnsupportedFeature occurs when a language feature is used that is not
|
||||
// supported at this Go version.
|
||||
UnsupportedFeature
|
||||
|
||||
/* type params */
|
||||
|
||||
// NotAGenericType occurs when a non-generic type is used where a generic
|
||||
// type is expected: in type or function instantiation.
|
||||
//
|
||||
// Example:
|
||||
// type T int
|
||||
//
|
||||
// var _ T[int]
|
||||
NotAGenericType
|
||||
|
||||
// WrongTypeArgCount occurs when a type or function is instantiated with an
|
||||
// incorrent 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.
|
||||
//
|
||||
// Example:
|
||||
// type T[p any] int
|
||||
//
|
||||
// var _ T[int, string]
|
||||
//
|
||||
// Example:
|
||||
// func f[T any]() {}
|
||||
//
|
||||
// var x = f
|
||||
WrongTypeArgCount
|
||||
|
||||
// CannotInferTypeArgs occurs when type or function type argument inference
|
||||
// fails to infer all type arguments.
|
||||
//
|
||||
// Example:
|
||||
// func f[T any]() {}
|
||||
//
|
||||
// func _() {
|
||||
// f()
|
||||
// }
|
||||
//
|
||||
// Example:
|
||||
// type N[P, Q any] struct{}
|
||||
//
|
||||
// var _ N[int]
|
||||
CannotInferTypeArgs
|
||||
|
||||
// InvalidTypeArg occurs when a type argument does not satisfy its
|
||||
// corresponding type parameter constraints.
|
||||
//
|
||||
// Example:
|
||||
// type T[P ~int] struct{}
|
||||
//
|
||||
// var _ T[string]
|
||||
InvalidTypeArg // arguments? InferenceFailed
|
||||
|
||||
// InvalidInstanceCycle occurs when an invalid cycle is detected
|
||||
// within the instantiation graph.
|
||||
//
|
||||
// Example:
|
||||
// func f[T any]() { f[*T]() }
|
||||
InvalidInstanceCycle
|
||||
|
||||
// InvalidUnion occurs when an embedded union or approximation element is
|
||||
// not valid.
|
||||
//
|
||||
// Example:
|
||||
// type _ interface {
|
||||
// ~int | interface{ m() }
|
||||
// }
|
||||
InvalidUnion
|
||||
|
||||
// MisplacedConstraintIface occurs when a constraint-type interface is used
|
||||
// outside of constraint position.
|
||||
//
|
||||
// Example:
|
||||
// type I interface { ~int }
|
||||
//
|
||||
// var _ I
|
||||
MisplacedConstraintIface
|
||||
|
||||
// InvalidMethodTypeParams occurs when methods have type parameters.
|
||||
//
|
||||
// It cannot be encountered with an AST parsed using go/parser.
|
||||
InvalidMethodTypeParams
|
||||
|
||||
// MisplacedTypeParam occurs when a type parameter is used in a place where
|
||||
// it is not permitted.
|
||||
//
|
||||
// Example:
|
||||
// type T[P any] P
|
||||
//
|
||||
// Example:
|
||||
// type T[P any] struct{ *P }
|
||||
MisplacedTypeParam
|
||||
)
|
||||
|
||||
18
vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go
generated
vendored
18
vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go
generated
vendored
@@ -138,11 +138,25 @@ func _() {
|
||||
_ = x[UnusedResults-128]
|
||||
_ = x[InvalidDefer-129]
|
||||
_ = x[InvalidGo-130]
|
||||
_ = x[BadDecl-131]
|
||||
_ = x[RepeatedDecl-132]
|
||||
_ = x[InvalidUnsafeAdd-133]
|
||||
_ = x[InvalidUnsafeSlice-134]
|
||||
_ = x[UnsupportedFeature-135]
|
||||
_ = x[NotAGenericType-136]
|
||||
_ = x[WrongTypeArgCount-137]
|
||||
_ = x[CannotInferTypeArgs-138]
|
||||
_ = x[InvalidTypeArg-139]
|
||||
_ = x[InvalidInstanceCycle-140]
|
||||
_ = x[InvalidUnion-141]
|
||||
_ = x[MisplacedConstraintIface-142]
|
||||
_ = x[InvalidMethodTypeParams-143]
|
||||
_ = x[MisplacedTypeParam-144]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGo"
|
||||
const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParam"
|
||||
|
||||
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}
|
||||
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}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 1
|
||||
|
||||
11
vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
11
vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
@@ -30,10 +30,15 @@ func SetUsesCgo(conf *types.Config) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func ReadGo116ErrorData(terr types.Error) (ErrorCode, token.Pos, token.Pos, bool) {
|
||||
// ReadGo116ErrorData extracts additional information from types.Error values
|
||||
// generated by Go version 1.16 and later: the error code, start position, and
|
||||
// end position. If all positions are valid, start <= err.Pos <= end.
|
||||
//
|
||||
// If the data could not be read, the final result parameter will be false.
|
||||
func ReadGo116ErrorData(err types.Error) (code ErrorCode, start, end token.Pos, ok bool) {
|
||||
var data [3]int
|
||||
// By coincidence all of these fields are ints, which simplifies things.
|
||||
v := reflect.ValueOf(terr)
|
||||
v := reflect.ValueOf(err)
|
||||
for i, name := range []string{"go116code", "go116start", "go116end"} {
|
||||
f := v.FieldByName(name)
|
||||
if !f.IsValid() {
|
||||
@@ -43,3 +48,5 @@ func ReadGo116ErrorData(terr types.Error) (ErrorCode, token.Pos, token.Pos, bool
|
||||
}
|
||||
return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true
|
||||
}
|
||||
|
||||
var SetGoVersion = func(conf *types.Config, version string) bool { return false }
|
||||
|
||||
19
vendor/golang.org/x/tools/internal/typesinternal/types_118.go
generated
vendored
Normal file
19
vendor/golang.org/x/tools/internal/typesinternal/types_118.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user