golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/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  	"golang.org/x/tools/go/ast/astutil"
    19  	"golang.org/x/tools/go/types/typeutil"
    20  	"golang.org/x/tools/internal/aliases"
    21  	"golang.org/x/tools/internal/typeparams"
    22  	"golang.org/x/tools/internal/typesinternal"
    23  )
    24  
    25  //// Sanity checking utilities
    26  
    27  // assert panics with the mesage msg if p is false.
    28  // Avoid combining with expensive string formatting.
    29  func assert(p bool, msg string) {
    30  	if !p {
    31  		panic(msg)
    32  	}
    33  }
    34  
    35  //// AST utilities
    36  
    37  func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
    38  
    39  // isBlankIdent returns true iff e is an Ident with name "_".
    40  // They have no associated types.Object, and thus no type.
    41  func isBlankIdent(e ast.Expr) bool {
    42  	id, ok := e.(*ast.Ident)
    43  	return ok && id.Name == "_"
    44  }
    45  
    46  // rangePosition is the position to give for the `range` token in a RangeStmt.
    47  var rangePosition = func(rng *ast.RangeStmt) token.Pos {
    48  	// Before 1.20, this is unreachable.
    49  	// rng.For is a close, but incorrect position.
    50  	return rng.For
    51  }
    52  
    53  //// Type utilities.  Some of these belong in go/types.
    54  
    55  // isNonTypeParamInterface reports whether t is an interface type but not a type parameter.
    56  func isNonTypeParamInterface(t types.Type) bool {
    57  	return !typeparams.IsTypeParam(t) && types.IsInterface(t)
    58  }
    59  
    60  // isBasic reports whether t is a basic type.
    61  // t is assumed to be an Underlying type (not Named or Alias).
    62  func isBasic(t types.Type) bool {
    63  	_, ok := t.(*types.Basic)
    64  	return ok
    65  }
    66  
    67  // isString reports whether t is exactly a string type.
    68  // t is assumed to be an Underlying type (not Named or Alias).
    69  func isString(t types.Type) bool {
    70  	basic, ok := t.(*types.Basic)
    71  	return ok && basic.Info()&types.IsString != 0
    72  }
    73  
    74  // isByteSlice reports whether t is of the form []~bytes.
    75  // t is assumed to be an Underlying type (not Named or Alias).
    76  func isByteSlice(t types.Type) bool {
    77  	if b, ok := t.(*types.Slice); ok {
    78  		e, _ := b.Elem().Underlying().(*types.Basic)
    79  		return e != nil && e.Kind() == types.Byte
    80  	}
    81  	return false
    82  }
    83  
    84  // isRuneSlice reports whether t is of the form []~runes.
    85  // t is assumed to be an Underlying type (not Named or Alias).
    86  func isRuneSlice(t types.Type) bool {
    87  	if b, ok := t.(*types.Slice); ok {
    88  		e, _ := b.Elem().Underlying().(*types.Basic)
    89  		return e != nil && e.Kind() == types.Rune
    90  	}
    91  	return false
    92  }
    93  
    94  // isBasicConvTypes returns true when a type set can be
    95  // one side of a Convert operation. This is when:
    96  // - All are basic, []byte, or []rune.
    97  // - At least 1 is basic.
    98  // - At most 1 is []byte or []rune.
    99  func isBasicConvTypes(tset termList) bool {
   100  	basics := 0
   101  	all := underIs(tset, func(t types.Type) bool {
   102  		if isBasic(t) {
   103  			basics++
   104  			return true
   105  		}
   106  		return isByteSlice(t) || isRuneSlice(t)
   107  	})
   108  	return all && basics >= 1 && tset.Len()-basics <= 1
   109  }
   110  
   111  // isPointer reports whether t's underlying type is a pointer.
   112  func isPointer(t types.Type) bool {
   113  	return is[*types.Pointer](t.Underlying())
   114  }
   115  
   116  // isPointerCore reports whether t's core type is a pointer.
   117  //
   118  // (Most pointer manipulation is related to receivers, in which case
   119  // isPointer is appropriate. tecallers can use isPointer(t).
   120  func isPointerCore(t types.Type) bool {
   121  	return is[*types.Pointer](typeparams.CoreType(t))
   122  }
   123  
   124  func is[T any](x any) bool {
   125  	_, ok := x.(T)
   126  	return ok
   127  }
   128  
   129  // recvType returns the receiver type of method obj.
   130  func recvType(obj *types.Func) types.Type {
   131  	return obj.Type().(*types.Signature).Recv().Type()
   132  }
   133  
   134  // fieldOf returns the index'th field of the (core type of) a struct type;
   135  // otherwise returns nil.
   136  func fieldOf(typ types.Type, index int) *types.Var {
   137  	if st, ok := typeparams.CoreType(typ).(*types.Struct); ok {
   138  		if 0 <= index && index < st.NumFields() {
   139  			return st.Field(index)
   140  		}
   141  	}
   142  	return nil
   143  }
   144  
   145  // isUntyped reports whether typ is the type of an untyped constant.
   146  func isUntyped(typ types.Type) bool {
   147  	// No Underlying/Unalias: untyped constant types cannot be Named or Alias.
   148  	b, ok := typ.(*types.Basic)
   149  	return ok && b.Info()&types.IsUntyped != 0
   150  }
   151  
   152  // logStack prints the formatted "start" message to stderr and
   153  // returns a closure that prints the corresponding "end" message.
   154  // Call using 'defer logStack(...)()' to show builder stack on panic.
   155  // Don't forget trailing parens!
   156  func logStack(format string, args ...interface{}) func() {
   157  	msg := fmt.Sprintf(format, args...)
   158  	io.WriteString(os.Stderr, msg)
   159  	io.WriteString(os.Stderr, "\n")
   160  	return func() {
   161  		io.WriteString(os.Stderr, msg)
   162  		io.WriteString(os.Stderr, " end\n")
   163  	}
   164  }
   165  
   166  // newVar creates a 'var' for use in a types.Tuple.
   167  func newVar(name string, typ types.Type) *types.Var {
   168  	return types.NewParam(token.NoPos, nil, name, typ)
   169  }
   170  
   171  // anonVar creates an anonymous 'var' for use in a types.Tuple.
   172  func anonVar(typ types.Type) *types.Var {
   173  	return newVar("", typ)
   174  }
   175  
   176  var lenResults = types.NewTuple(anonVar(tInt))
   177  
   178  // makeLen returns the len builtin specialized to type func(T)int.
   179  func makeLen(T types.Type) *Builtin {
   180  	lenParams := types.NewTuple(anonVar(T))
   181  	return &Builtin{
   182  		name: "len",
   183  		sig:  types.NewSignature(nil, lenParams, lenResults, false),
   184  	}
   185  }
   186  
   187  // receiverTypeArgs returns the type arguments to a method's receiver.
   188  // Returns an empty list if the receiver does not have type arguments.
   189  func receiverTypeArgs(method *types.Func) []types.Type {
   190  	recv := method.Type().(*types.Signature).Recv()
   191  	_, named := typesinternal.ReceiverNamed(recv)
   192  	if named == nil {
   193  		return nil // recv is anonymous struct/interface
   194  	}
   195  	ts := named.TypeArgs()
   196  	if ts.Len() == 0 {
   197  		return nil
   198  	}
   199  	targs := make([]types.Type, ts.Len())
   200  	for i := 0; i < ts.Len(); i++ {
   201  		targs[i] = ts.At(i)
   202  	}
   203  	return targs
   204  }
   205  
   206  // recvAsFirstArg takes a method signature and returns a function
   207  // signature with receiver as the first parameter.
   208  func recvAsFirstArg(sig *types.Signature) *types.Signature {
   209  	params := make([]*types.Var, 0, 1+sig.Params().Len())
   210  	params = append(params, sig.Recv())
   211  	for i := 0; i < sig.Params().Len(); i++ {
   212  		params = append(params, sig.Params().At(i))
   213  	}
   214  	return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
   215  }
   216  
   217  // instance returns whether an expression is a simple or qualified identifier
   218  // that is a generic instantiation.
   219  func instance(info *types.Info, expr ast.Expr) bool {
   220  	// Compare the logic here against go/types.instantiatedIdent,
   221  	// which also handles  *IndexExpr and *IndexListExpr.
   222  	var id *ast.Ident
   223  	switch x := expr.(type) {
   224  	case *ast.Ident:
   225  		id = x
   226  	case *ast.SelectorExpr:
   227  		id = x.Sel
   228  	default:
   229  		return false
   230  	}
   231  	_, ok := info.Instances[id]
   232  	return ok
   233  }
   234  
   235  // instanceArgs returns the Instance[id].TypeArgs as a slice.
   236  func instanceArgs(info *types.Info, id *ast.Ident) []types.Type {
   237  	targList := info.Instances[id].TypeArgs
   238  	if targList == nil {
   239  		return nil
   240  	}
   241  
   242  	targs := make([]types.Type, targList.Len())
   243  	for i, n := 0, targList.Len(); i < n; i++ {
   244  		targs[i] = targList.At(i)
   245  	}
   246  	return targs
   247  }
   248  
   249  // Mapping of a type T to a canonical instance C s.t. types.Indentical(T, C).
   250  // Thread-safe.
   251  type canonizer struct {
   252  	mu    sync.Mutex
   253  	types typeutil.Map // map from type to a canonical instance
   254  	lists typeListMap  // map from a list of types to a canonical instance
   255  }
   256  
   257  func newCanonizer() *canonizer {
   258  	c := &canonizer{}
   259  	h := typeutil.MakeHasher()
   260  	c.types.SetHasher(h)
   261  	c.lists.hasher = h
   262  	return c
   263  }
   264  
   265  // List returns a canonical representative of a list of types.
   266  // Representative of the empty list is nil.
   267  func (c *canonizer) List(ts []types.Type) *typeList {
   268  	if len(ts) == 0 {
   269  		return nil
   270  	}
   271  
   272  	unaliasAll := func(ts []types.Type) []types.Type {
   273  		// Is there some top level alias?
   274  		var found bool
   275  		for _, t := range ts {
   276  			if _, ok := t.(*aliases.Alias); ok {
   277  				found = true
   278  				break
   279  			}
   280  		}
   281  		if !found {
   282  			return ts // no top level alias
   283  		}
   284  
   285  		cp := make([]types.Type, len(ts)) // copy with top level aliases removed.
   286  		for i, t := range ts {
   287  			cp[i] = aliases.Unalias(t)
   288  		}
   289  		return cp
   290  	}
   291  	l := unaliasAll(ts)
   292  
   293  	c.mu.Lock()
   294  	defer c.mu.Unlock()
   295  	return c.lists.rep(l)
   296  }
   297  
   298  // Type returns a canonical representative of type T.
   299  // Removes top-level aliases.
   300  //
   301  // For performance, reasons the canonical instance is order-dependent,
   302  // and may contain deeply nested aliases.
   303  func (c *canonizer) Type(T types.Type) types.Type {
   304  	T = aliases.Unalias(T) // remove the top level alias.
   305  
   306  	c.mu.Lock()
   307  	defer c.mu.Unlock()
   308  
   309  	if r := c.types.At(T); r != nil {
   310  		return r.(types.Type)
   311  	}
   312  	c.types.Set(T, T)
   313  	return T
   314  }
   315  
   316  // A type for representing a canonized list of types.
   317  type typeList []types.Type
   318  
   319  func (l *typeList) identical(ts []types.Type) bool {
   320  	if l == nil {
   321  		return len(ts) == 0
   322  	}
   323  	n := len(*l)
   324  	if len(ts) != n {
   325  		return false
   326  	}
   327  	for i, left := range *l {
   328  		right := ts[i]
   329  		if !types.Identical(left, right) {
   330  			return false
   331  		}
   332  	}
   333  	return true
   334  }
   335  
   336  type typeListMap struct {
   337  	hasher  typeutil.Hasher
   338  	buckets map[uint32][]*typeList
   339  }
   340  
   341  // rep returns a canonical representative of a slice of types.
   342  func (m *typeListMap) rep(ts []types.Type) *typeList {
   343  	if m == nil || len(ts) == 0 {
   344  		return nil
   345  	}
   346  
   347  	if m.buckets == nil {
   348  		m.buckets = make(map[uint32][]*typeList)
   349  	}
   350  
   351  	h := m.hash(ts)
   352  	bucket := m.buckets[h]
   353  	for _, l := range bucket {
   354  		if l.identical(ts) {
   355  			return l
   356  		}
   357  	}
   358  
   359  	// not present. create a representative.
   360  	cp := make(typeList, len(ts))
   361  	copy(cp, ts)
   362  	rep := &cp
   363  
   364  	m.buckets[h] = append(bucket, rep)
   365  	return rep
   366  }
   367  
   368  func (m *typeListMap) hash(ts []types.Type) uint32 {
   369  	if m == nil {
   370  		return 0
   371  	}
   372  	// Some smallish prime far away from typeutil.Hash.
   373  	n := len(ts)
   374  	h := uint32(13619) + 2*uint32(n)
   375  	for i := 0; i < n; i++ {
   376  		h += 3 * m.hasher.Hash(ts[i])
   377  	}
   378  	return h
   379  }
   380  
   381  // instantiateMethod instantiates m with targs and returns a canonical representative for this method.
   382  func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func {
   383  	recv := recvType(m)
   384  	if p, ok := aliases.Unalias(recv).(*types.Pointer); ok {
   385  		recv = p.Elem()
   386  	}
   387  	named := aliases.Unalias(recv).(*types.Named)
   388  	inst, err := types.Instantiate(ctxt, named.Origin(), targs, false)
   389  	if err != nil {
   390  		panic(err)
   391  	}
   392  	rep := canon.Type(inst)
   393  	obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name())
   394  	return obj.(*types.Func)
   395  }
   396  
   397  // Exposed to ssautil using the linkname hack.
   398  func isSyntactic(pkg *Package) bool { return pkg.syntax }
   399  
   400  // mapValues returns a new unordered array of map values.
   401  func mapValues[K comparable, V any](m map[K]V) []V {
   402  	vals := make([]V, 0, len(m))
   403  	for _, fn := range m {
   404  		vals = append(vals, fn)
   405  	}
   406  	return vals
   407  
   408  }