github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/typesutil/typesutil.go (about)

     1  package typesutil
     2  
     3  import (
     4  	"fmt"
     5  	"go/types"
     6  )
     7  
     8  func IsJsPackage(pkg *types.Package) bool {
     9  	return pkg != nil && pkg.Path() == "github.com/gopherjs/gopherjs/js"
    10  }
    11  
    12  func IsJsObject(t types.Type) bool {
    13  	ptr, isPtr := t.(*types.Pointer)
    14  	if !isPtr {
    15  		return false
    16  	}
    17  	named, isNamed := ptr.Elem().(*types.Named)
    18  	return isNamed && IsJsPackage(named.Obj().Pkg()) && named.Obj().Name() == "Object"
    19  }
    20  
    21  // RecvType returns a named type of a method receiver, or nil if it's not a method.
    22  //
    23  // For methods on a pointer receiver, the underlying named type is returned.
    24  func RecvType(sig *types.Signature) *types.Named {
    25  	recv := sig.Recv()
    26  	if recv == nil {
    27  		return nil
    28  	}
    29  
    30  	typ := recv.Type()
    31  	if ptrType, ok := typ.(*types.Pointer); ok {
    32  		typ = ptrType.Elem()
    33  	}
    34  
    35  	return typ.(*types.Named)
    36  }
    37  
    38  // RecvAsFirstArg takes a method signature and returns a function
    39  // signature with receiver as the first parameter.
    40  func RecvAsFirstArg(sig *types.Signature) *types.Signature {
    41  	params := make([]*types.Var, 0, 1+sig.Params().Len())
    42  	params = append(params, sig.Recv())
    43  	for i := 0; i < sig.Params().Len(); i++ {
    44  		params = append(params, sig.Params().At(i))
    45  	}
    46  	return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic())
    47  }
    48  
    49  // Selection is a common interface for go/types.Selection and our custom-constructed
    50  // method and field selections.
    51  type Selection interface {
    52  	Kind() types.SelectionKind
    53  	Recv() types.Type
    54  	Index() []int
    55  	Obj() types.Object
    56  	Type() types.Type
    57  }
    58  
    59  // NewSelection creates a new selection.
    60  func NewSelection(kind types.SelectionKind, recv types.Type, index []int, obj types.Object, typ types.Type) Selection {
    61  	return &selectionImpl{
    62  		kind:  kind,
    63  		recv:  recv,
    64  		index: index,
    65  		obj:   obj,
    66  		typ:   typ,
    67  	}
    68  }
    69  
    70  type selectionImpl struct {
    71  	kind  types.SelectionKind
    72  	recv  types.Type
    73  	index []int
    74  	obj   types.Object
    75  	typ   types.Type
    76  }
    77  
    78  func (sel *selectionImpl) Kind() types.SelectionKind { return sel.kind }
    79  func (sel *selectionImpl) Recv() types.Type          { return sel.recv }
    80  func (sel *selectionImpl) Index() []int              { return sel.index }
    81  func (sel *selectionImpl) Obj() types.Object         { return sel.obj }
    82  func (sel *selectionImpl) Type() types.Type          { return sel.typ }
    83  
    84  func fieldsOf(s *types.Struct) []*types.Var {
    85  	fields := make([]*types.Var, s.NumFields())
    86  	for i := 0; i < s.NumFields(); i++ {
    87  		fields[i] = s.Field(i)
    88  	}
    89  	return fields
    90  }
    91  
    92  // OffsetOf returns byte offset of a struct field specified by the provided
    93  // selection.
    94  //
    95  // Adapted from go/types.Config.offsetof().
    96  func OffsetOf(sizes types.Sizes, sel Selection) int64 {
    97  	if sel.Kind() != types.FieldVal {
    98  		panic(fmt.Errorf("byte offsets are only defined for struct fields"))
    99  	}
   100  	typ := sel.Recv()
   101  	var o int64
   102  	for _, idx := range sel.Index() {
   103  		s := typ.Underlying().(*types.Struct)
   104  		o += sizes.Offsetsof(fieldsOf(s))[idx]
   105  		typ = s.Field(idx).Type()
   106  	}
   107  
   108  	return o
   109  }