github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/ir/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 ir
     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/amarpal/go-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  func relName(v Value, i Instruction) string {
    27  	if v == nil {
    28  		return "<nil>"
    29  	}
    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  	}
    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}", relType(v.Type(), from), v.name)
    62  }
    63  
    64  func (v *FreeVar) String() string {
    65  	from := v.Parent().pkg()
    66  	return fmt.Sprintf("FreeVar <%s> %s", relType(v.Type(), from), v.Name())
    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  	from := v.Parent().pkg()
    77  	storage := "Stack"
    78  	if v.Heap {
    79  		storage = "Heap"
    80  	}
    81  	return fmt.Sprintf("%sAlloc <%s>", storage, relType(v.Type(), from))
    82  }
    83  
    84  func (v *Sigma) String() string {
    85  	from := v.Parent().pkg()
    86  	s := fmt.Sprintf("Sigma <%s> [b%d] %s", relType(v.Type(), from), v.From.Index, v.X.Name())
    87  	return s
    88  }
    89  
    90  func (v *Phi) String() string {
    91  	var b bytes.Buffer
    92  	fmt.Fprintf(&b, "Phi <%s>", v.Type())
    93  	for i, edge := range v.Edges {
    94  		b.WriteString(" ")
    95  		// Be robust against malformed CFG.
    96  		if v.block == nil {
    97  			b.WriteString("??")
    98  			continue
    99  		}
   100  		block := -1
   101  		if i < len(v.block.Preds) {
   102  			block = v.block.Preds[i].Index
   103  		}
   104  		fmt.Fprintf(&b, "%d:", block)
   105  		edgeVal := "<nil>" // be robust
   106  		if edge != nil {
   107  			edgeVal = relName(edge, v)
   108  		}
   109  		b.WriteString(edgeVal)
   110  	}
   111  	return b.String()
   112  }
   113  
   114  func printCall(v *CallCommon, prefix string, instr Instruction) string {
   115  	var b bytes.Buffer
   116  	if !v.IsInvoke() {
   117  		if value, ok := instr.(Value); ok {
   118  			fmt.Fprintf(&b, "%s <%s> %s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr))
   119  		} else {
   120  			fmt.Fprintf(&b, "%s %s", prefix, relName(v.Value, instr))
   121  		}
   122  	} else {
   123  		if value, ok := instr.(Value); ok {
   124  			fmt.Fprintf(&b, "%sInvoke <%s> %s.%s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr), v.Method.Name())
   125  		} else {
   126  			fmt.Fprintf(&b, "%sInvoke %s.%s", prefix, relName(v.Value, instr), v.Method.Name())
   127  		}
   128  	}
   129  	for _, arg := range v.TypeArgs {
   130  		b.WriteString(" ")
   131  		b.WriteString(relType(arg, instr.Parent().pkg()))
   132  	}
   133  	for _, arg := range v.Args {
   134  		b.WriteString(" ")
   135  		b.WriteString(relName(arg, instr))
   136  	}
   137  	return b.String()
   138  }
   139  
   140  func (c *CallCommon) String() string {
   141  	return printCall(c, "", nil)
   142  }
   143  
   144  func (v *Call) String() string {
   145  	return printCall(&v.Call, "Call", v)
   146  }
   147  
   148  func (v *BinOp) String() string {
   149  	return fmt.Sprintf("BinOp <%s> {%s} %s %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v), relName(v.Y, v))
   150  }
   151  
   152  func (v *UnOp) String() string {
   153  	return fmt.Sprintf("UnOp <%s> {%s} %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v))
   154  }
   155  
   156  func (v *Load) String() string {
   157  	return fmt.Sprintf("Load <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v))
   158  }
   159  
   160  func (v *Copy) String() string {
   161  	return fmt.Sprintf("Copy <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v))
   162  }
   163  
   164  func printConv(prefix string, v, x Value) string {
   165  	from := v.Parent().pkg()
   166  	return fmt.Sprintf("%s <%s> %s",
   167  		prefix,
   168  		relType(v.Type(), from),
   169  		relName(x, v.(Instruction)))
   170  }
   171  
   172  func (v *ChangeType) String() string          { return printConv("ChangeType", v, v.X) }
   173  func (v *Convert) String() string             { return printConv("Convert", v, v.X) }
   174  func (v *ChangeInterface) String() string     { return printConv("ChangeInterface", v, v.X) }
   175  func (v *SliceToArrayPointer) String() string { return printConv("SliceToArrayPointer", v, v.X) }
   176  func (v *SliceToArray) String() string        { return printConv("SliceToArray", v, v.X) }
   177  func (v *MakeInterface) String() string       { return printConv("MakeInterface", v, v.X) }
   178  
   179  func (v *MakeClosure) String() string {
   180  	from := v.Parent().pkg()
   181  	var b bytes.Buffer
   182  	fmt.Fprintf(&b, "MakeClosure <%s> %s", relType(v.Type(), from), relName(v.Fn, v))
   183  	if v.Bindings != nil {
   184  		for _, c := range v.Bindings {
   185  			b.WriteString(" ")
   186  			b.WriteString(relName(c, v))
   187  		}
   188  	}
   189  	return b.String()
   190  }
   191  
   192  func (v *MakeSlice) String() string {
   193  	from := v.Parent().pkg()
   194  	return fmt.Sprintf("MakeSlice <%s> %s %s",
   195  		relType(v.Type(), from),
   196  		relName(v.Len, v),
   197  		relName(v.Cap, v))
   198  }
   199  
   200  func (v *Slice) String() string {
   201  	from := v.Parent().pkg()
   202  	return fmt.Sprintf("Slice <%s> %s %s %s %s",
   203  		relType(v.Type(), from), relName(v.X, v), relName(v.Low, v), relName(v.High, v), relName(v.Max, v))
   204  }
   205  
   206  func (v *MakeMap) String() string {
   207  	res := ""
   208  	if v.Reserve != nil {
   209  		res = relName(v.Reserve, v)
   210  	}
   211  	from := v.Parent().pkg()
   212  	return fmt.Sprintf("MakeMap <%s> %s", relType(v.Type(), from), res)
   213  }
   214  
   215  func (v *MakeChan) String() string {
   216  	from := v.Parent().pkg()
   217  	return fmt.Sprintf("MakeChan <%s> %s", relType(v.Type(), from), relName(v.Size, v))
   218  }
   219  
   220  func (v *FieldAddr) String() string {
   221  	from := v.Parent().pkg()
   222  	// v.X.Type() might be a pointer to a type parameter whose core type is a pointer to a struct
   223  	st := deref(typeutil.CoreType(deref(v.X.Type()))).Underlying().(*types.Struct)
   224  	// Be robust against a bad index.
   225  	name := "?"
   226  	if 0 <= v.Field && v.Field < st.NumFields() {
   227  		name = st.Field(v.Field).Name()
   228  	}
   229  	return fmt.Sprintf("FieldAddr <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v))
   230  }
   231  
   232  func (v *Field) String() string {
   233  	st := typeutil.CoreType(v.X.Type()).Underlying().(*types.Struct)
   234  	// Be robust against a bad index.
   235  	name := "?"
   236  	if 0 <= v.Field && v.Field < st.NumFields() {
   237  		name = st.Field(v.Field).Name()
   238  	}
   239  	from := v.Parent().pkg()
   240  	return fmt.Sprintf("Field <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v))
   241  }
   242  
   243  func (v *IndexAddr) String() string {
   244  	from := v.Parent().pkg()
   245  	return fmt.Sprintf("IndexAddr <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
   246  }
   247  
   248  func (v *Index) String() string {
   249  	from := v.Parent().pkg()
   250  	return fmt.Sprintf("Index <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
   251  }
   252  
   253  func (v *MapLookup) String() string {
   254  	from := v.Parent().pkg()
   255  	return fmt.Sprintf("MapLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
   256  }
   257  
   258  func (v *StringLookup) String() string {
   259  	from := v.Parent().pkg()
   260  	return fmt.Sprintf("StringLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v))
   261  }
   262  
   263  func (v *Range) String() string {
   264  	from := v.Parent().pkg()
   265  	return fmt.Sprintf("Range <%s> %s", relType(v.Type(), from), relName(v.X, v))
   266  }
   267  
   268  func (v *Next) String() string {
   269  	from := v.Parent().pkg()
   270  	return fmt.Sprintf("Next <%s> %s", relType(v.Type(), from), relName(v.Iter, v))
   271  }
   272  
   273  func (v *TypeAssert) String() string {
   274  	from := v.Parent().pkg()
   275  	return fmt.Sprintf("TypeAssert <%s> %s", relType(v.Type(), from), relName(v.X, v))
   276  }
   277  
   278  func (v *Extract) String() string {
   279  	from := v.Parent().pkg()
   280  	name := v.Tuple.Type().(*types.Tuple).At(v.Index).Name()
   281  	return fmt.Sprintf("Extract <%s> [%d] (%s) %s", relType(v.Type(), from), v.Index, name, relName(v.Tuple, v))
   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  	str := fmt.Sprintf("Jump → b%d", block)
   291  	if s.Comment() != "" {
   292  		str = fmt.Sprintf("%s # %s", str, s.Comment())
   293  	}
   294  	return str
   295  }
   296  
   297  func (s *Unreachable) String() string {
   298  	// Be robust against malformed CFG.
   299  	block := -1
   300  	if s.block != nil && len(s.block.Succs) == 1 {
   301  		block = s.block.Succs[0].Index
   302  	}
   303  	return fmt.Sprintf("Unreachable → b%d", block)
   304  }
   305  
   306  func (s *If) String() string {
   307  	// Be robust against malformed CFG.
   308  	tblock, fblock := -1, -1
   309  	if s.block != nil && len(s.block.Succs) == 2 {
   310  		tblock = s.block.Succs[0].Index
   311  		fblock = s.block.Succs[1].Index
   312  	}
   313  	return fmt.Sprintf("If %s → b%d b%d", relName(s.Cond, s), tblock, fblock)
   314  }
   315  
   316  func (s *ConstantSwitch) String() string {
   317  	var b bytes.Buffer
   318  	fmt.Fprintf(&b, "ConstantSwitch %s", relName(s.Tag, s))
   319  	for _, cond := range s.Conds {
   320  		fmt.Fprintf(&b, " %s", relName(cond, s))
   321  	}
   322  	fmt.Fprint(&b, " →")
   323  	for _, succ := range s.block.Succs {
   324  		fmt.Fprintf(&b, " b%d", succ.Index)
   325  	}
   326  	return b.String()
   327  }
   328  
   329  func (v *CompositeValue) String() string {
   330  	var b bytes.Buffer
   331  	from := v.Parent().pkg()
   332  	fmt.Fprintf(&b, "CompositeValue <%s>", relType(v.Type(), from))
   333  	if v.NumSet >= len(v.Values) {
   334  		// All values provided
   335  		fmt.Fprint(&b, " [all]")
   336  	} else if v.Bitmap.BitLen() == 0 {
   337  		// No values provided
   338  		fmt.Fprint(&b, " [none]")
   339  	} else {
   340  		// Some values provided
   341  		bits := []byte(fmt.Sprintf("%0*b", len(v.Values), &v.Bitmap))
   342  		for i := 0; i < len(bits)/2; i++ {
   343  			o := len(bits) - 1 - i
   344  			bits[i], bits[o] = bits[o], bits[i]
   345  		}
   346  		fmt.Fprintf(&b, " [%s]", bits)
   347  	}
   348  	for _, vv := range v.Values {
   349  		fmt.Fprintf(&b, " %s", relName(vv, v))
   350  	}
   351  	return b.String()
   352  }
   353  
   354  func (s *TypeSwitch) String() string {
   355  	from := s.Parent().pkg()
   356  	var b bytes.Buffer
   357  	fmt.Fprintf(&b, "TypeSwitch <%s> %s", relType(s.typ, from), relName(s.Tag, s))
   358  	for _, cond := range s.Conds {
   359  		fmt.Fprintf(&b, " %q", relType(cond, s.block.parent.pkg()))
   360  	}
   361  	return b.String()
   362  }
   363  
   364  func (s *Go) String() string {
   365  	return printCall(&s.Call, "Go", s)
   366  }
   367  
   368  func (s *Panic) String() string {
   369  	// Be robust against malformed CFG.
   370  	block := -1
   371  	if s.block != nil && len(s.block.Succs) == 1 {
   372  		block = s.block.Succs[0].Index
   373  	}
   374  	return fmt.Sprintf("Panic %s → b%d", relName(s.X, s), block)
   375  }
   376  
   377  func (s *Return) String() string {
   378  	var b bytes.Buffer
   379  	b.WriteString("Return")
   380  	for _, r := range s.Results {
   381  		b.WriteString(" ")
   382  		b.WriteString(relName(r, s))
   383  	}
   384  	return b.String()
   385  }
   386  
   387  func (*RunDefers) String() string {
   388  	return "RunDefers"
   389  }
   390  
   391  func (s *Send) String() string {
   392  	return fmt.Sprintf("Send %s %s", relName(s.Chan, s), relName(s.X, s))
   393  }
   394  
   395  func (recv *Recv) String() string {
   396  	from := recv.Parent().pkg()
   397  	return fmt.Sprintf("Recv <%s> %s", relType(recv.Type(), from), relName(recv.Chan, recv))
   398  }
   399  
   400  func (s *Defer) String() string {
   401  	return printCall(&s.Call, "Defer", s)
   402  }
   403  
   404  func (s *Select) String() string {
   405  	var b bytes.Buffer
   406  	for i, st := range s.States {
   407  		if i > 0 {
   408  			b.WriteString(", ")
   409  		}
   410  		if st.Dir == types.RecvOnly {
   411  			b.WriteString("<-")
   412  			b.WriteString(relName(st.Chan, s))
   413  		} else {
   414  			b.WriteString(relName(st.Chan, s))
   415  			b.WriteString("<-")
   416  			b.WriteString(relName(st.Send, s))
   417  		}
   418  	}
   419  	non := ""
   420  	if !s.Blocking {
   421  		non = "Non"
   422  	}
   423  	from := s.Parent().pkg()
   424  	return fmt.Sprintf("Select%sBlocking <%s> [%s]", non, relType(s.Type(), from), b.String())
   425  }
   426  
   427  func (s *Store) String() string {
   428  	return fmt.Sprintf("Store {%s} %s %s",
   429  		s.Val.Type(), relName(s.Addr, s), relName(s.Val, s))
   430  }
   431  
   432  func (s *BlankStore) String() string {
   433  	return fmt.Sprintf("BlankStore %s", relName(s.Val, s))
   434  }
   435  
   436  func (s *MapUpdate) String() string {
   437  	return fmt.Sprintf("MapUpdate %s %s %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
   438  }
   439  
   440  func (s *DebugRef) String() string {
   441  	p := s.Parent().Prog.Fset.Position(s.Pos())
   442  	var descr interface{}
   443  	if s.object != nil {
   444  		descr = s.object // e.g. "var x int"
   445  	} else {
   446  		descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr"
   447  	}
   448  	var addr string
   449  	if s.IsAddr {
   450  		addr = "address of "
   451  	}
   452  	return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name())
   453  }
   454  
   455  func (p *Package) String() string {
   456  	return "package " + p.Pkg.Path()
   457  }
   458  
   459  var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer
   460  
   461  func (p *Package) WriteTo(w io.Writer) (int64, error) {
   462  	var buf bytes.Buffer
   463  	WritePackage(&buf, p)
   464  	n, err := w.Write(buf.Bytes())
   465  	return int64(n), err
   466  }
   467  
   468  // WritePackage writes to buf a human-readable summary of p.
   469  func WritePackage(buf *bytes.Buffer, p *Package) {
   470  	fmt.Fprintf(buf, "%s:\n", p)
   471  
   472  	var names []string
   473  	maxname := 0
   474  	for name := range p.Members {
   475  		if l := len(name); l > maxname {
   476  			maxname = l
   477  		}
   478  		names = append(names, name)
   479  	}
   480  
   481  	from := p.Pkg
   482  	sort.Strings(names)
   483  	for _, name := range names {
   484  		switch mem := p.Members[name].(type) {
   485  		case *NamedConst:
   486  			fmt.Fprintf(buf, "  const %-*s %s = %s\n",
   487  				maxname, name, mem.Name(), mem.Value.RelString(from))
   488  
   489  		case *Function:
   490  			fmt.Fprintf(buf, "  func  %-*s %s\n",
   491  				maxname, name, relType(mem.Type(), from))
   492  
   493  		case *Type:
   494  			fmt.Fprintf(buf, "  type  %-*s %s\n",
   495  				maxname, name, relType(mem.Type().Underlying(), from))
   496  			for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
   497  				fmt.Fprintf(buf, "    %s\n", types.SelectionString(meth, types.RelativeTo(from)))
   498  			}
   499  
   500  		case *Global:
   501  			fmt.Fprintf(buf, "  var   %-*s %s\n",
   502  				maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from))
   503  		}
   504  	}
   505  
   506  	fmt.Fprintf(buf, "\n")
   507  }