github.com/goplus/gossa@v0.3.25/rtypes.go (about) 1 package gossa 2 3 import ( 4 "fmt" 5 "go/constant" 6 "go/token" 7 "go/types" 8 "reflect" 9 "runtime" 10 "strings" 11 12 "golang.org/x/tools/go/types/typeutil" 13 ) 14 15 var ( 16 xtypeTypeNames = make(map[string]*types.Basic) 17 ) 18 19 var ( 20 typesDummyStruct = types.NewStruct(nil, nil) 21 typesDummySig = types.NewSignature(nil, nil, nil, false) 22 typesError = types.Universe.Lookup("error").Type() 23 typesEmptyInterface = types.NewInterfaceType(nil, nil) 24 ) 25 26 var ( 27 tyEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem() 28 tyErrorInterface = reflect.TypeOf((*error)(nil)).Elem() 29 ) 30 31 func init() { 32 for i := types.Invalid; i <= types.UntypedNil; i++ { 33 typ := types.Typ[i] 34 xtypeTypeNames[typ.String()] = typ 35 } 36 } 37 38 type TypesLoader struct { 39 packages map[string]*types.Package 40 installed map[string]*Package 41 rcache map[reflect.Type]types.Type 42 tcache *typeutil.Map 43 curpkg *Package 44 mode Mode 45 } 46 47 // NewTypesLoader install package and readonly 48 func NewTypesLoader(mode Mode) Loader { 49 r := &TypesLoader{ 50 packages: make(map[string]*types.Package), 51 installed: make(map[string]*Package), 52 rcache: make(map[reflect.Type]types.Type), 53 tcache: &typeutil.Map{}, 54 mode: mode, 55 } 56 r.packages["unsafe"] = types.Unsafe 57 r.rcache[tyErrorInterface] = typesError 58 r.rcache[tyEmptyInterface] = typesEmptyInterface 59 return r 60 } 61 62 func (r *TypesLoader) Installed(path string) (pkg *Package, ok bool) { 63 pkg, ok = r.installed[path] 64 return 65 } 66 67 func (r *TypesLoader) Packages() (pkgs []*types.Package) { 68 for _, pkg := range r.packages { 69 pkgs = append(pkgs, pkg) 70 } 71 return 72 } 73 74 func (r *TypesLoader) LookupPackage(pkgpath string) (*types.Package, bool) { 75 pkg, ok := r.packages[pkgpath] 76 return pkg, ok 77 } 78 79 func (r *TypesLoader) LookupReflect(typ types.Type) (reflect.Type, bool) { 80 if rt := r.tcache.At(typ); rt != nil { 81 return rt.(reflect.Type), true 82 } 83 return nil, false 84 } 85 86 func (r *TypesLoader) LookupTypes(typ reflect.Type) (types.Type, bool) { 87 t, ok := r.rcache[typ] 88 return t, ok 89 } 90 91 func (r *TypesLoader) Import(path string) (*types.Package, error) { 92 if p, ok := r.packages[path]; ok { 93 return p, nil 94 } 95 pkg, ok := registerPkgs[path] 96 if !ok { 97 return nil, fmt.Errorf("Not found package %v", path) 98 } 99 p := types.NewPackage(pkg.Path, pkg.Name) 100 r.packages[path] = p 101 var list []*types.Package 102 for dep, _ := range pkg.Deps { 103 p, err := r.Import(dep) 104 if err == nil { 105 list = append(list, p) 106 } 107 } 108 if err := r.installPackage(pkg); err != nil { 109 return nil, err 110 } 111 p.SetImports(list) 112 p.MarkComplete() 113 return p, nil 114 } 115 116 func (r *TypesLoader) installPackage(pkg *Package) (err error) { 117 defer func() { 118 if e := recover(); e != nil { 119 err = e.(error) 120 } 121 r.curpkg = nil 122 }() 123 r.curpkg = pkg 124 r.installed[pkg.Path] = pkg 125 p, ok := r.packages[pkg.Path] 126 if !ok { 127 p = types.NewPackage(pkg.Path, pkg.Name) 128 r.packages[pkg.Path] = p 129 } 130 for name, typ := range pkg.Interfaces { 131 r.InsertInterface(p, name, typ) 132 } 133 for name, typ := range pkg.NamedTypes { 134 r.InsertNamedType(p, name, typ) 135 } 136 for name, typ := range pkg.AliasTypes { 137 r.InsertAlias(p, name, typ) 138 } 139 for name, fn := range pkg.Funcs { 140 r.InsertFunc(p, name, fn) 141 } 142 for name, v := range pkg.Vars { 143 r.InsertVar(p, name, v.Elem()) 144 } 145 for name, c := range pkg.TypedConsts { 146 r.InsertTypedConst(p, name, c) 147 } 148 for name, c := range pkg.UntypedConsts { 149 r.InsertUntypedConst(p, name, c) 150 } 151 return 152 } 153 154 func (r *TypesLoader) InsertInterface(p *types.Package, name string, rt reflect.Type) { 155 r.ToType(rt) 156 } 157 158 func (r *TypesLoader) InsertNamedType(p *types.Package, name string, t NamedType) { 159 r.ToType(t.Typ) 160 } 161 162 func (r *TypesLoader) InsertAlias(p *types.Package, name string, rt reflect.Type) { 163 typ := r.ToType(rt) 164 p.Scope().Insert(types.NewTypeName(token.NoPos, p, name, typ)) 165 } 166 167 func (r *TypesLoader) InsertFunc(p *types.Package, name string, v reflect.Value) { 168 typ := r.ToType(v.Type()) 169 p.Scope().Insert(types.NewFunc(token.NoPos, p, name, typ.(*types.Signature))) 170 } 171 172 func (r *TypesLoader) InsertVar(p *types.Package, name string, v reflect.Value) { 173 typ := r.ToType(v.Type()) 174 p.Scope().Insert(types.NewVar(token.NoPos, p, name, typ)) 175 } 176 177 func (r *TypesLoader) InsertConst(p *types.Package, name string, typ types.Type, c constant.Value) { 178 p.Scope().Insert(types.NewConst(token.NoPos, p, name, typ, c)) 179 } 180 181 func splitPath(path string) (pkg string, name string, ok bool) { 182 pos := strings.LastIndex(path, ".") 183 if pos == -1 { 184 return path, "", false 185 } 186 return path[:pos], path[pos+1:], true 187 } 188 189 func (r *TypesLoader) parserNamed(path string) (*types.Package, string) { 190 if pkg, name, ok := splitPath(path); ok { 191 if p := r.GetPackage(pkg); p != nil { 192 return p, name 193 } 194 } 195 panic(fmt.Errorf("parse path failed: %v", path)) 196 } 197 198 func (r *TypesLoader) LookupType(typ string) types.Type { 199 if t, ok := xtypeTypeNames[typ]; ok { 200 return t 201 } 202 p, name := r.parserNamed(typ) 203 return p.Scope().Lookup(name).Type() 204 } 205 206 func (r *TypesLoader) InsertTypedConst(p *types.Package, name string, v TypedConst) { 207 typ := r.ToType(v.Typ) 208 r.InsertConst(p, name, typ, v.Value) 209 } 210 211 func (r *TypesLoader) InsertUntypedConst(p *types.Package, name string, v UntypedConst) { 212 var typ types.Type 213 if t, ok := xtypeTypeNames[v.Typ]; ok { 214 typ = t 215 } else { 216 typ = r.LookupType(v.Typ) 217 } 218 r.InsertConst(p, name, typ, v.Value) 219 } 220 221 func (r *TypesLoader) GetPackage(pkg string) *types.Package { 222 if pkg == "" { 223 return nil 224 } 225 if p, ok := r.packages[pkg]; ok { 226 return p 227 } 228 var name string 229 if r.curpkg != nil { 230 name = r.curpkg.Deps[pkg] 231 } 232 if name == "" { 233 pkgs := strings.Split(pkg, "/") 234 name = pkgs[len(pkgs)-1] 235 } 236 p := types.NewPackage(pkg, name) 237 r.packages[pkg] = p 238 return p 239 } 240 241 func toTypeChanDir(dir reflect.ChanDir) types.ChanDir { 242 switch dir { 243 case reflect.RecvDir: 244 return types.RecvOnly 245 case reflect.SendDir: 246 return types.SendOnly 247 case reflect.BothDir: 248 return types.SendRecv 249 } 250 panic("unreachable") 251 } 252 253 func (r *TypesLoader) Insert(v reflect.Value) { 254 typ := r.ToType(v.Type()) 255 if v.Kind() == reflect.Func { 256 name := runtime.FuncForPC(v.Pointer()).Name() 257 names := strings.Split(name, ".") 258 pkg := r.GetPackage(names[0]) 259 pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, names[1], typ.(*types.Signature))) 260 } 261 } 262 263 func (r *TypesLoader) toFunc(pkg *types.Package, recv *types.Var, inoff int, rt reflect.Type) *types.Signature { 264 numIn := rt.NumIn() 265 numOut := rt.NumOut() 266 in := make([]*types.Var, numIn-inoff, numIn-inoff) 267 out := make([]*types.Var, numOut, numOut) 268 for i := inoff; i < numIn; i++ { 269 it := r.ToType(rt.In(i)) 270 in[i-inoff] = types.NewVar(token.NoPos, pkg, "", it) 271 } 272 for i := 0; i < numOut; i++ { 273 it := r.ToType(rt.Out(i)) 274 out[i] = types.NewVar(token.NoPos, pkg, "", it) 275 } 276 return types.NewSignature(recv, types.NewTuple(in...), types.NewTuple(out...), rt.IsVariadic()) 277 } 278 279 func (r *TypesLoader) ToType(rt reflect.Type) types.Type { 280 if t, ok := r.rcache[rt]; ok { 281 return t 282 } 283 var typ types.Type 284 var fields []*types.Var 285 var imethods []*types.Func 286 kind := rt.Kind() 287 switch kind { 288 case reflect.Invalid: 289 typ = types.Typ[types.Invalid] 290 case reflect.Bool: 291 typ = types.Typ[types.Bool] 292 case reflect.Int: 293 typ = types.Typ[types.Int] 294 case reflect.Int8: 295 typ = types.Typ[types.Int8] 296 case reflect.Int16: 297 typ = types.Typ[types.Int16] 298 case reflect.Int32: 299 typ = types.Typ[types.Int32] 300 case reflect.Int64: 301 typ = types.Typ[types.Int64] 302 case reflect.Uint: 303 typ = types.Typ[types.Uint] 304 case reflect.Uint8: 305 typ = types.Typ[types.Uint8] 306 case reflect.Uint16: 307 typ = types.Typ[types.Uint16] 308 case reflect.Uint32: 309 typ = types.Typ[types.Uint32] 310 case reflect.Uint64: 311 typ = types.Typ[types.Uint64] 312 case reflect.Uintptr: 313 typ = types.Typ[types.Uintptr] 314 case reflect.Float32: 315 typ = types.Typ[types.Float32] 316 case reflect.Float64: 317 typ = types.Typ[types.Float64] 318 case reflect.Complex64: 319 typ = types.Typ[types.Complex64] 320 case reflect.Complex128: 321 typ = types.Typ[types.Complex128] 322 case reflect.Array: 323 elem := r.ToType(rt.Elem()) 324 typ = types.NewArray(elem, int64(rt.Len())) 325 case reflect.Chan: 326 elem := r.ToType(rt.Elem()) 327 dir := toTypeChanDir(rt.ChanDir()) 328 typ = types.NewChan(dir, elem) 329 case reflect.Func: 330 pkg := r.GetPackage(r.curpkg.Path) 331 typ = r.toFunc(pkg, nil, 0, rt) 332 case reflect.Interface: 333 n := rt.NumMethod() 334 imethods = make([]*types.Func, n, n) 335 pkg := r.GetPackage(rt.PkgPath()) 336 for i := 0; i < n; i++ { 337 im := rt.Method(i) 338 sig := typesDummySig 339 imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig) 340 } 341 typ = types.NewInterfaceType(imethods, nil) 342 case reflect.Map: 343 key := r.ToType(rt.Key()) 344 elem := r.ToType(rt.Elem()) 345 typ = types.NewMap(key, elem) 346 case reflect.Ptr: 347 elem := r.ToType(rt.Elem()) 348 typ = types.NewPointer(elem) 349 case reflect.Slice: 350 elem := r.ToType(rt.Elem()) 351 typ = types.NewSlice(elem) 352 case reflect.String: 353 typ = types.Typ[types.String] 354 case reflect.Struct: 355 n := rt.NumField() 356 fields = make([]*types.Var, n, n) 357 tags := make([]string, n, n) 358 pkg := r.GetPackage(rt.PkgPath()) 359 for i := 0; i < n; i++ { 360 f := rt.Field(i) 361 ft := types.Typ[types.UnsafePointer] //r.ToType(f.Type) 362 fields[i] = types.NewVar(token.NoPos, pkg, f.Name, ft) 363 tags[i] = string(f.Tag) 364 } 365 typ = types.NewStruct(fields, tags) 366 case reflect.UnsafePointer: 367 typ = types.Typ[types.UnsafePointer] 368 default: 369 panic("unreachable") 370 } 371 var named *types.Named 372 if path := rt.PkgPath(); path != "" { 373 pkg := r.GetPackage(path) 374 obj := types.NewTypeName(token.NoPos, pkg, rt.Name(), nil) 375 named = types.NewNamed(obj, typ, nil) 376 typ = named 377 pkg.Scope().Insert(obj) 378 } 379 r.rcache[rt] = typ 380 r.tcache.Set(typ, rt) 381 if kind == reflect.Struct { 382 n := rt.NumField() 383 pkg := r.GetPackage(rt.PkgPath()) 384 for i := 0; i < n; i++ { 385 f := rt.Field(i) 386 ft := r.ToType(f.Type) 387 fields[i] = types.NewField(token.NoPos, pkg, f.Name, ft, f.Anonymous) 388 } 389 } else if kind == reflect.Interface { 390 n := rt.NumMethod() 391 pkg := named.Obj().Pkg() 392 recv := types.NewVar(token.NoPos, pkg, "", typ) 393 for i := 0; i < n; i++ { 394 im := rt.Method(i) 395 sig := r.toFunc(pkg, recv, 0, im.Type) 396 imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig) 397 } 398 typ.Underlying().(*types.Interface).Complete() 399 } 400 if named != nil { 401 if kind != reflect.Interface { 402 var filter func(name string, ptr bool) bool 403 pkg := named.Obj().Pkg() 404 if p, ok := r.installed[pkg.Path()]; ok { 405 if t, ok := p.NamedTypes[named.Obj().Name()]; ok { 406 m := make(map[string]bool) 407 pm := make(map[string]bool) 408 for _, v := range strings.Split(t.Methods, ",") { 409 m[v] = true 410 } 411 for _, v := range strings.Split(t.PtrMethods, ",") { 412 pm[v] = true 413 } 414 filter = func(name string, ptr bool) bool { 415 if ptr { 416 return pm[name] 417 } 418 return m[name] 419 } 420 } 421 } 422 423 prt := reflect.PtrTo(rt) 424 ptyp := r.ToType(prt) 425 precv := types.NewVar(token.NoPos, pkg, "", ptyp) 426 427 skip := make(map[string]bool) 428 for _, im := range AllMethod(prt, r.mode&DisableUnexportMethods == 0) { 429 if filter != nil && !filter(im.Name, true) { 430 continue 431 } 432 var sig *types.Signature 433 if im.Type != nil { 434 sig = r.toFunc(pkg, precv, 1, im.Type) 435 } else { 436 sig = typesDummySig 437 } 438 skip[im.Name] = true 439 named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig)) 440 } 441 recv := types.NewVar(token.NoPos, pkg, "", typ) 442 for _, im := range AllMethod(rt, r.mode&DisableUnexportMethods == 0) { 443 if skip[im.Name] { 444 continue 445 } 446 if filter != nil && !filter(im.Name, false) { 447 continue 448 } 449 var sig *types.Signature 450 if im.Type != nil { 451 sig = r.toFunc(pkg, recv, 1, im.Type) 452 } else { 453 sig = typesDummySig 454 } 455 named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig)) 456 } 457 } 458 } 459 return typ 460 }