github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/bind/types.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bind
     6  
     7  import (
     8  	"fmt"
     9  	"go/types"
    10  	"log"
    11  	"strings"
    12  )
    13  
    14  type ifaceSummary struct {
    15  	iface         *types.Interface
    16  	callable      []*types.Func
    17  	implementable bool
    18  }
    19  
    20  func makeIfaceSummary(iface *types.Interface) ifaceSummary {
    21  	summary := ifaceSummary{
    22  		iface:         iface,
    23  		implementable: true,
    24  	}
    25  	methodset := types.NewMethodSet(iface)
    26  	for i := 0; i < methodset.Len(); i++ {
    27  		obj := methodset.At(i).Obj()
    28  		if !obj.Exported() {
    29  			summary.implementable = false
    30  			continue
    31  		}
    32  		m, ok := obj.(*types.Func)
    33  		if !ok {
    34  			log.Panicf("unexpected methodset obj: %s (%T)", obj, obj)
    35  		}
    36  		if !isImplementable(m.Type().(*types.Signature)) {
    37  			summary.implementable = false
    38  		}
    39  		if isCallable(m) {
    40  			summary.callable = append(summary.callable, m)
    41  		}
    42  	}
    43  	return summary
    44  }
    45  
    46  func isCallable(t *types.Func) bool {
    47  	// TODO(crawshaw): functions that are not implementable from
    48  	// another language may still be callable (for example, a
    49  	// returned value with an unexported type can be treated as
    50  	// an opaque value by the caller). This restriction could be
    51  	// lifted.
    52  	return isImplementable(t.Type().(*types.Signature))
    53  }
    54  
    55  func isImplementable(sig *types.Signature) bool {
    56  	params := sig.Params()
    57  	for i := 0; i < params.Len(); i++ {
    58  		if !isExported(params.At(i).Type()) {
    59  			return false
    60  		}
    61  	}
    62  	res := sig.Results()
    63  	for i := 0; i < res.Len(); i++ {
    64  		if !isExported(res.At(i).Type()) {
    65  			return false
    66  		}
    67  	}
    68  	return true
    69  }
    70  
    71  func exportedMethodSet(T types.Type) []*types.Func {
    72  	var methods []*types.Func
    73  	methodset := types.NewMethodSet(T)
    74  	for i := 0; i < methodset.Len(); i++ {
    75  		obj := methodset.At(i).Obj()
    76  		if !obj.Exported() {
    77  			continue
    78  		}
    79  		// Skip methods from the embedded classes, so that
    80  		// only methods that are implemented in Go are included.
    81  		if pref := pkgFirstElem(obj.Pkg()); pref == "Java" || pref == "ObjC" {
    82  			continue
    83  		}
    84  		switch obj := obj.(type) {
    85  		case *types.Func:
    86  			methods = append(methods, obj)
    87  		default:
    88  			log.Panicf("unexpected methodset obj: %s", obj)
    89  		}
    90  	}
    91  	return methods
    92  }
    93  
    94  func exportedFields(T *types.Struct) []*types.Var {
    95  	var fields []*types.Var
    96  	for i := 0; i < T.NumFields(); i++ {
    97  		f := T.Field(i)
    98  		if !f.Exported() {
    99  			continue
   100  		}
   101  		fields = append(fields, f)
   102  	}
   103  	return fields
   104  }
   105  
   106  func isErrorType(t types.Type) bool {
   107  	return types.Identical(t, types.Universe.Lookup("error").Type())
   108  }
   109  
   110  func isExported(t types.Type) bool {
   111  	if isErrorType(t) {
   112  		return true
   113  	}
   114  	switch t := t.(type) {
   115  	case *types.Basic:
   116  		return true
   117  	case *types.Named:
   118  		return t.Obj().Exported()
   119  	case *types.Pointer:
   120  		return isExported(t.Elem())
   121  	default:
   122  		return true
   123  	}
   124  }
   125  
   126  func isRefType(t types.Type) bool {
   127  	if isErrorType(t) {
   128  		return false
   129  	}
   130  	switch t := t.(type) {
   131  	case *types.Named:
   132  		switch u := t.Underlying().(type) {
   133  		case *types.Interface:
   134  			return true
   135  		default:
   136  			panic(fmt.Sprintf("unsupported named type: %s / %T", u, u))
   137  		}
   138  	case *types.Pointer:
   139  		return isRefType(t.Elem())
   140  	default:
   141  		return false
   142  	}
   143  }
   144  
   145  func isNullableType(t types.Type) bool {
   146  	return types.AssignableTo(types.Typ[types.UntypedNil].Underlying(), t) || t.String() == "string" // string is mapped to NSString*, which is nullable
   147  }
   148  
   149  func typePkgFirstElem(t types.Type) string {
   150  	nt, ok := t.(*types.Named)
   151  	if !ok {
   152  		return ""
   153  	}
   154  	return pkgFirstElem(nt.Obj().Pkg())
   155  }
   156  
   157  func pkgFirstElem(p *types.Package) string {
   158  	if p == nil {
   159  		return ""
   160  	}
   161  	path := p.Path()
   162  	idx := strings.Index(path, "/")
   163  	if idx == -1 {
   164  		return path
   165  	}
   166  	return path[:idx]
   167  }
   168  
   169  func isWrapperType(t types.Type) bool {
   170  	e := typePkgFirstElem(t)
   171  	return e == "Java" || e == "ObjC"
   172  }