зеркало из https://github.com/golang/tools.git
x/tools: add explicit Unalias operations
This change is the result of an audit of all type assertions and type switches whose operand is a types.Type. (These were enumerated with an analyzer tool.) If the operand is already the result of a call to Underlying or Unalias, there is nothing to do, but in other cases, explicit Unalias operations were added in order to preserve the existing behavior when go/types starts creating explicit Alias types. This change does not address any desired behavior changes required for the ideal handling of aliases; they will wait for a followup. In a number of places I have added comments matching "TODO.*alias". It may be prudent to split this change by top-level directory, both for ease of review, and of later bisection if needed. During the audit, there appeared to be a recurring need for the following operators: - (*types.Func).Signature (golang/go#65772); - Deref(Type): it's easy to forget to strip off the Alias constructor; - ReceiverName (CL 565075), for destructuring receiver types such as T and *T, in which up to two Aliases might be present. Updates golang/go#65294 Change-Id: I5180b9bae1c9191807026b8e0dc6f15ed4953b9a Reviewed-on: https://go-review.googlesource.com/c/tools/+/565035 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com> Auto-Submit: Alan Donovan <adonovan@google.com>
This commit is contained in:
Родитель
a6c03c86fe
Коммит
38b0e9bfdb
|
@ -12,6 +12,8 @@ import (
|
|||
"go/types"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// TODO(gri) use tabwriter for alignment?
|
||||
|
@ -56,7 +58,7 @@ func (p *printer) printf(format string, args ...interface{}) {
|
|||
// denoted by obj is not an interface and has methods. Otherwise it returns
|
||||
// the zero value.
|
||||
func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
|
||||
named, _ := obj.Type().(*types.Named)
|
||||
named, _ := aliases.Unalias(obj.Type()).(*types.Named)
|
||||
if named == nil {
|
||||
// A type name's type can also be the
|
||||
// exported basic type unsafe.Pointer.
|
||||
|
|
|
@ -12,7 +12,11 @@
|
|||
|
||||
package main
|
||||
|
||||
import "go/types"
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
func (p *printer) writeType(this *types.Package, typ types.Type) {
|
||||
p.writeTypeInternal(this, typ, make([]types.Type, 8))
|
||||
|
@ -173,6 +177,10 @@ func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited
|
|||
p.print(")")
|
||||
}
|
||||
|
||||
case *aliases.Alias:
|
||||
// TODO(adonovan): display something aliasy.
|
||||
p.writeTypeInternal(this, aliases.Unalias(t), visited)
|
||||
|
||||
case *types.Named:
|
||||
s := "<Named w/o object>"
|
||||
if obj := t.Obj(); obj != nil {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/loader"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
@ -358,7 +359,7 @@ func appendNames(names []*types.Named, typ types.Type) []*types.Named {
|
|||
Elem() types.Type
|
||||
}
|
||||
|
||||
switch t := typ.(type) {
|
||||
switch t := aliases.Unalias(typ).(type) {
|
||||
case *types.Named:
|
||||
names = append(names, t)
|
||||
case *types.Map:
|
||||
|
@ -469,7 +470,7 @@ func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error)
|
|||
description = "alias of "
|
||||
} else if obj.Pos() == n.Pos() {
|
||||
description = "definition of " // (Named type)
|
||||
} else if _, ok := typ.(*types.Basic); ok {
|
||||
} else if _, ok := aliases.Unalias(typ).(*types.Basic); ok {
|
||||
description = "reference to built-in "
|
||||
} else {
|
||||
description = "reference to " // (Named type)
|
||||
|
@ -486,7 +487,7 @@ func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error)
|
|||
description = description + "type " + qpos.typeString(typ)
|
||||
|
||||
// Show sizes for structs and named types (it's fairly obvious for others).
|
||||
switch typ.(type) {
|
||||
switch aliases.Unalias(typ).(type) {
|
||||
case *types.Named, *types.Struct:
|
||||
szs := types.StdSizes{WordSize: 8, MaxAlign: 8} // assume amd64
|
||||
description = fmt.Sprintf("%s (size %d, align %d)", description,
|
||||
|
@ -576,7 +577,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
|
|||
printf(r.node, "%s", r.description)
|
||||
|
||||
// Show the underlying type for a reference to a named type.
|
||||
if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
|
||||
if nt, ok := aliases.Unalias(r.typ).(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
|
||||
// TODO(adonovan): improve display of complex struct/interface types.
|
||||
printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
|
||||
}
|
||||
|
@ -585,7 +586,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
|
|||
if len(r.methods) == 0 {
|
||||
// Only report null result for type kinds
|
||||
// capable of bearing methods.
|
||||
switch r.typ.(type) {
|
||||
switch aliases.Unalias(r.typ).(type) {
|
||||
case *types.Interface, *types.Struct, *types.Named:
|
||||
printf(r.node, "No methods.")
|
||||
}
|
||||
|
@ -596,7 +597,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
|
|||
|
||||
func (r *describeTypeResult) JSON(fset *token.FileSet) []byte {
|
||||
var namePos, nameDef string
|
||||
if nt, ok := r.typ.(*types.Named); ok {
|
||||
if nt, ok := aliases.Unalias(r.typ).(*types.Named); ok {
|
||||
namePos = fset.Position(nt.Obj().Pos()).String()
|
||||
nameDef = nt.Underlying().String()
|
||||
}
|
||||
|
@ -727,7 +728,7 @@ func formatMember(obj types.Object, maxname int) string {
|
|||
}
|
||||
var typestr string
|
||||
// Abbreviate long aggregate type names.
|
||||
switch typ := typ.(type) {
|
||||
switch typ := aliases.Unalias(typ).(type) {
|
||||
case *types.Interface:
|
||||
if typ.NumMethods() > 1 {
|
||||
typestr = "interface{...}"
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"golang.org/x/tools/cmd/guru/serial"
|
||||
"golang.org/x/tools/go/loader"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/refactor/importgraph"
|
||||
)
|
||||
|
||||
|
@ -157,7 +158,7 @@ func implements(q *Query) error {
|
|||
}
|
||||
|
||||
var pos interface{} = qpos
|
||||
if nt, ok := deref(T).(*types.Named); ok {
|
||||
if nt, ok := aliases.Unalias(deref(T)).(*types.Named); ok {
|
||||
pos = nt.Obj()
|
||||
}
|
||||
|
||||
|
@ -230,7 +231,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
|
|||
for i, sub := range r.to {
|
||||
if !isInterface(sub) {
|
||||
if r.method == nil {
|
||||
printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
|
||||
printf(aliases.Unalias(deref(sub)).(*types.Named).Obj(), "\t%s %s type %s",
|
||||
relation, typeKind(sub), r.qpos.typeString(sub))
|
||||
} else {
|
||||
meth(r.toMethod[i])
|
||||
|
@ -240,7 +241,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
|
|||
for i, sub := range r.to {
|
||||
if isInterface(sub) {
|
||||
if r.method == nil {
|
||||
printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
|
||||
printf(aliases.Unalias(sub).(*types.Named).Obj(), "\t%s %s type %s",
|
||||
relation, typeKind(sub), r.qpos.typeString(sub))
|
||||
} else {
|
||||
meth(r.toMethod[i])
|
||||
|
@ -251,7 +252,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
|
|||
relation = "implements"
|
||||
for i, super := range r.from {
|
||||
if r.method == nil {
|
||||
printf(super.(*types.Named).Obj(), "\t%s %s",
|
||||
printf(aliases.Unalias(super).(*types.Named).Obj(), "\t%s %s",
|
||||
relation, r.qpos.typeString(super))
|
||||
} else {
|
||||
meth(r.fromMethod[i])
|
||||
|
@ -270,7 +271,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
|
|||
}
|
||||
for i, super := range r.from {
|
||||
if r.method == nil {
|
||||
printf(super.(*types.Named).Obj(), "\t%s %s",
|
||||
printf(aliases.Unalias(super).(*types.Named).Obj(), "\t%s %s",
|
||||
relation, r.qpos.typeString(super))
|
||||
} else {
|
||||
meth(r.fromMethod[i])
|
||||
|
@ -288,7 +289,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
|
|||
|
||||
for i, psuper := range r.fromPtr {
|
||||
if r.method == nil {
|
||||
printf(psuper.(*types.Named).Obj(), "\t%s %s",
|
||||
printf(aliases.Unalias(psuper).(*types.Named).Obj(), "\t%s %s",
|
||||
relation, r.qpos.typeString(psuper))
|
||||
} else {
|
||||
meth(r.fromPtrMethod[i])
|
||||
|
@ -332,7 +333,7 @@ func makeImplementsTypes(tt []types.Type, fset *token.FileSet) []serial.Implemen
|
|||
|
||||
func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType {
|
||||
var pos token.Pos
|
||||
if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named
|
||||
if nt, ok := aliases.Unalias(deref(T)).(*types.Named); ok { // implementsResult.t may be non-named
|
||||
pos = nt.Obj().Pos()
|
||||
}
|
||||
return serial.ImplementsType{
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -71,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||
return
|
||||
}
|
||||
var structuralTypes []types.Type
|
||||
switch typ := typ.(type) {
|
||||
switch typ := aliases.Unalias(typ).(type) {
|
||||
case *types.TypeParam:
|
||||
terms, err := typeparams.StructuralTerms(typ)
|
||||
if err != nil {
|
||||
|
@ -84,7 +85,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||
structuralTypes = append(structuralTypes, typ)
|
||||
}
|
||||
for _, typ := range structuralTypes {
|
||||
under := deref(typ.Underlying())
|
||||
// TODO(adonovan): this operation is questionable.
|
||||
under := aliases.Unalias(deref(typ.Underlying()))
|
||||
strct, ok := under.(*types.Struct)
|
||||
if !ok {
|
||||
// skip non-struct composite literals
|
||||
|
@ -142,9 +144,11 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Note: this is not the usual deref operator!
|
||||
// It strips off all Pointer constructors (and their Aliases).
|
||||
func deref(typ types.Type) types.Type {
|
||||
for {
|
||||
ptr, ok := typ.(*types.Pointer)
|
||||
ptr, ok := aliases.Unalias(typ).(*types.Pointer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
@ -153,18 +157,18 @@ func deref(typ types.Type) types.Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
// isLocalType reports whether typ belongs to the same package as pass.
|
||||
// TODO(adonovan): local means "internal to a function"; rename to isSamePackageType.
|
||||
func isLocalType(pass *analysis.Pass, typ types.Type) bool {
|
||||
switch x := typ.(type) {
|
||||
switch x := aliases.Unalias(typ).(type) {
|
||||
case *types.Struct:
|
||||
// struct literals are local types
|
||||
return true
|
||||
case *types.Pointer:
|
||||
return isLocalType(pass, x.Elem())
|
||||
case *types.Named:
|
||||
case interface{ Obj() *types.TypeName }: // *Named or *TypeParam (aliases were removed already)
|
||||
// names in package foo are local to foo_test too
|
||||
return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
|
||||
case *types.TypeParam:
|
||||
return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -255,7 +256,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
|
|||
}
|
||||
seen[typ] = true
|
||||
|
||||
if tpar, ok := typ.(*types.TypeParam); ok {
|
||||
if tpar, ok := aliases.Unalias(typ).(*types.TypeParam); ok {
|
||||
terms, err := typeparams.StructuralTerms(tpar)
|
||||
if err != nil {
|
||||
return nil // invalid type
|
||||
|
|
|
@ -102,8 +102,7 @@ func containsError(typ types.Type) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
case *types.Named,
|
||||
*aliases.Alias:
|
||||
case *types.Named, *aliases.Alias:
|
||||
return check(t.Underlying())
|
||||
|
||||
// We list the remaining valid type kinds for completeness.
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
@ -136,7 +137,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
|
|||
if analysisutil.IsNamedType(typ, "net/http", "Client") {
|
||||
return true // method on http.Client.
|
||||
}
|
||||
ptr, ok := typ.(*types.Pointer)
|
||||
ptr, ok := aliases.Unalias(typ).(*types.Pointer)
|
||||
return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ package ifaceassert
|
|||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -94,6 +95,10 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
|
|||
case *types.Chan:
|
||||
return w.isParameterized(t.Elem())
|
||||
|
||||
case *aliases.Alias:
|
||||
// TODO(adonovan): think about generic aliases.
|
||||
return w.isParameterized(aliases.Unalias(t))
|
||||
|
||||
case *types.Named:
|
||||
list := t.TypeArgs()
|
||||
for i, n := 0, list.Len(); i < n; i++ {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"go/types"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
|
@ -115,7 +116,7 @@ func Imports(pkg *types.Package, path string) bool {
|
|||
// This function avoids allocating the concatenation of "pkg.Name",
|
||||
// which is important for the performance of syntax matching.
|
||||
func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
|
||||
n, ok := t.(*types.Named)
|
||||
n, ok := aliases.Unalias(t).(*types.Named)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -959,6 +960,8 @@ func isStringer(sig *types.Signature) bool {
|
|||
// It is almost always a mistake to print a function value.
|
||||
func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
|
||||
if typ := pass.TypesInfo.Types[e].Type; typ != nil {
|
||||
// Don't call Underlying: a named func type with a String method is ok.
|
||||
// TODO(adonovan): it would be more precise to check isStringer.
|
||||
_, ok := typ.(*types.Signature)
|
||||
return ok
|
||||
}
|
||||
|
@ -1010,7 +1013,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
|
|||
// Skip checking functions with unknown type.
|
||||
return
|
||||
}
|
||||
if sig, ok := typ.(*types.Signature); ok {
|
||||
if sig, ok := typ.Underlying().(*types.Signature); ok {
|
||||
if !sig.Variadic() {
|
||||
// Skip checking non-variadic functions.
|
||||
return
|
||||
|
@ -1020,7 +1023,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
|
|||
|
||||
typ := params.At(firstArg).Type()
|
||||
typ = typ.(*types.Slice).Elem()
|
||||
it, ok := typ.(*types.Interface)
|
||||
it, ok := aliases.Unalias(typ).(*types.Interface)
|
||||
if !ok || !it.Empty() {
|
||||
// Skip variadic functions accepting non-interface{} args.
|
||||
return
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -72,7 +73,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
if typ, _ := typ.(*types.TypeParam); typ != nil {
|
||||
if typ, _ := aliases.Unalias(typ).(*types.TypeParam); typ != nil {
|
||||
// Avoid infinite recursion through type parameters.
|
||||
if m.seen[typ] {
|
||||
return true
|
||||
|
@ -275,7 +276,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
|
|||
}
|
||||
|
||||
func isConvertibleToString(typ types.Type) bool {
|
||||
if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
|
||||
if bt, ok := aliases.Unalias(typ).(*types.Basic); ok && bt.Kind() == types.UntypedNil {
|
||||
// We explicitly don't want untyped nil, which is
|
||||
// convertible to both of the interfaces below, as it
|
||||
// would just panic anyway.
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -99,7 +100,7 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
|
|||
return
|
||||
}
|
||||
var structuralTypes []types.Type
|
||||
switch t := t.(type) {
|
||||
switch t := aliases.Unalias(t).(type) {
|
||||
case *types.TypeParam:
|
||||
terms, err := typeparams.StructuralTerms(t)
|
||||
if err != nil {
|
||||
|
|
|
@ -60,10 +60,12 @@ func describe(typ, inType types.Type, inName string) string {
|
|||
}
|
||||
|
||||
func typeName(typ types.Type) string {
|
||||
if v, _ := typ.(interface{ Name() string }); v != nil {
|
||||
typ = aliases.Unalias(typ)
|
||||
// TODO(adonovan): don't discard alias type, return its name.
|
||||
if v, _ := typ.(*types.Basic); v != nil {
|
||||
return v.Name()
|
||||
}
|
||||
if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil {
|
||||
if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil { // Named, TypeParam
|
||||
return v.Obj().Name()
|
||||
}
|
||||
return ""
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
@ -270,7 +271,7 @@ func forbiddenMethod(info *types.Info, call *ast.CallExpr) (*types.Var, *types.S
|
|||
func formatMethod(sel *types.Selection, fn *types.Func) string {
|
||||
var ptr string
|
||||
rtype := sel.Recv()
|
||||
if p, ok := rtype.(*types.Pointer); ok {
|
||||
if p, ok := aliases.Unalias(rtype).(*types.Pointer); ok {
|
||||
ptr = "*"
|
||||
rtype = p.Elem()
|
||||
}
|
||||
|
|
|
@ -252,6 +252,8 @@ func validateFuzzArgs(pass *analysis.Pass, params *types.Tuple, expr ast.Expr) b
|
|||
}
|
||||
|
||||
func isTestingType(typ types.Type, testingType string) bool {
|
||||
// No Unalias here: I doubt "go test" recognizes
|
||||
// "type A = *testing.T; func Test(A) {}" as a test.
|
||||
ptr, ok := typ.(*types.Pointer)
|
||||
if !ok {
|
||||
return false
|
||||
|
|
|
@ -107,7 +107,7 @@ func badFormatAt(info *types.Info, e ast.Expr) int {
|
|||
return -1
|
||||
}
|
||||
|
||||
t, ok := tv.Type.(*types.Basic)
|
||||
t, ok := tv.Type.(*types.Basic) // sic, no unalias
|
||||
if !ok || t.Info()&types.IsString == 0 {
|
||||
return -1
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
@ -88,7 +89,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
|
|||
// by the time we get to the conversion at the end.
|
||||
// For now approximate by saying that *Header is okay
|
||||
// but Header is not.
|
||||
pt, ok := info.Types[x.X].Type.(*types.Pointer)
|
||||
pt, ok := aliases.Unalias(info.Types[x.X].Type).(*types.Pointer)
|
||||
if ok && isReflectHeader(pt.Elem()) {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -125,10 +125,7 @@ func isDeadStore(store *ssa.Store, obj ssa.Value, addr ssa.Instruction) bool {
|
|||
|
||||
// isStructOrArray returns whether the underlying type is struct or array.
|
||||
func isStructOrArray(tp types.Type) bool {
|
||||
if named, ok := tp.(*types.Named); ok {
|
||||
tp = named.Underlying()
|
||||
}
|
||||
switch tp.(type) {
|
||||
switch tp.Underlying().(type) {
|
||||
case *types.Array:
|
||||
return true
|
||||
case *types.Struct:
|
||||
|
@ -146,7 +143,7 @@ func hasStructOrArrayType(v ssa.Value) bool {
|
|||
// func (t T) f() { ...}
|
||||
// the receiver object is of type *T:
|
||||
// t0 = local T (t) *T
|
||||
if tp, ok := alloc.Type().(*types.Pointer); ok {
|
||||
if tp, ok := aliases.Unalias(alloc.Type()).(*types.Pointer); ok {
|
||||
return isStructOrArray(tp.Elem())
|
||||
}
|
||||
return false
|
||||
|
@ -162,14 +159,12 @@ func hasStructOrArrayType(v ssa.Value) bool {
|
|||
func getFieldName(tp types.Type, index int) string {
|
||||
// TODO(adonovan): use
|
||||
// stp, ok := typeparams.Deref(tp).Underlying().(*types.Struct); ok {
|
||||
// when Deref is defined.
|
||||
// when Deref is defined. But see CL 565456 for a better fix.
|
||||
|
||||
if pt, ok := aliases.Unalias(tp).(*types.Pointer); ok {
|
||||
tp = pt.Elem()
|
||||
}
|
||||
if named, ok := aliases.Unalias(tp).(*types.Named); ok {
|
||||
tp = named.Underlying()
|
||||
}
|
||||
if stp, ok := tp.(*types.Struct); ok {
|
||||
if stp, ok := tp.Underlying().(*types.Struct); ok {
|
||||
return stp.Field(index).Name()
|
||||
}
|
||||
return fmt.Sprintf("%d", index)
|
||||
|
|
|
@ -375,7 +375,7 @@ func (r *rta) interfaces(C types.Type) []*types.Interface {
|
|||
// and update the 'implements' relation.
|
||||
r.interfaceTypes.Iterate(func(I types.Type, v interface{}) {
|
||||
iinfo := v.(*interfaceTypeInfo)
|
||||
if I := I.(*types.Interface); implements(cinfo, iinfo) {
|
||||
if I := aliases.Unalias(I).(*types.Interface); implements(cinfo, iinfo) {
|
||||
iinfo.implementations = append(iinfo.implementations, C)
|
||||
cinfo.implements = append(cinfo.implements, I)
|
||||
}
|
||||
|
@ -457,7 +457,7 @@ func (r *rta) addRuntimeType(T types.Type, skip bool) {
|
|||
// Each package maintains its own set of types it has visited.
|
||||
|
||||
var n *types.Named
|
||||
switch T := T.(type) {
|
||||
switch T := aliases.Unalias(T).(type) {
|
||||
case *types.Named:
|
||||
n = T
|
||||
case *types.Pointer:
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"golang.org/x/tools/go/callgraph"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -410,7 +411,7 @@ func (b *builder) tassert(a *ssa.TypeAssert) {
|
|||
// The case where a is <a.AssertedType, bool> register so there
|
||||
// is a flow from a.X to a[0]. Here, a[0] is represented as an
|
||||
// indexedLocal: an entry into local tuple register a at index 0.
|
||||
tup := a.Type().Underlying().(*types.Tuple)
|
||||
tup := a.Type().(*types.Tuple)
|
||||
t := tup.At(0).Type()
|
||||
|
||||
local := indexedLocal{val: a, typ: t, index: 0}
|
||||
|
@ -421,7 +422,7 @@ func (b *builder) tassert(a *ssa.TypeAssert) {
|
|||
// and t1 where the source is indexed local representing a value
|
||||
// from tuple register t2 at index i and the target is t1.
|
||||
func (b *builder) extract(e *ssa.Extract) {
|
||||
tup := e.Tuple.Type().Underlying().(*types.Tuple)
|
||||
tup := e.Tuple.Type().(*types.Tuple)
|
||||
t := tup.At(e.Index).Type()
|
||||
|
||||
local := indexedLocal{val: e.Tuple, typ: t, index: e.Index}
|
||||
|
@ -527,7 +528,7 @@ func (b *builder) next(n *ssa.Next) {
|
|||
if n.IsString {
|
||||
return
|
||||
}
|
||||
tup := n.Type().Underlying().(*types.Tuple)
|
||||
tup := n.Type().(*types.Tuple)
|
||||
kt := tup.At(1).Type()
|
||||
vt := tup.At(2).Type()
|
||||
|
||||
|
@ -657,7 +658,7 @@ func addReturnFlows(b *builder, r *ssa.Return, site ssa.Value) {
|
|||
return
|
||||
}
|
||||
|
||||
tup := site.Type().Underlying().(*types.Tuple)
|
||||
tup := site.Type().(*types.Tuple)
|
||||
for i, r := range results {
|
||||
local := indexedLocal{val: site, typ: tup.At(i).Type(), index: i}
|
||||
b.addInFlowEdge(b.nodeFromVal(r), local)
|
||||
|
@ -671,7 +672,7 @@ func (b *builder) multiconvert(c *ssa.MultiConvert) {
|
|||
// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
|
||||
var terms []*types.Term
|
||||
var err error
|
||||
switch typ := typ.(type) {
|
||||
switch typ := aliases.Unalias(typ).(type) {
|
||||
case *types.TypeParam:
|
||||
terms, err = typeparams.StructuralTerms(typ)
|
||||
case *types.Union:
|
||||
|
@ -692,7 +693,7 @@ func (b *builder) multiconvert(c *ssa.MultiConvert) {
|
|||
}
|
||||
// isValuePreserving returns true if a conversion from ut_src to
|
||||
// ut_dst is value-preserving, i.e. just a change of type.
|
||||
// Precondition: neither argument is a named type.
|
||||
// Precondition: neither argument is a named or alias type.
|
||||
isValuePreserving := func(ut_src, ut_dst types.Type) bool {
|
||||
// Identical underlying types?
|
||||
if types.IdenticalIgnoreTags(ut_dst, ut_src) {
|
||||
|
@ -740,7 +741,7 @@ func (b *builder) addInFlowEdge(s, d node) {
|
|||
|
||||
// Creates const, pointer, global, func, and local nodes based on register instructions.
|
||||
func (b *builder) nodeFromVal(val ssa.Value) node {
|
||||
if p, ok := val.Type().(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
|
||||
if p, ok := aliases.Unalias(val.Type()).(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
|
||||
// Nested pointer to interfaces are modeled as a special
|
||||
// nestedPtrInterface node.
|
||||
if i := interfaceUnderPtr(p.Elem()); i != nil {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"golang.org/x/tools/go/callgraph/cha"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
func TestNodeInterface(t *testing.T) {
|
||||
|
@ -35,7 +36,7 @@ func TestNodeInterface(t *testing.T) {
|
|||
reg := firstRegInstr(main) // t0 := *gl
|
||||
X := pkg.Type("X").Type()
|
||||
gl := pkg.Var("gl")
|
||||
glPtrType, ok := gl.Type().(*types.Pointer)
|
||||
glPtrType, ok := aliases.Unalias(gl.Type()).(*types.Pointer)
|
||||
if !ok {
|
||||
t.Fatalf("could not cast gl variable to pointer type")
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/callgraph"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,7 @@ func isReferenceNode(n node) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
if _, ok := n.Type().(*types.Pointer); ok {
|
||||
if _, ok := aliases.Unalias(n.Type()).(*types.Pointer); ok {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -166,6 +167,7 @@ func siteCallees(c ssa.CallInstruction, callgraph *callgraph.Graph) []*ssa.Funct
|
|||
}
|
||||
|
||||
func canHaveMethods(t types.Type) bool {
|
||||
t = aliases.Unalias(t)
|
||||
if _, ok := t.(*types.Named); ok {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"strings"
|
||||
"text/scanner"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
|
@ -241,7 +243,7 @@ func (p *parser) parseName() string {
|
|||
}
|
||||
|
||||
func deref(typ types.Type) types.Type {
|
||||
if p, _ := typ.(*types.Pointer); p != nil {
|
||||
if p, _ := aliases.Unalias(typ).(*types.Pointer); p != nil {
|
||||
typ = p.Elem()
|
||||
}
|
||||
return typ
|
||||
|
@ -260,7 +262,7 @@ func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
|
|||
if aname, ok := p.aliases[n]; ok {
|
||||
name = aname
|
||||
} else {
|
||||
switch typ := deref(typ).(type) {
|
||||
switch typ := aliases.Unalias(deref(typ)).(type) {
|
||||
case *types.Basic:
|
||||
name = typ.Name()
|
||||
case *types.Named:
|
||||
|
@ -579,7 +581,7 @@ func (p *parser) parseNamedType(nlist []interface{}) types.Type {
|
|||
t := obj.Type()
|
||||
p.update(t, nlist)
|
||||
|
||||
nt, ok := t.(*types.Named)
|
||||
nt, ok := aliases.Unalias(t).(*types.Named)
|
||||
if !ok {
|
||||
// This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
|
||||
pt := p.parseType(pkg)
|
||||
|
@ -1334,7 +1336,7 @@ func (p *parser) parsePackage() *types.Package {
|
|||
}
|
||||
p.fixups = nil
|
||||
for _, typ := range p.typeList {
|
||||
if it, ok := typ.(*types.Interface); ok {
|
||||
if it, ok := aliases.Unalias(typ).(*types.Interface); ok {
|
||||
it.Complete()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,16 +81,15 @@ import (
|
|||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
type opaqueType struct {
|
||||
types.Type
|
||||
name string
|
||||
}
|
||||
type opaqueType struct{ name string }
|
||||
|
||||
func (t *opaqueType) String() string { return t.name }
|
||||
func (t *opaqueType) String() string { return t.name }
|
||||
func (t *opaqueType) Underlying() types.Type { return t }
|
||||
|
||||
var (
|
||||
varOk = newVar("ok", tBool)
|
||||
|
@ -103,7 +102,7 @@ var (
|
|||
tInvalid = types.Typ[types.Invalid]
|
||||
tString = types.Typ[types.String]
|
||||
tUntypedNil = types.Typ[types.UntypedNil]
|
||||
tRangeIter = &opaqueType{nil, "iter"} // the type of all "range" iterators
|
||||
tRangeIter = &opaqueType{"iter"} // the type of all "range" iterators
|
||||
tEface = types.NewInterfaceType(nil, nil).Complete()
|
||||
|
||||
// SSA Value constants.
|
||||
|
@ -802,7 +801,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
|
|||
if types.IsInterface(rt) {
|
||||
// If v may be an interface type I (after instantiating),
|
||||
// we must emit a check that v is non-nil.
|
||||
if recv, ok := sel.recv.(*types.TypeParam); ok {
|
||||
if recv, ok := aliases.Unalias(sel.recv).(*types.TypeParam); ok {
|
||||
// Emit a nil check if any possible instantiation of the
|
||||
// type parameter is an interface type.
|
||||
if typeSetOf(recv).Len() > 0 {
|
||||
|
@ -1253,7 +1252,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
|
|||
case *types.Array, *types.Slice:
|
||||
var at *types.Array
|
||||
var array Value
|
||||
switch t := t.(type) {
|
||||
switch t := aliases.Unalias(t).(type) {
|
||||
case *types.Slice:
|
||||
at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts))
|
||||
array = emitNew(fn, at, e.Lbrace, "slicelit")
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/testenv"
|
||||
"golang.org/x/tools/txtar"
|
||||
)
|
||||
|
@ -1091,7 +1092,7 @@ func TestIssue58491Rec(t *testing.T) {
|
|||
// Find the local type result instantiated with int.
|
||||
var found bool
|
||||
for _, rt := range p.Prog.RuntimeTypes() {
|
||||
if n, ok := rt.(*types.Named); ok {
|
||||
if n, ok := aliases.Unalias(rt).(*types.Named); ok {
|
||||
if u, ok := n.Underlying().(*types.Struct); ok {
|
||||
found = true
|
||||
if got, want := n.String(), "p.result"; got != want {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -47,7 +48,7 @@ func soleTypeKind(typ types.Type) types.BasicInfo {
|
|||
state := types.IsBoolean | types.IsInteger | types.IsString
|
||||
underIs(typeSetOf(typ), func(t types.Type) bool {
|
||||
var c types.BasicInfo
|
||||
if t, ok := t.(*types.Basic); ok {
|
||||
if t, ok := aliases.Unalias(t).(*types.Basic); ok {
|
||||
c = t.Info()
|
||||
}
|
||||
if c&types.IsNumeric != 0 { // int/float/complex
|
||||
|
@ -113,7 +114,7 @@ func zeroString(t types.Type, from *types.Package) string {
|
|||
}
|
||||
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
|
||||
return "nil"
|
||||
case *types.Named:
|
||||
case *types.Named, *aliases.Alias:
|
||||
return zeroString(t.Underlying(), from)
|
||||
case *types.Array, *types.Struct:
|
||||
return relType(t, from) + "{}"
|
||||
|
|
|
@ -7,6 +7,7 @@ package ssa
|
|||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -49,7 +50,7 @@ func typeSetOf(typ types.Type) termList {
|
|||
// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
|
||||
var terms []*types.Term
|
||||
var err error
|
||||
switch typ := typ.(type) {
|
||||
switch typ := aliases.Unalias(typ).(type) {
|
||||
case *types.TypeParam:
|
||||
terms, err = typeparams.StructuralTerms(typ)
|
||||
case *types.Union:
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -184,7 +185,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
|
|||
|
||||
// isValuePreserving returns true if a conversion from ut_src to
|
||||
// ut_dst is value-preserving, i.e. just a change of type.
|
||||
// Precondition: neither argument is a named type.
|
||||
// Precondition: neither argument is a named or alias type.
|
||||
func isValuePreserving(ut_src, ut_dst types.Type) bool {
|
||||
// Identical underlying types?
|
||||
if types.IdenticalIgnoreTags(ut_dst, ut_src) {
|
||||
|
@ -283,11 +284,11 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
|
|||
}
|
||||
|
||||
// Conversion from slice to array or slice to array pointer?
|
||||
if slice, ok := s.(*types.Slice); ok {
|
||||
if slice, ok := aliases.Unalias(s).(*types.Slice); ok {
|
||||
var arr *types.Array
|
||||
var ptr bool
|
||||
// Conversion from slice to array pointer?
|
||||
switch d := d.(type) {
|
||||
switch d := aliases.Unalias(d).(type) {
|
||||
case *types.Array:
|
||||
arr = d
|
||||
case *types.Pointer:
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// If the target program panics, the interpreter panics with this type.
|
||||
|
@ -172,7 +173,7 @@ func asUnsigned(x value) (value, bool) {
|
|||
|
||||
// zero returns a new "zero" value of the specified type.
|
||||
func zero(t types.Type) value {
|
||||
switch t := t.(type) {
|
||||
switch t := aliases.Unalias(t).(type) {
|
||||
case *types.Basic:
|
||||
if t.Kind() == types.UntypedNil {
|
||||
panic("untyped nil has no zero value")
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
type opaqueType struct {
|
||||
|
@ -119,7 +120,7 @@ func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
|
|||
|
||||
func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
|
||||
// Signature: func (t reflect.rtype) int
|
||||
return args[0].(rtype).t.(*types.Signature).Params().Len()
|
||||
return args[0].(rtype).t.Underlying().(*types.Signature).Params().Len()
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
|
||||
|
@ -129,13 +130,13 @@ func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
|
|||
|
||||
func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
|
||||
// Signature: func (t reflect.rtype) int
|
||||
return args[0].(rtype).t.(*types.Signature).Results().Len()
|
||||
return args[0].(rtype).t.Underlying().(*types.Signature).Results().Len()
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
|
||||
// Signature: func (t reflect.rtype, i int) int
|
||||
i := args[1].(int)
|
||||
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
|
||||
return makeReflectType(rtype{args[0].(rtype).t.Underlying().(*types.Signature).Results().At(i).Type()})
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
|
||||
|
@ -178,7 +179,7 @@ func ext۰reflect۰Zero(fr *frame, args []value) value {
|
|||
}
|
||||
|
||||
func reflectKind(t types.Type) reflect.Kind {
|
||||
switch t := t.(type) {
|
||||
switch t := aliases.Unalias(t).(type) {
|
||||
case *types.Named:
|
||||
return reflectKind(t.Underlying())
|
||||
case *types.Basic:
|
||||
|
|
|
@ -45,6 +45,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
type value interface{}
|
||||
|
@ -117,7 +118,7 @@ func usesBuiltinMap(t types.Type) bool {
|
|||
switch t := t.(type) {
|
||||
case *types.Basic, *types.Chan, *types.Pointer:
|
||||
return true
|
||||
case *types.Named:
|
||||
case *types.Named, *aliases.Alias:
|
||||
return usesBuiltinMap(t.Underlying())
|
||||
case *types.Interface, *types.Array, *types.Struct:
|
||||
return false
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -209,6 +210,9 @@ func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types
|
|||
}
|
||||
|
||||
switch T := T.(type) {
|
||||
case *aliases.Alias:
|
||||
visit(aliases.Unalias(T), false)
|
||||
|
||||
case *types.Basic:
|
||||
// nop
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"go/types"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -48,6 +49,9 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
|
|||
case nil, *types.Basic: // TODO(gri) should nil be handled here?
|
||||
break
|
||||
|
||||
case *aliases.Alias:
|
||||
return w.isParameterizedLocked(aliases.Unalias(t))
|
||||
|
||||
case *types.Array:
|
||||
return w.isParameterizedLocked(t.Elem())
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
|
|||
|
||||
// Check that "untyped" types only appear on constant operands.
|
||||
if _, ok := (*op).(*Const); !ok {
|
||||
if basic, ok := (*op).Type().(*types.Basic); ok {
|
||||
if basic, ok := (*op).Type().Underlying().(*types.Basic); ok {
|
||||
if basic.Info()&types.IsUntyped != 0 {
|
||||
s.errorf("operand #%d of %s is untyped: %s", i, instr, basic)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package ssa
|
|||
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// Type substituter for a fixed set of replacement types.
|
||||
|
@ -80,6 +82,9 @@ func (subst *subster) typ(t types.Type) (res types.Type) {
|
|||
|
||||
// fall through if result r will be identical to t, types.Identical(r, t).
|
||||
switch t := t.(type) {
|
||||
case *aliases.Alias:
|
||||
return subst.typ(aliases.Unalias(t))
|
||||
|
||||
case *types.TypeParam:
|
||||
r := subst.replacements[t]
|
||||
assert(r != nil, "type param without replacement encountered")
|
||||
|
@ -466,7 +471,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) {
|
|||
return true
|
||||
}
|
||||
}
|
||||
case *types.Named:
|
||||
case *types.Named, *aliases.Alias:
|
||||
return reaches(t.Underlying(), c)
|
||||
default:
|
||||
panic("unreachable")
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
@ -51,16 +52,19 @@ func isNonTypeParamInterface(t types.Type) bool {
|
|||
|
||||
// isBasic reports whether t is a basic type.
|
||||
func isBasic(t types.Type) bool {
|
||||
_, ok := t.(*types.Basic)
|
||||
_, ok := aliases.Unalias(t).(*types.Basic)
|
||||
return ok
|
||||
}
|
||||
|
||||
// isString reports whether t is exactly a string type.
|
||||
// t is assumed to be an Underlying type (not Named or Alias).
|
||||
func isString(t types.Type) bool {
|
||||
return isBasic(t) && t.(*types.Basic).Info()&types.IsString != 0
|
||||
basic, ok := t.(*types.Basic)
|
||||
return ok && basic.Info()&types.IsString != 0
|
||||
}
|
||||
|
||||
// isByteSlice reports whether t is of the form []~bytes.
|
||||
// t is assumed to be an Underlying type (not Named or Alias).
|
||||
func isByteSlice(t types.Type) bool {
|
||||
if b, ok := t.(*types.Slice); ok {
|
||||
e, _ := b.Elem().Underlying().(*types.Basic)
|
||||
|
@ -70,6 +74,7 @@ func isByteSlice(t types.Type) bool {
|
|||
}
|
||||
|
||||
// isRuneSlice reports whether t is of the form []~runes.
|
||||
// t is assumed to be an Underlying type (not Named or Alias).
|
||||
func isRuneSlice(t types.Type) bool {
|
||||
if b, ok := t.(*types.Slice); ok {
|
||||
e, _ := b.Elem().Underlying().(*types.Basic)
|
||||
|
@ -131,8 +136,9 @@ func fieldOf(typ types.Type, index int) *types.Var {
|
|||
return nil
|
||||
}
|
||||
|
||||
// isUntyped returns true for types that are untyped.
|
||||
// isUntyped reports whether typ is the type of an untyped constant.
|
||||
func isUntyped(typ types.Type) bool {
|
||||
// No Underlying/Unalias: untyped constant types cannot be Named or Alias.
|
||||
b, ok := typ.(*types.Basic)
|
||||
return ok && b.Info()&types.IsUntyped != 0
|
||||
}
|
||||
|
@ -342,10 +348,10 @@ func (m *typeListMap) hash(ts []types.Type) uint32 {
|
|||
// instantiateMethod instantiates m with targs and returns a canonical representative for this method.
|
||||
func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func {
|
||||
recv := recvType(m)
|
||||
if p, ok := recv.(*types.Pointer); ok {
|
||||
if p, ok := aliases.Unalias(recv).(*types.Pointer); ok {
|
||||
recv = p.Elem()
|
||||
}
|
||||
named := recv.(*types.Named)
|
||||
named := aliases.Unalias(recv).(*types.Named)
|
||||
inst, err := types.Instantiate(ctxt, named.Origin(), targs, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
@ -285,7 +286,7 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
|
|||
if obj.IsAlias() {
|
||||
kind = "type alias"
|
||||
}
|
||||
if named, ok := obj.Type().(*types.Named); ok {
|
||||
if named, ok := aliases.Unalias(obj.Type()).(*types.Named); ok {
|
||||
origin = named.Obj()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,13 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
// TODO(adonovan): think about generic aliases.
|
||||
|
||||
// A Path is an opaque name that identifies a types.Object
|
||||
// relative to its package. Conceptually, the name consists of a
|
||||
// sequence of destructuring operations applied to the package scope
|
||||
|
@ -224,7 +227,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
|
|||
// Reject obviously non-viable cases.
|
||||
switch obj := obj.(type) {
|
||||
case *types.TypeName:
|
||||
if _, ok := obj.Type().(*types.TypeParam); !ok {
|
||||
if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok {
|
||||
// With the exception of type parameters, only package-level type names
|
||||
// have a path.
|
||||
return "", fmt.Errorf("no path for %v", obj)
|
||||
|
@ -311,7 +314,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
|
|||
}
|
||||
|
||||
// Inspect declared methods of defined types.
|
||||
if T, ok := o.Type().(*types.Named); ok {
|
||||
if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok {
|
||||
path = append(path, opType)
|
||||
// The method index here is always with respect
|
||||
// to the underlying go/types data structures,
|
||||
|
@ -440,6 +443,8 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
|
|||
// nil, it will be allocated as necessary.
|
||||
func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte {
|
||||
switch T := T.(type) {
|
||||
case *aliases.Alias:
|
||||
return find(obj, aliases.Unalias(T), path, seen)
|
||||
case *types.Basic, *types.Named:
|
||||
// Named types belonging to pkg were handled already,
|
||||
// so T must belong to another package. No path.
|
||||
|
@ -612,6 +617,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
|
|||
|
||||
// Inv: t != nil, obj == nil
|
||||
|
||||
t = aliases.Unalias(t)
|
||||
switch code {
|
||||
case opElem:
|
||||
hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map
|
||||
|
|
|
@ -6,7 +6,11 @@ package typeutil
|
|||
|
||||
// This file defines utilities for user interfaces that display types.
|
||||
|
||||
import "go/types"
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// IntuitiveMethodSet returns the intuitive method set of a type T,
|
||||
// which is the set of methods you can call on an addressable value of
|
||||
|
@ -24,7 +28,7 @@ import "go/types"
|
|||
// 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)
|
||||
ptr, ok := aliases.Unalias(T).(*types.Pointer)
|
||||
return ok && !types.IsInterface(ptr.Elem())
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import (
|
|||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
|
||||
|
@ -28,7 +30,10 @@ func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos
|
|||
}
|
||||
|
||||
func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
|
||||
under := typ
|
||||
// TODO(adonovan): think about generics, and also generic aliases.
|
||||
under := aliases.Unalias(typ)
|
||||
// Don't call Underlying unconditionally: although it removed
|
||||
// Named and Alias, it also removes TypeParam.
|
||||
if n, ok := typ.(*types.Named); ok {
|
||||
under = n.Underlying()
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/facts"
|
||||
"golang.org/x/tools/internal/testenv"
|
||||
)
|
||||
|
@ -360,7 +361,7 @@ func find(p *types.Package, expr string) types.Object {
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if n, ok := tv.Type.(*types.Named); ok {
|
||||
if n, ok := aliases.Unalias(tv.Type).(*types.Named); ok {
|
||||
return n.Obj()
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -6,6 +6,8 @@ package facts
|
|||
|
||||
import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// importMap computes the import map for a package by traversing the
|
||||
|
@ -45,6 +47,8 @@ func importMap(imports []*types.Package) map[string]*types.Package {
|
|||
|
||||
addType = func(T types.Type) {
|
||||
switch T := T.(type) {
|
||||
case *aliases.Alias:
|
||||
addType(aliases.Unalias(T))
|
||||
case *types.Basic:
|
||||
// nop
|
||||
case *types.Named:
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/gcimporter"
|
||||
)
|
||||
|
||||
|
@ -30,6 +31,8 @@ func fileLine(fset *token.FileSet, obj types.Object) string {
|
|||
}
|
||||
|
||||
func equalType(x, y types.Type) error {
|
||||
x = aliases.Unalias(x)
|
||||
y = aliases.Unalias(y)
|
||||
if reflect.TypeOf(x) != reflect.TypeOf(y) {
|
||||
return fmt.Errorf("unequal kinds: %T vs %T", x, y)
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/goroot"
|
||||
"golang.org/x/tools/internal/testenv"
|
||||
)
|
||||
|
@ -438,7 +439,7 @@ func TestImportedTypes(t *testing.T) {
|
|||
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
|
||||
}
|
||||
|
||||
if named, _ := obj.Type().(*types.Named); named != nil {
|
||||
if named, _ := aliases.Unalias(obj.Type()).(*types.Named); named != nil {
|
||||
verifyInterfaceMethodRecvs(t, named, 0)
|
||||
}
|
||||
}
|
||||
|
@ -521,7 +522,7 @@ func verifyInterfaceMethodRecvs(t *testing.T, named *types.Named, level int) {
|
|||
// check embedded interfaces (if they are named, too)
|
||||
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
||||
// embedding of interfaces cannot have cycles; recursion will terminate
|
||||
if etype, _ := iface.EmbeddedType(i).(*types.Named); etype != nil {
|
||||
if etype, _ := aliases.Unalias(iface.EmbeddedType(i)).(*types.Named); etype != nil {
|
||||
verifyInterfaceMethodRecvs(t, etype, level+1)
|
||||
}
|
||||
}
|
||||
|
@ -541,7 +542,7 @@ func TestIssue5815(t *testing.T) {
|
|||
t.Errorf("no pkg for %s", obj)
|
||||
}
|
||||
if tname, _ := obj.(*types.TypeName); tname != nil {
|
||||
named := tname.Type().(*types.Named)
|
||||
named := aliases.Unalias(tname.Type()).(*types.Named)
|
||||
for i := 0; i < named.NumMethods(); i++ {
|
||||
m := named.Method(i)
|
||||
if m.Pkg() == nil {
|
||||
|
@ -641,7 +642,7 @@ func TestIssue13898(t *testing.T) {
|
|||
|
||||
// look for go/types.Object type
|
||||
obj := lookupObj(t, goTypesPkg.Scope(), "Object")
|
||||
typ, ok := obj.Type().(*types.Named)
|
||||
typ, ok := aliases.Unalias(obj.Type()).(*types.Named)
|
||||
if !ok {
|
||||
t.Fatalf("go/types.Object type is %v; wanted named type", typ)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/types/objectpath"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/tokeninternal"
|
||||
)
|
||||
|
||||
|
@ -506,13 +507,13 @@ func (p *iexporter) doDecl(obj types.Object) {
|
|||
case *types.TypeName:
|
||||
t := obj.Type()
|
||||
|
||||
if tparam, ok := t.(*types.TypeParam); ok {
|
||||
if tparam, ok := aliases.Unalias(t).(*types.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 {
|
||||
if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil {
|
||||
implicit = iface.IsImplicit()
|
||||
}
|
||||
w.bool(implicit)
|
||||
|
@ -738,6 +739,8 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
}()
|
||||
}
|
||||
switch t := t.(type) {
|
||||
// TODO(adonovan): support types.Alias.
|
||||
|
||||
case *types.Named:
|
||||
if targs := t.TypeArgs(); targs.Len() > 0 {
|
||||
w.startType(instanceType)
|
||||
|
@ -843,7 +846,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
for i := 0; i < n; i++ {
|
||||
ft := t.EmbeddedType(i)
|
||||
tPkg := pkg
|
||||
if named, _ := ft.(*types.Named); named != nil {
|
||||
if named, _ := aliases.Unalias(ft).(*types.Named); named != nil {
|
||||
w.pos(named.Obj().Pos())
|
||||
} else {
|
||||
w.pos(token.NoPos)
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/types/objectpath"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
@ -523,7 +524,7 @@ func canReuse(def *types.Named, rhs types.Type) bool {
|
|||
if def == nil {
|
||||
return true
|
||||
}
|
||||
iface, _ := rhs.(*types.Interface)
|
||||
iface, _ := aliases.Unalias(rhs).(*types.Interface)
|
||||
if iface == nil {
|
||||
return true
|
||||
}
|
||||
|
@ -594,7 +595,7 @@ func (r *importReader) obj(name string) {
|
|||
if targs.Len() > 0 {
|
||||
rparams = make([]*types.TypeParam, targs.Len())
|
||||
for i := range rparams {
|
||||
rparams[i] = targs.At(i).(*types.TypeParam)
|
||||
rparams[i] = aliases.Unalias(targs.At(i)).(*types.TypeParam)
|
||||
}
|
||||
}
|
||||
msig := r.signature(recv, rparams, nil)
|
||||
|
@ -624,7 +625,7 @@ func (r *importReader) obj(name string) {
|
|||
}
|
||||
constraint := r.typ()
|
||||
if implicit {
|
||||
iface, _ := constraint.(*types.Interface)
|
||||
iface, _ := aliases.Unalias(constraint).(*types.Interface)
|
||||
if iface == nil {
|
||||
errorf("non-interface constraint marked implicit")
|
||||
}
|
||||
|
@ -831,7 +832,7 @@ func (r *importReader) typ() types.Type {
|
|||
}
|
||||
|
||||
func isInterface(t types.Type) bool {
|
||||
_, ok := t.(*types.Interface)
|
||||
_, ok := aliases.Unalias(t).(*types.Interface)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
@ -1030,7 +1031,7 @@ func (r *importReader) tparamList() []*types.TypeParam {
|
|||
for i := range xs {
|
||||
// Note: the standard library importer is tolerant of nil types here,
|
||||
// though would panic in SetTypeParams.
|
||||
xs[i] = r.typ().(*types.TypeParam)
|
||||
xs[i] = aliases.Unalias(r.typ()).(*types.TypeParam)
|
||||
}
|
||||
return xs
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/pkgbits"
|
||||
)
|
||||
|
||||
|
@ -553,7 +554,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
// If the underlying type is an interface, we need to
|
||||
// duplicate its methods so we can replace the receiver
|
||||
// parameter's type (#49906).
|
||||
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
||||
if iface, ok := aliases.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
||||
methods := make([]*types.Func, iface.NumExplicitMethods())
|
||||
for i := range methods {
|
||||
fn := iface.ExplicitMethod(i)
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
@ -74,9 +75,9 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
|
|||
}
|
||||
}
|
||||
|
||||
// IsTypeParam reports whether t is a type parameter.
|
||||
// IsTypeParam reports whether t is a type parameter (or an alias of one).
|
||||
func IsTypeParam(t types.Type) bool {
|
||||
_, ok := t.(*types.TypeParam)
|
||||
_, ok := aliases.Unalias(t).(*types.TypeParam)
|
||||
return ok
|
||||
}
|
||||
|
||||
|
@ -155,6 +156,9 @@ func OriginMethod(fn *types.Func) *types.Func {
|
|||
// In this case, GenericAssignableTo reports that instantiations of Container
|
||||
// are assignable to the corresponding instantiation of Interface.
|
||||
func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool {
|
||||
V = aliases.Unalias(V)
|
||||
T = aliases.Unalias(T)
|
||||
|
||||
// If V and T are not both named, or do not have matching non-empty type
|
||||
// parameter lists, fall back on types.AssignableTo.
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ package typeparams
|
|||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// CoreType returns the core type of T or nil if T does not have a core type.
|
||||
|
@ -110,7 +112,7 @@ func CoreType(T types.Type) types.Type {
|
|||
// _NormalTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func _NormalTerms(typ types.Type) ([]*types.Term, error) {
|
||||
switch typ := typ.(type) {
|
||||
switch typ := aliases.Unalias(typ).(type) {
|
||||
case *types.TypeParam:
|
||||
return StructuralTerms(typ)
|
||||
case *types.Union:
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// Features is a set of flags reporting which features of generic Go code a
|
||||
|
@ -92,7 +93,7 @@ func ForPackage(inspect *inspector.Inspector, info *types.Info) Features {
|
|||
})
|
||||
|
||||
for _, inst := range info.Instances {
|
||||
switch inst.Type.(type) {
|
||||
switch aliases.Unalias(inst.Type).(type) {
|
||||
case *types.Named:
|
||||
direct |= TypeInstantiation
|
||||
case *types.Signature:
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
"golang.org/x/tools/refactor/satisfy"
|
||||
)
|
||||
|
||||
|
@ -467,9 +468,10 @@ func (r *renamer) checkStructField(from *types.Var) {
|
|||
// type T int // this and
|
||||
// var s struct {T} // this must change too.
|
||||
if from.Anonymous() {
|
||||
if named, ok := from.Type().(*types.Named); ok {
|
||||
// TODO(adonovan): think carefully about aliases.
|
||||
if named, ok := aliases.Unalias(from.Type()).(*types.Named); ok {
|
||||
r.check(named.Obj())
|
||||
} else if named, ok := deref(from.Type()).(*types.Named); ok {
|
||||
} else if named, ok := aliases.Unalias(deref(from.Type())).(*types.Named); ok {
|
||||
r.check(named.Obj())
|
||||
}
|
||||
}
|
||||
|
@ -777,7 +779,7 @@ func (r *renamer) checkMethod(from *types.Func) {
|
|||
var iface string
|
||||
|
||||
I := recv(imeth).Type()
|
||||
if named, ok := I.(*types.Named); ok {
|
||||
if named, ok := aliases.Unalias(I).(*types.Named); ok {
|
||||
pos = named.Obj().Pos()
|
||||
iface = "interface " + named.Obj().Name()
|
||||
} else {
|
||||
|
@ -851,7 +853,7 @@ func someUse(info *loader.PackageInfo, obj types.Object) *ast.Ident {
|
|||
func isInterface(T types.Type) bool { return types.IsInterface(T) }
|
||||
|
||||
func deref(typ types.Type) types.Type {
|
||||
if p, _ := typ.(*types.Pointer); p != nil {
|
||||
if p, _ := aliases.Unalias(typ).(*types.Pointer); p != nil {
|
||||
return p.Elem()
|
||||
}
|
||||
return typ
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
"golang.org/x/tools/go/loader"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
// A spec specifies an entity to rename.
|
||||
|
@ -465,9 +466,9 @@ func findObjects(info *loader.PackageInfo, spec *spec) ([]types.Object, error) {
|
|||
if spec.searchFor == "" {
|
||||
// If it is an embedded field, return the type of the field.
|
||||
if v, ok := obj.(*types.Var); ok && v.Anonymous() {
|
||||
switch t := v.Type().(type) {
|
||||
switch t := aliases.Unalias(v.Type()).(type) {
|
||||
case *types.Pointer:
|
||||
return []types.Object{t.Elem().(*types.Named).Obj()}, nil
|
||||
return []types.Object{aliases.Unalias(t.Elem()).(*types.Named).Obj()}, nil
|
||||
case *types.Named:
|
||||
return []types.Object{t.Obj()}, nil
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче