1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
7 // This file implements the String() methods for all Value and
18 "golang.org/x/tools/go/types/typeutil"
21 // relName returns the name of v relative to i.
22 // In most cases, this is identical to v.Name(), but references to
23 // Functions (including methods) and Globals use RelString and
24 // all types are displayed with relType, so that only cross-package
25 // references are package-qualified.
27 func relName(v Value, i Instruction) string {
28 var from *types.Package
30 from = i.Parent().pkg()
32 switch v := v.(type) {
33 case Member: // *Function or *Global
34 return v.RelString(from)
36 return v.RelString(from)
41 func relType(t types.Type, from *types.Package) string {
42 return types.TypeString(t, types.RelativeTo(from))
45 func relString(m Member, from *types.Package) string {
46 // NB: not all globals have an Object (e.g. init$guard),
47 // so use Package().Object not Object.Package().
48 if pkg := m.Package().Pkg; pkg != nil && pkg != from {
49 return fmt.Sprintf("%s.%s", pkg.Path(), m.Name())
56 // This method is provided only for debugging.
57 // It never appears in disassembly, which uses Value.Name().
59 func (v *Parameter) String() string {
60 from := v.Parent().pkg()
61 return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from))
64 func (v *FreeVar) String() string {
65 from := v.Parent().pkg()
66 return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from))
69 func (v *Builtin) String() string {
70 return fmt.Sprintf("builtin %s", v.Name())
73 // Instruction.String()
75 func (v *Alloc) String() string {
80 from := v.Parent().pkg()
81 return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment)
84 func (v *Phi) String() string {
86 b.WriteString("phi [")
87 for i, edge := range v.Edges {
91 // Be robust against malformed CFG.
97 if i < len(v.block.Preds) {
98 block = v.block.Preds[i].Index
100 fmt.Fprintf(&b, "%d: ", block)
101 edgeVal := "<nil>" // be robust
103 edgeVal = relName(edge, v)
105 b.WriteString(edgeVal)
110 b.WriteString(v.Comment)
115 func printCall(v *CallCommon, prefix string, instr Instruction) string {
117 b.WriteString(prefix)
119 b.WriteString(relName(v.Value, instr))
121 fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name())
124 for i, arg := range v.Args {
128 b.WriteString(relName(arg, instr))
130 if v.Signature().Variadic() {
137 func (c *CallCommon) String() string {
138 return printCall(c, "", nil)
141 func (v *Call) String() string {
142 return printCall(&v.Call, "", v)
145 func (v *BinOp) String() string {
146 return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v))
149 func (v *UnOp) String() string {
150 return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk))
153 func printConv(prefix string, v, x Value) string {
154 from := v.Parent().pkg()
155 return fmt.Sprintf("%s %s <- %s (%s)",
157 relType(v.Type(), from),
158 relType(x.Type(), from),
159 relName(x, v.(Instruction)))
162 func (v *ChangeType) String() string { return printConv("changetype", v, v.X) }
163 func (v *Convert) String() string { return printConv("convert", v, v.X) }
164 func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) }
165 func (v *MakeInterface) String() string { return printConv("make", v, v.X) }
167 func (v *MakeClosure) String() string {
169 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v))
170 if v.Bindings != nil {
172 for i, c := range v.Bindings {
176 b.WriteString(relName(c, v))
183 func (v *MakeSlice) String() string {
184 from := v.Parent().pkg()
185 return fmt.Sprintf("make %s %s %s",
186 relType(v.Type(), from),
191 func (v *Slice) String() string {
193 b.WriteString("slice ")
194 b.WriteString(relName(v.X, v))
197 b.WriteString(relName(v.Low, v))
201 b.WriteString(relName(v.High, v))
205 b.WriteString(relName(v.Max, v))
211 func (v *MakeMap) String() string {
213 if v.Reserve != nil {
214 res = relName(v.Reserve, v)
216 from := v.Parent().pkg()
217 return fmt.Sprintf("make %s %s", relType(v.Type(), from), res)
220 func (v *MakeChan) String() string {
221 from := v.Parent().pkg()
222 return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v))
225 func (v *FieldAddr) String() string {
226 st := deref(v.X.Type()).Underlying().(*types.Struct)
227 // Be robust against a bad index.
229 if 0 <= v.Field && v.Field < st.NumFields() {
230 name = st.Field(v.Field).Name()
232 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
235 func (v *Field) String() string {
236 st := v.X.Type().Underlying().(*types.Struct)
237 // Be robust against a bad index.
239 if 0 <= v.Field && v.Field < st.NumFields() {
240 name = st.Field(v.Field).Name()
242 return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
245 func (v *IndexAddr) String() string {
246 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v))
249 func (v *Index) String() string {
250 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v))
253 func (v *Lookup) String() string {
254 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk))
257 func (v *Range) String() string {
258 return "range " + relName(v.X, v)
261 func (v *Next) String() string {
262 return "next " + relName(v.Iter, v)
265 func (v *TypeAssert) String() string {
266 from := v.Parent().pkg()
267 return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from))
270 func (v *Extract) String() string {
271 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index)
274 func (s *Jump) String() string {
275 // Be robust against malformed CFG.
277 if s.block != nil && len(s.block.Succs) == 1 {
278 block = s.block.Succs[0].Index
280 return fmt.Sprintf("jump %d", block)
283 func (s *If) String() string {
284 // Be robust against malformed CFG.
285 tblock, fblock := -1, -1
286 if s.block != nil && len(s.block.Succs) == 2 {
287 tblock = s.block.Succs[0].Index
288 fblock = s.block.Succs[1].Index
290 return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock)
293 func (s *Go) String() string {
294 return printCall(&s.Call, "go ", s)
297 func (s *Panic) String() string {
298 return "panic " + relName(s.X, s)
301 func (s *Return) String() string {
303 b.WriteString("return")
304 for i, r := range s.Results {
310 b.WriteString(relName(r, s))
315 func (*RunDefers) String() string {
319 func (s *Send) String() string {
320 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s))
323 func (s *Defer) String() string {
324 return printCall(&s.Call, "defer ", s)
327 func (s *Select) String() string {
329 for i, st := range s.States {
333 if st.Dir == types.RecvOnly {
335 b.WriteString(relName(st.Chan, s))
337 b.WriteString(relName(st.Chan, s))
339 b.WriteString(relName(st.Send, s))
346 return fmt.Sprintf("select %sblocking [%s]", non, b.String())
349 func (s *Store) String() string {
350 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s))
353 func (s *MapUpdate) String() string {
354 return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
357 func (s *DebugRef) String() string {
358 p := s.Parent().Prog.Fset.Position(s.Pos())
359 var descr interface{}
361 descr = s.object // e.g. "var x int"
363 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr"
369 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name())
372 func (p *Package) String() string {
373 return "package " + p.Pkg.Path()
376 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer
378 func (p *Package) WriteTo(w io.Writer) (int64, error) {
380 WritePackage(&buf, p)
381 n, err := w.Write(buf.Bytes())
385 // WritePackage writes to buf a human-readable summary of p.
386 func WritePackage(buf *bytes.Buffer, p *Package) {
387 fmt.Fprintf(buf, "%s:\n", p)
391 for name := range p.Members {
392 if l := len(name); l > maxname {
395 names = append(names, name)
400 for _, name := range names {
401 switch mem := p.Members[name].(type) {
403 fmt.Fprintf(buf, " const %-*s %s = %s\n",
404 maxname, name, mem.Name(), mem.Value.RelString(from))
407 fmt.Fprintf(buf, " func %-*s %s\n",
408 maxname, name, relType(mem.Type(), from))
411 fmt.Fprintf(buf, " type %-*s %s\n",
412 maxname, name, relType(mem.Type().Underlying(), from))
413 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
414 fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from)))
418 fmt.Fprintf(buf, " var %-*s %s\n",
419 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from))
423 fmt.Fprintf(buf, "\n")
426 func commaOk(x bool) string {