diff --git a/go/callgraph/rta/rta_test.go b/go/callgraph/rta/rta_test.go index aef788df1b..26eec49445 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 c7adb459b8..ee47425eec 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 e72c30f0cc..73a4747fc7 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 d14928a72c..f5c45abbde 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 fec527b5ce..a9c0f75004 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 9fda3a48ae..88c31f6879 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 0a9dd0e19b..0c0049b1f3 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 0b448045b1..a9b6c43f5a 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 7418eef9fc..0ac6767290 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 1c7016550a..124e0d39f0 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 3d1af20a10..1df8b45b28 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 9a537e8177..abee8abb56 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 8693687c08..975b62389c 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 149b60c027..a98d294429 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 bd1b0c1dc3..83e19c1730 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 00c0525bb1..ea1c5ecf7c 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 580c97b218..400a118f6b 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 65ac9edd9e..544cfa410f 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 55ec391aca..c6567e4dbb 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]