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