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  }