print.go (11055B)
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. 4 5 package ssa 6 7 // This file implements the String() methods for all Value and 8 // Instruction types. 9 10 import ( 11 "bytes" 12 "fmt" 13 "go/types" 14 "io" 15 "reflect" 16 "sort" 17 "strings" 18 19 "golang.org/x/tools/go/types/typeutil" 20 "golang.org/x/tools/internal/typeparams" 21 ) 22 23 // relName returns the name of v relative to i. 24 // In most cases, this is identical to v.Name(), but references to 25 // Functions (including methods) and Globals use RelString and 26 // all types are displayed with relType, so that only cross-package 27 // references are package-qualified. 28 func relName(v Value, i Instruction) string { 29 var from *types.Package 30 if i != nil { 31 from = i.Parent().relPkg() 32 } 33 switch v := v.(type) { 34 case Member: // *Function or *Global 35 return v.RelString(from) 36 case *Const: 37 return v.RelString(from) 38 } 39 return v.Name() 40 } 41 42 func relType(t types.Type, from *types.Package) string { 43 return types.TypeString(t, types.RelativeTo(from)) 44 } 45 46 func relTerm(term *types.Term, from *types.Package) string { 47 s := relType(term.Type(), from) 48 if term.Tilde() { 49 return "~" + s 50 } 51 return s 52 } 53 54 func relString(m Member, from *types.Package) string { 55 // NB: not all globals have an Object (e.g. init$guard), 56 // so use Package().Object not Object.Package(). 57 if pkg := m.Package().Pkg; pkg != nil && pkg != from { 58 return fmt.Sprintf("%s.%s", pkg.Path(), m.Name()) 59 } 60 return m.Name() 61 } 62 63 // Value.String() 64 // 65 // This method is provided only for debugging. 66 // It never appears in disassembly, which uses Value.Name(). 67 68 func (v *Parameter) String() string { 69 from := v.Parent().relPkg() 70 return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from)) 71 } 72 73 func (v *FreeVar) String() string { 74 from := v.Parent().relPkg() 75 return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from)) 76 } 77 78 func (v *Builtin) String() string { 79 return fmt.Sprintf("builtin %s", v.Name()) 80 } 81 82 // Instruction.String() 83 84 func (v *Alloc) String() string { 85 op := "local" 86 if v.Heap { 87 op = "new" 88 } 89 from := v.Parent().relPkg() 90 return fmt.Sprintf("%s %s (%s)", op, relType(typeparams.MustDeref(v.Type()), from), v.Comment) 91 } 92 93 func (v *Phi) String() string { 94 var b bytes.Buffer 95 b.WriteString("phi [") 96 for i, edge := range v.Edges { 97 if i > 0 { 98 b.WriteString(", ") 99 } 100 // Be robust against malformed CFG. 101 if v.block == nil { 102 b.WriteString("??") 103 continue 104 } 105 block := -1 106 if i < len(v.block.Preds) { 107 block = v.block.Preds[i].Index 108 } 109 fmt.Fprintf(&b, "%d: ", block) 110 edgeVal := "<nil>" // be robust 111 if edge != nil { 112 edgeVal = relName(edge, v) 113 } 114 b.WriteString(edgeVal) 115 } 116 b.WriteString("]") 117 if v.Comment != "" { 118 b.WriteString(" #") 119 b.WriteString(v.Comment) 120 } 121 return b.String() 122 } 123 124 func printCall(v *CallCommon, prefix string, instr Instruction) string { 125 var b bytes.Buffer 126 b.WriteString(prefix) 127 if !v.IsInvoke() { 128 b.WriteString(relName(v.Value, instr)) 129 } else { 130 fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name()) 131 } 132 b.WriteString("(") 133 for i, arg := range v.Args { 134 if i > 0 { 135 b.WriteString(", ") 136 } 137 b.WriteString(relName(arg, instr)) 138 } 139 if v.Signature().Variadic() { 140 b.WriteString("...") 141 } 142 b.WriteString(")") 143 return b.String() 144 } 145 146 func (c *CallCommon) String() string { 147 return printCall(c, "", nil) 148 } 149 150 func (v *Call) String() string { 151 return printCall(&v.Call, "", v) 152 } 153 154 func (v *BinOp) String() string { 155 return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v)) 156 } 157 158 func (v *UnOp) String() string { 159 return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk)) 160 } 161 162 func printConv(prefix string, v, x Value) string { 163 from := v.Parent().relPkg() 164 return fmt.Sprintf("%s %s <- %s (%s)", 165 prefix, 166 relType(v.Type(), from), 167 relType(x.Type(), from), 168 relName(x, v.(Instruction))) 169 } 170 171 func (v *ChangeType) String() string { return printConv("changetype", v, v.X) } 172 func (v *Convert) String() string { return printConv("convert", v, v.X) } 173 func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) } 174 func (v *SliceToArrayPointer) String() string { return printConv("slice to array pointer", v, v.X) } 175 func (v *MakeInterface) String() string { return printConv("make", v, v.X) } 176 177 func (v *MultiConvert) String() string { 178 from := v.Parent().relPkg() 179 180 var b strings.Builder 181 b.WriteString(printConv("multiconvert", v, v.X)) 182 b.WriteString(" [") 183 for i, s := range termListOf(v.from) { 184 for j, d := range termListOf(v.to) { 185 if i != 0 || j != 0 { 186 b.WriteString(" | ") 187 } 188 fmt.Fprintf(&b, "%s <- %s", relTerm(d, from), relTerm(s, from)) 189 } 190 } 191 b.WriteString("]") 192 return b.String() 193 } 194 195 func (v *MakeClosure) String() string { 196 var b bytes.Buffer 197 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v)) 198 if v.Bindings != nil { 199 b.WriteString(" [") 200 for i, c := range v.Bindings { 201 if i > 0 { 202 b.WriteString(", ") 203 } 204 b.WriteString(relName(c, v)) 205 } 206 b.WriteString("]") 207 } 208 return b.String() 209 } 210 211 func (v *MakeSlice) String() string { 212 from := v.Parent().relPkg() 213 return fmt.Sprintf("make %s %s %s", 214 relType(v.Type(), from), 215 relName(v.Len, v), 216 relName(v.Cap, v)) 217 } 218 219 func (v *Slice) String() string { 220 var b bytes.Buffer 221 b.WriteString("slice ") 222 b.WriteString(relName(v.X, v)) 223 b.WriteString("[") 224 if v.Low != nil { 225 b.WriteString(relName(v.Low, v)) 226 } 227 b.WriteString(":") 228 if v.High != nil { 229 b.WriteString(relName(v.High, v)) 230 } 231 if v.Max != nil { 232 b.WriteString(":") 233 b.WriteString(relName(v.Max, v)) 234 } 235 b.WriteString("]") 236 return b.String() 237 } 238 239 func (v *MakeMap) String() string { 240 res := "" 241 if v.Reserve != nil { 242 res = relName(v.Reserve, v) 243 } 244 from := v.Parent().relPkg() 245 return fmt.Sprintf("make %s %s", relType(v.Type(), from), res) 246 } 247 248 func (v *MakeChan) String() string { 249 from := v.Parent().relPkg() 250 return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v)) 251 } 252 253 func (v *FieldAddr) String() string { 254 // Be robust against a bad index. 255 name := "?" 256 if fld := fieldOf(typeparams.MustDeref(v.X.Type()), v.Field); fld != nil { 257 name = fld.Name() 258 } 259 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) 260 } 261 262 func (v *Field) String() string { 263 // Be robust against a bad index. 264 name := "?" 265 if fld := fieldOf(v.X.Type(), v.Field); fld != nil { 266 name = fld.Name() 267 } 268 return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) 269 } 270 271 func (v *IndexAddr) String() string { 272 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v)) 273 } 274 275 func (v *Index) String() string { 276 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) 277 } 278 279 func (v *Lookup) String() string { 280 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk)) 281 } 282 283 func (v *Range) String() string { 284 return "range " + relName(v.X, v) 285 } 286 287 func (v *Next) String() string { 288 return "next " + relName(v.Iter, v) 289 } 290 291 func (v *TypeAssert) String() string { 292 from := v.Parent().relPkg() 293 return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from)) 294 } 295 296 func (v *Extract) String() string { 297 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index) 298 } 299 300 func (s *Jump) String() string { 301 // Be robust against malformed CFG. 302 block := -1 303 if s.block != nil && len(s.block.Succs) == 1 { 304 block = s.block.Succs[0].Index 305 } 306 return fmt.Sprintf("jump %d", block) 307 } 308 309 func (s *If) String() string { 310 // Be robust against malformed CFG. 311 tblock, fblock := -1, -1 312 if s.block != nil && len(s.block.Succs) == 2 { 313 tblock = s.block.Succs[0].Index 314 fblock = s.block.Succs[1].Index 315 } 316 return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock) 317 } 318 319 func (s *Go) String() string { 320 return printCall(&s.Call, "go ", s) 321 } 322 323 func (s *Panic) String() string { 324 return "panic " + relName(s.X, s) 325 } 326 327 func (s *Return) String() string { 328 var b bytes.Buffer 329 b.WriteString("return") 330 for i, r := range s.Results { 331 if i == 0 { 332 b.WriteString(" ") 333 } else { 334 b.WriteString(", ") 335 } 336 b.WriteString(relName(r, s)) 337 } 338 return b.String() 339 } 340 341 func (*RunDefers) String() string { 342 return "rundefers" 343 } 344 345 func (s *Send) String() string { 346 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s)) 347 } 348 349 func (s *Defer) String() string { 350 prefix := "defer " 351 if s.DeferStack != nil { 352 prefix += "[" + relName(s.DeferStack, s) + "] " 353 } 354 c := printCall(&s.Call, prefix, s) 355 return c 356 } 357 358 func (s *Select) String() string { 359 var b bytes.Buffer 360 for i, st := range s.States { 361 if i > 0 { 362 b.WriteString(", ") 363 } 364 if st.Dir == types.RecvOnly { 365 b.WriteString("<-") 366 b.WriteString(relName(st.Chan, s)) 367 } else { 368 b.WriteString(relName(st.Chan, s)) 369 b.WriteString("<-") 370 b.WriteString(relName(st.Send, s)) 371 } 372 } 373 non := "" 374 if !s.Blocking { 375 non = "non" 376 } 377 return fmt.Sprintf("select %sblocking [%s]", non, b.String()) 378 } 379 380 func (s *Store) String() string { 381 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s)) 382 } 383 384 func (s *MapUpdate) String() string { 385 return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) 386 } 387 388 func (s *DebugRef) String() string { 389 p := s.Parent().Prog.Fset.Position(s.Pos()) 390 var descr any 391 if s.object != nil { 392 descr = s.object // e.g. "var x int" 393 } else { 394 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr" 395 } 396 var addr string 397 if s.IsAddr { 398 addr = "address of " 399 } 400 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name()) 401 } 402 403 func (p *Package) String() string { 404 return "package " + p.Pkg.Path() 405 } 406 407 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer 408 409 func (p *Package) WriteTo(w io.Writer) (int64, error) { 410 var buf bytes.Buffer 411 WritePackage(&buf, p) 412 n, err := w.Write(buf.Bytes()) 413 return int64(n), err 414 } 415 416 // WritePackage writes to buf a human-readable summary of p. 417 func WritePackage(buf *bytes.Buffer, p *Package) { 418 fmt.Fprintf(buf, "%s:\n", p) 419 420 var names []string 421 maxname := 0 422 for name := range p.Members { 423 if l := len(name); l > maxname { 424 maxname = l 425 } 426 names = append(names, name) 427 } 428 429 from := p.Pkg 430 sort.Strings(names) 431 for _, name := range names { 432 switch mem := p.Members[name].(type) { 433 case *NamedConst: 434 fmt.Fprintf(buf, " const %-*s %s = %s\n", 435 maxname, name, mem.Name(), mem.Value.RelString(from)) 436 437 case *Function: 438 fmt.Fprintf(buf, " func %-*s %s\n", 439 maxname, name, relType(mem.Type(), from)) 440 441 case *Type: 442 fmt.Fprintf(buf, " type %-*s %s\n", 443 maxname, name, relType(mem.Type().Underlying(), from)) 444 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) { 445 fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from))) 446 } 447 448 case *Global: 449 fmt.Fprintf(buf, " var %-*s %s\n", 450 maxname, name, relType(typeparams.MustDeref(mem.Type()), from)) 451 } 452 } 453 454 fmt.Fprintf(buf, "\n") 455 } 456 457 func commaOk(x bool) string { 458 if x { 459 return ",ok" 460 } 461 return "" 462 }