github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/fakereflect/fakereflect.go (about) 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 := 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 }