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