| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package ssa
- // This file implements the String() methods for all Value and
- // Instruction types.
- import (
- "bytes"
- "fmt"
- "go/types"
- "io"
- "reflect"
- "sort"
- "golang.org/x/tools/go/types/typeutil"
- )
- // relName returns the name of v relative to i.
- // 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().pkg()
- }
- switch v := v.(type) {
- case Member: // *Function or *Global
- return v.RelString(from)
- case *Const:
- return v.RelString(from)
- }
- return v.Name()
- }
- func relType(t types.Type, from *types.Package) string {
- return types.TypeString(t, types.RelativeTo(from))
- }
- 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 pkg := m.Package().Pkg; pkg != nil && pkg != from {
- return fmt.Sprintf("%s.%s", pkg.Path(), m.Name())
- }
- return m.Name()
- }
- // Value.String()
- //
- // This method is provided only for debugging.
- // It never appears in disassembly, which uses Value.Name().
- func (v *Parameter) String() string {
- from := v.Parent().pkg()
- return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from))
- }
- func (v *FreeVar) String() string {
- from := v.Parent().pkg()
- return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from))
- }
- func (v *Builtin) String() string {
- return fmt.Sprintf("builtin %s", v.Name())
- }
- // Instruction.String()
- func (v *Alloc) String() string {
- op := "local"
- if v.Heap {
- op = "new"
- }
- from := v.Parent().pkg()
- return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment)
- }
- func (v *Phi) String() string {
- var b bytes.Buffer
- b.WriteString("phi [")
- for i, edge := range v.Edges {
- if i > 0 {
- b.WriteString(", ")
- }
- // Be robust against malformed CFG.
- if v.block == nil {
- b.WriteString("??")
- continue
- }
- block := -1
- if i < len(v.block.Preds) {
- block = v.block.Preds[i].Index
- }
- fmt.Fprintf(&b, "%d: ", block)
- edgeVal := "<nil>" // be robust
- if edge != nil {
- edgeVal = relName(edge, v)
- }
- b.WriteString(edgeVal)
- }
- b.WriteString("]")
- if v.Comment != "" {
- b.WriteString(" #")
- b.WriteString(v.Comment)
- }
- return b.String()
- }
- func printCall(v *CallCommon, prefix string, instr Instruction) string {
- var b bytes.Buffer
- b.WriteString(prefix)
- if !v.IsInvoke() {
- b.WriteString(relName(v.Value, instr))
- } else {
- fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name())
- }
- b.WriteString("(")
- for i, arg := range v.Args {
- if i > 0 {
- b.WriteString(", ")
- }
- b.WriteString(relName(arg, instr))
- }
- if v.Signature().Variadic() {
- b.WriteString("...")
- }
- b.WriteString(")")
- return b.String()
- }
- func (c *CallCommon) String() string {
- return printCall(c, "", nil)
- }
- func (v *Call) String() string {
- return printCall(&v.Call, "", v)
- }
- func (v *BinOp) String() string {
- return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v))
- }
- func (v *UnOp) String() string {
- return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk))
- }
- func printConv(prefix string, v, x Value) string {
- from := v.Parent().pkg()
- return fmt.Sprintf("%s %s <- %s (%s)",
- prefix,
- relType(v.Type(), from),
- relType(x.Type(), from),
- relName(x, v.(Instruction)))
- }
- func (v *ChangeType) String() string { return printConv("changetype", v, v.X) }
- func (v *Convert) String() string { return printConv("convert", v, v.X) }
- func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) }
- func (v *MakeInterface) String() string { return printConv("make", v, v.X) }
- func (v *MakeClosure) String() string {
- var b bytes.Buffer
- fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v))
- if v.Bindings != nil {
- b.WriteString(" [")
- for i, c := range v.Bindings {
- if i > 0 {
- b.WriteString(", ")
- }
- b.WriteString(relName(c, v))
- }
- b.WriteString("]")
- }
- return b.String()
- }
- func (v *MakeSlice) String() string {
- from := v.Parent().pkg()
- return fmt.Sprintf("make %s %s %s",
- relType(v.Type(), from),
- relName(v.Len, v),
- relName(v.Cap, v))
- }
- func (v *Slice) String() string {
- var b bytes.Buffer
- b.WriteString("slice ")
- b.WriteString(relName(v.X, v))
- b.WriteString("[")
- if v.Low != nil {
- b.WriteString(relName(v.Low, v))
- }
- b.WriteString(":")
- if v.High != nil {
- b.WriteString(relName(v.High, v))
- }
- if v.Max != nil {
- b.WriteString(":")
- b.WriteString(relName(v.Max, v))
- }
- b.WriteString("]")
- return b.String()
- }
- func (v *MakeMap) String() string {
- res := ""
- if v.Reserve != nil {
- res = relName(v.Reserve, v)
- }
- from := v.Parent().pkg()
- return fmt.Sprintf("make %s %s", relType(v.Type(), from), res)
- }
- func (v *MakeChan) String() string {
- from := v.Parent().pkg()
- return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v))
- }
- func (v *FieldAddr) String() string {
- st := deref(v.X.Type()).Underlying().(*types.Struct)
- // Be robust against a bad index.
- name := "?"
- if 0 <= v.Field && v.Field < st.NumFields() {
- name = st.Field(v.Field).Name()
- }
- return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
- }
- func (v *Field) String() string {
- st := v.X.Type().Underlying().(*types.Struct)
- // Be robust against a bad index.
- name := "?"
- if 0 <= v.Field && v.Field < st.NumFields() {
- name = st.Field(v.Field).Name()
- }
- return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
- }
- func (v *IndexAddr) String() string {
- return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v))
- }
- func (v *Index) String() string {
- return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v))
- }
- func (v *Lookup) String() string {
- return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk))
- }
- func (v *Range) String() string {
- return "range " + relName(v.X, v)
- }
- func (v *Next) String() string {
- return "next " + relName(v.Iter, v)
- }
- func (v *TypeAssert) String() string {
- from := v.Parent().pkg()
- return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from))
- }
- func (v *Extract) String() string {
- return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index)
- }
- func (s *Jump) String() string {
- // Be robust against malformed CFG.
- block := -1
- if s.block != nil && len(s.block.Succs) == 1 {
- block = s.block.Succs[0].Index
- }
- return fmt.Sprintf("jump %d", block)
- }
- func (s *If) String() string {
- // Be robust against malformed CFG.
- tblock, fblock := -1, -1
- if s.block != nil && len(s.block.Succs) == 2 {
- tblock = s.block.Succs[0].Index
- fblock = s.block.Succs[1].Index
- }
- return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock)
- }
- func (s *Go) String() string {
- return printCall(&s.Call, "go ", s)
- }
- func (s *Panic) String() string {
- return "panic " + relName(s.X, s)
- }
- func (s *Return) String() string {
- var b bytes.Buffer
- b.WriteString("return")
- for i, r := range s.Results {
- if i == 0 {
- b.WriteString(" ")
- } else {
- b.WriteString(", ")
- }
- b.WriteString(relName(r, s))
- }
- return b.String()
- }
- func (*RunDefers) String() string {
- return "rundefers"
- }
- func (s *Send) String() string {
- return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s))
- }
- func (s *Defer) String() string {
- return printCall(&s.Call, "defer ", s)
- }
- func (s *Select) String() string {
- var b bytes.Buffer
- for i, st := range s.States {
- if i > 0 {
- b.WriteString(", ")
- }
- if st.Dir == types.RecvOnly {
- b.WriteString("<-")
- b.WriteString(relName(st.Chan, s))
- } else {
- b.WriteString(relName(st.Chan, s))
- b.WriteString("<-")
- b.WriteString(relName(st.Send, s))
- }
- }
- non := ""
- if !s.Blocking {
- non = "non"
- }
- return fmt.Sprintf("select %sblocking [%s]", non, b.String())
- }
- func (s *Store) String() string {
- return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s))
- }
- func (s *BlankStore) String() string {
- return fmt.Sprintf("_ = %s", relName(s.Val, s))
- }
- func (s *MapUpdate) String() string {
- return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
- }
- func (s *DebugRef) String() string {
- p := s.Parent().Prog.Fset.Position(s.Pos())
- var descr interface{}
- if s.object != nil {
- descr = s.object // e.g. "var x int"
- } else {
- descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr"
- }
- var addr string
- if s.IsAddr {
- addr = "address of "
- }
- return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name())
- }
- func (p *Package) String() string {
- return "package " + p.Pkg.Path()
- }
- var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer
- func (p *Package) WriteTo(w io.Writer) (int64, error) {
- var buf bytes.Buffer
- WritePackage(&buf, p)
- n, err := w.Write(buf.Bytes())
- return int64(n), err
- }
- // WritePackage writes to buf a human-readable summary of p.
- func WritePackage(buf *bytes.Buffer, p *Package) {
- fmt.Fprintf(buf, "%s:\n", p)
- var names []string
- maxname := 0
- for name := range p.Members {
- if l := len(name); l > maxname {
- maxname = l
- }
- names = append(names, name)
- }
- from := p.Pkg
- sort.Strings(names)
- for _, name := range names {
- switch mem := p.Members[name].(type) {
- case *NamedConst:
- fmt.Fprintf(buf, " const %-*s %s = %s\n",
- maxname, name, mem.Name(), mem.Value.RelString(from))
- case *Function:
- fmt.Fprintf(buf, " func %-*s %s\n",
- maxname, name, relType(mem.Type(), from))
- case *Type:
- 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(meth, types.RelativeTo(from)))
- }
- case *Global:
- fmt.Fprintf(buf, " var %-*s %s\n",
- maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from))
- }
- }
- fmt.Fprintf(buf, "\n")
- }
- func commaOk(x bool) string {
- if x {
- return ",ok"
- }
- return ""
- }
|