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 {
31 var from *types.Package
33 from = i.Parent().pkg()
35 switch v := v.(type) {
36 case Member: // *Function or *Global
37 return v.RelString(from)
42 func relType(t types.Type, from *types.Package) string {
43 return types.TypeString(t, types.RelativeTo(from))
46 func relString(m Member, from *types.Package) string {
47 // NB: not all globals have an Object (e.g. init$guard),
48 // so use Package().Object not Object.Package().
49 if pkg := m.Package().Pkg; pkg != nil && pkg != from {
50 return fmt.Sprintf("%s.%s", pkg.Path(), m.Name())
57 // This method is provided only for debugging.
58 // It never appears in disassembly, which uses Value.Name().
60 func (v *Parameter) String() string {
61 from := v.Parent().pkg()
62 return fmt.Sprintf("Parameter <%s> {%s}", relType(v.Type(), from), v.name)
65 func (v *FreeVar) String() string {
66 from := v.Parent().pkg()
67 return fmt.Sprintf("FreeVar <%s> %s", relType(v.Type(), from), v.Name())
70 func (v *Builtin) String() string {
71 return fmt.Sprintf("Builtin %s", v.Name())
74 // Instruction.String()
76 func (v *Alloc) String() string {
77 from := v.Parent().pkg()
82 return fmt.Sprintf("%sAlloc <%s>", storage, relType(v.Type(), from))
85 func (v *Sigma) String() string {
86 from := v.Parent().pkg()
87 s := fmt.Sprintf("Sigma <%s> [b%d] %s", relType(v.Type(), from), v.From.Index, v.X.Name())
91 func (v *Phi) String() string {
93 fmt.Fprintf(&b, "Phi <%s>", v.Type())
94 for i, edge := range v.Edges {
96 // Be robust against malformed CFG.
102 if i < len(v.block.Preds) {
103 block = v.block.Preds[i].Index
105 fmt.Fprintf(&b, "%d:", block)
106 edgeVal := "<nil>" // be robust
108 edgeVal = relName(edge, v)
110 b.WriteString(edgeVal)
115 func printCall(v *CallCommon, prefix string, instr Instruction) string {
118 if value, ok := instr.(Value); ok {
119 fmt.Fprintf(&b, "%s <%s> %s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr))
121 fmt.Fprintf(&b, "%s %s", prefix, relName(v.Value, instr))
124 if value, ok := instr.(Value); ok {
125 fmt.Fprintf(&b, "%sInvoke <%s> %s.%s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr), v.Method.Name())
127 fmt.Fprintf(&b, "%sInvoke %s.%s", prefix, relName(v.Value, instr), v.Method.Name())
130 for _, arg := range v.Args {
132 b.WriteString(relName(arg, instr))
137 func (c *CallCommon) String() string {
138 return printCall(c, "", nil)
141 func (v *Call) String() string {
142 return printCall(&v.Call, "Call", v)
145 func (v *BinOp) String() string {
146 return fmt.Sprintf("BinOp <%s> {%s} %s %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v), relName(v.Y, v))
149 func (v *UnOp) String() string {
150 return fmt.Sprintf("UnOp <%s> {%s} %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v))
153 func (v *Load) String() string {
154 return fmt.Sprintf("Load <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v))
157 func printConv(prefix string, v, x Value) string {
158 from := v.Parent().pkg()
159 return fmt.Sprintf("%s <%s> %s",
161 relType(v.Type(), from),
162 relName(x, v.(Instruction)))
165 func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) }
166 func (v *Convert) String() string { return printConv("Convert", v, v.X) }
167 func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) }
168 func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }
170 func (v *MakeClosure) String() string {
171 from := v.Parent().pkg()
173 fmt.Fprintf(&b, "MakeClosure <%s> %s", relType(v.Type(), from), relName(v.Fn, v))
174 if v.Bindings != nil {
175 for _, c := range v.Bindings {
177 b.WriteString(relName(c, v))
183 func (v *MakeSlice) String() string {
184 from := v.Parent().pkg()
185 return fmt.Sprintf("MakeSlice <%s> %s %s",
186 relType(v.Type(), from),
191 func (v *Slice) String() string {
192 from := v.Parent().pkg()
193 return fmt.Sprintf("Slice <%s> %s %s %s %s",
194 relType(v.Type(), from), relName(v.X, v), relName(v.Low, v), relName(v.High, v), relName(v.Max, v))
197 func (v *MakeMap) String() string {
199 if v.Reserve != nil {
200 res = relName(v.Reserve, v)
202 from := v.Parent().pkg()
203 return fmt.Sprintf("MakeMap <%s> %s", relType(v.Type(), from), res)
206 func (v *MakeChan) String() string {
207 from := v.Parent().pkg()
208 return fmt.Sprintf("MakeChan <%s> %s", relType(v.Type(), from), relName(v.Size, v))
211 func (v *FieldAddr) String() string {
212 from := v.Parent().pkg()
213 st := deref(v.X.Type()).Underlying().(*types.Struct)
214 // Be robust against a bad index.
216 if 0 <= v.Field && v.Field < st.NumFields() {
217 name = st.Field(v.Field).Name()
219 return fmt.Sprintf("FieldAddr <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v))
222 func (v *Field) String() string {
223 st := v.X.Type().Underlying().(*types.Struct)
224 // Be robust against a bad index.
226 if 0 <= v.Field && v.Field < st.NumFields() {
227 name = st.Field(v.Field).Name()
229 from := v.Parent().pkg()
230 return fmt.Sprintf("Field <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v))
233 func (v *IndexAddr) String() string {
234 from := v.Parent().pkg()
235 return fmt.Sprintf("IndexAddr <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
238 func (v *Index) String() string {
239 from := v.Parent().pkg()
240 return fmt.Sprintf("Index <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
243 func (v *MapLookup) String() string {
244 from := v.Parent().pkg()
245 return fmt.Sprintf("MapLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
248 func (v *StringLookup) String() string {
249 from := v.Parent().pkg()
250 return fmt.Sprintf("StringLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
253 func (v *Range) String() string {
254 from := v.Parent().pkg()
255 return fmt.Sprintf("Range <%s> %s", relType(v.Type(), from), relName(v.X, v))
258 func (v *Next) String() string {
259 from := v.Parent().pkg()
260 return fmt.Sprintf("Next <%s> %s", relType(v.Type(), from), relName(v.Iter, v))
263 func (v *TypeAssert) String() string {
264 from := v.Parent().pkg()
265 return fmt.Sprintf("TypeAssert <%s> %s", relType(v.Type(), from), relName(v.X, v))
268 func (v *Extract) String() string {
269 from := v.Parent().pkg()
270 name := v.Tuple.Type().(*types.Tuple).At(v.Index).Name()
271 return fmt.Sprintf("Extract <%s> [%d] (%s) %s", relType(v.Type(), from), v.Index, name, relName(v.Tuple, v))
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 str := fmt.Sprintf("Jump → b%d", block)
282 str = fmt.Sprintf("%s # %s", str, s.Comment)
287 func (s *Unreachable) String() string {
288 // Be robust against malformed CFG.
290 if s.block != nil && len(s.block.Succs) == 1 {
291 block = s.block.Succs[0].Index
293 return fmt.Sprintf("Unreachable → b%d", block)
296 func (s *If) String() string {
297 // Be robust against malformed CFG.
298 tblock, fblock := -1, -1
299 if s.block != nil && len(s.block.Succs) == 2 {
300 tblock = s.block.Succs[0].Index
301 fblock = s.block.Succs[1].Index
303 return fmt.Sprintf("If %s → b%d b%d", relName(s.Cond, s), tblock, fblock)
306 func (s *ConstantSwitch) String() string {
308 fmt.Fprintf(&b, "ConstantSwitch %s", relName(s.Tag, s))
309 for _, cond := range s.Conds {
310 fmt.Fprintf(&b, " %s", relName(cond, s))
313 for _, succ := range s.block.Succs {
314 fmt.Fprintf(&b, " b%d", succ.Index)
319 func (s *TypeSwitch) String() string {
320 from := s.Parent().pkg()
322 fmt.Fprintf(&b, "TypeSwitch <%s> %s", relType(s.typ, from), relName(s.Tag, s))
323 for _, cond := range s.Conds {
324 fmt.Fprintf(&b, " %q", relType(cond, s.block.parent.pkg()))
329 func (s *Go) String() string {
330 return printCall(&s.Call, "Go", s)
333 func (s *Panic) String() string {
334 // Be robust against malformed CFG.
336 if s.block != nil && len(s.block.Succs) == 1 {
337 block = s.block.Succs[0].Index
339 return fmt.Sprintf("Panic %s → b%d", relName(s.X, s), block)
342 func (s *Return) String() string {
344 b.WriteString("Return")
345 for _, r := range s.Results {
347 b.WriteString(relName(r, s))
352 func (*RunDefers) String() string {
356 func (s *Send) String() string {
357 return fmt.Sprintf("Send %s %s", relName(s.Chan, s), relName(s.X, s))
360 func (recv *Recv) String() string {
361 from := recv.Parent().pkg()
362 return fmt.Sprintf("Recv <%s> %s", relType(recv.Type(), from), relName(recv.Chan, recv))
365 func (s *Defer) String() string {
366 return printCall(&s.Call, "Defer", s)
369 func (s *Select) String() string {
371 for i, st := range s.States {
375 if st.Dir == types.RecvOnly {
377 b.WriteString(relName(st.Chan, s))
379 b.WriteString(relName(st.Chan, s))
381 b.WriteString(relName(st.Send, s))
388 from := s.Parent().pkg()
389 return fmt.Sprintf("Select%sBlocking <%s> [%s]", non, relType(s.Type(), from), b.String())
392 func (s *Store) String() string {
393 return fmt.Sprintf("Store {%s} %s %s",
394 s.Val.Type(), relName(s.Addr, s), relName(s.Val, s))
397 func (s *BlankStore) String() string {
398 return fmt.Sprintf("BlankStore %s", relName(s.Val, s))
401 func (s *MapUpdate) String() string {
402 return fmt.Sprintf("MapUpdate %s %s %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
405 func (s *DebugRef) String() string {
406 p := s.Parent().Prog.Fset.Position(s.Pos())
407 var descr interface{}
409 descr = s.object // e.g. "var x int"
411 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr"
417 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name())
420 func (p *Package) String() string {
421 return "package " + p.Pkg.Path()
424 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer
426 func (p *Package) WriteTo(w io.Writer) (int64, error) {
428 WritePackage(&buf, p)
429 n, err := w.Write(buf.Bytes())
433 // WritePackage writes to buf a human-readable summary of p.
434 func WritePackage(buf *bytes.Buffer, p *Package) {
435 fmt.Fprintf(buf, "%s:\n", p)
439 for name := range p.Members {
440 if l := len(name); l > maxname {
443 names = append(names, name)
448 for _, name := range names {
449 switch mem := p.Members[name].(type) {
451 fmt.Fprintf(buf, " const %-*s %s = %s\n",
452 maxname, name, mem.Name(), mem.Value.RelString(from))
455 fmt.Fprintf(buf, " func %-*s %s\n",
456 maxname, name, relType(mem.Type(), from))
459 fmt.Fprintf(buf, " type %-*s %s\n",
460 maxname, name, relType(mem.Type().Underlying(), from))
461 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
462 fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from)))
466 fmt.Fprintf(buf, " var %-*s %s\n",
467 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from))
471 fmt.Fprintf(buf, "\n")