github.com/jd-ly/tools@v0.5.7/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 18 "github.com/jd-ly/tools/go/types/typeutil" 19 ) 20 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. 26 // 27 func relName(v Value, i Instruction) string { 28 var from *types.Package 29 if i != nil { 30 from = i.Parent().pkg() 31 } 32 switch v := v.(type) { 33 case Member: // *Function or *Global 34 return v.RelString(from) 35 case *Const: 36 return v.RelString(from) 37 } 38 return v.Name() 39 } 40 41 func relType(t types.Type, from *types.Package) string { 42 return types.TypeString(t, types.RelativeTo(from)) 43 } 44 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()) 50 } 51 return m.Name() 52 } 53 54 // Value.String() 55 // 56 // This method is provided only for debugging. 57 // It never appears in disassembly, which uses Value.Name(). 58 59 func (v *Parameter) String() string { 60 from := v.Parent().pkg() 61 return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from)) 62 } 63 64 func (v *FreeVar) String() string { 65 from := v.Parent().pkg() 66 return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from)) 67 } 68 69 func (v *Builtin) String() string { 70 return fmt.Sprintf("builtin %s", v.Name()) 71 } 72 73 // Instruction.String() 74 75 func (v *Alloc) String() string { 76 op := "local" 77 if v.Heap { 78 op = "new" 79 } 80 from := v.Parent().pkg() 81 return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment) 82 } 83 84 func (v *Phi) String() string { 85 var b bytes.Buffer 86 b.WriteString("phi [") 87 for i, edge := range v.Edges { 88 if i > 0 { 89 b.WriteString(", ") 90 } 91 // Be robust against malformed CFG. 92 if v.block == nil { 93 b.WriteString("??") 94 continue 95 } 96 block := -1 97 if i < len(v.block.Preds) { 98 block = v.block.Preds[i].Index 99 } 100 fmt.Fprintf(&b, "%d: ", block) 101 edgeVal := "<nil>" // be robust 102 if edge != nil { 103 edgeVal = relName(edge, v) 104 } 105 b.WriteString(edgeVal) 106 } 107 b.WriteString("]") 108 if v.Comment != "" { 109 b.WriteString(" #") 110 b.WriteString(v.Comment) 111 } 112 return b.String() 113 } 114 115 func printCall(v *CallCommon, prefix string, instr Instruction) string { 116 var b bytes.Buffer 117 b.WriteString(prefix) 118 if !v.IsInvoke() { 119 b.WriteString(relName(v.Value, instr)) 120 } else { 121 fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name()) 122 } 123 b.WriteString("(") 124 for i, arg := range v.Args { 125 if i > 0 { 126 b.WriteString(", ") 127 } 128 b.WriteString(relName(arg, instr)) 129 } 130 if v.Signature().Variadic() { 131 b.WriteString("...") 132 } 133 b.WriteString(")") 134 return b.String() 135 } 136 137 func (c *CallCommon) String() string { 138 return printCall(c, "", nil) 139 } 140 141 func (v *Call) String() string { 142 return printCall(&v.Call, "", v) 143 } 144 145 func (v *BinOp) String() string { 146 return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v)) 147 } 148 149 func (v *UnOp) String() string { 150 return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk)) 151 } 152 153 func printConv(prefix string, v, x Value) string { 154 from := v.Parent().pkg() 155 return fmt.Sprintf("%s %s <- %s (%s)", 156 prefix, 157 relType(v.Type(), from), 158 relType(x.Type(), from), 159 relName(x, v.(Instruction))) 160 } 161 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) } 166 167 func (v *MakeClosure) String() string { 168 var b bytes.Buffer 169 fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v)) 170 if v.Bindings != nil { 171 b.WriteString(" [") 172 for i, c := range v.Bindings { 173 if i > 0 { 174 b.WriteString(", ") 175 } 176 b.WriteString(relName(c, v)) 177 } 178 b.WriteString("]") 179 } 180 return b.String() 181 } 182 183 func (v *MakeSlice) String() string { 184 from := v.Parent().pkg() 185 return fmt.Sprintf("make %s %s %s", 186 relType(v.Type(), from), 187 relName(v.Len, v), 188 relName(v.Cap, v)) 189 } 190 191 func (v *Slice) String() string { 192 var b bytes.Buffer 193 b.WriteString("slice ") 194 b.WriteString(relName(v.X, v)) 195 b.WriteString("[") 196 if v.Low != nil { 197 b.WriteString(relName(v.Low, v)) 198 } 199 b.WriteString(":") 200 if v.High != nil { 201 b.WriteString(relName(v.High, v)) 202 } 203 if v.Max != nil { 204 b.WriteString(":") 205 b.WriteString(relName(v.Max, v)) 206 } 207 b.WriteString("]") 208 return b.String() 209 } 210 211 func (v *MakeMap) String() string { 212 res := "" 213 if v.Reserve != nil { 214 res = relName(v.Reserve, v) 215 } 216 from := v.Parent().pkg() 217 return fmt.Sprintf("make %s %s", relType(v.Type(), from), res) 218 } 219 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)) 223 } 224 225 func (v *FieldAddr) String() string { 226 st := deref(v.X.Type()).Underlying().(*types.Struct) 227 // Be robust against a bad index. 228 name := "?" 229 if 0 <= v.Field && v.Field < st.NumFields() { 230 name = st.Field(v.Field).Name() 231 } 232 return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) 233 } 234 235 func (v *Field) String() string { 236 st := 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 *IndexAddr) String() string { 246 return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v)) 247 } 248 249 func (v *Index) String() string { 250 return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) 251 } 252 253 func (v *Lookup) String() string { 254 return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk)) 255 } 256 257 func (v *Range) String() string { 258 return "range " + relName(v.X, v) 259 } 260 261 func (v *Next) String() string { 262 return "next " + relName(v.Iter, v) 263 } 264 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)) 268 } 269 270 func (v *Extract) String() string { 271 return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index) 272 } 273 274 func (s *Jump) String() string { 275 // Be robust against malformed CFG. 276 block := -1 277 if s.block != nil && len(s.block.Succs) == 1 { 278 block = s.block.Succs[0].Index 279 } 280 return fmt.Sprintf("jump %d", block) 281 } 282 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 289 } 290 return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock) 291 } 292 293 func (s *Go) String() string { 294 return printCall(&s.Call, "go ", s) 295 } 296 297 func (s *Panic) String() string { 298 return "panic " + relName(s.X, s) 299 } 300 301 func (s *Return) String() string { 302 var b bytes.Buffer 303 b.WriteString("return") 304 for i, r := range s.Results { 305 if i == 0 { 306 b.WriteString(" ") 307 } else { 308 b.WriteString(", ") 309 } 310 b.WriteString(relName(r, s)) 311 } 312 return b.String() 313 } 314 315 func (*RunDefers) String() string { 316 return "rundefers" 317 } 318 319 func (s *Send) String() string { 320 return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s)) 321 } 322 323 func (s *Defer) String() string { 324 return printCall(&s.Call, "defer ", s) 325 } 326 327 func (s *Select) String() string { 328 var b bytes.Buffer 329 for i, st := range s.States { 330 if i > 0 { 331 b.WriteString(", ") 332 } 333 if st.Dir == types.RecvOnly { 334 b.WriteString("<-") 335 b.WriteString(relName(st.Chan, s)) 336 } else { 337 b.WriteString(relName(st.Chan, s)) 338 b.WriteString("<-") 339 b.WriteString(relName(st.Send, s)) 340 } 341 } 342 non := "" 343 if !s.Blocking { 344 non = "non" 345 } 346 return fmt.Sprintf("select %sblocking [%s]", non, b.String()) 347 } 348 349 func (s *Store) String() string { 350 return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s)) 351 } 352 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)) 355 } 356 357 func (s *DebugRef) String() string { 358 p := s.Parent().Prog.Fset.Position(s.Pos()) 359 var descr interface{} 360 if s.object != nil { 361 descr = s.object // e.g. "var x int" 362 } else { 363 descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr" 364 } 365 var addr string 366 if s.IsAddr { 367 addr = "address of " 368 } 369 return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name()) 370 } 371 372 func (p *Package) String() string { 373 return "package " + p.Pkg.Path() 374 } 375 376 var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer 377 378 func (p *Package) WriteTo(w io.Writer) (int64, error) { 379 var buf bytes.Buffer 380 WritePackage(&buf, p) 381 n, err := w.Write(buf.Bytes()) 382 return int64(n), err 383 } 384 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) 388 389 var names []string 390 maxname := 0 391 for name := range p.Members { 392 if l := len(name); l > maxname { 393 maxname = l 394 } 395 names = append(names, name) 396 } 397 398 from := p.Pkg 399 sort.Strings(names) 400 for _, name := range names { 401 switch mem := p.Members[name].(type) { 402 case *NamedConst: 403 fmt.Fprintf(buf, " const %-*s %s = %s\n", 404 maxname, name, mem.Name(), mem.Value.RelString(from)) 405 406 case *Function: 407 fmt.Fprintf(buf, " func %-*s %s\n", 408 maxname, name, relType(mem.Type(), from)) 409 410 case *Type: 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))) 415 } 416 417 case *Global: 418 fmt.Fprintf(buf, " var %-*s %s\n", 419 maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) 420 } 421 } 422 423 fmt.Fprintf(buf, "\n") 424 } 425 426 func commaOk(x bool) string { 427 if x { 428 return ",ok" 429 } 430 return "" 431 }