github.com/goplus/igop@v0.25.0/xtypes.go (about) 1 /* 2 * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package igop 18 19 import ( 20 "fmt" 21 "go/token" 22 "go/types" 23 "log" 24 "reflect" 25 "strconv" 26 "unsafe" 27 28 "github.com/goplus/reflectx" 29 "golang.org/x/tools/go/ssa" 30 "golang.org/x/tools/go/types/typeutil" 31 ) 32 33 var ( 34 tyEmptyStruct = reflect.TypeOf((*struct{})(nil)).Elem() 35 tyEmptyPtr = reflect.TypeOf((*struct{})(nil)) 36 tyEmptyMap = reflect.TypeOf((*map[struct{}]struct{})(nil)).Elem() 37 tyEmptySlice = reflect.TypeOf((*[]struct{})(nil)).Elem() 38 tyEmptyArray = reflect.TypeOf((*[0]struct{})(nil)).Elem() 39 tyEmptyChan = reflect.TypeOf((*chan struct{})(nil)).Elem() 40 tyEmptyFunc = reflect.TypeOf((*func())(nil)).Elem() 41 ) 42 43 /* 44 Array 45 Chan 46 Func 47 Interface 48 Map 49 Ptr 50 Slice 51 String 52 Struct 53 UnsafePointer 54 */ 55 56 func emptyType(kind reflect.Kind) reflect.Type { 57 switch kind { 58 case reflect.Array: 59 return tyEmptyArray 60 case reflect.Chan: 61 return tyEmptyChan 62 case reflect.Func: 63 return tyEmptyFunc 64 case reflect.Interface: 65 return tyEmptyInterface 66 case reflect.Map: 67 return tyEmptyMap 68 case reflect.Ptr: 69 return tyEmptyPtr 70 case reflect.Slice: 71 return tyEmptySlice 72 case reflect.Struct: 73 return tyEmptyStruct 74 default: 75 return xtypeTypes[kind] 76 } 77 } 78 79 func toMockType(typ types.Type) reflect.Type { 80 switch t := typ.(type) { 81 case *types.Basic: 82 kind := t.Kind() 83 if kind > types.Invalid && kind < types.UntypedNil { 84 return xtypeTypes[kind] 85 } 86 panic(fmt.Errorf("toMockType: invalid type %v", typ)) 87 case *types.Pointer: 88 return tyEmptyPtr 89 case *types.Slice: 90 return tyEmptySlice 91 case *types.Array: 92 e := toMockType(t.Elem()) 93 return reflect.ArrayOf(int(t.Len()), e) 94 case *types.Map: 95 return tyEmptyMap 96 case *types.Chan: 97 return tyEmptyChan 98 case *types.Struct: 99 n := t.NumFields() 100 fs := make([]reflect.StructField, n) 101 for i := 0; i < n; i++ { 102 ft := t.Field(i) 103 fs[i].Name = "F" + strconv.Itoa(i) 104 fs[i].Type = toMockType(ft.Type()) 105 fs[i].Anonymous = ft.Embedded() 106 } 107 return reflect.StructOf(fs) 108 case *types.Named: 109 return toMockType(typ.Underlying()) 110 case *types.Interface: 111 return tyEmptyInterface 112 case *types.Signature: 113 in := t.Params().Len() 114 out := t.Results().Len() 115 if in+out == 0 { 116 return tyEmptyFunc 117 } 118 ins := make([]reflect.Type, in) 119 outs := make([]reflect.Type, out) 120 variadic := t.Variadic() 121 if variadic { 122 for i := 0; i < in-1; i++ { 123 ins[i] = tyEmptyStruct 124 } 125 ins[in-1] = tyEmptySlice 126 } else { 127 for i := 0; i < in; i++ { 128 ins[i] = tyEmptyStruct 129 } 130 } 131 for i := 0; i < out; i++ { 132 outs[i] = tyEmptyStruct 133 } 134 return reflect.FuncOf(ins, outs, variadic) 135 default: 136 panic(fmt.Errorf("toEmptyType: unreachable %v", typ)) 137 } 138 } 139 140 var xtypeTypes = [...]reflect.Type{ 141 types.Bool: reflect.TypeOf(false), 142 types.Int: reflect.TypeOf(0), 143 types.Int8: reflect.TypeOf(int8(0)), 144 types.Int16: reflect.TypeOf(int16(0)), 145 types.Int32: reflect.TypeOf(int32(0)), 146 types.Int64: reflect.TypeOf(int64(0)), 147 types.Uint: reflect.TypeOf(uint(0)), 148 types.Uint8: reflect.TypeOf(uint8(0)), 149 types.Uint16: reflect.TypeOf(uint16(0)), 150 types.Uint32: reflect.TypeOf(uint32(0)), 151 types.Uint64: reflect.TypeOf(uint64(0)), 152 types.Uintptr: reflect.TypeOf(uintptr(0)), 153 types.Float32: reflect.TypeOf(float32(0)), 154 types.Float64: reflect.TypeOf(float64(0)), 155 types.Complex64: reflect.TypeOf(complex64(0)), 156 types.Complex128: reflect.TypeOf(complex128(0)), 157 types.String: reflect.TypeOf(""), 158 types.UnsafePointer: reflect.TypeOf(unsafe.Pointer(nil)), 159 160 types.UntypedBool: reflect.TypeOf(false), 161 types.UntypedInt: reflect.TypeOf(0), 162 types.UntypedRune: reflect.TypeOf('a'), 163 types.UntypedFloat: reflect.TypeOf(0.1), 164 types.UntypedComplex: reflect.TypeOf(0 + 1i), 165 types.UntypedString: reflect.TypeOf(""), 166 } 167 168 type FindMethod interface { 169 FindMethod(mtyp reflect.Type, fn *types.Func) func([]reflect.Value) []reflect.Value 170 } 171 172 type TypesRecord struct { 173 rctx *reflectx.Context // reflectx context 174 loader Loader 175 finder FindMethod 176 rcache map[reflect.Type]types.Type 177 tcache *typeutil.Map 178 ncache *typeutil.Map //nested cache 179 fntargs string //reflect type arguments used to instantiate the current func 180 nested map[*types.Named]int 181 nstack nestedStack 182 } 183 184 func (r *TypesRecord) Release() { 185 r.rctx.Reset() 186 r.loader = nil 187 r.rcache = nil 188 r.tcache = nil 189 r.ncache = nil 190 r.finder = nil 191 r.nested = nil 192 } 193 194 func NewTypesRecord(rctx *reflectx.Context, loader Loader, finder FindMethod, nested map[*types.Named]int) *TypesRecord { 195 return &TypesRecord{ 196 rctx: rctx, 197 loader: loader, 198 finder: finder, 199 rcache: make(map[reflect.Type]types.Type), 200 tcache: &typeutil.Map{}, 201 nested: nested, 202 } 203 } 204 205 func (r *TypesRecord) LookupLocalTypes(rt reflect.Type) (typ types.Type, ok bool) { 206 typ, ok = r.rcache[rt] 207 return 208 } 209 210 func (r *TypesRecord) LookupTypes(rt reflect.Type) (typ types.Type, ok bool) { 211 typ, ok = r.loader.LookupTypes(rt) 212 if !ok { 213 typ, ok = r.rcache[rt] 214 } 215 return 216 } 217 218 func (r *TypesRecord) saveType(typ types.Type, rt reflect.Type, nested bool) { 219 r.rcache[rt] = typ 220 if nested { 221 r.ncache.Set(typ, rt) 222 return 223 } 224 r.tcache.Set(typ, rt) 225 return 226 } 227 228 func (r *TypesRecord) ToType(typ types.Type) (reflect.Type, bool) { 229 if rt, ok, nested := r.LookupReflect(typ); ok { 230 return rt, nested 231 } 232 var nested bool 233 var rt reflect.Type 234 switch t := typ.(type) { 235 case *types.Basic: 236 kind := t.Kind() 237 if kind > types.Invalid && kind < types.UntypedNil { 238 rt = xtypeTypes[kind] 239 } 240 case *types.Pointer: 241 var elem reflect.Type 242 elem, nested = r.ToType(t.Elem()) 243 rt = reflect.PtrTo(elem) 244 case *types.Slice: 245 var elem reflect.Type 246 elem, nested = r.ToType(t.Elem()) 247 rt = reflect.SliceOf(elem) 248 case *types.Array: 249 var elem reflect.Type 250 elem, nested = r.ToType(t.Elem()) 251 rt = reflect.ArrayOf(int(t.Len()), elem) 252 case *types.Map: 253 key, n1 := r.ToType(t.Key()) 254 elem, n2 := r.ToType(t.Elem()) 255 nested = n1 || n2 256 rt = reflect.MapOf(key, elem) 257 case *types.Chan: 258 var elem reflect.Type 259 elem, nested = r.ToType(t.Elem()) 260 rt = reflect.ChanOf(toReflectChanDir(t.Dir()), elem) 261 case *types.Struct: 262 rt, nested = r.toStructType(t) 263 case *types.Named: 264 rt, nested = r.toNamedType(t) 265 case *types.Interface: 266 rt, nested = r.toInterfaceType(t) 267 case *types.Signature: 268 in, n1 := r.ToTypeList(t.Params()) 269 out, n2 := r.ToTypeList(t.Results()) 270 nested = n1 || n2 271 b := t.Variadic() 272 if b && len(in) > 0 { 273 last := in[len(in)-1] 274 if last.Kind() == reflect.String { 275 in[len(in)-1] = reflect.TypeOf([]byte{}) 276 } 277 } 278 rt = reflect.FuncOf(in, out, b) 279 case *types.Tuple: 280 _, nested = r.ToTypeList(t) 281 rt = reflect.TypeOf((*_tuple)(nil)).Elem() 282 default: 283 panic(fmt.Errorf("ToType: not handled %v", typ)) 284 } 285 r.saveType(typ, rt, nested) 286 return rt, nested 287 } 288 289 type _tuple struct{} 290 291 func (r *TypesRecord) toInterfaceType(t *types.Interface) (reflect.Type, bool) { 292 n := t.NumMethods() 293 if n == 0 { 294 return tyEmptyInterface, false 295 } 296 var nested bool 297 ms := make([]reflect.Method, n) 298 for i := 0; i < n; i++ { 299 fn := t.Method(i) 300 mtyp, n := r.ToType(fn.Type()) 301 if n { 302 nested = true 303 } 304 ms[i] = reflect.Method{ 305 Name: fn.Name(), 306 Type: mtyp, 307 } 308 if pkg := fn.Pkg(); pkg != nil { 309 ms[i].PkgPath = pkg.Path() 310 } 311 } 312 return r.rctx.InterfaceOf(nil, ms), nested 313 } 314 315 func (r *TypesRecord) toNamedType(t *types.Named) (reflect.Type, bool) { 316 ut := t.Underlying() 317 pkgpath, name, typeargs, nested := r.extractNamed(t, false) 318 if pkgpath == "" { 319 if name == "error" { 320 return tyErrorInterface, false 321 } 322 return r.ToType(ut) 323 } 324 methods := typeutil.IntuitiveMethodSet(t, nil) 325 hasMethod := len(methods) > 0 326 etyp := toMockType(ut) 327 typ := reflectx.NamedTypeOf(pkgpath, name, etyp) 328 if hasMethod { 329 var mcount, pcount int 330 for i := 0; i < len(methods); i++ { 331 sig := methods[i].Type().(*types.Signature) 332 if !isPointer(sig.Recv().Type()) { 333 mcount++ 334 } 335 pcount++ 336 } 337 typ = r.rctx.NewMethodSet(typ, mcount, pcount) 338 } 339 r.saveType(t, typ, nested) 340 utype, _ := r.ToType(ut) 341 reflectx.SetUnderlying(typ, utype) 342 if typeargs { 343 pkgpath, name, _, _ = r.extractNamed(t, true) 344 reflectx.SetTypeName(typ, pkgpath, name) 345 } 346 if hasMethod && typ.Kind() != reflect.Interface { 347 r.setMethods(typ, methods) 348 } 349 return typ, nested 350 } 351 352 func (r *TypesRecord) toStructType(t *types.Struct) (reflect.Type, bool) { 353 n := t.NumFields() 354 if n == 0 { 355 return tyEmptyStruct, false 356 } 357 var nested bool 358 flds := make([]reflect.StructField, n) 359 for i := 0; i < n; i++ { 360 f := t.Field(i) 361 typ, n := r.ToType(f.Type()) 362 if n { 363 nested = true 364 } 365 flds[i] = r.toStructField(f, typ, t.Tag(i)) 366 } 367 typ := r.rctx.StructOf(flds) 368 methods := typeutil.IntuitiveMethodSet(t, nil) 369 if numMethods := len(methods); numMethods != 0 { 370 // anonymous structs with methods. struct { T } 371 var mcount, pcount int 372 for i := 0; i < numMethods; i++ { 373 sig := methods[i].Type().(*types.Signature) 374 if !isPointer(sig.Recv().Type()) { 375 mcount++ 376 } 377 pcount++ 378 } 379 typ = r.rctx.NewMethodSet(typ, mcount, pcount) 380 r.setMethods(typ, methods) 381 } 382 return typ, nested 383 } 384 385 func (r *TypesRecord) toStructField(v *types.Var, typ reflect.Type, tag string) reflect.StructField { 386 name := v.Name() 387 fld := reflect.StructField{ 388 Name: name, 389 Type: typ, 390 Tag: reflect.StructTag(tag), 391 Anonymous: v.Anonymous(), 392 } 393 if !token.IsExported(name) { 394 fld.PkgPath = v.Pkg().Path() 395 } 396 return fld 397 } 398 399 func (r *TypesRecord) ToTypeList(tuple *types.Tuple) ([]reflect.Type, bool) { 400 n := tuple.Len() 401 if n == 0 { 402 return nil, false 403 } 404 var nested bool 405 var ne bool 406 list := make([]reflect.Type, n) 407 for i := 0; i < n; i++ { 408 list[i], ne = r.ToType(tuple.At(i).Type()) 409 if ne { 410 nested = true 411 } 412 } 413 return list, nested 414 } 415 416 func isPointer(typ types.Type) bool { 417 _, ok := typ.Underlying().(*types.Pointer) 418 return ok 419 } 420 421 func (r *TypesRecord) setMethods(typ reflect.Type, methods []*types.Selection) { 422 numMethods := len(methods) 423 var ms []reflectx.Method 424 for i := 0; i < numMethods; i++ { 425 fn := methods[i].Obj().(*types.Func) 426 sig := methods[i].Type().(*types.Signature) 427 pointer := isPointer(sig.Recv().Type()) 428 mtyp, _ := r.ToType(sig) 429 var mfn func(args []reflect.Value) []reflect.Value 430 idx := methods[i].Index() 431 if len(idx) > 1 { 432 isptr := isPointer(fn.Type().Underlying().(*types.Signature).Recv().Type()) 433 variadic := mtyp.IsVariadic() 434 mfn = func(args []reflect.Value) []reflect.Value { 435 v := args[0] 436 for v.Kind() == reflect.Ptr { 437 v = v.Elem() 438 } 439 v = reflectx.FieldByIndexX(v, idx[:len(idx)-1]) 440 if isptr && v.Kind() != reflect.Ptr { 441 v = v.Addr() 442 } 443 if v.Kind() == reflect.Interface { 444 if variadic { 445 return v.MethodByName(fn.Name()).CallSlice(args[1:]) 446 } 447 return v.MethodByName(fn.Name()).Call(args[1:]) 448 } 449 m, _ := reflectx.MethodByName(v.Type(), fn.Name()) 450 args[0] = v 451 if variadic { 452 return m.Func.CallSlice(args) 453 } 454 return m.Func.Call(args) 455 } 456 } else { 457 mfn = r.finder.FindMethod(mtyp, fn) 458 } 459 var pkgpath string 460 if pkg := fn.Pkg(); pkg != nil { 461 pkgpath = pkg.Path() 462 } 463 ms = append(ms, reflectx.MakeMethod(fn.Name(), pkgpath, pointer, mtyp, mfn)) 464 } 465 err := r.rctx.SetMethodSet(typ, ms, false) 466 if err != nil { 467 log.Fatalf("SetMethodSet %v err, %v\n", typ, err) 468 } 469 } 470 471 func toReflectChanDir(d types.ChanDir) reflect.ChanDir { 472 switch d { 473 case types.SendRecv: 474 return reflect.BothDir 475 case types.SendOnly: 476 return reflect.SendDir 477 case types.RecvOnly: 478 return reflect.RecvDir 479 } 480 return 0 481 } 482 483 func (r *TypesRecord) Load(pkg *ssa.Package) { 484 checked := make(map[types.Type]bool) 485 for _, v := range pkg.Members { 486 typ := v.Type() 487 if checked[typ] { 488 continue 489 } 490 checked[typ] = true 491 if hasTypeParam(typ) { 492 continue 493 } 494 r.ToType(typ) 495 } 496 }