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  }