From 997b3545fd86c3a2d8e5fe6366174d7786e71278 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 26 Jun 2015 16:11:46 -0400 Subject: [PATCH] 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 --- go/callgraph/rta/rta_test.go | 2 +- go/gccgoimporter/importer_test.go | 2 +- go/gcimporter/gcimporter_test.go | 2 +- go/loader/stdlib_test.go | 3 +- go/ssa/func.go | 4 +- go/ssa/print.go | 4 +- go/types/errors.go | 13 ++++- go/types/object.go | 68 +++++++++++++--------- go/types/operand.go | 8 +-- go/types/selection.go | 14 ++--- go/types/type.go | 22 +++---- go/types/typestring.go | 96 ++++++++++++++++++++----------- go/types/typestring_test.go | 8 ++- godoc/analysis/callgraph.go | 2 +- godoc/analysis/typeinfo.go | 19 +++--- oracle/describe.go | 14 +++-- oracle/freevars.go | 3 +- oracle/oracle.go | 6 +- refactor/lexical/lexical.go | 19 ++++-- 19 files changed, 186 insertions(+), 123 deletions(-) diff --git a/go/callgraph/rta/rta_test.go b/go/callgraph/rta/rta_test.go index aef788df1b5ed..26eec49445a17 100644 --- a/go/callgraph/rta/rta_test.go +++ b/go/callgraph/rta/rta_test.go @@ -126,7 +126,7 @@ func printResult(res *rta.Result, from *types.Package) string { var rtypes []string res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) { if value == false { // accessible to reflection - rtypes = append(rtypes, types.TypeString(from, key)) + rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from))) } }) writeSorted(rtypes) diff --git a/go/gccgoimporter/importer_test.go b/go/gccgoimporter/importer_test.go index c7adb459b8cf8..ee47425eece1f 100644 --- a/go/gccgoimporter/importer_test.go +++ b/go/gccgoimporter/importer_test.go @@ -34,7 +34,7 @@ func runImporterTest(t *testing.T, imp types.Importer, initmap map[*types.Packag return } - got := types.ObjectString(pkg, obj) + got := types.ObjectString(obj, types.RelativeTo(pkg)) if got != test.want { t.Errorf("%s: got %q; want %q", test.name, got, test.want) } diff --git a/go/gcimporter/gcimporter_test.go b/go/gcimporter/gcimporter_test.go index e72c30f0cc5bb..73a4747fc74f8 100644 --- a/go/gcimporter/gcimporter_test.go +++ b/go/gcimporter/gcimporter_test.go @@ -177,7 +177,7 @@ func TestImportedTypes(t *testing.T) { continue } - got := types.ObjectString(pkg, obj) + got := types.ObjectString(obj, types.RelativeTo(pkg)) if got != test.want { t.Errorf("%s: got %q; want %q", test.name, got, test.want) } diff --git a/go/loader/stdlib_test.go b/go/loader/stdlib_test.go index d14928a72c3d4..f5c45abbde3ca 100644 --- a/go/loader/stdlib_test.go +++ b/go/loader/stdlib_test.go @@ -62,9 +62,10 @@ func TestStdlib(t *testing.T) { for pkg := range prog.AllPackages { fmt.Printf("Package %s:\n", pkg.Path()) scope := pkg.Scope() + qualifier := types.RelativeTo(pkg) for _, name := range scope.Names() { 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() diff --git a/go/ssa/func.go b/go/ssa/func.go index fec527b5cec11..a9c0f750044a1 100644 --- a/go/ssa/func.go +++ b/go/ssa/func.go @@ -522,11 +522,11 @@ func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *ty buf.WriteString(n) buf.WriteString(" ") } - types.WriteType(buf, from, params[0].Type()) + types.WriteType(buf, params[0].Type(), types.RelativeTo(from)) buf.WriteString(") ") } buf.WriteString(name) - types.WriteSignature(buf, from, sig) + types.WriteSignature(buf, sig, types.RelativeTo(from)) } func (f *Function) pkgobj() *types.Package { diff --git a/go/ssa/print.go b/go/ssa/print.go index 9fda3a48aef4f..88c31f6879a35 100644 --- a/go/ssa/print.go +++ b/go/ssa/print.go @@ -39,7 +39,7 @@ func relName(v Value, i Instruction) 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 { @@ -407,7 +407,7 @@ func WritePackage(buf *bytes.Buffer, p *Package) { fmt.Fprintf(buf, " type %-*s %s\n", maxname, name, relType(mem.Type().Underlying(), from)) 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: diff --git a/go/types/errors.go b/go/types/errors.go index 0a9dd0e19ba14..0c0049b1f3e21 100644 --- a/go/types/errors.go +++ b/go/types/errors.go @@ -23,6 +23,13 @@ func 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 { for i, arg := range args { switch a := arg.(type) { @@ -31,15 +38,15 @@ func (check *Checker) sprintf(format string, args ...interface{}) string { case operand: panic("internal error: should always pass *operand") case *operand: - arg = operandString(check.pkg, a) + arg = operandString(a, check.qualifier) case token.Pos: arg = check.fset.Position(a).String() case ast.Expr: arg = ExprString(a) case Object: - arg = ObjectString(check.pkg, a) + arg = ObjectString(a, check.qualifier) case Type: - arg = TypeString(check.pkg, a) + arg = TypeString(a, check.qualifier) } args[i] = arg } diff --git a/go/types/object.go b/go/types/object.go index 0b448045b1faa..a9b6c43f5a0a3 100644 --- a/go/types/object.go +++ b/go/types/object.go @@ -208,7 +208,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { // function or method obj. func (obj *Func) FullName() string { var buf bytes.Buffer - writeFuncName(&buf, nil, obj) + writeFuncName(&buf, obj, nil) return buf.String() } @@ -242,7 +242,7 @@ type Nil struct { object } -func writeObject(buf *bytes.Buffer, this *Package, obj Object) { +func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { typ := obj.Type() switch obj := obj.(type) { case *PkgName: @@ -268,9 +268,9 @@ func writeObject(buf *bytes.Buffer, this *Package, obj Object) { case *Func: buf.WriteString("func ") - writeFuncName(buf, this, obj) + writeFuncName(buf, obj, qf) if typ != nil { - WriteSignature(buf, this, typ.(*Signature)) + WriteSignature(buf, typ.(*Signature), qf) } return @@ -292,39 +292,52 @@ func writeObject(buf *bytes.Buffer, this *Package, obj Object) { buf.WriteByte(' ') - // For package-level objects, package-qualify the name, - // except for intra-package references (this != nil). - if pkg := obj.Pkg(); pkg != nil && this != pkg && pkg.scope.Lookup(obj.Name()) == obj { - buf.WriteString(pkg.path) - buf.WriteByte('.') + // For package-level objects, qualify the name. + if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj { + writePackage(buf, obj.Pkg(), qf) } buf.WriteString(obj.Name()) if typ != nil { 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. -// Object and type names are printed package-qualified -// only if they do not belong to this package. -// -func ObjectString(this *Package, obj Object) string { +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func ObjectString(obj Object, qf Qualifier) string { var buf bytes.Buffer - writeObject(&buf, this, obj) + writeObject(&buf, obj, qf) return buf.String() } -func (obj *PkgName) String() string { return ObjectString(nil, obj) } -func (obj *Const) String() string { return ObjectString(nil, obj) } -func (obj *TypeName) String() string { return ObjectString(nil, obj) } -func (obj *Var) String() string { return ObjectString(nil, obj) } -func (obj *Func) String() string { return ObjectString(nil, obj) } -func (obj *Label) String() string { return ObjectString(nil, obj) } -func (obj *Builtin) String() string { return ObjectString(nil, obj) } -func (obj *Nil) String() string { return ObjectString(nil, obj) } +func (obj *PkgName) String() string { return ObjectString(obj, nil) } +func (obj *Const) String() string { return ObjectString(obj, nil) } +func (obj *TypeName) String() string { return ObjectString(obj, nil) } +func (obj *Var) String() string { return ObjectString(obj, nil) } +func (obj *Func) String() string { return ObjectString(obj, nil) } +func (obj *Label) String() string { return ObjectString(obj, nil) } +func (obj *Builtin) String() string { return ObjectString(obj, nil) } +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 { sig := f.typ.(*Signature) 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. buf.WriteString("interface") } else { - WriteType(buf, this, recv.Type()) + WriteType(buf, recv.Type(), qf) } buf.WriteByte(')') buf.WriteByte('.') - } else if f.pkg != nil && f.pkg != this { - buf.WriteString(f.pkg.path) - buf.WriteByte('.') + } else if f.pkg != nil { + writePackage(buf, f.pkg, qf) } } buf.WriteString(f.name) diff --git a/go/types/operand.go b/go/types/operand.go index 7418eef9fcf2c..0ac6767290e3b 100644 --- a/go/types/operand.go +++ b/go/types/operand.go @@ -94,7 +94,7 @@ func (x *operand) pos() token.Pos { // commaok ( ) // commaok ( of type ) // -func operandString(this *Package, x *operand) string { +func operandString(x *operand, qf Qualifier) string { var buf bytes.Buffer var expr string @@ -105,7 +105,7 @@ func operandString(this *Package, x *operand) string { case builtin: expr = predeclaredFuncs[x.id].name case typexpr: - expr = TypeString(this, x.typ) + expr = TypeString(x.typ, qf) case constant: expr = x.val.String() } @@ -147,7 +147,7 @@ func operandString(this *Package, x *operand) string { if hasType { if x.typ != Typ[Invalid] { buf.WriteString(" of type ") - WriteType(&buf, this, x.typ) + WriteType(&buf, x.typ, qf) } else { buf.WriteString(" with invalid type") } @@ -162,7 +162,7 @@ func operandString(this *Package, x *operand) string { } func (x *operand) String() string { - return operandString(nil, x) + return operandString(x, nil) } // setConst sets x to the untyped constant for literal lit. diff --git a/go/types/selection.go b/go/types/selection.go index 1c7016550a6de..124e0d39f02b9 100644 --- a/go/types/selection.go +++ b/go/types/selection.go @@ -105,18 +105,18 @@ func (s *Selection) Index() []int { return s.index } // x to f in x.f. 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. -// Type names are printed package-qualified -// only if they do not belong to this package. +// The Qualifier controls the printing of +// package-level objects, and may be nil. // // Examples: // "field (T) f int" // "method (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 switch s.kind { case FieldVal: @@ -131,13 +131,13 @@ func SelectionString(this *Package, s *Selection) string { var buf bytes.Buffer buf.WriteString(k) buf.WriteByte('(') - WriteType(&buf, this, s.Recv()) + WriteType(&buf, s.Recv(), qf) fmt.Fprintf(&buf, ") %s", s.obj.Name()) if T := s.Type(); s.kind == FieldVal { buf.WriteByte(' ') - WriteType(&buf, this, T) + WriteType(&buf, T, qf) } else { - WriteSignature(&buf, this, T.(*Signature)) + WriteSignature(&buf, T.(*Signature), qf) } return buf.String() } diff --git a/go/types/type.go b/go/types/type.go index 3d1af20a103a3..1df8b45b28553 100644 --- a/go/types/type.go +++ b/go/types/type.go @@ -441,14 +441,14 @@ func (t *Map) Underlying() Type { return t } func (t *Chan) Underlying() Type { return t } func (t *Named) Underlying() Type { return t.underlying } -func (t *Basic) String() string { return TypeString(nil, t) } -func (t *Array) String() string { return TypeString(nil, t) } -func (t *Slice) String() string { return TypeString(nil, t) } -func (t *Struct) String() string { return TypeString(nil, t) } -func (t *Pointer) String() string { return TypeString(nil, t) } -func (t *Tuple) String() string { return TypeString(nil, t) } -func (t *Signature) String() string { return TypeString(nil, t) } -func (t *Interface) String() string { return TypeString(nil, t) } -func (t *Map) String() string { return TypeString(nil, t) } -func (t *Chan) String() string { return TypeString(nil, t) } -func (t *Named) String() string { return TypeString(nil, t) } +func (t *Basic) String() string { return TypeString(t, nil) } +func (t *Array) String() string { return TypeString(t, nil) } +func (t *Slice) String() string { return TypeString(t, nil) } +func (t *Struct) String() string { return TypeString(t, nil) } +func (t *Pointer) String() string { return TypeString(t, nil) } +func (t *Tuple) String() string { return TypeString(t, nil) } +func (t *Signature) String() string { return TypeString(t, nil) } +func (t *Interface) String() string { return TypeString(t, nil) } +func (t *Map) String() string { return TypeString(t, nil) } +func (t *Chan) String() string { return TypeString(t, nil) } +func (t *Named) String() string { return TypeString(t, nil) } diff --git a/go/types/typestring.go b/go/types/typestring.go index 9a537e8177372..abee8abb56737 100644 --- a/go/types/typestring.go +++ b/go/types/typestring.go @@ -11,6 +11,33 @@ import ( "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 // to match the representation of some types in the gc compiler: // @@ -28,22 +55,22 @@ import ( var GcCompatibilityMode bool // TypeString returns the string representation of typ. -// Named types are printed package-qualified if they -// do not belong to this package. -func TypeString(this *Package, typ Type) string { +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func TypeString(typ Type, qf Qualifier) string { var buf bytes.Buffer - WriteType(&buf, this, typ) + WriteType(&buf, typ, qf) return buf.String() } // WriteType writes the string representation of typ to buf. -// Named types are printed package-qualified if they -// do not belong to this package. -func WriteType(buf *bytes.Buffer, this *Package, typ Type) { - writeType(buf, this, typ, make([]Type, 8)) +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) { + 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 // practice deeply nested composite types with unnamed component // 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: fmt.Fprintf(buf, "[%d]", t.len) - writeType(buf, this, t.elem, visited) + writeType(buf, t.elem, qf, visited) case *Slice: buf.WriteString("[]") - writeType(buf, this, t.elem, visited) + writeType(buf, t.elem, qf, visited) case *Struct: buf.WriteString("struct{") @@ -93,7 +120,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) { buf.WriteString(f.name) buf.WriteByte(' ') } - writeType(buf, this, f.typ, visited) + writeType(buf, f.typ, qf, visited) if tag := t.Tag(i); tag != "" { fmt.Fprintf(buf, " %q", tag) } @@ -102,14 +129,14 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) { case *Pointer: buf.WriteByte('*') - writeType(buf, this, t.base, visited) + writeType(buf, t.base, qf, visited) case *Tuple: - writeTuple(buf, this, t, false, visited) + writeTuple(buf, t, false, qf, visited) case *Signature: buf.WriteString("func") - writeSignature(buf, this, t, visited) + writeSignature(buf, t, qf, visited) case *Interface: // 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(m.name) - writeSignature(buf, this, m.typ.(*Signature), visited) + writeSignature(buf, m.typ.(*Signature), qf, visited) } } else { // 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(m.name) - writeSignature(buf, this, m.typ.(*Signature), visited) + writeSignature(buf, m.typ.(*Signature), qf, visited) } for i, typ := range t.embeddeds { if i > 0 || len(t.methods) > 0 { buf.WriteString("; ") } - writeType(buf, this, typ, visited) + writeType(buf, typ, qf, visited) } } buf.WriteByte('}') case *Map: buf.WriteString("map[") - writeType(buf, this, t.key, visited) + writeType(buf, t.key, qf, visited) buf.WriteByte(']') - writeType(buf, this, t.elem, visited) + writeType(buf, t.elem, qf, visited) case *Chan: var s string @@ -179,7 +206,7 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) { if parens { buf.WriteByte('(') } - writeType(buf, this, t.elem, visited) + writeType(buf, t.elem, qf, visited) if parens { buf.WriteByte(')') } @@ -187,9 +214,8 @@ func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) { case *Named: s := "" if obj := t.obj; obj != nil { - if pkg := obj.pkg; pkg != nil && pkg != this { - buf.WriteString(pkg.path) - buf.WriteByte('.') + if obj.pkg != nil { + writePackage(buf, obj.pkg, qf) } // TODO(gri): function-local named types should be displayed // 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('(') if tup != nil { 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 { panic("internal error: string type expected") } - writeType(buf, this, typ, visited) + writeType(buf, typ, qf, visited) buf.WriteString("...") continue } } - writeType(buf, this, typ, visited) + writeType(buf, typ, qf, visited) } } 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, // without a leading "func" keyword. -// Named types are printed package-qualified if they -// do not belong to this package. -func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) { - writeSignature(buf, this, sig, make([]Type, 8)) +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { + writeSignature(buf, sig, qf, make([]Type, 8)) } -func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) { - writeTuple(buf, this, sig.params, sig.variadic, visited) +func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { + writeTuple(buf, sig.params, sig.variadic, qf, visited) n := sig.results.Len() if n == 0 { @@ -257,10 +283,10 @@ func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited [] buf.WriteByte(' ') if n == 1 && sig.results.vars[0].name == "" { // single unnamed result - writeType(buf, this, sig.results.vars[0].typ, visited) + writeType(buf, sig.results.vars[0].typ, qf, visited) return } // multiple or named result(s) - writeTuple(buf, this, sig.results, false, visited) + writeTuple(buf, sig.results, false, qf, visited) } diff --git a/go/types/typestring_test.go b/go/types/typestring_test.go index 8693687c08a4a..975b62389cb49 100644 --- a/go/types/typestring_test.go +++ b/go/types/typestring_test.go @@ -152,7 +152,13 @@ func TestQualifiedTypeString(t *testing.T) { {NewPointer(pT), 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", test.this, test.typ, got, test.want) } diff --git a/godoc/analysis/callgraph.go b/godoc/analysis/callgraph.go index 149b60c027a7a..a98d294429e11 100644 --- a/godoc/analysis/callgraph.go +++ b/godoc/analysis/callgraph.go @@ -237,7 +237,7 @@ func funcToken(fn *ssa.Function) token.Pos { func prettyFunc(this *types.Package, fn *ssa.Function) string { if fn.Parent() != nil { return fmt.Sprintf("%s in %s", - types.TypeString(this, fn.Signature), + types.TypeString(fn.Signature, types.RelativeTo(this)), prettyFunc(this, fn.Parent())) } if fn.Synthetic != "" && fn.Name() == "init" { diff --git a/godoc/analysis/typeinfo.go b/godoc/analysis/typeinfo.go index bd1b0c1dc36d0..83e19c1730e5d 100644 --- a/godoc/analysis/typeinfo.go +++ b/godoc/analysis/typeinfo.go @@ -69,6 +69,7 @@ func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Na } // RESOLUTION + qualifier := types.RelativeTo(info.Pkg) for id, obj := range info.Uses { // Position of the object definition. pos := obj.Pos() @@ -92,7 +93,7 @@ func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Na fi.addLink(aLink{ start: offset, end: offset + len(id.Name), - title: types.ObjectString(info.Pkg, obj), + title: types.ObjectString(obj, qualifier), 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) { - this := obj.Pkg() + qualifier := types.RelativeTo(obj.Pkg()) T := obj.Type().(*types.Named) v := &TypeInfoJSON{ Name: obj.Name(), @@ -130,7 +131,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im ByKind: byKind, Other: anchorJSON{ 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 "... // "T implements "... group := implGroupJSON{ - Descr: types.TypeString(this, T), + Descr: types.TypeString(T, qualifier), } // Show concrete types first; use two passes. 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 { // "T implements "... group := implGroupJSON{ - Descr: types.TypeString(this, T), + Descr: types.TypeString(T, qualifier), } for _, super := range r.from { addFact(&group, super, false) @@ -174,7 +175,7 @@ func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]im if r.fromPtr != nil { // "*C implements "... group := implGroupJSON{ - Descr: "*" + types.TypeString(this, T), + Descr: "*" + types.TypeString(T, qualifier), } for _, psuper := range r.fromPtr { 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 v.Methods = append(v.Methods, anchorJSON{ 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. 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. - a.result.pkgInfo(this.Path()).addType(v) + a.result.pkgInfo(obj.Pkg().Path()).addType(v) } } diff --git a/oracle/describe.go b/oracle/describe.go index 00c0525bb107c..ea1c5ecf7cff0 100644 --- a/oracle/describe.go +++ b/oracle/describe.go @@ -590,20 +590,21 @@ func (r *describePackageResult) display(printf printfFunc) { for _, mem := range r.members { printf(mem.obj, "\t%s", formatMember(mem.obj, maxname)) 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 { + qualifier := types.RelativeTo(obj.Pkg()) var buf bytes.Buffer fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name()) switch obj := obj.(type) { 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: - fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type())) + fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier)) case *types.TypeName: // Abbreviate long aggregate type names. @@ -619,13 +620,13 @@ func formatMember(obj types.Object, maxname int) string { } } if abbrev == "" { - fmt.Fprintf(&buf, " %s", types.TypeString(obj.Pkg(), obj.Type().Underlying())) + fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type().Underlying(), qualifier)) } else { fmt.Fprintf(&buf, " %s", abbrev) } 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() } @@ -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 { + qualifier := types.RelativeTo(this) var jmethods []serial.DescribeMethod for _, meth := range methods { var ser serial.DescribeMethod if meth != nil { // may contain nils when called by implements (on a method) ser = serial.DescribeMethod{ - Name: types.SelectionString(this, meth), + Name: types.SelectionString(meth, qualifier), Pos: fset.Position(meth.Obj().Pos()).String(), } } diff --git a/oracle/freevars.go b/oracle/freevars.go index 580c97b218811..400a118f6badd 100644 --- a/oracle/freevars.go +++ b/oracle/freevars.go @@ -180,11 +180,12 @@ func (r *freevarsResult) display(printf printfFunc) { printf(r.qpos, "No free identifiers.") } else { printf(r.qpos, "Free identifiers:") + qualifier := types.RelativeTo(r.qpos.info.Pkg) for _, ref := range r.refs { // Avoid printing "type T T". var typstr string 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) } diff --git a/oracle/oracle.go b/oracle/oracle.go index 65ac9edd9ecde..544cfa410f4a7 100644 --- a/oracle/oracle.go +++ b/oracle/oracle.go @@ -58,17 +58,17 @@ type queryPos struct { // TypeString prints type T relative to the query position. 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. 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. 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. diff --git a/refactor/lexical/lexical.go b/refactor/lexical/lexical.go index 55ec391aca6c4..c6567e4dbb65f 100644 --- a/refactor/lexical/lexical.go +++ b/refactor/lexical/lexical.go @@ -189,6 +189,13 @@ func (r *resolver) setBlock(kind string, syntax ast.Node) *Block { 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) { if id.Name == "_" { 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 { // sanity check against go/types resolver 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()), want) } 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}) @@ -248,7 +255,7 @@ func (r *resolver) defineObject(b *Block, name string, obj types.Object) { b.bindings = append(b.bindings, obj) b.index[name] = i 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 } @@ -323,7 +330,7 @@ func (r *resolver) expr(n ast.Expr) { // id := kv.Key.(*ast.Ident) // obj := r.info.Uses[id] // 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? } else { r.expr(elt) @@ -344,10 +351,10 @@ func (r *resolver) expr(n ast.Expr) { // switch sel.Kind() { // case types.FieldVal: // 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: // 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 // obj := r.info.Uses[n.Sel]