github.com/petergtz/pegomock@v2.9.1-0.20230424204322-eb0e044013df+incompatible/modelgen/gomock/reflect_helpers.go (about) 1 package gomock 2 3 import ( 4 "encoding/gob" 5 "fmt" 6 "reflect" 7 8 "github.com/petergtz/pegomock/model" 9 ) 10 11 func init() { 12 gob.Register(&model.ArrayType{}) 13 gob.Register(&model.ChanType{}) 14 gob.Register(&model.FuncType{}) 15 gob.Register(&model.MapType{}) 16 gob.Register(&model.NamedType{}) 17 gob.Register(&model.PointerType{}) 18 gob.Register(model.PredeclaredType("")) 19 } 20 21 func InterfaceFromInterfaceType(it reflect.Type) (*model.Interface, error) { 22 if it.Kind() != reflect.Interface { 23 return nil, fmt.Errorf("%v is not an interface", it) 24 } 25 intf := &model.Interface{} 26 27 for i := 0; i < it.NumMethod(); i++ { 28 mt := it.Method(i) 29 // TODO: need to skip unexported methods? or just raise an error? 30 m := &model.Method{ 31 Name: mt.Name, 32 } 33 34 var err error 35 m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type) 36 if err != nil { 37 return nil, err 38 } 39 40 intf.Methods = append(intf.Methods, m) 41 } 42 43 return intf, nil 44 } 45 46 // t's Kind must be a reflect.Func. 47 func funcArgsFromType(t reflect.Type) (in []*model.Parameter, variadic *model.Parameter, out []*model.Parameter, err error) { 48 nin := t.NumIn() 49 if t.IsVariadic() { 50 nin-- 51 } 52 var p *model.Parameter 53 for i := 0; i < nin; i++ { 54 p, err = parameterFromType(t.In(i)) 55 if err != nil { 56 return 57 } 58 in = append(in, p) 59 } 60 if t.IsVariadic() { 61 p, err = parameterFromType(t.In(nin).Elem()) 62 if err != nil { 63 return 64 } 65 variadic = p 66 } 67 for i := 0; i < t.NumOut(); i++ { 68 p, err = parameterFromType(t.Out(i)) 69 if err != nil { 70 return 71 } 72 out = append(out, p) 73 } 74 return 75 } 76 77 func parameterFromType(t reflect.Type) (*model.Parameter, error) { 78 tt, err := typeFromType(t) 79 if err != nil { 80 return nil, err 81 } 82 return &model.Parameter{Type: tt}, nil 83 } 84 85 var errorType = reflect.TypeOf((*error)(nil)).Elem() 86 87 var byteType = reflect.TypeOf(byte(0)) 88 89 func typeFromType(t reflect.Type) (model.Type, error) { 90 // Hack workaround for https://golang.org/issue/3853. 91 // This explicit check should not be necessary. 92 if t == byteType { 93 return model.PredeclaredType("byte"), nil 94 } 95 96 if imp := t.PkgPath(); imp != "" { 97 return &model.NamedType{ 98 Package: imp, 99 Type: t.Name(), 100 }, nil 101 } 102 103 // only unnamed or predeclared types after here 104 105 // Lots of types have element types. Let's do the parsing and error checking for all of them. 106 var elemType model.Type 107 switch t.Kind() { 108 case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice: 109 var err error 110 elemType, err = typeFromType(t.Elem()) 111 if err != nil { 112 return nil, err 113 } 114 } 115 116 switch t.Kind() { 117 case reflect.Array: 118 return &model.ArrayType{ 119 Len: t.Len(), 120 Type: elemType, 121 }, nil 122 case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 123 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 124 reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String: 125 return model.PredeclaredType(t.Kind().String()), nil 126 case reflect.Chan: 127 var dir model.ChanDir 128 switch t.ChanDir() { 129 case reflect.RecvDir: 130 dir = model.RecvDir 131 case reflect.SendDir: 132 dir = model.SendDir 133 } 134 return &model.ChanType{ 135 Dir: dir, 136 Type: elemType, 137 }, nil 138 case reflect.Func: 139 in, variadic, out, err := funcArgsFromType(t) 140 if err != nil { 141 return nil, err 142 } 143 return &model.FuncType{ 144 In: in, 145 Out: out, 146 Variadic: variadic, 147 }, nil 148 case reflect.Interface: 149 // Two special interfaces. 150 if t.NumMethod() == 0 { 151 return model.PredeclaredType("interface{}"), nil 152 } 153 if t == errorType { 154 return model.PredeclaredType("error"), nil 155 } 156 case reflect.Map: 157 kt, err := typeFromType(t.Key()) 158 if err != nil { 159 return nil, err 160 } 161 return &model.MapType{ 162 Key: kt, 163 Value: elemType, 164 }, nil 165 case reflect.Ptr: 166 return &model.PointerType{ 167 Type: elemType, 168 }, nil 169 case reflect.Slice: 170 return &model.ArrayType{ 171 Len: -1, 172 Type: elemType, 173 }, nil 174 case reflect.Struct: 175 if t.NumField() == 0 { 176 return model.PredeclaredType("struct{}"), nil 177 } 178 } 179 180 // TODO: Struct, UnsafePointer 181 return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind()) 182 }