fakereflect.go raw

   1  package fakereflect
   2  
   3  import (
   4  	"fmt"
   5  	"go/types"
   6  	"reflect"
   7  )
   8  
   9  type TypeAndCanAddr struct {
  10  	Type    types.Type
  11  	canAddr bool
  12  }
  13  
  14  type StructField struct {
  15  	Index     []int
  16  	Name      string
  17  	Anonymous bool
  18  	Tag       reflect.StructTag
  19  	f         *types.Var
  20  	Type      TypeAndCanAddr
  21  }
  22  
  23  func (sf StructField) IsExported() bool { return sf.f.Exported() }
  24  
  25  func (t TypeAndCanAddr) Field(i int) StructField {
  26  	st := t.Type.Underlying().(*types.Struct)
  27  	f := st.Field(i)
  28  	return StructField{
  29  		f:         f,
  30  		Index:     []int{i},
  31  		Name:      f.Name(),
  32  		Anonymous: f.Anonymous(),
  33  		Tag:       reflect.StructTag(st.Tag(i)),
  34  		Type: TypeAndCanAddr{
  35  			Type:    f.Type(),
  36  			canAddr: t.canAddr,
  37  		},
  38  	}
  39  }
  40  
  41  func (t TypeAndCanAddr) FieldByIndex(index []int) StructField {
  42  	f := t.Field(index[0])
  43  	for _, idx := range index[1:] {
  44  		f = f.Type.Field(idx)
  45  	}
  46  	f.Index = index
  47  	return f
  48  }
  49  
  50  func PtrTo(t TypeAndCanAddr) TypeAndCanAddr {
  51  	// Note that we don't care about canAddr here because it's irrelevant to all uses of PtrTo
  52  	return TypeAndCanAddr{Type: types.NewPointer(t.Type)}
  53  }
  54  
  55  func (t TypeAndCanAddr) CanAddr() bool { return t.canAddr }
  56  
  57  func (t TypeAndCanAddr) Implements(ityp *types.Interface) bool {
  58  	return types.Implements(t.Type, ityp)
  59  }
  60  
  61  func (t TypeAndCanAddr) IsSlice() bool {
  62  	_, ok := t.Type.Underlying().(*types.Slice)
  63  	return ok
  64  }
  65  
  66  func (t TypeAndCanAddr) IsArray() bool {
  67  	_, ok := t.Type.Underlying().(*types.Array)
  68  	return ok
  69  }
  70  
  71  func (t TypeAndCanAddr) IsPtr() bool {
  72  	_, ok := t.Type.Underlying().(*types.Pointer)
  73  	return ok
  74  }
  75  
  76  func (t TypeAndCanAddr) IsInterface() bool {
  77  	_, ok := t.Type.Underlying().(*types.Interface)
  78  	return ok
  79  }
  80  
  81  func (t TypeAndCanAddr) IsStruct() bool {
  82  	_, ok := t.Type.Underlying().(*types.Struct)
  83  	return ok
  84  }
  85  
  86  func (t TypeAndCanAddr) Name() string {
  87  	named, ok := types.Unalias(t.Type).(*types.Named)
  88  	if !ok {
  89  		return ""
  90  	}
  91  	return named.Obj().Name()
  92  }
  93  
  94  func (t TypeAndCanAddr) NumField() int {
  95  	return t.Type.Underlying().(*types.Struct).NumFields()
  96  }
  97  
  98  func (t TypeAndCanAddr) String() string {
  99  	return t.Type.String()
 100  }
 101  
 102  func (t TypeAndCanAddr) Key() TypeAndCanAddr {
 103  	return TypeAndCanAddr{Type: t.Type.Underlying().(*types.Map).Key()}
 104  }
 105  
 106  func (t TypeAndCanAddr) Elem() TypeAndCanAddr {
 107  	switch typ := t.Type.Underlying().(type) {
 108  	case *types.Pointer:
 109  		return TypeAndCanAddr{
 110  			Type:    typ.Elem(),
 111  			canAddr: true,
 112  		}
 113  	case *types.Slice:
 114  		return TypeAndCanAddr{
 115  			Type:    typ.Elem(),
 116  			canAddr: true,
 117  		}
 118  	case *types.Array:
 119  		return TypeAndCanAddr{
 120  			Type:    typ.Elem(),
 121  			canAddr: t.canAddr,
 122  		}
 123  	case *types.Map:
 124  		return TypeAndCanAddr{
 125  			Type:    typ.Elem(),
 126  			canAddr: false,
 127  		}
 128  	default:
 129  		panic(fmt.Sprintf("unhandled type %T", typ))
 130  	}
 131  }
 132