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  }