github.com/F4RD1N/gomobile@v1.0.1/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 }