go.tools/ssa: display named types package-qualified using types.TypeString.
Details: - use relative (non-qualified) names in more places - Member interface now has Package(), RelString() methods. - (*Function).DumpTo: add "# Package: " header. - Added sanity checks for String functions. R=gri, gri CC=golang-dev https://golang.org/cl/26380043
This commit is contained in:
parent
0820934407
commit
9fcd20e680
20
ssa/const.go
20
ssa/const.go
|
@ -65,21 +65,27 @@ func zeroConst(t types.Type) *Const {
|
|||
panic(fmt.Sprint("zeroConst: unexpected ", t))
|
||||
}
|
||||
|
||||
func (c *Const) Name() string {
|
||||
var s string
|
||||
func (c *Const) valstring() string {
|
||||
if c.Value == nil {
|
||||
s = "nil"
|
||||
return "nil"
|
||||
} else if c.Value.Kind() == exact.String {
|
||||
s = exact.StringVal(c.Value)
|
||||
s := exact.StringVal(c.Value)
|
||||
const max = 20
|
||||
if len(s) > max {
|
||||
s = s[:max-3] + "..." // abbreviate
|
||||
}
|
||||
s = strconv.Quote(s)
|
||||
return strconv.Quote(s)
|
||||
} else {
|
||||
s = c.Value.String()
|
||||
return c.Value.String()
|
||||
}
|
||||
return s + ":" + c.typ.String()
|
||||
}
|
||||
|
||||
func (c *Const) Name() string {
|
||||
return fmt.Sprintf("%s:%s", c.valstring(), c.typ)
|
||||
}
|
||||
|
||||
func (v *Const) String() string {
|
||||
return v.Name()
|
||||
}
|
||||
|
||||
func (c *Const) Type() types.Type {
|
||||
|
|
|
@ -71,12 +71,16 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
|||
switch obj := obj.(type) {
|
||||
case *types.TypeName:
|
||||
pkg.values[obj] = nil // for needMethods
|
||||
pkg.Members[name] = &Type{object: obj}
|
||||
pkg.Members[name] = &Type{
|
||||
object: obj,
|
||||
pkg: pkg,
|
||||
}
|
||||
|
||||
case *types.Const:
|
||||
c := &NamedConst{
|
||||
object: obj,
|
||||
Value: NewConst(obj.Val(), obj.Type()),
|
||||
pkg: pkg,
|
||||
}
|
||||
pkg.values[obj] = c.Value
|
||||
pkg.Members[name] = c
|
||||
|
|
|
@ -82,6 +82,7 @@ func main() {
|
|||
// const message message = "Hello, World!":untyped string
|
||||
//
|
||||
// # Name: main.init
|
||||
// # Package: main
|
||||
// # Synthetic: package initializer
|
||||
// func init():
|
||||
// .0.entry: P:0 S:2
|
||||
|
@ -95,6 +96,7 @@ func main() {
|
|||
// return
|
||||
//
|
||||
// # Name: main.main
|
||||
// # Package: main
|
||||
// # Location: hello.go:8:6
|
||||
// func main():
|
||||
// .0.entry: P:0 S:0
|
||||
|
|
37
ssa/func.go
37
ssa/func.go
|
@ -444,7 +444,7 @@ func (f *Function) emit(instr Instruction) Value {
|
|||
return f.currentBlock.emit(instr)
|
||||
}
|
||||
|
||||
// FullName returns the full name of this function, qualified by
|
||||
// RelString returns the full name of this function, qualified by
|
||||
// package name, receiver type, etc.
|
||||
//
|
||||
// The specific formatting rules are not guaranteed and may change.
|
||||
|
@ -453,13 +453,13 @@ func (f *Function) emit(instr Instruction) Value {
|
|||
// "math.IsNaN" // a package-level function
|
||||
// "IsNaN" // intra-package reference to same
|
||||
// "(*sync.WaitGroup).Add" // a declared method
|
||||
// "(*exp/ssa.Return).Block" // a promotion wrapper method
|
||||
// "(ssa.Instruction).Block" // an interface method wrapper
|
||||
// "(*Return).Block" // a promotion wrapper method (intra-package ref)
|
||||
// "(Instruction).Block" // an interface method wrapper (intra-package ref)
|
||||
// "func@5.32" // an anonymous function
|
||||
// "bound$(*T).f" // a bound method wrapper
|
||||
//
|
||||
// If from==f.Pkg, suppress package qualification.
|
||||
func (f *Function) fullName(from *Package) string {
|
||||
func (f *Function) RelString(from *types.Package) string {
|
||||
// TODO(adonovan): expose less fragile case discrimination
|
||||
// using f.method.
|
||||
|
||||
|
@ -490,8 +490,8 @@ func (f *Function) fullName(from *Package) string {
|
|||
|
||||
// Package-level function.
|
||||
// Prefix with package name for cross-package references only.
|
||||
if from != f.Pkg {
|
||||
return fmt.Sprintf("%s.%s", f.Pkg.Object.Path(), f.name)
|
||||
if p := f.pkgobj(); p != from {
|
||||
return fmt.Sprintf("%s.%s", p.Path(), f.name)
|
||||
}
|
||||
return f.name
|
||||
}
|
||||
|
@ -499,7 +499,7 @@ func (f *Function) fullName(from *Package) string {
|
|||
// writeSignature writes to w the signature sig in declaration syntax.
|
||||
// Derived from types.Signature.String().
|
||||
//
|
||||
func writeSignature(w io.Writer, pkg *Package, name string, sig *types.Signature, params []*Parameter) {
|
||||
func writeSignature(w io.Writer, pkg *types.Package, name string, sig *types.Signature, params []*Parameter) {
|
||||
io.WriteString(w, "func ")
|
||||
if recv := sig.Recv(); recv != nil {
|
||||
io.WriteString(w, "(")
|
||||
|
@ -533,16 +533,26 @@ func writeSignature(w io.Writer, pkg *Package, name string, sig *types.Signature
|
|||
if n == 1 && r.At(0).Name() == "" {
|
||||
io.WriteString(w, relType(r.At(0).Type(), pkg))
|
||||
} else {
|
||||
io.WriteString(w, r.String()) // TODO(adonovan): use relType
|
||||
io.WriteString(w, relType(r, pkg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Function) pkgobj() *types.Package {
|
||||
if f.Pkg != nil {
|
||||
return f.Pkg.Object
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DumpTo prints to w a human readable "disassembly" of the SSA code of
|
||||
// all basic blocks of function f.
|
||||
//
|
||||
func (f *Function) DumpTo(w io.Writer) {
|
||||
fmt.Fprintf(w, "# Name: %s\n", f.String())
|
||||
if f.Pkg != nil {
|
||||
fmt.Fprintf(w, "# Package: %s\n", f.Pkg.Object.Path())
|
||||
}
|
||||
if syn := f.Synthetic; syn != "" {
|
||||
fmt.Fprintln(w, "# Synthetic:", syn)
|
||||
}
|
||||
|
@ -558,21 +568,22 @@ func (f *Function) DumpTo(w io.Writer) {
|
|||
fmt.Fprintf(w, "# Recover: %s\n", f.Recover)
|
||||
}
|
||||
|
||||
pkgobj := f.pkgobj()
|
||||
|
||||
if f.FreeVars != nil {
|
||||
io.WriteString(w, "# Free variables:\n")
|
||||
for i, fv := range f.FreeVars {
|
||||
fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), f.Pkg))
|
||||
fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), pkgobj))
|
||||
}
|
||||
}
|
||||
|
||||
if len(f.Locals) > 0 {
|
||||
io.WriteString(w, "# Locals:\n")
|
||||
for i, l := range f.Locals {
|
||||
fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), f.Pkg))
|
||||
fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), pkgobj))
|
||||
}
|
||||
}
|
||||
|
||||
writeSignature(w, f.Pkg, f.Name(), f.Signature, f.Params)
|
||||
writeSignature(w, pkgobj, f.Name(), f.Signature, f.Params)
|
||||
io.WriteString(w, ":\n")
|
||||
|
||||
if f.Blocks == nil {
|
||||
|
@ -608,7 +619,7 @@ func (f *Function) DumpTo(w io.Writer) {
|
|||
l -= n
|
||||
// Right-align the type.
|
||||
if t := v.Type(); t != nil {
|
||||
fmt.Fprintf(w, " %*s", l-10, relType(t, f.Pkg))
|
||||
fmt.Fprintf(w, " %*s", l-10, relType(t, pkgobj))
|
||||
}
|
||||
case nil:
|
||||
// Be robust against bad transforms.
|
||||
|
|
87
ssa/print.go
87
ssa/print.go
|
@ -14,57 +14,41 @@ import (
|
|||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
// relName returns the name of v relative to i.
|
||||
// In most cases, this is identical to v.Name(), but for references to
|
||||
// Functions (including methods) and Globals, the FullName is used
|
||||
// instead, explicitly package-qualified for cross-package references.
|
||||
// In most cases, this is identical to v.Name(), but references to
|
||||
// Functions (including methods) and Globals use RelString and
|
||||
// all types are displayed with relType, so that only cross-package
|
||||
// references are package-qualified.
|
||||
//
|
||||
func relName(v Value, i Instruction) string {
|
||||
var from *types.Package
|
||||
if i != nil {
|
||||
from = i.Parent().pkgobj()
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case *Global:
|
||||
if i != nil && v.Pkg == i.Parent().Pkg {
|
||||
return v.Name()
|
||||
}
|
||||
return v.FullName()
|
||||
case *Function:
|
||||
var pkg *Package
|
||||
if i != nil {
|
||||
pkg = i.Parent().Pkg
|
||||
}
|
||||
return v.fullName(pkg)
|
||||
case Member: // *Function or *Global
|
||||
return v.RelString(from)
|
||||
case *Const:
|
||||
return v.valstring() + ":" + relType(v.Type(), from)
|
||||
}
|
||||
return v.Name()
|
||||
}
|
||||
|
||||
// relType is like t.String(), but if t is a Named type belonging to
|
||||
// package from, optionally wrapped by one or more Pointer
|
||||
// constructors, package qualification is suppressed.
|
||||
//
|
||||
// TODO(gri): provide this functionality in go/types (using a
|
||||
// *types.Package, obviously).
|
||||
//
|
||||
func relType(t types.Type, from *Package) string {
|
||||
if from != nil {
|
||||
t2 := t
|
||||
var nptr int // number of Pointers stripped off
|
||||
for {
|
||||
ptr, ok := t2.(*types.Pointer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
t2 = ptr.Elem()
|
||||
nptr++
|
||||
}
|
||||
if n, ok := t2.(*types.Named); ok && n.Obj().Pkg() == from.Object {
|
||||
return strings.Repeat("*", nptr) + n.Obj().Name()
|
||||
}
|
||||
func relType(t types.Type, from *types.Package) string {
|
||||
return types.TypeString(from, t)
|
||||
}
|
||||
|
||||
func relString(m Member, from *types.Package) string {
|
||||
// NB: not all globals have an Object (e.g. init$guard),
|
||||
// so use Package().Object not Object.Package().
|
||||
if obj := m.Package().Object; obj != nil && obj != from {
|
||||
return fmt.Sprintf("%s.%s", obj.Path(), m.Name())
|
||||
}
|
||||
return t.String()
|
||||
return m.Name()
|
||||
}
|
||||
|
||||
// Value.String()
|
||||
|
@ -72,10 +56,6 @@ func relType(t types.Type, from *Package) string {
|
|||
// This method is provided only for debugging.
|
||||
// It never appears in disassembly, which uses Value.Name().
|
||||
|
||||
func (v *Const) String() string {
|
||||
return v.Name()
|
||||
}
|
||||
|
||||
func (v *Parameter) String() string {
|
||||
return fmt.Sprintf("parameter %s : %s", v.Name(), v.Type())
|
||||
}
|
||||
|
@ -84,23 +64,10 @@ func (v *Capture) String() string {
|
|||
return fmt.Sprintf("capture %s : %s", v.Name(), v.Type())
|
||||
}
|
||||
|
||||
func (v *Global) String() string {
|
||||
return v.FullName()
|
||||
}
|
||||
|
||||
func (v *Builtin) String() string {
|
||||
return fmt.Sprintf("builtin %s", v.Name())
|
||||
}
|
||||
|
||||
func (v *Function) String() string {
|
||||
return v.fullName(nil)
|
||||
}
|
||||
|
||||
// FullName returns g's package-qualified name.
|
||||
func (g *Global) FullName() string {
|
||||
return fmt.Sprintf("%s.%s", g.Pkg.Object.Path(), g.name)
|
||||
}
|
||||
|
||||
// Instruction.String()
|
||||
|
||||
func (v *Alloc) String() string {
|
||||
|
@ -108,7 +75,7 @@ func (v *Alloc) String() string {
|
|||
if v.Heap {
|
||||
op = "new"
|
||||
}
|
||||
return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), v.Parent().Pkg), v.Comment)
|
||||
return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), v.Parent().pkgobj()), v.Comment)
|
||||
}
|
||||
|
||||
func (v *Phi) String() string {
|
||||
|
@ -170,7 +137,7 @@ func (v *Call) String() string {
|
|||
}
|
||||
|
||||
func (v *ChangeType) String() string {
|
||||
return fmt.Sprintf("changetype %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), v.X.Type(), relName(v.X, v))
|
||||
return fmt.Sprintf("changetype %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), v.X.Type(), relName(v.X, v))
|
||||
}
|
||||
|
||||
func (v *BinOp) String() string {
|
||||
|
@ -182,7 +149,7 @@ func (v *UnOp) String() string {
|
|||
}
|
||||
|
||||
func (v *Convert) String() string {
|
||||
return fmt.Sprintf("convert %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), v.X.Type(), relName(v.X, v))
|
||||
return fmt.Sprintf("convert %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), v.X.Type(), relName(v.X, v))
|
||||
}
|
||||
|
||||
func (v *ChangeInterface) String() string {
|
||||
|
@ -190,7 +157,7 @@ func (v *ChangeInterface) String() string {
|
|||
}
|
||||
|
||||
func (v *MakeInterface) String() string {
|
||||
return fmt.Sprintf("make %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), relType(v.X.Type(), v.Parent().Pkg), relName(v.X, v))
|
||||
return fmt.Sprintf("make %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), relType(v.X.Type(), v.Parent().pkgobj()), relName(v.X, v))
|
||||
}
|
||||
|
||||
func (v *MakeClosure) String() string {
|
||||
|
@ -289,7 +256,7 @@ func (v *Next) String() string {
|
|||
}
|
||||
|
||||
func (v *TypeAssert) String() string {
|
||||
return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), v.AssertedType)
|
||||
return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, v.Parent().pkgobj()))
|
||||
}
|
||||
|
||||
func (v *Extract) String() string {
|
||||
|
|
|
@ -367,6 +367,10 @@ func (s *sanity) checkFunction(fn *Function) bool {
|
|||
if fn.Prog == nil {
|
||||
s.errorf("nil Prog")
|
||||
}
|
||||
|
||||
fn.String() // must not crash
|
||||
fn.RelString(fn.pkgobj()) // must not crash
|
||||
|
||||
// All functions have a package, except wrappers (which are
|
||||
// shared across packages, or duplicated as weak symbols in a
|
||||
// separate-compilation model), and error.Error.
|
||||
|
@ -430,6 +434,11 @@ func (s *sanity) checkFunction(fn *Function) bool {
|
|||
// It does not require that the package is built.
|
||||
// Unlike sanityCheck (for functions), it just panics at the first error.
|
||||
func sanityCheckPackage(pkg *Package) {
|
||||
if pkg.Object == nil {
|
||||
panic(fmt.Sprintf("Package %s has no Object", pkg))
|
||||
}
|
||||
pkg.String() // must not crash
|
||||
|
||||
for name, mem := range pkg.Members {
|
||||
if name != mem.Name() {
|
||||
panic(fmt.Sprintf("%s: %T.Name() = %s, want %s",
|
||||
|
|
67
ssa/ssa.go
67
ssa/ssa.go
|
@ -61,12 +61,14 @@ type Package struct {
|
|||
// const, var, func and type declarations respectively.
|
||||
//
|
||||
type Member interface {
|
||||
Name() string // declared name of the package member
|
||||
String() string // package-qualified name of the package member
|
||||
Object() types.Object // typechecker's object for this member, if any
|
||||
Pos() token.Pos // position of member's declaration, if known
|
||||
Type() types.Type // type of the package member
|
||||
Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
|
||||
Name() string // declared name of the package member
|
||||
String() string // package-qualified name of the package member
|
||||
RelString(*types.Package) string // like String, but relative refs are unqualified
|
||||
Object() types.Object // typechecker's object for this member, if any
|
||||
Pos() token.Pos // position of member's declaration, if known
|
||||
Type() types.Type // type of the package member
|
||||
Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
|
||||
Package() *Package // returns the containing package. (TODO: rename Pkg)
|
||||
}
|
||||
|
||||
// A Type is a Member of a Package representing a package-level named type.
|
||||
|
@ -75,6 +77,7 @@ type Member interface {
|
|||
//
|
||||
type Type struct {
|
||||
object *types.TypeName
|
||||
pkg *Package
|
||||
}
|
||||
|
||||
// A NamedConst is a Member of Package representing a package-level
|
||||
|
@ -90,6 +93,7 @@ type NamedConst struct {
|
|||
object *types.Const
|
||||
Value *Const
|
||||
pos token.Pos
|
||||
pkg *Package
|
||||
}
|
||||
|
||||
// An SSA value that can be referenced by an instruction.
|
||||
|
@ -1149,7 +1153,7 @@ type MapUpdate struct {
|
|||
}
|
||||
|
||||
// A DebugRef instruction maps a source-level expression Expr to the
|
||||
// SSA value that represents the value (!IsAddr) or address (IsAddr)
|
||||
// SSA value X that represents the value (!IsAddr) or address (IsAddr)
|
||||
// of that expression.
|
||||
//
|
||||
// DebugRef is a pseudo-instruction: it has no dynamic effect.
|
||||
|
@ -1361,18 +1365,23 @@ func (v *Capture) Referrers() *[]Instruction { return &v.referrers }
|
|||
func (v *Capture) Pos() token.Pos { return v.pos }
|
||||
func (v *Capture) Parent() *Function { return v.parent }
|
||||
|
||||
func (v *Global) Type() types.Type { return v.typ }
|
||||
func (v *Global) Name() string { return v.name }
|
||||
func (v *Global) Pos() token.Pos { return v.pos }
|
||||
func (*Global) Referrers() *[]Instruction { return nil }
|
||||
func (v *Global) Token() token.Token { return token.VAR }
|
||||
func (v *Global) Object() types.Object { return v.object }
|
||||
func (v *Global) Type() types.Type { return v.typ }
|
||||
func (v *Global) Name() string { return v.name }
|
||||
func (v *Global) Pos() token.Pos { return v.pos }
|
||||
func (v *Global) Referrers() *[]Instruction { return nil }
|
||||
func (v *Global) Token() token.Token { return token.VAR }
|
||||
func (v *Global) Object() types.Object { return v.object }
|
||||
func (v *Global) String() string { return v.RelString(nil) }
|
||||
func (v *Global) Package() *Package { return v.Pkg }
|
||||
func (v *Global) RelString(from *types.Package) string { return relString(v, from) }
|
||||
|
||||
func (v *Function) Name() string { return v.name }
|
||||
func (v *Function) Type() types.Type { return v.Signature }
|
||||
func (v *Function) Pos() token.Pos { return v.pos }
|
||||
func (v *Function) Token() token.Token { return token.FUNC }
|
||||
func (v *Function) Object() types.Object { return v.object }
|
||||
func (v *Function) String() string { return v.RelString(nil) }
|
||||
func (v *Function) Package() *Package { return v.Pkg }
|
||||
func (v *Function) Referrers() *[]Instruction {
|
||||
if v.Enclosing != nil {
|
||||
return &v.referrers
|
||||
|
@ -1403,23 +1412,23 @@ func (v *anInstruction) Parent() *Function { return v.block.parent }
|
|||
func (v *anInstruction) Block() *BasicBlock { return v.block }
|
||||
func (v *anInstruction) setBlock(block *BasicBlock) { v.block = block }
|
||||
|
||||
func (t *Type) Name() string { return t.object.Name() }
|
||||
func (t *Type) Pos() token.Pos { return t.object.Pos() }
|
||||
func (t *Type) Type() types.Type { return t.object.Type() }
|
||||
func (t *Type) Token() token.Token { return token.TYPE }
|
||||
func (t *Type) Object() types.Object { return t.object }
|
||||
func (t *Type) String() string {
|
||||
return fmt.Sprintf("%s.%s", t.object.Pkg().Path(), t.object.Name())
|
||||
}
|
||||
func (t *Type) Name() string { return t.object.Name() }
|
||||
func (t *Type) Pos() token.Pos { return t.object.Pos() }
|
||||
func (t *Type) Type() types.Type { return t.object.Type() }
|
||||
func (t *Type) Token() token.Token { return token.TYPE }
|
||||
func (t *Type) Object() types.Object { return t.object }
|
||||
func (t *Type) String() string { return t.RelString(nil) }
|
||||
func (t *Type) Package() *Package { return t.pkg }
|
||||
func (t *Type) RelString(from *types.Package) string { return relString(t, from) }
|
||||
|
||||
func (c *NamedConst) Name() string { return c.object.Name() }
|
||||
func (c *NamedConst) Pos() token.Pos { return c.object.Pos() }
|
||||
func (c *NamedConst) String() string {
|
||||
return fmt.Sprintf("%s.%s", c.object.Pkg().Path(), c.object.Name())
|
||||
}
|
||||
func (c *NamedConst) Type() types.Type { return c.object.Type() }
|
||||
func (c *NamedConst) Token() token.Token { return token.CONST }
|
||||
func (c *NamedConst) Object() types.Object { return c.object }
|
||||
func (c *NamedConst) Name() string { return c.object.Name() }
|
||||
func (c *NamedConst) Pos() token.Pos { return c.object.Pos() }
|
||||
func (c *NamedConst) String() string { return c.RelString(nil) }
|
||||
func (c *NamedConst) Type() types.Type { return c.object.Type() }
|
||||
func (c *NamedConst) Token() token.Token { return token.CONST }
|
||||
func (c *NamedConst) Object() types.Object { return c.object }
|
||||
func (c *NamedConst) Package() *Package { return c.pkg }
|
||||
func (c *NamedConst) RelString(from *types.Package) string { return relString(c, from) }
|
||||
|
||||
// Func returns the package-level function of the specified name,
|
||||
// or nil if not found.
|
||||
|
|
Loading…
Reference in New Issue