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  }