github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/print.go (about) 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 "github.com/powerman/golang-tools/go/types/typeutil" 20 ) 21 22 // relName returns the name of v relative to i. 23 // In most cases, this is identical to v.Name(), but references to 24 // Functions (including methods) and Globals use RelString and 25 // all types are displayed with relType, so that only cross-package 26 // references are package-qualified. 27 // 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 // normalizeAnyFortesting controls whether we replace occurrences of 43 // interface{} with any. It is only used for normalizing test output. 44 var normalizeAnyForTesting bool 45 46 func relType(t types.Type, from *types.Package) string { 47 s := types.TypeString(t, types.RelativeTo(from)) 48 if normalizeAnyForTesting { 49 s = strings.ReplaceAll(s, "interface{}", "any") 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(deref(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 *MakeClosure) String() string { 178 var b bytes.Buffer 179 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v)) 180 if v.Bindings != nil { 181 b.WriteString(" [") 182 for i, c := range v.Bindings { 183 if i > 0 { 184 b.WriteString(", ") 185 } 186 b.WriteString(relName(c, v)) 187 } 188 b.WriteString("]") 189 } 190 return b.String() 191 } 192 193 func (v *MakeSlice) String() string { 194 from := v.Parent().relPkg() 195 return fmt.Sprintf("make %s %s %s", 196 relType(v.Type(), from), 197 relName(v.Len, v), 198 relName(v.Cap, v)) 199 } 200 201 func (v *Slice) String() string { 202 var b bytes.Buffer 203 b.WriteString("slice ") 204 b.WriteString(relName(v.X, v)) 205 b.WriteString("[") 206 if v.Low != nil { 207 b.WriteString(relName(v.Low, v)) 208 } 209 b.WriteString(":") 210 if v.High != nil { 211 b.WriteString(relName(v.High, v)) 212 } 213 if v.Max != nil { 214 b.WriteString(":") 215 b.WriteString(relName(v.Max, v)) 216 } 217 b.WriteString("]") 218 return b.String() 219 } 220 221 func (v *MakeMap) String() string { 222 res := "" 223 if v.Reserve != nil { 224 res = relName(v.Reserve, v) 225 } 226 from := v.Parent().relPkg() 227 return fmt.Sprintf("make %s %s", relType(v.Type(), from), res) 228 } 229 230 func (v *MakeChan) String() string { 231 from := v.Parent().relPkg() 232 return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v)) 233 } 234 235 func (v *FieldAddr) String() string { 236 st := deref(v.X.Type()).Underlying().(*types.Struct) 237 // Be robust against a bad index. 238 name := "?" 239 if 0 <= v.Field && v.Field < st.NumFields() { 240 name = st.Field(v.Field).Name() 241 } 242 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) 243 } 244 245 func (v *Field) String() string { 246 st := v.X.Type().Underlying().(*types.Struct) 247 // Be robust against a bad index. 248 name := "?" 249 if 0 <= v.Field && v.Field < st.NumFields() { 250 name = st.Field(v.Field).Name() 251 } 252 return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) 253 } 254 255 func (v *IndexAddr) String() string { 256 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v)) 257 } 258 259 func (v *Index) String() string { 260 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) 261 } 262 263 func (v *Lookup) String() string { 264 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk)) 265 } 266 267 func (v *Range) String() string { 268 return "range " + relName(v.X, v) 269 } 270 271 func (v *Next) String() string { 272 return "next " + relName(v.Iter, v) 273 } 274 275 func (v *TypeAssert) String() string { 276 from := v.Parent().relPkg() 277 return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from)) 278 } 279 280 func (v *Extract) String() string { 281 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index) 282 } 283 284 func (s *Jump) String() string { 285 // Be robust against malformed CFG. 286 block := -1 287 if s.block != nil && len(s.block.Succs) == 1 { 288 block = s.block.Succs[0].Index 289 } 290 return fmt.Sprintf("jump %d", block) 291 } 292 293 func (s *If) String() string { 294 // Be robust against malformed CFG. 295 tblock, fblock := -1, -1 296 if s.block != nil && len(s.block.Succs) == 2 { 297 tblock = s.block.Succs[0].Index 298 fblock = s.block.Succs[1].Index 299 } 300 return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock) 301 } 302 303 func (s *Go) String() string { 304 return printCall(&s.Call, "go ", s) 305 } 306 307 func (s *Panic) String() string { 308 return "panic " + relName(s.X, s) 309 } 310 311 func (s *Return) String() string { 312 var b bytes.Buffer 313 b.WriteString("return") 314 for i, r := range s.Results { 315 if i == 0 { 316 b.WriteString(" ") 317 } else { 318 b.WriteString(", ") 319 } 320 b.WriteString(relName(r, s)) 321 } 322 return b.String() 323 } 324 325 func (*RunDefers) String() string { 326 return "rundefers" 327 } 328 329 func (s *Send) String() string { 330 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s)) 331 } 332 333 func (s *Defer) String() string { 334 return printCall(&s.Call, "defer ", s) 335 } 336 337 func (s *Select) String() string { 338 var b bytes.Buffer 339 for i, st := range s.States { 340 if i > 0 { 341 b.WriteString(", ") 342 } 343 if st.Dir == types.RecvOnly { 344 b.WriteString("<-") 345 b.WriteString(relName(st.Chan, s)) 346 } else { 347 b.WriteString(relName(st.Chan, s)) 348 b.WriteString("<-") 349 b.WriteString(relName(st.Send, s)) 350 } 351 } 352 non := "" 353 if !s.Blocking { 354 non = "non" 355 } 356 return fmt.Sprintf("select %sblocking [%s]", non, b.String()) 357 } 358 359 func (s *Store) String() string { 360 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s)) 361 } 362 363 func (s *MapUpdate) String() string { 364 return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) 365 } 366 367 func (s *DebugRef) String() string { 368 p := s.Parent().Prog.Fset.Position(s.Pos()) 369 var descr interface{} 370 if s.object != nil { 371 descr = s.object // e.g. "var x int" 372 } else { 373 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr" 374 } 375 var addr string 376 if s.IsAddr { 377 addr = "address of " 378 } 379 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name()) 380 } 381 382 func (p *Package) String() string { 383 return "package " + p.Pkg.Path() 384 } 385 386 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer 387 388 func (p *Package) WriteTo(w io.Writer) (int64, error) { 389 var buf bytes.Buffer 390 WritePackage(&buf, p) 391 n, err := w.Write(buf.Bytes()) 392 return int64(n), err 393 } 394 395 // WritePackage writes to buf a human-readable summary of p. 396 func WritePackage(buf *bytes.Buffer, p *Package) { 397 fmt.Fprintf(buf, "%s:\n", p) 398 399 var names []string 400 maxname := 0 401 for name := range p.Members { 402 if l := len(name); l > maxname { 403 maxname = l 404 } 405 names = append(names, name) 406 } 407 408 from := p.Pkg 409 sort.Strings(names) 410 for _, name := range names { 411 switch mem := p.Members[name].(type) { 412 case *NamedConst: 413 fmt.Fprintf(buf, " const %-*s %s = %s\n", 414 maxname, name, mem.Name(), mem.Value.RelString(from)) 415 416 case *Function: 417 fmt.Fprintf(buf, " func %-*s %s\n", 418 maxname, name, relType(mem.Type(), from)) 419 420 case *Type: 421 fmt.Fprintf(buf, " type %-*s %s\n", 422 maxname, name, relType(mem.Type().Underlying(), from)) 423 for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) { 424 fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from))) 425 } 426 427 case *Global: 428 fmt.Fprintf(buf, " var %-*s %s\n", 429 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) 430 } 431 } 432 433 fmt.Fprintf(buf, "\n") 434 } 435 436 func commaOk(x bool) string { 437 if x { 438 return ",ok" 439 } 440 return "" 441 }