github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/util.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 defines a number of miscellaneous utility functions.
     8  
     9  import (
    10  	"fmt"
    11  	"go/ast"
    12  	"go/token"
    13  	"go/types"
    14  	"io"
    15  	"os"
    16  	"sync"
    17  
    18  	"github.com/powerman/golang-tools/go/ast/astutil"
    19  	"github.com/powerman/golang-tools/go/types/typeutil"
    20  	"github.com/powerman/golang-tools/internal/typeparams"
    21  )
    22  
    23  //// Sanity checking utilities
    24  
    25  // assert panics with the mesage msg if p is false.
    26  // Avoid combining with expensive string formatting.
    27  func assert(p bool, msg string) {
    28  	if !p {
    29  		panic(msg)
    30  	}
    31  }
    32  
    33  //// AST utilities
    34  
    35  func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
    36  
    37  // isBlankIdent returns true iff e is an Ident with name "_".
    38  // They have no associated types.Object, and thus no type.
    39  //
    40  func isBlankIdent(e ast.Expr) bool {
    41  	id, ok := e.(*ast.Ident)
    42  	return ok && id.Name == "_"
    43  }
    44  
    45  //// Type utilities.  Some of these belong in go/types.
    46  
    47  // isPointer returns true for types whose underlying type is a pointer.
    48  func isPointer(typ types.Type) bool {
    49  	_, ok := typ.Underlying().(*types.Pointer)
    50  	return ok
    51  }
    52  
    53  func isInterface(T types.Type) bool { return types.IsInterface(T) }
    54  
    55  // deref returns a pointer's element type; otherwise it returns typ.
    56  func deref(typ types.Type) types.Type {
    57  	if p, ok := typ.Underlying().(*types.Pointer); ok {
    58  		return p.Elem()
    59  	}
    60  	return typ
    61  }
    62  
    63  // recvType returns the receiver type of method obj.
    64  func recvType(obj *types.Func) types.Type {
    65  	return obj.Type().(*types.Signature).Recv().Type()
    66  }
    67  
    68  // isUntyped returns true for types that are untyped.
    69  func isUntyped(typ types.Type) bool {
    70  	b, ok := typ.(*types.Basic)
    71  	return ok && b.Info()&types.IsUntyped != 0
    72  }
    73  
    74  // logStack prints the formatted "start" message to stderr and
    75  // returns a closure that prints the corresponding "end" message.
    76  // Call using 'defer logStack(...)()' to show builder stack on panic.
    77  // Don't forget trailing parens!
    78  //
    79  func logStack(format string, args ...interface{}) func() {
    80  	msg := fmt.Sprintf(format, args...)
    81  	io.WriteString(os.Stderr, msg)
    82  	io.WriteString(os.Stderr, "\n")
    83  	return func() {
    84  		io.WriteString(os.Stderr, msg)
    85  		io.WriteString(os.Stderr, " end\n")
    86  	}
    87  }
    88  
    89  // newVar creates a 'var' for use in a types.Tuple.
    90  func newVar(name string, typ types.Type) *types.Var {
    91  	return types.NewParam(token.NoPos, nil, name, typ)
    92  }
    93  
    94  // anonVar creates an anonymous 'var' for use in a types.Tuple.
    95  func anonVar(typ types.Type) *types.Var {
    96  	return newVar("", typ)
    97  }
    98  
    99  var lenResults = types.NewTuple(anonVar(tInt))
   100  
   101  // makeLen returns the len builtin specialized to type func(T)int.
   102  func makeLen(T types.Type) *Builtin {
   103  	lenParams := types.NewTuple(anonVar(T))
   104  	return &Builtin{
   105  		name: "len",
   106  		sig:  types.NewSignature(nil, lenParams, lenResults, false),
   107  	}
   108  }
   109  
   110  // nonbasicTypes returns a list containing all of the types T in ts that are non-basic.
   111  func nonbasicTypes(ts []types.Type) []types.Type {
   112  	if len(ts) == 0 {
   113  		return nil
   114  	}
   115  	added := make(map[types.Type]bool) // additionally filter duplicates
   116  	var filtered []types.Type
   117  	for _, T := range ts {
   118  		if _, basic := T.(*types.Basic); !basic {
   119  			if !added[T] {
   120  				added[T] = true
   121  				filtered = append(filtered, T)
   122  			}
   123  		}
   124  	}
   125  	return filtered
   126  }
   127  
   128  // isGeneric returns true if a package-level member is generic.
   129  func isGeneric(m Member) bool {
   130  	switch m := m.(type) {
   131  	case *NamedConst, *Global:
   132  		return false
   133  	case *Type:
   134  		// lifted from types.isGeneric.
   135  		named, _ := m.Type().(*types.Named)
   136  		return named != nil && named.Obj() != nil && typeparams.NamedTypeArgs(named) == nil && typeparams.ForNamed(named) != nil
   137  	case *Function:
   138  		return len(m._TypeParams) != len(m._TypeArgs)
   139  	default:
   140  		panic("unreachable")
   141  	}
   142  }
   143  
   144  // receiverTypeArgs returns the type arguments to a function's reciever.
   145  // Returns an empty list if obj does not have a reciever or its reciever does not have type arguments.
   146  func receiverTypeArgs(obj *types.Func) []types.Type {
   147  	rtype := recvType(obj)
   148  	if rtype == nil {
   149  		return nil
   150  	}
   151  	if isPointer(rtype) {
   152  		rtype = rtype.(*types.Pointer).Elem()
   153  	}
   154  	named, ok := rtype.(*types.Named)
   155  	if !ok {
   156  		return nil
   157  	}
   158  	ts := typeparams.NamedTypeArgs(named)
   159  	if ts.Len() == 0 {
   160  		return nil
   161  	}
   162  	targs := make([]types.Type, ts.Len())
   163  	for i := 0; i < ts.Len(); i++ {
   164  		targs[i] = ts.At(i)
   165  	}
   166  	return targs
   167  }
   168  
   169  // Mapping of a type T to a canonical instance C s.t. types.Indentical(T, C).
   170  // Thread-safe.
   171  type canonizer struct {
   172  	mu    sync.Mutex
   173  	types typeutil.Map // map from type to a canonical instance
   174  	lists typeListMap  // map from a list of types to a canonical instance
   175  }
   176  
   177  func newCanonizer() *canonizer {
   178  	c := &canonizer{}
   179  	h := typeutil.MakeHasher()
   180  	c.types.SetHasher(h)
   181  	c.lists.hasher = h
   182  	return c
   183  }
   184  
   185  // List returns a canonical representative of a list of types.
   186  // Representative of the empty list is nil.
   187  func (c *canonizer) List(ts []types.Type) *typeList {
   188  	if len(ts) == 0 {
   189  		return nil
   190  	}
   191  
   192  	c.mu.Lock()
   193  	defer c.mu.Unlock()
   194  	return c.lists.rep(ts)
   195  }
   196  
   197  // Type returns a canonical representative of type T.
   198  func (c *canonizer) Type(T types.Type) types.Type {
   199  	c.mu.Lock()
   200  	defer c.mu.Unlock()
   201  
   202  	if r := c.types.At(T); r != nil {
   203  		return r.(types.Type)
   204  	}
   205  	c.types.Set(T, T)
   206  	return T
   207  }
   208  
   209  // A type for representating an canonized list of types.
   210  type typeList []types.Type
   211  
   212  func (l *typeList) identical(ts []types.Type) bool {
   213  	if l == nil {
   214  		return len(ts) == 0
   215  	}
   216  	n := len(*l)
   217  	if len(ts) != n {
   218  		return false
   219  	}
   220  	for i, left := range *l {
   221  		right := ts[i]
   222  		if !types.Identical(left, right) {
   223  			return false
   224  		}
   225  	}
   226  	return true
   227  }
   228  
   229  type typeListMap struct {
   230  	hasher  typeutil.Hasher
   231  	buckets map[uint32][]*typeList
   232  }
   233  
   234  // rep returns a canonical representative of a slice of types.
   235  func (m *typeListMap) rep(ts []types.Type) *typeList {
   236  	if m == nil || len(ts) == 0 {
   237  		return nil
   238  	}
   239  
   240  	if m.buckets == nil {
   241  		m.buckets = make(map[uint32][]*typeList)
   242  	}
   243  
   244  	h := m.hash(ts)
   245  	bucket := m.buckets[h]
   246  	for _, l := range bucket {
   247  		if l.identical(ts) {
   248  			return l
   249  		}
   250  	}
   251  
   252  	// not present. create a representative.
   253  	cp := make(typeList, len(ts))
   254  	copy(cp, ts)
   255  	rep := &cp
   256  
   257  	m.buckets[h] = append(bucket, rep)
   258  	return rep
   259  }
   260  
   261  func (m *typeListMap) hash(ts []types.Type) uint32 {
   262  	if m == nil {
   263  		return 0
   264  	}
   265  	// Some smallish prime far away from typeutil.Hash.
   266  	n := len(ts)
   267  	h := uint32(13619) + 2*uint32(n)
   268  	for i := 0; i < n; i++ {
   269  		h += 3 * m.hasher.Hash(ts[i])
   270  	}
   271  	return h
   272  }