mirror of
https://github.com/golang/go
synced 2024-11-18 11:24:41 -07:00
go/types: change {Type,Object,Selection}String to accept a Qualifier function
The optional Qualifier function determines what prefix to attach to package-level names, enabling clients to qualify packages in different ways, for example, using only the package name instead of its complete path, or using the locally appropriate name for package given a set of (possibly renaming) imports. Prior to this change, clients wanting this behavior had to copy hundreds of lines of complex printing logic. Fun fact: (*types.Package).Path and (*types.Package).Name are valid Qualifier functions. We provide the RelativeTo helper function to create Qualifiers so that the old behavior remains a one-liner. Fixes golang/go#11133 Change-Id: Ibd63f639c7b3aa1738826d6165f2d810efeb8293 Reviewed-on: https://go-review.googlesource.com/11692 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
749901c676
commit
997b3545fd
@ -126,7 +126,7 @@ func printResult(res *rta.Result, from *types.Package) string {
|
|||||||
var rtypes []string
|
var rtypes []string
|
||||||
res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
|
res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
|
||||||
if value == false { // accessible to reflection
|
if value == false { // accessible to reflection
|
||||||
rtypes = append(rtypes, types.TypeString(from, key))
|
rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
writeSorted(rtypes)
|
writeSorted(rtypes)
|
||||||
|
@ -34,7 +34,7 @@ func runImporterTest(t *testing.T, imp types.Importer, initmap map[*types.Packag
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
got := types.ObjectString(pkg, obj)
|
got := types.ObjectString(obj, types.RelativeTo(pkg))
|
||||||
if got != test.want {
|
if got != test.want {
|
||||||
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
|
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ func TestImportedTypes(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
got := types.ObjectString(pkg, obj)
|
got := types.ObjectString(obj, types.RelativeTo(pkg))
|
||||||
if got != test.want {
|
if got != test.want {
|
||||||
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
|
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,10 @@ func TestStdlib(t *testing.T) {
|
|||||||
for pkg := range prog.AllPackages {
|
for pkg := range prog.AllPackages {
|
||||||
fmt.Printf("Package %s:\n", pkg.Path())
|
fmt.Printf("Package %s:\n", pkg.Path())
|
||||||
scope := pkg.Scope()
|
scope := pkg.Scope()
|
||||||
|
qualifier := types.RelativeTo(pkg)
|
||||||
for _, name := range scope.Names() {
|
for _, name := range scope.Names() {
|
||||||
if ast.IsExported(name) {
|
if ast.IsExported(name) {
|
||||||
fmt.Printf("\t%s\n", types.ObjectString(pkg, scope.Lookup(name)))
|
fmt.Printf("\t%s\n", types.ObjectString(scope.Lookup(name), qualifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
@ -522,11 +522,11 @@ func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *ty
|
|||||||
buf.WriteString(n)
|
buf.WriteString(n)
|
||||||
buf.WriteString(" ")
|
buf.WriteString(" ")
|
||||||
}
|
}
|
||||||
types.WriteType(buf, from, params[0].Type())
|
types.WriteType(buf, params[0].Type(), types.RelativeTo(from))
|
||||||
buf.WriteString(") ")
|
buf.WriteString(") ")
|
||||||
}
|
}
|
||||||
buf.WriteString(name)
|
buf.WriteString(name)
|
||||||
types.WriteSignature(buf, from, sig)
|
types.WriteSignature(buf, sig, types.RelativeTo(from))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) pkgobj() *types.Package {
|
func (f *Function) pkgobj() *types.Package {
|
||||||
|
@ -39,7 +39,7 @@ func relName(v Value, i Instruction) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func relType(t types.Type, from *types.Package) string {
|
func relType(t types.Type, from *types.Package) string {
|
||||||
return types.TypeString(from, t)
|
return types.TypeString(t, types.RelativeTo(from))
|
||||||
}
|
}
|
||||||
|
|
||||||
func relString(m Member, from *types.Package) string {
|
func relString(m Member, from *types.Package) string {
|
||||||
@ -407,7 +407,7 @@ func WritePackage(buf *bytes.Buffer, p *Package) {
|
|||||||
fmt.Fprintf(buf, " type %-*s %s\n",
|
fmt.Fprintf(buf, " type %-*s %s\n",
|
||||||
maxname, name, relType(mem.Type().Underlying(), from))
|
maxname, name, relType(mem.Type().Underlying(), from))
|
||||||
for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
|
for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
|
||||||
fmt.Fprintf(buf, " %s\n", types.SelectionString(from, meth))
|
fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from)))
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Global:
|
case *Global:
|
||||||
|
@ -23,6 +23,13 @@ func unreachable() {
|
|||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (check *Checker) qualifier(pkg *Package) string {
|
||||||
|
if pkg != check.pkg {
|
||||||
|
return pkg.path
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (check *Checker) sprintf(format string, args ...interface{}) string {
|
func (check *Checker) sprintf(format string, args ...interface{}) string {
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
switch a := arg.(type) {
|
switch a := arg.(type) {
|
||||||
@ -31,15 +38,15 @@ func (check *Checker) sprintf(format string, args ...interface{}) string {
|
|||||||
case operand:
|
case operand:
|
||||||
panic("internal error: should always pass *operand")
|
panic("internal error: should always pass *operand")
|
||||||
case *operand:
|
case *operand:
|
||||||
arg = operandString(check.pkg, a)
|
arg = operandString(a, check.qualifier)
|
||||||
case token.Pos:
|
case token.Pos:
|
||||||
arg = check.fset.Position(a).String()
|
arg = check.fset.Position(a).String()
|
||||||
case ast.Expr:
|
case ast.Expr:
|
||||||
arg = ExprString(a)
|
arg = ExprString(a)
|
||||||
case Object:
|
case Object:
|
||||||
arg = ObjectString(check.pkg, a)
|
arg = ObjectString(a, check.qualifier)
|
||||||
case Type:
|
case Type:
|
||||||
arg = TypeString(check.pkg, a)
|
arg = TypeString(a, check.qualifier)
|
||||||
}
|
}
|
||||||
args[i] = arg
|
args[i] = arg
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
|
|||||||
// function or method obj.
|
// function or method obj.
|
||||||
func (obj *Func) FullName() string {
|
func (obj *Func) FullName() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
writeFuncName(&buf, nil, obj)
|
writeFuncName(&buf, obj, nil)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ type Nil struct {
|
|||||||
object
|
object
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeObject(buf *bytes.Buffer, this *Package, obj Object) {
|
func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
||||||
typ := obj.Type()
|
typ := obj.Type()
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *PkgName:
|
case *PkgName:
|
||||||
@ -268,9 +268,9 @@ func writeObject(buf *bytes.Buffer, this *Package, obj Object) {
|
|||||||
|
|
||||||
case *Func:
|
case *Func:
|
||||||
buf.WriteString("func ")
|
buf.WriteString("func ")
|
||||||
writeFuncName(buf, this, obj)
|
writeFuncName(buf, obj, qf)
|
||||||
if typ != nil {
|
if typ != nil {
|
||||||
WriteSignature(buf, this, typ.(*Signature))
|
WriteSignature(buf, typ.(*Signature), qf)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -292,39 +292,52 @@ func writeObject(buf *bytes.Buffer, this *Package, obj Object) {
|
|||||||
|
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
|
|
||||||
// For package-level objects, package-qualify the name,
|
// For package-level objects, qualify the name.
|
||||||
// except for intra-package references (this != nil).
|
if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj {
|
||||||
if pkg := obj.Pkg(); pkg != nil && this != pkg && pkg.scope.Lookup(obj.Name()) == obj {
|
writePackage(buf, obj.Pkg(), qf)
|
||||||
buf.WriteString(pkg.path)
|
|
||||||
buf.WriteByte('.')
|
|
||||||
}
|
}
|
||||||
buf.WriteString(obj.Name())
|
buf.WriteString(obj.Name())
|
||||||
if typ != nil {
|
if typ != nil {
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
WriteType(buf, this, typ)
|
WriteType(buf, typ, qf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
|
||||||
|
if pkg == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
if qf != nil {
|
||||||
|
s = qf(pkg)
|
||||||
|
} else {
|
||||||
|
s = pkg.Path()
|
||||||
|
}
|
||||||
|
if s != "" {
|
||||||
|
buf.WriteString(s)
|
||||||
|
buf.WriteByte('.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectString returns the string form of obj.
|
// ObjectString returns the string form of obj.
|
||||||
// Object and type names are printed package-qualified
|
// The Qualifier controls the printing of
|
||||||
// only if they do not belong to this package.
|
// package-level objects, and may be nil.
|
||||||
//
|
func ObjectString(obj Object, qf Qualifier) string {
|
||||||
func ObjectString(this *Package, obj Object) string {
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
writeObject(&buf, this, obj)
|
writeObject(&buf, obj, qf)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *PkgName) String() string { return ObjectString(nil, obj) }
|
func (obj *PkgName) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Const) String() string { return ObjectString(nil, obj) }
|
func (obj *Const) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *TypeName) String() string { return ObjectString(nil, obj) }
|
func (obj *TypeName) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Var) String() string { return ObjectString(nil, obj) }
|
func (obj *Var) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Func) String() string { return ObjectString(nil, obj) }
|
func (obj *Func) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Label) String() string { return ObjectString(nil, obj) }
|
func (obj *Label) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Builtin) String() string { return ObjectString(nil, obj) }
|
func (obj *Builtin) String() string { return ObjectString(obj, nil) }
|
||||||
func (obj *Nil) String() string { return ObjectString(nil, obj) }
|
func (obj *Nil) String() string { return ObjectString(obj, nil) }
|
||||||
|
|
||||||
func writeFuncName(buf *bytes.Buffer, this *Package, f *Func) {
|
func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
|
||||||
if f.typ != nil {
|
if f.typ != nil {
|
||||||
sig := f.typ.(*Signature)
|
sig := f.typ.(*Signature)
|
||||||
if recv := sig.Recv(); recv != nil {
|
if recv := sig.Recv(); recv != nil {
|
||||||
@ -336,13 +349,12 @@ func writeFuncName(buf *bytes.Buffer, this *Package, f *Func) {
|
|||||||
// Don't print it in full.
|
// Don't print it in full.
|
||||||
buf.WriteString("interface")
|
buf.WriteString("interface")
|
||||||
} else {
|
} else {
|
||||||
WriteType(buf, this, recv.Type())
|
WriteType(buf, recv.Type(), qf)
|
||||||
}
|
}
|
||||||
buf.WriteByte(')')
|
buf.WriteByte(')')
|
||||||
buf.WriteByte('.')
|
buf.WriteByte('.')
|
||||||
} else if f.pkg != nil && f.pkg != this {
|
} else if f.pkg != nil {
|
||||||
buf.WriteString(f.pkg.path)
|
writePackage(buf, f.pkg, qf)
|
||||||
buf.WriteByte('.')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteString(f.name)
|
buf.WriteString(f.name)
|
||||||
|
@ -94,7 +94,7 @@ func (x *operand) pos() token.Pos {
|
|||||||
// commaok <expr> (<untyped kind> <mode> )
|
// commaok <expr> (<untyped kind> <mode> )
|
||||||
// commaok <expr> ( <mode> of type <typ>)
|
// commaok <expr> ( <mode> of type <typ>)
|
||||||
//
|
//
|
||||||
func operandString(this *Package, x *operand) string {
|
func operandString(x *operand, qf Qualifier) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
var expr string
|
var expr string
|
||||||
@ -105,7 +105,7 @@ func operandString(this *Package, x *operand) string {
|
|||||||
case builtin:
|
case builtin:
|
||||||
expr = predeclaredFuncs[x.id].name
|
expr = predeclaredFuncs[x.id].name
|
||||||
case typexpr:
|
case typexpr:
|
||||||
expr = TypeString(this, x.typ)
|
expr = TypeString(x.typ, qf)
|
||||||
case constant:
|
case constant:
|
||||||
expr = x.val.String()
|
expr = x.val.String()
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ func operandString(this *Package, x *operand) string {
|
|||||||
if hasType {
|
if hasType {
|
||||||
if x.typ != Typ[Invalid] {
|
if x.typ != Typ[Invalid] {
|
||||||
buf.WriteString(" of type ")
|
buf.WriteString(" of type ")
|
||||||
WriteType(&buf, this, x.typ)
|
WriteType(&buf, x.typ, qf)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteString(" with invalid type")
|
buf.WriteString(" with invalid type")
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ func operandString(this *Package, x *operand) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (x *operand) String() string {
|
func (x *operand) String() string {
|
||||||
return operandString(nil, x)
|
return operandString(x, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setConst sets x to the untyped constant for literal lit.
|
// setConst sets x to the untyped constant for literal lit.
|
||||||
|
@ -105,18 +105,18 @@ func (s *Selection) Index() []int { return s.index }
|
|||||||
// x to f in x.f.
|
// x to f in x.f.
|
||||||
func (s *Selection) Indirect() bool { return s.indirect }
|
func (s *Selection) Indirect() bool { return s.indirect }
|
||||||
|
|
||||||
func (s *Selection) String() string { return SelectionString(nil, s) }
|
func (s *Selection) String() string { return SelectionString(s, nil) }
|
||||||
|
|
||||||
// SelectionString returns the string form of s.
|
// SelectionString returns the string form of s.
|
||||||
// Type names are printed package-qualified
|
// The Qualifier controls the printing of
|
||||||
// only if they do not belong to this package.
|
// package-level objects, and may be nil.
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// "field (T) f int"
|
// "field (T) f int"
|
||||||
// "method (T) f(X) Y"
|
// "method (T) f(X) Y"
|
||||||
// "method expr (T) f(X) Y"
|
// "method expr (T) f(X) Y"
|
||||||
//
|
//
|
||||||
func SelectionString(this *Package, s *Selection) string {
|
func SelectionString(s *Selection, qf Qualifier) string {
|
||||||
var k string
|
var k string
|
||||||
switch s.kind {
|
switch s.kind {
|
||||||
case FieldVal:
|
case FieldVal:
|
||||||
@ -131,13 +131,13 @@ func SelectionString(this *Package, s *Selection) string {
|
|||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(k)
|
buf.WriteString(k)
|
||||||
buf.WriteByte('(')
|
buf.WriteByte('(')
|
||||||
WriteType(&buf, this, s.Recv())
|
WriteType(&buf, s.Recv(), qf)
|
||||||
fmt.Fprintf(&buf, ") %s", s.obj.Name())
|
fmt.Fprintf(&buf, ") %s", s.obj.Name())
|
||||||
if T := s.Type(); s.kind == FieldVal {
|
if T := s.Type(); s.kind == FieldVal {
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
WriteType(&buf, this, T)
|
WriteType(&buf, T, qf)
|
||||||
} else {
|
} else {
|
||||||
WriteSignature(&buf, this, T.(*Signature))
|
WriteSignature(&buf, T.(*Signature), qf)
|
||||||
}
|
}
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
@ -441,14 +441,14 @@ func (t *Map) Underlying() Type { return t }
|
|||||||
func (t *Chan) Underlying() Type { return t }
|
func (t *Chan) Underlying() Type { return t }
|
||||||
func (t *Named) Underlying() Type { return t.underlying }
|
func (t *Named) Underlying() Type { return t.underlying }
|
||||||
|
|
||||||
func (t *Basic) String() string { return TypeString(nil, t) }
|
func (t *Basic) String() string { return TypeString(t, nil) }
|
||||||
func (t *Array) String() string { return TypeString(nil, t) }
|
func (t *Array) String() string { return TypeString(t, nil) }
|
||||||
func (t *Slice) String() string { return TypeString(nil, t) }
|
func (t *Slice) String() string { return TypeString(t, nil) }
|
||||||
func (t *Struct) String() string { return TypeString(nil, t) }
|
func (t *Struct) String() string { return TypeString(t, nil) }
|
||||||
func (t *Pointer) String() string { return TypeString(nil, t) }
|
func (t *Pointer) String() string { return TypeString(t, nil) }
|
||||||
func (t *Tuple) String() string { return TypeString(nil, t) }
|
func (t *Tuple) String() string { return TypeString(t, nil) }
|
||||||
func (t *Signature) String() string { return TypeString(nil, t) }
|
func (t *Signature) String() string { return TypeString(t, nil) }
|
||||||
func (t *Interface) String() string { return TypeString(nil, t) }
|
func (t *Interface) String() string { return TypeString(t, nil) }
|
||||||
func (t *Map) String() string { return TypeString(nil, t) }
|
func (t *Map) String() string { return TypeString(t, nil) }
|
||||||
func (t *Chan) String() string { return TypeString(nil, t) }
|
func (t *Chan) String() string { return TypeString(t, nil) }
|
||||||
func (t *Named) String() string { return TypeString(nil, t) }
|
func (t *Named) String() string { return TypeString(t, nil) }
|
||||||
|
@ -11,6 +11,33 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A Qualifier controls how named package-level objects are printed in
|
||||||
|
// calls to TypeString, ObjectString, and SelectionString.
|
||||||
|
//
|
||||||
|
// These three formatting routines call the Qualifier for each
|
||||||
|
// package-level object O, and if the Qualifier returns a non-empty
|
||||||
|
// string p, the object is printed in the form p.O.
|
||||||
|
// If it returns an empty string, only the object name O is printed.
|
||||||
|
//
|
||||||
|
// Using a nil Qualifier is equivalent to using (*Package).Path: the
|
||||||
|
// object is qualified by the import path, e.g., "encoding/json.Marshal".
|
||||||
|
//
|
||||||
|
type Qualifier func(*Package) string
|
||||||
|
|
||||||
|
// RelativeTo(pkg) returns a Qualifier that fully qualifies members of
|
||||||
|
// all packages other than pkg.
|
||||||
|
func RelativeTo(pkg *Package) Qualifier {
|
||||||
|
if pkg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return func(other *Package) string {
|
||||||
|
if pkg == other {
|
||||||
|
return "" // same package; unqualified
|
||||||
|
}
|
||||||
|
return other.Path()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If GcCompatibilityMode is set, printing of types is modified
|
// If GcCompatibilityMode is set, printing of types is modified
|
||||||
// to match the representation of some types in the gc compiler:
|
// to match the representation of some types in the gc compiler:
|
||||||
//
|
//
|
||||||
@ -28,22 +55,22 @@ import (
|
|||||||
var GcCompatibilityMode bool
|
var GcCompatibilityMode bool
|
||||||
|
|
||||||
// TypeString returns the string representation of typ.
|
// TypeString returns the string representation of typ.
|
||||||
// Named types are printed package-qualified if they
|
// The Qualifier controls the printing of
|
||||||
// do not belong to this package.
|
// package-level objects, and may be nil.
|
||||||
func TypeString(this *Package, typ Type) string {
|
func TypeString(typ Type, qf Qualifier) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
WriteType(&buf, this, typ)
|
WriteType(&buf, typ, qf)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteType writes the string representation of typ to buf.
|
// WriteType writes the string representation of typ to buf.
|
||||||
// Named types are printed package-qualified if they
|
// The Qualifier controls the printing of
|
||||||
// do not belong to this package.
|
// package-level objects, and may be nil.
|
||||||
func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
|
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
|
||||||
writeType(buf, this, typ, make([]Type, 8))
|
writeType(buf, typ, qf, make([]Type, 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
||||||
// Theoretically, this is a quadratic lookup algorithm, but in
|
// Theoretically, this is a quadratic lookup algorithm, but in
|
||||||
// practice deeply nested composite types with unnamed component
|
// practice deeply nested composite types with unnamed component
|
||||||
// types are uncommon. This code is likely more efficient than
|
// types are uncommon. This code is likely more efficient than
|
||||||
@ -77,11 +104,11 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
|
|
||||||
case *Array:
|
case *Array:
|
||||||
fmt.Fprintf(buf, "[%d]", t.len)
|
fmt.Fprintf(buf, "[%d]", t.len)
|
||||||
writeType(buf, this, t.elem, visited)
|
writeType(buf, t.elem, qf, visited)
|
||||||
|
|
||||||
case *Slice:
|
case *Slice:
|
||||||
buf.WriteString("[]")
|
buf.WriteString("[]")
|
||||||
writeType(buf, this, t.elem, visited)
|
writeType(buf, t.elem, qf, visited)
|
||||||
|
|
||||||
case *Struct:
|
case *Struct:
|
||||||
buf.WriteString("struct{")
|
buf.WriteString("struct{")
|
||||||
@ -93,7 +120,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
buf.WriteString(f.name)
|
buf.WriteString(f.name)
|
||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
}
|
}
|
||||||
writeType(buf, this, f.typ, visited)
|
writeType(buf, f.typ, qf, visited)
|
||||||
if tag := t.Tag(i); tag != "" {
|
if tag := t.Tag(i); tag != "" {
|
||||||
fmt.Fprintf(buf, " %q", tag)
|
fmt.Fprintf(buf, " %q", tag)
|
||||||
}
|
}
|
||||||
@ -102,14 +129,14 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
|
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
buf.WriteByte('*')
|
buf.WriteByte('*')
|
||||||
writeType(buf, this, t.base, visited)
|
writeType(buf, t.base, qf, visited)
|
||||||
|
|
||||||
case *Tuple:
|
case *Tuple:
|
||||||
writeTuple(buf, this, t, false, visited)
|
writeTuple(buf, t, false, qf, visited)
|
||||||
|
|
||||||
case *Signature:
|
case *Signature:
|
||||||
buf.WriteString("func")
|
buf.WriteString("func")
|
||||||
writeSignature(buf, this, t, visited)
|
writeSignature(buf, t, qf, visited)
|
||||||
|
|
||||||
case *Interface:
|
case *Interface:
|
||||||
// We write the source-level methods and embedded types rather
|
// We write the source-level methods and embedded types rather
|
||||||
@ -132,7 +159,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
buf.WriteString("; ")
|
buf.WriteString("; ")
|
||||||
}
|
}
|
||||||
buf.WriteString(m.name)
|
buf.WriteString(m.name)
|
||||||
writeSignature(buf, this, m.typ.(*Signature), visited)
|
writeSignature(buf, m.typ.(*Signature), qf, visited)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// print explicit interface methods and embedded types
|
// print explicit interface methods and embedded types
|
||||||
@ -141,22 +168,22 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
buf.WriteString("; ")
|
buf.WriteString("; ")
|
||||||
}
|
}
|
||||||
buf.WriteString(m.name)
|
buf.WriteString(m.name)
|
||||||
writeSignature(buf, this, m.typ.(*Signature), visited)
|
writeSignature(buf, m.typ.(*Signature), qf, visited)
|
||||||
}
|
}
|
||||||
for i, typ := range t.embeddeds {
|
for i, typ := range t.embeddeds {
|
||||||
if i > 0 || len(t.methods) > 0 {
|
if i > 0 || len(t.methods) > 0 {
|
||||||
buf.WriteString("; ")
|
buf.WriteString("; ")
|
||||||
}
|
}
|
||||||
writeType(buf, this, typ, visited)
|
writeType(buf, typ, qf, visited)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteByte('}')
|
buf.WriteByte('}')
|
||||||
|
|
||||||
case *Map:
|
case *Map:
|
||||||
buf.WriteString("map[")
|
buf.WriteString("map[")
|
||||||
writeType(buf, this, t.key, visited)
|
writeType(buf, t.key, qf, visited)
|
||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
writeType(buf, this, t.elem, visited)
|
writeType(buf, t.elem, qf, visited)
|
||||||
|
|
||||||
case *Chan:
|
case *Chan:
|
||||||
var s string
|
var s string
|
||||||
@ -179,7 +206,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
if parens {
|
if parens {
|
||||||
buf.WriteByte('(')
|
buf.WriteByte('(')
|
||||||
}
|
}
|
||||||
writeType(buf, this, t.elem, visited)
|
writeType(buf, t.elem, qf, visited)
|
||||||
if parens {
|
if parens {
|
||||||
buf.WriteByte(')')
|
buf.WriteByte(')')
|
||||||
}
|
}
|
||||||
@ -187,9 +214,8 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
case *Named:
|
case *Named:
|
||||||
s := "<Named w/o object>"
|
s := "<Named w/o object>"
|
||||||
if obj := t.obj; obj != nil {
|
if obj := t.obj; obj != nil {
|
||||||
if pkg := obj.pkg; pkg != nil && pkg != this {
|
if obj.pkg != nil {
|
||||||
buf.WriteString(pkg.path)
|
writePackage(buf, obj.pkg, qf)
|
||||||
buf.WriteByte('.')
|
|
||||||
}
|
}
|
||||||
// TODO(gri): function-local named types should be displayed
|
// TODO(gri): function-local named types should be displayed
|
||||||
// differently from named types at package level to avoid
|
// differently from named types at package level to avoid
|
||||||
@ -204,7 +230,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, visited []Type) {
|
func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
|
||||||
buf.WriteByte('(')
|
buf.WriteByte('(')
|
||||||
if tup != nil {
|
if tup != nil {
|
||||||
for i, v := range tup.vars {
|
for i, v := range tup.vars {
|
||||||
@ -226,12 +252,12 @@ func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, vis
|
|||||||
if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
|
if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
|
||||||
panic("internal error: string type expected")
|
panic("internal error: string type expected")
|
||||||
}
|
}
|
||||||
writeType(buf, this, typ, visited)
|
writeType(buf, typ, qf, visited)
|
||||||
buf.WriteString("...")
|
buf.WriteString("...")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeType(buf, this, typ, visited)
|
writeType(buf, typ, qf, visited)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf.WriteByte(')')
|
buf.WriteByte(')')
|
||||||
@ -239,14 +265,14 @@ func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, vis
|
|||||||
|
|
||||||
// WriteSignature writes the representation of the signature sig to buf,
|
// WriteSignature writes the representation of the signature sig to buf,
|
||||||
// without a leading "func" keyword.
|
// without a leading "func" keyword.
|
||||||
// Named types are printed package-qualified if they
|
// The Qualifier controls the printing of
|
||||||
// do not belong to this package.
|
// package-level objects, and may be nil.
|
||||||
func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) {
|
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
|
||||||
writeSignature(buf, this, sig, make([]Type, 8))
|
writeSignature(buf, sig, qf, make([]Type, 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) {
|
func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
|
||||||
writeTuple(buf, this, sig.params, sig.variadic, visited)
|
writeTuple(buf, sig.params, sig.variadic, qf, visited)
|
||||||
|
|
||||||
n := sig.results.Len()
|
n := sig.results.Len()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@ -257,10 +283,10 @@ func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []
|
|||||||
buf.WriteByte(' ')
|
buf.WriteByte(' ')
|
||||||
if n == 1 && sig.results.vars[0].name == "" {
|
if n == 1 && sig.results.vars[0].name == "" {
|
||||||
// single unnamed result
|
// single unnamed result
|
||||||
writeType(buf, this, sig.results.vars[0].typ, visited)
|
writeType(buf, sig.results.vars[0].typ, qf, visited)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple or named result(s)
|
// multiple or named result(s)
|
||||||
writeTuple(buf, this, sig.results, false, visited)
|
writeTuple(buf, sig.results, false, qf, visited)
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,13 @@ func TestQualifiedTypeString(t *testing.T) {
|
|||||||
{NewPointer(pT), p, "*T"},
|
{NewPointer(pT), p, "*T"},
|
||||||
{NewPointer(pT), q, "*p.T"},
|
{NewPointer(pT), q, "*p.T"},
|
||||||
} {
|
} {
|
||||||
if got := TypeString(test.this, test.typ); got != test.want {
|
qualifier := func(pkg *Package) string {
|
||||||
|
if pkg != test.this {
|
||||||
|
return pkg.Name()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if got := TypeString(test.typ, qualifier); got != test.want {
|
||||||
t.Errorf("TypeString(%s, %s) = %s, want %s",
|
t.Errorf("TypeString(%s, %s) = %s, want %s",
|
||||||
test.this, test.typ, got, test.want)
|
test.this, test.typ, got, test.want)
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ func funcToken(fn *ssa.Function) token.Pos {
|
|||||||
func prettyFunc(this *types.Package, fn *ssa.Function) string {
|
func prettyFunc(this *types.Package, fn *ssa.Function) string {
|
||||||
if fn.Parent() != nil {
|
if fn.Parent() != nil {
|
||||||
return fmt.Sprintf("%s in %s",
|
return fmt.Sprintf("%s in %s",
|
||||||
types.TypeString(this, fn.Signature),
|
types.TypeString(fn.Signature, types.RelativeTo(this)),
|
||||||
prettyFunc(this, fn.Parent()))
|
prettyFunc(this, fn.Parent()))
|
||||||
}
|
}
|
||||||
if fn.Synthetic != "" && fn.Name() == "init" {
|
if fn.Synthetic != "" && fn.Name() == "init" {
|
||||||
|
@ -69,6 +69,7 @@ func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Na
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RESOLUTION
|
// RESOLUTION
|
||||||
|
qualifier := types.RelativeTo(info.Pkg)
|
||||||
for id, obj := range info.Uses {
|
for id, obj := range info.Uses {
|
||||||
// Position of the object definition.
|
// Position of the object definition.
|
||||||
pos := obj.Pos()
|
pos := obj.Pos()
|
||||||
@ -92,7 +93,7 @@ func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Na
|
|||||||
fi.addLink(aLink{
|
fi.addLink(aLink{
|
||||||
start: offset,
|
start: offset,
|
||||||
end: offset + len(id.Name),
|
end: offset + len(id.Name),
|
||||||
title: types.ObjectString(info.Pkg, obj),
|
title: types.ObjectString(obj, qualifier),
|
||||||
href: a.posURL(pos, Len),
|
href: a.posURL(pos, Len),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -106,7 +107,7 @@ func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Na
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]implementsFacts) {
|
func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]implementsFacts) {
|
||||||
this := obj.Pkg()
|
qualifier := types.RelativeTo(obj.Pkg())
|
||||||
T := obj.Type().(*types.Named)
|
T := obj.Type().(*types.Named)
|
||||||
v := &TypeInfoJSON{
|
v := &TypeInfoJSON{
|
||||||
Name: obj.Name(),
|
Name: obj.Name(),
|
||||||
@ -130,7 +131,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
ByKind: byKind,
|
ByKind: byKind,
|
||||||
Other: anchorJSON{
|
Other: anchorJSON{
|
||||||
Href: a.posURL(Tobj.Pos(), len(Tobj.Name())),
|
Href: a.posURL(Tobj.Pos(), len(Tobj.Name())),
|
||||||
Text: types.TypeString(this, T),
|
Text: types.TypeString(T, qualifier),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -142,7 +143,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
// "T is implemented by <iface>"...
|
// "T is implemented by <iface>"...
|
||||||
// "T implements <iface>"...
|
// "T implements <iface>"...
|
||||||
group := implGroupJSON{
|
group := implGroupJSON{
|
||||||
Descr: types.TypeString(this, T),
|
Descr: types.TypeString(T, qualifier),
|
||||||
}
|
}
|
||||||
// Show concrete types first; use two passes.
|
// Show concrete types first; use two passes.
|
||||||
for _, sub := range r.to {
|
for _, sub := range r.to {
|
||||||
@ -164,7 +165,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
if r.from != nil {
|
if r.from != nil {
|
||||||
// "T implements <iface>"...
|
// "T implements <iface>"...
|
||||||
group := implGroupJSON{
|
group := implGroupJSON{
|
||||||
Descr: types.TypeString(this, T),
|
Descr: types.TypeString(T, qualifier),
|
||||||
}
|
}
|
||||||
for _, super := range r.from {
|
for _, super := range r.from {
|
||||||
addFact(&group, super, false)
|
addFact(&group, super, false)
|
||||||
@ -174,7 +175,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
if r.fromPtr != nil {
|
if r.fromPtr != nil {
|
||||||
// "*C implements <iface>"...
|
// "*C implements <iface>"...
|
||||||
group := implGroupJSON{
|
group := implGroupJSON{
|
||||||
Descr: "*" + types.TypeString(this, T),
|
Descr: "*" + types.TypeString(T, qualifier),
|
||||||
}
|
}
|
||||||
for _, psuper := range r.fromPtr {
|
for _, psuper := range r.fromPtr {
|
||||||
addFact(&group, psuper, false)
|
addFact(&group, psuper, false)
|
||||||
@ -190,7 +191,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
pos := meth.Pos() // may be 0 for error.Error
|
pos := meth.Pos() // may be 0 for error.Error
|
||||||
v.Methods = append(v.Methods, anchorJSON{
|
v.Methods = append(v.Methods, anchorJSON{
|
||||||
Href: a.posURL(pos, len(meth.Name())),
|
Href: a.posURL(pos, len(meth.Name())),
|
||||||
Text: types.SelectionString(this, sel),
|
Text: types.SelectionString(sel, qualifier),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,9 +208,9 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im
|
|||||||
|
|
||||||
// Add info for exported package-level types to the package info.
|
// Add info for exported package-level types to the package info.
|
||||||
if obj.Exported() && isPackageLevel(obj) {
|
if obj.Exported() && isPackageLevel(obj) {
|
||||||
// TODO(adonovan): this.Path() is not unique!
|
// TODO(adonovan): Path is not unique!
|
||||||
// It is possible to declare a non-test package called x_test.
|
// It is possible to declare a non-test package called x_test.
|
||||||
a.result.pkgInfo(this.Path()).addType(v)
|
a.result.pkgInfo(obj.Pkg().Path()).addType(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,20 +590,21 @@ func (r *describePackageResult) display(printf printfFunc) {
|
|||||||
for _, mem := range r.members {
|
for _, mem := range r.members {
|
||||||
printf(mem.obj, "\t%s", formatMember(mem.obj, maxname))
|
printf(mem.obj, "\t%s", formatMember(mem.obj, maxname))
|
||||||
for _, meth := range mem.methods {
|
for _, meth := range mem.methods {
|
||||||
printf(meth.Obj(), "\t\t%s", types.SelectionString(r.pkg, meth))
|
printf(meth.Obj(), "\t\t%s", types.SelectionString(meth, types.RelativeTo(r.pkg)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatMember(obj types.Object, maxname int) string {
|
func formatMember(obj types.Object, maxname int) string {
|
||||||
|
qualifier := types.RelativeTo(obj.Pkg())
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name())
|
fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name())
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *types.Const:
|
case *types.Const:
|
||||||
fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Pkg(), obj.Type()), obj.Val().String())
|
fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Type(), qualifier), obj.Val().String())
|
||||||
|
|
||||||
case *types.Func:
|
case *types.Func:
|
||||||
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type()))
|
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
|
||||||
|
|
||||||
case *types.TypeName:
|
case *types.TypeName:
|
||||||
// Abbreviate long aggregate type names.
|
// Abbreviate long aggregate type names.
|
||||||
@ -619,13 +620,13 @@ func formatMember(obj types.Object, maxname int) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if abbrev == "" {
|
if abbrev == "" {
|
||||||
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type().Underlying()))
|
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type().Underlying(), qualifier))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&buf, " %s", abbrev)
|
fmt.Fprintf(&buf, " %s", abbrev)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *types.Var:
|
case *types.Var:
|
||||||
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type()))
|
fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
|
||||||
}
|
}
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
@ -746,12 +747,13 @@ func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
|
func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
|
||||||
|
qualifier := types.RelativeTo(this)
|
||||||
var jmethods []serial.DescribeMethod
|
var jmethods []serial.DescribeMethod
|
||||||
for _, meth := range methods {
|
for _, meth := range methods {
|
||||||
var ser serial.DescribeMethod
|
var ser serial.DescribeMethod
|
||||||
if meth != nil { // may contain nils when called by implements (on a method)
|
if meth != nil { // may contain nils when called by implements (on a method)
|
||||||
ser = serial.DescribeMethod{
|
ser = serial.DescribeMethod{
|
||||||
Name: types.SelectionString(this, meth),
|
Name: types.SelectionString(meth, qualifier),
|
||||||
Pos: fset.Position(meth.Obj().Pos()).String(),
|
Pos: fset.Position(meth.Obj().Pos()).String(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,11 +180,12 @@ func (r *freevarsResult) display(printf printfFunc) {
|
|||||||
printf(r.qpos, "No free identifiers.")
|
printf(r.qpos, "No free identifiers.")
|
||||||
} else {
|
} else {
|
||||||
printf(r.qpos, "Free identifiers:")
|
printf(r.qpos, "Free identifiers:")
|
||||||
|
qualifier := types.RelativeTo(r.qpos.info.Pkg)
|
||||||
for _, ref := range r.refs {
|
for _, ref := range r.refs {
|
||||||
// Avoid printing "type T T".
|
// Avoid printing "type T T".
|
||||||
var typstr string
|
var typstr string
|
||||||
if ref.kind != "type" {
|
if ref.kind != "type" {
|
||||||
typstr = " " + types.TypeString(r.qpos.info.Pkg, ref.typ)
|
typstr = " " + types.TypeString(ref.typ, qualifier)
|
||||||
}
|
}
|
||||||
printf(ref.obj, "%s %s%s", ref.kind, ref.ref, typstr)
|
printf(ref.obj, "%s %s%s", ref.kind, ref.ref, typstr)
|
||||||
}
|
}
|
||||||
|
@ -58,17 +58,17 @@ type queryPos struct {
|
|||||||
|
|
||||||
// TypeString prints type T relative to the query position.
|
// TypeString prints type T relative to the query position.
|
||||||
func (qpos *queryPos) typeString(T types.Type) string {
|
func (qpos *queryPos) typeString(T types.Type) string {
|
||||||
return types.TypeString(qpos.info.Pkg, T)
|
return types.TypeString(T, types.RelativeTo(qpos.info.Pkg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectString prints object obj relative to the query position.
|
// ObjectString prints object obj relative to the query position.
|
||||||
func (qpos *queryPos) objectString(obj types.Object) string {
|
func (qpos *queryPos) objectString(obj types.Object) string {
|
||||||
return types.ObjectString(qpos.info.Pkg, obj)
|
return types.ObjectString(obj, types.RelativeTo(qpos.info.Pkg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectionString prints selection sel relative to the query position.
|
// SelectionString prints selection sel relative to the query position.
|
||||||
func (qpos *queryPos) selectionString(sel *types.Selection) string {
|
func (qpos *queryPos) selectionString(sel *types.Selection) string {
|
||||||
return types.SelectionString(qpos.info.Pkg, sel)
|
return types.SelectionString(sel, types.RelativeTo(qpos.info.Pkg))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Query specifies a single oracle query.
|
// A Query specifies a single oracle query.
|
||||||
|
@ -189,6 +189,13 @@ func (r *resolver) setBlock(kind string, syntax ast.Node) *Block {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *resolver) qualifier(pkg *types.Package) string {
|
||||||
|
if pkg == r.pkg {
|
||||||
|
return "" // unqualified intra-package reference
|
||||||
|
}
|
||||||
|
return pkg.Path()
|
||||||
|
}
|
||||||
|
|
||||||
func (r *resolver) use(id *ast.Ident, env Environment) {
|
func (r *resolver) use(id *ast.Ident, env Environment) {
|
||||||
if id.Name == "_" {
|
if id.Name == "_" {
|
||||||
return // an error
|
return // an error
|
||||||
@ -199,12 +206,12 @@ func (r *resolver) use(id *ast.Ident, env Environment) {
|
|||||||
} else if want := r.info.Uses[id]; obj != want {
|
} else if want := r.info.Uses[id]; obj != want {
|
||||||
// sanity check against go/types resolver
|
// sanity check against go/types resolver
|
||||||
logf("%s: internal error: lookup of %s yielded wrong object: got %v (%s), want %v\n",
|
logf("%s: internal error: lookup of %s yielded wrong object: got %v (%s), want %v\n",
|
||||||
r.fset.Position(id.Pos()), id.Name, types.ObjectString(r.pkg, obj),
|
r.fset.Position(id.Pos()), id.Name, types.ObjectString(obj, r.qualifier),
|
||||||
r.fset.Position(obj.Pos()),
|
r.fset.Position(obj.Pos()),
|
||||||
want)
|
want)
|
||||||
}
|
}
|
||||||
if trace {
|
if trace {
|
||||||
logf("use %s = %v in %s\n", id.Name, types.ObjectString(r.pkg, obj), env)
|
logf("use %s = %v in %s\n", id.Name, types.ObjectString(obj, r.qualifier), env)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.result.Refs[obj] = append(r.result.Refs[obj], Reference{id, env})
|
r.result.Refs[obj] = append(r.result.Refs[obj], Reference{id, env})
|
||||||
@ -248,7 +255,7 @@ func (r *resolver) defineObject(b *Block, name string, obj types.Object) {
|
|||||||
b.bindings = append(b.bindings, obj)
|
b.bindings = append(b.bindings, obj)
|
||||||
b.index[name] = i
|
b.index[name] = i
|
||||||
if trace {
|
if trace {
|
||||||
logf("def %s = %s in %s\n", name, types.ObjectString(r.pkg, obj), b)
|
logf("def %s = %s in %s\n", name, types.ObjectString(obj, r.qualifier), b)
|
||||||
}
|
}
|
||||||
r.result.Defs[obj] = b
|
r.result.Defs[obj] = b
|
||||||
}
|
}
|
||||||
@ -323,7 +330,7 @@ func (r *resolver) expr(n ast.Expr) {
|
|||||||
// id := kv.Key.(*ast.Ident)
|
// id := kv.Key.(*ast.Ident)
|
||||||
// obj := r.info.Uses[id]
|
// obj := r.info.Uses[id]
|
||||||
// logf("use %s = %v (field)\n",
|
// logf("use %s = %v (field)\n",
|
||||||
// id.Name, types.ObjectString(r.pkg, obj))
|
// id.Name, types.ObjectString(obj, r.qualifier))
|
||||||
// TODO make a fake FieldVal selection?
|
// TODO make a fake FieldVal selection?
|
||||||
} else {
|
} else {
|
||||||
r.expr(elt)
|
r.expr(elt)
|
||||||
@ -344,10 +351,10 @@ func (r *resolver) expr(n ast.Expr) {
|
|||||||
// switch sel.Kind() {
|
// switch sel.Kind() {
|
||||||
// case types.FieldVal:
|
// case types.FieldVal:
|
||||||
// logf("use %s = %v (field)\n",
|
// logf("use %s = %v (field)\n",
|
||||||
// n.Sel.Name, types.ObjectString(r.pkg, sel.Obj()))
|
// n.Sel.Name, types.ObjectString(sel.Obj(), r.qualifier))
|
||||||
// case types.MethodExpr, types.MethodVal:
|
// case types.MethodExpr, types.MethodVal:
|
||||||
// logf("use %s = %v (method)\n",
|
// logf("use %s = %v (method)\n",
|
||||||
// n.Sel.Name, types.ObjectString(r.pkg, sel.Obj()))
|
// n.Sel.Name, types.ObjectString(sel.Obj(), r.qualifier))
|
||||||
// }
|
// }
|
||||||
// } else { // qualified identifier
|
// } else { // qualified identifier
|
||||||
// obj := r.info.Uses[n.Sel]
|
// obj := r.info.Uses[n.Sel]
|
||||||
|
Loading…
Reference in New Issue
Block a user