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  }