| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package bind |
| |
| import ( |
| "go/types" |
| "log" |
| ) |
| |
| type ifaceSummary struct { |
| iface *types.Interface |
| callable []*types.Func |
| implementable bool |
| } |
| |
| func makeIfaceSummary(iface *types.Interface) ifaceSummary { |
| summary := ifaceSummary{ |
| iface: iface, |
| implementable: true, |
| } |
| methodset := types.NewMethodSet(iface) |
| for i := 0; i < methodset.Len(); i++ { |
| obj := methodset.At(i).Obj() |
| if !obj.Exported() { |
| summary.implementable = false |
| continue |
| } |
| m, ok := obj.(*types.Func) |
| if !ok { |
| log.Panicf("unexpected methodset obj: %s (%T)", obj, obj) |
| } |
| if !isImplementable(m.Type().(*types.Signature)) { |
| summary.implementable = false |
| } |
| if isCallable(m) { |
| summary.callable = append(summary.callable, m) |
| } |
| } |
| return summary |
| } |
| |
| func isCallable(t *types.Func) bool { |
| // TODO(crawshaw): functions that are not implementable from |
| // another language may still be callable (for example, a |
| // returned value with an unexported type can be treated as |
| // an opaque value by the caller). This restriction could be |
| // lifted. |
| return isImplementable(t.Type().(*types.Signature)) |
| } |
| |
| func isImplementable(sig *types.Signature) bool { |
| params := sig.Params() |
| for i := 0; i < params.Len(); i++ { |
| if !isExported(params.At(i).Type()) { |
| return false |
| } |
| } |
| res := sig.Results() |
| for i := 0; i < res.Len(); i++ { |
| if !isExported(res.At(i).Type()) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func exportedMethodSet(T types.Type) []*types.Func { |
| var methods []*types.Func |
| methodset := types.NewMethodSet(T) |
| for i := 0; i < methodset.Len(); i++ { |
| obj := methodset.At(i).Obj() |
| if !obj.Exported() { |
| continue |
| } |
| switch obj := obj.(type) { |
| case *types.Func: |
| methods = append(methods, obj) |
| default: |
| log.Panicf("unexpected methodset obj: %s", obj) |
| } |
| } |
| return methods |
| } |
| |
| func exportedFields(T *types.Struct) []*types.Var { |
| var fields []*types.Var |
| for i := 0; i < T.NumFields(); i++ { |
| f := T.Field(i) |
| if !f.Exported() { |
| continue |
| } |
| fields = append(fields, f) |
| } |
| return fields |
| } |
| |
| func isErrorType(t types.Type) bool { |
| return types.Identical(t, types.Universe.Lookup("error").Type()) |
| } |
| |
| func isExported(t types.Type) bool { |
| if isErrorType(t) { |
| return true |
| } |
| switch t := t.(type) { |
| case *types.Basic: |
| return true |
| case *types.Named: |
| return t.Obj().Exported() |
| case *types.Pointer: |
| return isExported(t.Elem()) |
| default: |
| return true |
| } |
| } |