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