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 }