132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
|
package fakereflect
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"go/types"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
type TypeAndCanAddr struct {
|
||
|
Type types.Type
|
||
|
canAddr bool
|
||
|
}
|
||
|
|
||
|
type StructField struct {
|
||
|
Index []int
|
||
|
Name string
|
||
|
Anonymous bool
|
||
|
Tag reflect.StructTag
|
||
|
f *types.Var
|
||
|
Type TypeAndCanAddr
|
||
|
}
|
||
|
|
||
|
func (sf StructField) IsExported() bool { return sf.f.Exported() }
|
||
|
|
||
|
func (t TypeAndCanAddr) Field(i int) StructField {
|
||
|
st := t.Type.Underlying().(*types.Struct)
|
||
|
f := st.Field(i)
|
||
|
return StructField{
|
||
|
f: f,
|
||
|
Index: []int{i},
|
||
|
Name: f.Name(),
|
||
|
Anonymous: f.Anonymous(),
|
||
|
Tag: reflect.StructTag(st.Tag(i)),
|
||
|
Type: TypeAndCanAddr{
|
||
|
Type: f.Type(),
|
||
|
canAddr: t.canAddr,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) FieldByIndex(index []int) StructField {
|
||
|
f := t.Field(index[0])
|
||
|
for _, idx := range index[1:] {
|
||
|
f = f.Type.Field(idx)
|
||
|
}
|
||
|
f.Index = index
|
||
|
return f
|
||
|
}
|
||
|
|
||
|
func PtrTo(t TypeAndCanAddr) TypeAndCanAddr {
|
||
|
// Note that we don't care about canAddr here because it's irrelevant to all uses of PtrTo
|
||
|
return TypeAndCanAddr{Type: types.NewPointer(t.Type)}
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) CanAddr() bool { return t.canAddr }
|
||
|
|
||
|
func (t TypeAndCanAddr) Implements(ityp *types.Interface) bool {
|
||
|
return types.Implements(t.Type, ityp)
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) IsSlice() bool {
|
||
|
_, ok := t.Type.Underlying().(*types.Slice)
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) IsArray() bool {
|
||
|
_, ok := t.Type.Underlying().(*types.Array)
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) IsPtr() bool {
|
||
|
_, ok := t.Type.Underlying().(*types.Pointer)
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) IsInterface() bool {
|
||
|
_, ok := t.Type.Underlying().(*types.Interface)
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) IsStruct() bool {
|
||
|
_, ok := t.Type.Underlying().(*types.Struct)
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) Name() string {
|
||
|
named, ok := t.Type.(*types.Named)
|
||
|
if !ok {
|
||
|
return ""
|
||
|
}
|
||
|
return named.Obj().Name()
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) NumField() int {
|
||
|
return t.Type.Underlying().(*types.Struct).NumFields()
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) String() string {
|
||
|
return t.Type.String()
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) Key() TypeAndCanAddr {
|
||
|
return TypeAndCanAddr{Type: t.Type.Underlying().(*types.Map).Key()}
|
||
|
}
|
||
|
|
||
|
func (t TypeAndCanAddr) Elem() TypeAndCanAddr {
|
||
|
switch typ := t.Type.Underlying().(type) {
|
||
|
case *types.Pointer:
|
||
|
return TypeAndCanAddr{
|
||
|
Type: typ.Elem(),
|
||
|
canAddr: true,
|
||
|
}
|
||
|
case *types.Slice:
|
||
|
return TypeAndCanAddr{
|
||
|
Type: typ.Elem(),
|
||
|
canAddr: true,
|
||
|
}
|
||
|
case *types.Array:
|
||
|
return TypeAndCanAddr{
|
||
|
Type: typ.Elem(),
|
||
|
canAddr: t.canAddr,
|
||
|
}
|
||
|
case *types.Map:
|
||
|
return TypeAndCanAddr{
|
||
|
Type: typ.Elem(),
|
||
|
canAddr: false,
|
||
|
}
|
||
|
default:
|
||
|
panic(fmt.Sprintf("unhandled type %T", typ))
|
||
|
}
|
||
|
}
|