github.com/acrespo/mobile@v0.0.0-20190107162257-dc0771356504/bind/genobjc.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/constant"
    10  	"go/types"
    11  	"math"
    12  	"strings"
    13  
    14  	"golang.org/x/mobile/internal/importers/objc"
    15  )
    16  
    17  // TODO(hyangah): handle method name conflicts.
    18  //   - struct with SetF method and exported F field.
    19  //   - method names conflicting with NSObject methods. e.g. Init
    20  //   - interface type with InitWithRef.
    21  
    22  // TODO(hyangah): error code/domain propagation
    23  
    24  type ObjcGen struct {
    25  	Prefix string // prefix arg passed by flag.
    26  
    27  	*Generator
    28  
    29  	// fields set by init.
    30  	namePrefix string
    31  	// Map of all wrapped Objc types
    32  	wrapMap map[string]*objc.Named
    33  	// Structs that embeds Objc wrapper types.
    34  	ostructs map[*types.TypeName]*objcClassInfo
    35  	modules  []string
    36  	// Constructors is a map from Go struct types to a list
    37  	// of exported constructor functions for the type, on the form
    38  	// func New<Type>(...) *Type
    39  	constructors map[*types.TypeName][]*types.Func
    40  }
    41  
    42  type objcClassInfo struct {
    43  	// The Objc class this class extends.
    44  	extends *objc.Named
    45  	// All classes and protocols this class extends and conforms to.
    46  	supers  []*objc.Named
    47  	methods map[string]*objc.Func
    48  }
    49  
    50  func (g *ObjcGen) Init(wrappers []*objc.Named) {
    51  	g.Generator.Init()
    52  	g.namePrefix = g.namePrefixOf(g.Pkg)
    53  	g.wrapMap = make(map[string]*objc.Named)
    54  	g.constructors = make(map[*types.TypeName][]*types.Func)
    55  	modMap := make(map[string]struct{})
    56  	for _, w := range wrappers {
    57  		g.wrapMap[w.GoName] = w
    58  		if _, exists := modMap[w.Module]; !exists {
    59  			if !w.Generated {
    60  				g.modules = append(g.modules, w.Module)
    61  			}
    62  			modMap[w.Module] = struct{}{}
    63  		}
    64  	}
    65  	if _, exists := modMap["Foundation"]; !exists {
    66  		g.modules = append(g.modules, "Foundation")
    67  	}
    68  	g.ostructs = make(map[*types.TypeName]*objcClassInfo)
    69  	for _, s := range g.structs {
    70  		embds := embeddedObjcTypes(s.t)
    71  		if len(embds) == 0 {
    72  			continue
    73  		}
    74  		inf := &objcClassInfo{
    75  			methods: make(map[string]*objc.Func),
    76  		}
    77  		for _, n := range embds {
    78  			t := g.wrapMap[n]
    79  			for _, f := range t.AllMethods {
    80  				inf.methods[f.GoName] = f
    81  			}
    82  			inf.supers = append(inf.supers, t)
    83  			if !t.Protocol {
    84  				if inf.extends != nil {
    85  					g.errorf("%s embeds more than one ObjC class; only one is allowed.", s.obj)
    86  				}
    87  				inf.extends = t
    88  			}
    89  		}
    90  		g.ostructs[s.obj] = inf
    91  	}
    92  	for _, f := range g.funcs {
    93  		if t := g.constructorType(f); t != nil {
    94  			g.constructors[t] = append(g.constructors[t], f)
    95  		}
    96  	}
    97  }
    98  
    99  func (g *ObjcGen) namePrefixOf(pkg *types.Package) string {
   100  	if pkg == nil {
   101  		return "Universe"
   102  	}
   103  	p := g.Prefix
   104  	return p + strings.Title(pkg.Name())
   105  }
   106  
   107  func (g *ObjcGen) GenGoH() error {
   108  	var pkgPath string
   109  	if g.Pkg != nil {
   110  		pkgPath = g.Pkg.Path()
   111  	}
   112  	g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath)
   113  	g.Printf("#ifndef __GO_%s_H__\n", g.pkgName)
   114  	g.Printf("#define __GO_%s_H__\n\n", g.pkgName)
   115  	g.Printf("#include <stdint.h>\n")
   116  	g.Printf("#include <objc/objc.h>\n")
   117  
   118  	for _, i := range g.interfaces {
   119  		if !i.summary.implementable {
   120  			continue
   121  		}
   122  		for _, m := range i.summary.callable {
   123  			if !g.isSigSupported(m.Type()) {
   124  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name())
   125  				continue
   126  			}
   127  			g.genInterfaceMethodSignature(m, i.obj.Name(), true, g.paramName)
   128  			g.Printf("\n")
   129  		}
   130  	}
   131  
   132  	g.Printf("#endif\n")
   133  
   134  	if len(g.err) > 0 {
   135  		return g.err
   136  	}
   137  	return nil
   138  }
   139  
   140  func (g *ObjcGen) GenH() error {
   141  	var pkgPath string
   142  	if g.Pkg != nil {
   143  		pkgPath = g.Pkg.Path()
   144  	}
   145  	g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath)
   146  	g.Printf("#ifndef __%s_H__\n", g.namePrefix)
   147  	g.Printf("#define __%s_H__\n", g.namePrefix)
   148  	g.Printf("\n")
   149  	for _, m := range g.modules {
   150  		g.Printf("@import %s;\n", m)
   151  	}
   152  	if g.Pkg != nil {
   153  		g.Printf("#include \"Universe.objc.h\"\n\n")
   154  	}
   155  
   156  	if g.Pkg != nil {
   157  		for _, pkg := range g.Pkg.Imports() {
   158  			if g.validPkg(pkg) {
   159  				g.Printf("#include %q\n", g.namePrefixOf(pkg)+".objc.h")
   160  			}
   161  		}
   162  	}
   163  	g.Printf("\n")
   164  
   165  	// Forward declaration of @class and @protocol
   166  	for _, s := range g.structs {
   167  		g.Printf("@class %s%s;\n", g.namePrefix, s.obj.Name())
   168  	}
   169  	for _, i := range g.interfaces {
   170  		g.Printf("@protocol %s%s;\n", g.namePrefix, i.obj.Name())
   171  		if i.summary.implementable {
   172  			g.Printf("@class %s%s;\n", g.namePrefix, i.obj.Name())
   173  			// Forward declaration for other cases will be handled at the beginning of GenM.
   174  		}
   175  	}
   176  	if len(g.structs) > 0 || len(g.interfaces) > 0 {
   177  		g.Printf("\n")
   178  	}
   179  
   180  	// @interfaces
   181  	for _, i := range g.interfaces {
   182  		g.genInterfaceH(i.obj, i.t)
   183  		g.Printf("\n")
   184  	}
   185  	for _, s := range g.structs {
   186  		g.genStructH(s.obj, s.t)
   187  		g.Printf("\n")
   188  	}
   189  
   190  	// const
   191  	// TODO: prefix with k?, or use a class method?
   192  	for _, obj := range g.constants {
   193  		if _, ok := obj.Type().(*types.Basic); !ok || !g.isSupported(obj.Type()) {
   194  			g.Printf("// skipped const %s with unsupported type: %s\n\n", obj.Name(), obj.Type())
   195  			continue
   196  		}
   197  		g.objcdoc(g.docs[obj.Name()].Doc())
   198  		switch b := obj.Type().(*types.Basic); b.Kind() {
   199  		case types.String, types.UntypedString:
   200  			g.Printf("FOUNDATION_EXPORT NSString* const %s%s;\n", g.namePrefix, obj.Name())
   201  		default:
   202  			g.Printf("FOUNDATION_EXPORT const %s %s%s;\n", g.objcType(obj.Type()), g.namePrefix, obj.Name())
   203  		}
   204  	}
   205  	if len(g.constants) > 0 {
   206  		g.Printf("\n")
   207  	}
   208  
   209  	// var
   210  	if len(g.vars) > 0 {
   211  		g.Printf("@interface %s : NSObject\n", g.namePrefix)
   212  		for _, obj := range g.vars {
   213  			if t := obj.Type(); !g.isSupported(t) {
   214  				g.Printf("// skipped variable %s with unsupported type: %s\n\n", obj.Name(), t)
   215  				continue
   216  			}
   217  			objcType := g.objcType(obj.Type())
   218  			g.objcdoc(g.docs[obj.Name()].Doc())
   219  			g.Printf("+ (%s) %s;\n", objcType, objcNameReplacer(lowerFirst(obj.Name())))
   220  			g.Printf("+ (void) set%s:(%s)v;\n", obj.Name(), objcType)
   221  			g.Printf("\n")
   222  		}
   223  		g.Printf("@end\n\n")
   224  	}
   225  
   226  	// static functions.
   227  	for _, obj := range g.funcs {
   228  		g.genFuncH(obj)
   229  		g.Printf("\n")
   230  	}
   231  
   232  	for _, i := range g.interfaces {
   233  		if i.summary.implementable {
   234  			g.Printf("@class %s%s;\n\n", g.namePrefix, i.obj.Name())
   235  		}
   236  	}
   237  	for _, i := range g.interfaces {
   238  		if i.summary.implementable {
   239  			// @interface Interface -- similar to what genStructH does.
   240  			g.genInterfaceInterface(i.obj, i.summary, true)
   241  			g.Printf("\n")
   242  		}
   243  	}
   244  
   245  	g.Printf("#endif\n")
   246  
   247  	if len(g.err) > 0 {
   248  		return g.err
   249  	}
   250  	return nil
   251  }
   252  
   253  func (g *ObjcGen) gobindOpts() string {
   254  	opts := []string{"-lang=objc"}
   255  	if g.Prefix != "" {
   256  		opts = append(opts, fmt.Sprintf("-prefix=%q", g.Prefix))
   257  	}
   258  	return strings.Join(opts, " ")
   259  }
   260  
   261  func (g *ObjcGen) GenM() error {
   262  	var pkgPath string
   263  	if g.Pkg != nil {
   264  		pkgPath = g.Pkg.Path()
   265  	}
   266  	g.Printf(objcPreamble, pkgPath, g.gobindOpts(), pkgPath)
   267  	g.Printf("#include <Foundation/Foundation.h>\n")
   268  	g.Printf("#include \"seq.h\"\n")
   269  	g.Printf("#include \"_cgo_export.h\"\n")
   270  	g.Printf("#include %q\n", g.namePrefix+".objc.h")
   271  	g.Printf("\n")
   272  
   273  	// struct
   274  	for _, s := range g.structs {
   275  		g.genStructM(s.obj, s.t)
   276  		g.Printf("\n")
   277  	}
   278  
   279  	// interface
   280  	var needProxy []*types.TypeName
   281  	for _, i := range g.interfaces {
   282  		if g.genInterfaceM(i.obj, i.t) {
   283  			needProxy = append(needProxy, i.obj)
   284  		}
   285  		g.Printf("\n")
   286  	}
   287  
   288  	// const
   289  	for _, o := range g.constants {
   290  		g.genConstM(o)
   291  	}
   292  	if len(g.constants) > 0 {
   293  		g.Printf("\n")
   294  	}
   295  
   296  	// vars
   297  	if len(g.vars) > 0 {
   298  		g.Printf("@implementation %s\n", g.namePrefix)
   299  		for _, o := range g.vars {
   300  			g.genVarM(o)
   301  		}
   302  		g.Printf("@end\n\n")
   303  	}
   304  
   305  	g.Printf("\n")
   306  
   307  	for _, obj := range g.funcs {
   308  		if !g.isSigSupported(obj.Type()) {
   309  			g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name())
   310  			continue
   311  		}
   312  		g.genFuncM(obj)
   313  		g.Printf("\n")
   314  	}
   315  
   316  	for _, i := range g.interfaces {
   317  		for _, m := range i.summary.callable {
   318  			if !g.isSigSupported(m.Type()) {
   319  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name())
   320  				continue
   321  			}
   322  			g.genInterfaceMethodProxy(i.obj, m)
   323  		}
   324  	}
   325  
   326  	g.Printf("__attribute__((constructor)) static void init() {\n")
   327  	g.Indent()
   328  	g.Printf("init_seq();\n")
   329  	g.Outdent()
   330  	g.Printf("}\n")
   331  
   332  	if len(g.err) > 0 {
   333  		return g.err
   334  	}
   335  
   336  	return nil
   337  }
   338  
   339  func (g *ObjcGen) genVarM(o *types.Var) {
   340  	if t := o.Type(); !g.isSupported(t) {
   341  		g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t)
   342  		return
   343  	}
   344  	objcType := g.objcType(o.Type())
   345  
   346  	// setter
   347  	g.Printf("+ (void) set%s:(%s)v {\n", o.Name(), objcType)
   348  	g.Indent()
   349  	g.genWrite("v", o.Type(), modeRetained)
   350  	g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name())
   351  	g.genRelease("v", o.Type(), modeRetained)
   352  	g.Outdent()
   353  	g.Printf("}\n\n")
   354  
   355  	// getter
   356  	g.Printf("+ (%s) %s {\n", objcType, objcNameReplacer(lowerFirst(o.Name())))
   357  	g.Indent()
   358  	g.Printf("%s r0 = ", g.cgoType(o.Type()))
   359  	g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name())
   360  	g.genRead("_r0", "r0", o.Type(), modeRetained)
   361  	g.Printf("return _r0;\n")
   362  	g.Outdent()
   363  	g.Printf("}\n\n")
   364  }
   365  
   366  func (g *ObjcGen) genConstM(o *types.Const) {
   367  	if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) {
   368  		g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type())
   369  		return
   370  	}
   371  	cName := fmt.Sprintf("%s%s", g.namePrefix, o.Name())
   372  	objcType := g.objcType(o.Type())
   373  
   374  	switch b := o.Type().(*types.Basic); b.Kind() {
   375  	case types.Bool, types.UntypedBool:
   376  		v := "NO"
   377  		if constant.BoolVal(o.Val()) {
   378  			v = "YES"
   379  		}
   380  		g.Printf("const BOOL %s = %s;\n", cName, v)
   381  
   382  	case types.String, types.UntypedString:
   383  		g.Printf("NSString* const %s = @%s;\n", cName, o.Val().ExactString())
   384  
   385  	case types.Int, types.Int8, types.Int16, types.Int32:
   386  		g.Printf("const %s %s = %s;\n", objcType, cName, o.Val())
   387  
   388  	case types.Int64, types.UntypedInt:
   389  		i, exact := constant.Int64Val(o.Val())
   390  		if !exact {
   391  			g.errorf("const value %s for %s cannot be represented as %s", o.Val(), o.Name(), objcType)
   392  			return
   393  		}
   394  		if i == math.MinInt64 {
   395  			// -9223372036854775808LL does not work because 922337203685477508 is
   396  			// larger than max int64.
   397  			g.Printf("const int64_t %s = %dLL-1;\n", cName, i+1)
   398  		} else {
   399  			g.Printf("const int64_t %s = %dLL;\n", cName, i)
   400  		}
   401  
   402  	case types.Float32, types.Float64, types.UntypedFloat:
   403  		f, _ := constant.Float64Val(o.Val())
   404  		if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 {
   405  			g.errorf("const value %s for %s cannot be represented as double", o.Val(), o.Name())
   406  			return
   407  		}
   408  		g.Printf("const %s %s = %g;\n", objcType, cName, f)
   409  
   410  	default:
   411  		g.errorf("unsupported const type %s for %s", b, o.Name())
   412  	}
   413  }
   414  
   415  type funcSummary struct {
   416  	name              string
   417  	goname            string
   418  	ret               string
   419  	sig               *types.Signature
   420  	params, retParams []paramInfo
   421  	hasself           bool
   422  	initName          string
   423  }
   424  
   425  type paramInfo struct {
   426  	typ  types.Type
   427  	name string
   428  }
   429  
   430  func (g *ObjcGen) funcSummary(obj *types.TypeName, f *types.Func) *funcSummary {
   431  	sig := f.Type().(*types.Signature)
   432  	s := &funcSummary{goname: f.Name(), sig: sig}
   433  	var om *objc.Func
   434  	var sigElems []string
   435  	oinf := g.ostructs[obj]
   436  	if oinf != nil {
   437  		om = oinf.methods[f.Name()]
   438  	}
   439  	if om != nil {
   440  		sigElems = strings.Split(om.Sig, ":")
   441  		s.name = sigElems[0]
   442  	} else {
   443  		s.name = f.Name()
   444  	}
   445  	params := sig.Params()
   446  	first := 0
   447  	if oinf != nil {
   448  		if params.Len() > 0 {
   449  			v := params.At(0)
   450  			if v.Name() == "self" {
   451  				t := v.Type()
   452  				if t, ok := t.(*types.Named); ok {
   453  					if pkg := t.Obj().Pkg(); pkgFirstElem(pkg) == "ObjC" {
   454  						s.hasself = true
   455  						module := pkg.Path()[len("ObjC/"):]
   456  						typName := module + "." + t.Obj().Name()
   457  						exp := g.namePrefix + "." + obj.Name()
   458  						if typName != exp {
   459  							g.errorf("the type %s of the `this` argument to method %s is not %s", typName, f.Name(), exp)
   460  						}
   461  					}
   462  				}
   463  			}
   464  		}
   465  	}
   466  	for i := first; i < params.Len(); i++ {
   467  		p := params.At(i)
   468  		v := paramInfo{
   469  			typ: p.Type(),
   470  		}
   471  		if om != nil {
   472  			v.name = sigElems[i-first]
   473  		} else {
   474  			v.name = g.paramName(params, i)
   475  		}
   476  		s.params = append(s.params, v)
   477  	}
   478  	if obj != nil {
   479  		if pref := "New" + obj.Name(); strings.Index(f.Name(), pref) != -1 {
   480  			s.initName = "init" + f.Name()[len(pref):]
   481  		}
   482  	}
   483  	res := sig.Results()
   484  	switch res.Len() {
   485  	case 0:
   486  		s.ret = "void"
   487  	case 1:
   488  		p := res.At(0)
   489  		if isErrorType(p.Type()) {
   490  			s.retParams = append(s.retParams, paramInfo{
   491  				typ:  p.Type(),
   492  				name: "error",
   493  			})
   494  			s.ret = "BOOL"
   495  		} else {
   496  			name := p.Name()
   497  			if name == "" || paramRE.MatchString(name) {
   498  				name = "ret0_"
   499  			}
   500  			typ := p.Type()
   501  			s.retParams = append(s.retParams, paramInfo{typ: typ, name: name})
   502  			s.ret = g.objcType(typ)
   503  		}
   504  	case 2:
   505  		name := res.At(0).Name()
   506  		if name == "" || paramRE.MatchString(name) {
   507  			name = "ret0_"
   508  		}
   509  		typ := res.At(0).Type()
   510  		s.retParams = append(s.retParams, paramInfo{
   511  			typ:  typ,
   512  			name: name,
   513  		})
   514  		if isNullableType(typ) {
   515  			s.ret = g.objcType(typ) // Return is nullable, so satisfies the ObjC/Swift error protocol
   516  		} else {
   517  			s.ret = "BOOL" // Return is not nullable, must use an output parameter and return bool
   518  		}
   519  
   520  		if !isErrorType(res.At(1).Type()) {
   521  			g.errorf("second result value must be of type error: %s", f)
   522  			return nil
   523  		}
   524  		s.retParams = append(s.retParams, paramInfo{
   525  			typ:  res.At(1).Type(),
   526  			name: "error", // TODO(hyangah): name collision check.
   527  		})
   528  	default:
   529  		// TODO(hyangah): relax the constraint on multiple return params.
   530  		g.errorf("too many result values: %s", f)
   531  		return nil
   532  	}
   533  
   534  	return s
   535  }
   536  
   537  func (s *funcSummary) asFunc(g *ObjcGen) string {
   538  	var params []string
   539  	for _, p := range s.params {
   540  		params = append(params, g.objcType(p.typ)+" "+p.name)
   541  	}
   542  	skip := 0
   543  	if s.returnsVal() {
   544  		skip = 1
   545  	}
   546  	for _, p := range s.retParams[skip:] {
   547  		params = append(params, g.objcType(p.typ)+"* "+p.name)
   548  	}
   549  	paramContents := "void"
   550  	if len(params) > 0 {
   551  		paramContents = strings.Join(params, ", ")
   552  	}
   553  	return fmt.Sprintf("%s %s%s(%s)", s.ret, g.namePrefix, s.name, paramContents)
   554  }
   555  
   556  func (s *funcSummary) asMethod(g *ObjcGen) string {
   557  	return fmt.Sprintf("(%s)%s%s", s.ret, objcNameReplacer(lowerFirst(s.name)), s.asSignature(g))
   558  }
   559  
   560  func (s *funcSummary) asSignature(g *ObjcGen) string {
   561  	var params []string
   562  	skip := 0
   563  	if s.hasself {
   564  		skip = 1
   565  	}
   566  	for i, p := range s.params[skip:] {
   567  		var key string
   568  		if i != 0 {
   569  			key = p.name
   570  		}
   571  		params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name))
   572  	}
   573  	skip = 0
   574  	if s.returnsVal() {
   575  		skip = 1
   576  	}
   577  	for _, p := range s.retParams[skip:] {
   578  		var key string
   579  		if len(params) > 0 {
   580  			key = p.name
   581  		}
   582  		params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ)+"*", p.name))
   583  	}
   584  	return strings.Join(params, " ")
   585  }
   586  
   587  func (s *funcSummary) asInitSignature(g *ObjcGen) string {
   588  	var params []string
   589  	for i, p := range s.params {
   590  		var key string
   591  		if i > 0 {
   592  			key = p.name
   593  		}
   594  		params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name))
   595  	}
   596  	return strings.Join(params, " ")
   597  }
   598  
   599  func (s *funcSummary) callMethod(g *ObjcGen) string {
   600  	var params []string
   601  	for i, p := range s.params {
   602  		var key string
   603  		if i != 0 {
   604  			key = p.name
   605  		}
   606  		params = append(params, fmt.Sprintf("%s:_%s", key, p.name))
   607  	}
   608  	skip := 0
   609  	if s.returnsVal() {
   610  		skip = 1
   611  	}
   612  	for _, p := range s.retParams[skip:] {
   613  		var key string
   614  		if len(params) > 0 {
   615  			key = p.name
   616  		}
   617  		params = append(params, fmt.Sprintf("%s:&%s", key, p.name))
   618  	}
   619  	return fmt.Sprintf("%s%s", objcNameReplacer(lowerFirst(s.name)), strings.Join(params, " "))
   620  }
   621  
   622  func (s *funcSummary) returnsVal() bool {
   623  	return (len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ)) || (len(s.retParams) == 2 && isNullableType(s.retParams[0].typ))
   624  }
   625  
   626  func (g *ObjcGen) paramName(params *types.Tuple, pos int) string {
   627  	name := basicParamName(params, pos)
   628  	return objcNameReplacer(name)
   629  }
   630  
   631  func (g *ObjcGen) genFuncH(obj *types.Func) {
   632  	if !g.isSigSupported(obj.Type()) {
   633  		g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name())
   634  		return
   635  	}
   636  	if s := g.funcSummary(nil, obj); s != nil {
   637  		g.objcdoc(g.docs[obj.Name()].Doc())
   638  		g.Printf("FOUNDATION_EXPORT %s;\n", s.asFunc(g))
   639  	}
   640  }
   641  
   642  func (g *ObjcGen) genFuncM(obj *types.Func) {
   643  	s := g.funcSummary(nil, obj)
   644  	if s == nil {
   645  		return
   646  	}
   647  	g.Printf("%s {\n", s.asFunc(g))
   648  	g.Indent()
   649  	g.genFunc(s, "")
   650  	g.Outdent()
   651  	g.Printf("}\n")
   652  }
   653  
   654  func (g *ObjcGen) genGetter(oName string, f *types.Var) {
   655  	t := f.Type()
   656  	g.Printf("- (%s)%s {\n", g.objcType(t), objcNameReplacer(lowerFirst(f.Name())))
   657  	g.Indent()
   658  	g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
   659  	g.Printf("%s r0 = ", g.cgoType(f.Type()))
   660  	g.Printf("proxy%s_%s_%s_Get(refnum);\n", g.pkgPrefix, oName, f.Name())
   661  	g.genRead("_r0", "r0", f.Type(), modeRetained)
   662  	g.Printf("return _r0;\n")
   663  	g.Outdent()
   664  	g.Printf("}\n\n")
   665  }
   666  
   667  func (g *ObjcGen) genSetter(oName string, f *types.Var) {
   668  	t := f.Type()
   669  
   670  	g.Printf("- (void)set%s:(%s)v {\n", f.Name(), g.objcType(t))
   671  	g.Indent()
   672  	g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
   673  	g.genWrite("v", f.Type(), modeRetained)
   674  	g.Printf("proxy%s_%s_%s_Set(refnum, _v);\n", g.pkgPrefix, oName, f.Name())
   675  	g.genRelease("v", f.Type(), modeRetained)
   676  	g.Outdent()
   677  	g.Printf("}\n\n")
   678  }
   679  
   680  func (g *ObjcGen) genWrite(varName string, t types.Type, mode varMode) {
   681  	switch t := t.(type) {
   682  	case *types.Basic:
   683  		switch t.Kind() {
   684  		case types.String:
   685  			g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", varName, varName)
   686  		default:
   687  			g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
   688  		}
   689  	case *types.Slice:
   690  		switch e := t.Elem().(type) {
   691  		case *types.Basic:
   692  			switch e.Kind() {
   693  			case types.Uint8: // Byte.
   694  				g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", varName, varName, toCFlag(mode == modeRetained))
   695  			default:
   696  				g.errorf("unsupported type: %s", t)
   697  			}
   698  		default:
   699  			g.errorf("unsupported type: %s", t)
   700  		}
   701  	case *types.Named:
   702  		switch u := t.Underlying().(type) {
   703  		case *types.Interface:
   704  			g.genRefWrite(varName)
   705  		default:
   706  			g.errorf("unsupported named type: %s / %T", u, u)
   707  		}
   708  	case *types.Pointer:
   709  		g.genRefWrite(varName)
   710  	default:
   711  		g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
   712  	}
   713  }
   714  
   715  func (g *ObjcGen) genRefWrite(varName string) {
   716  	g.Printf("int32_t _%s;\n", varName)
   717  	g.Printf("if ([%s conformsToProtocol:@protocol(goSeqRefInterface)]) {\n", varName)
   718  	g.Indent()
   719  	g.Printf("id<goSeqRefInterface> %[1]s_proxy = (id<goSeqRefInterface>)(%[1]s);\n", varName)
   720  	g.Printf("_%s = go_seq_go_to_refnum(%s_proxy._ref);\n", varName, varName)
   721  	g.Outdent()
   722  	g.Printf("} else {\n")
   723  	g.Indent()
   724  	g.Printf("_%s = go_seq_to_refnum(%s);\n", varName, varName)
   725  	g.Outdent()
   726  	g.Printf("}\n")
   727  }
   728  
   729  func (g *ObjcGen) genRefRead(toName, fromName string, t types.Type) {
   730  	ptype := g.refTypeBase(t)
   731  	g.Printf("%s* %s = nil;\n", ptype, toName)
   732  	g.Printf("GoSeqRef* %s_ref = go_seq_from_refnum(%s);\n", toName, fromName)
   733  	g.Printf("if (%s_ref != NULL) {\n", toName)
   734  	g.Printf("	%s = %s_ref.obj;\n", toName, toName)
   735  	g.Printf("	if (%s == nil) {\n", toName)
   736  	if isObjcType(t) {
   737  		g.Printf("		LOG_FATAL(@\"unexpected NULL reference\");\n")
   738  	} else {
   739  		g.Printf("		%s = [[%s alloc] initWithRef:%s_ref];\n", toName, ptype, toName)
   740  	}
   741  	g.Printf("	}\n")
   742  	g.Printf("}\n")
   743  }
   744  
   745  func (g *ObjcGen) genRead(toName, fromName string, t types.Type, mode varMode) {
   746  	switch t := t.(type) {
   747  	case *types.Basic:
   748  		switch t.Kind() {
   749  		case types.String:
   750  			g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName)
   751  		case types.Bool:
   752  			g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName)
   753  		default:
   754  			g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName)
   755  		}
   756  	case *types.Slice:
   757  		switch e := t.Elem().(type) {
   758  		case *types.Basic:
   759  			switch e.Kind() {
   760  			case types.Uint8: // Byte.
   761  				g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, toCFlag(mode == modeRetained))
   762  			default:
   763  				g.errorf("unsupported type: %s", t)
   764  			}
   765  		default:
   766  			g.errorf("unsupported type: %s", t)
   767  		}
   768  	case *types.Pointer:
   769  		switch t := t.Elem().(type) {
   770  		case *types.Named:
   771  			g.genRefRead(toName, fromName, types.NewPointer(t))
   772  		default:
   773  			g.errorf("unsupported type %s", t)
   774  		}
   775  	case *types.Named:
   776  		switch t.Underlying().(type) {
   777  		case *types.Interface, *types.Pointer:
   778  			g.genRefRead(toName, fromName, t)
   779  		default:
   780  			g.errorf("unsupported, direct named type %s", t)
   781  		}
   782  	default:
   783  		g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName)
   784  	}
   785  }
   786  
   787  func (g *ObjcGen) genFunc(s *funcSummary, objName string) {
   788  	skip := 0
   789  	if objName != "" {
   790  		g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
   791  		if s.hasself {
   792  			skip = 1
   793  			g.Printf("int32_t _self = go_seq_to_refnum(self);\n")
   794  		}
   795  	}
   796  	for _, p := range s.params[skip:] {
   797  		g.genWrite(p.name, p.typ, modeTransient)
   798  	}
   799  	resPrefix := ""
   800  	if len(s.retParams) > 0 {
   801  		if len(s.retParams) == 1 {
   802  			g.Printf("%s r0 = ", g.cgoType(s.retParams[0].typ))
   803  		} else {
   804  			resPrefix = "res."
   805  			g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, objName, s.goname)
   806  		}
   807  	}
   808  	g.Printf("proxy%s_%s_%s(", g.pkgPrefix, objName, s.goname)
   809  	if objName != "" {
   810  		g.Printf("refnum")
   811  		if s.hasself {
   812  			g.Printf(", _self")
   813  		}
   814  	}
   815  	for i, p := range s.params[skip:] {
   816  		if i > 0 || objName != "" {
   817  			g.Printf(", ")
   818  		}
   819  		g.Printf("_%s", p.name)
   820  	}
   821  	g.Printf(");\n")
   822  	for _, p := range s.params {
   823  		g.genRelease(p.name, p.typ, modeTransient)
   824  	}
   825  
   826  	for i, r := range s.retParams {
   827  		g.genRead("_"+r.name, fmt.Sprintf("%sr%d", resPrefix, i), r.typ, modeRetained)
   828  	}
   829  	skip = 0
   830  	if s.returnsVal() {
   831  		skip = 1
   832  	}
   833  	for _, p := range s.retParams[skip:] {
   834  		if isErrorType(p.typ) {
   835  			g.Printf("if (_%s != nil && %s != nil) {\n", p.name, p.name)
   836  			g.Indent()
   837  			g.Printf("*%s = _%s;\n", p.name, p.name)
   838  			g.Outdent()
   839  			g.Printf("}\n")
   840  		} else {
   841  			g.Printf("*%s = _%s;\n", p.name, p.name)
   842  		}
   843  	}
   844  
   845  	if n := len(s.retParams); n > 0 {
   846  		var (
   847  			first = s.retParams[0]
   848  			last  = s.retParams[n-1]
   849  		)
   850  		if (n == 1 && isErrorType(last.typ)) || (n == 2 && !isNullableType(first.typ) && isErrorType(last.typ)) {
   851  			g.Printf("return (_%s == nil);\n", last.name)
   852  		} else {
   853  			if s.returnsVal() && isErrorType(last.typ) {
   854  				g.Printf("if (_%s != nil) {\n", last.name)
   855  				g.Indent()
   856  				g.Printf("return nil;\n")
   857  				g.Outdent()
   858  				g.Printf("}\n")
   859  			}
   860  			g.Printf("return _%s;\n", first.name)
   861  		}
   862  	}
   863  }
   864  
   865  func (g *ObjcGen) genInterfaceInterface(obj *types.TypeName, summary ifaceSummary, isProtocol bool) {
   866  	doc := g.docs[obj.Name()]
   867  	g.objcdoc(doc.Doc())
   868  	g.Printf("@interface %[1]s%[2]s : ", g.namePrefix, obj.Name())
   869  	if isErrorType(obj.Type()) {
   870  		g.Printf("NSError")
   871  	} else {
   872  		g.Printf("NSObject")
   873  	}
   874  	prots := []string{"goSeqRefInterface"}
   875  	if isProtocol {
   876  		prots = append(prots, fmt.Sprintf("%[1]s%[2]s", g.namePrefix, obj.Name()))
   877  	}
   878  	g.Printf(" <%s>", strings.Join(prots, ", "))
   879  	g.Printf(" {\n}\n")
   880  	g.Printf("@property(strong, readonly) id _ref;\n")
   881  	g.Printf("\n")
   882  	g.Printf("- (instancetype)initWithRef:(id)ref;\n")
   883  	for _, m := range summary.callable {
   884  		if !g.isSigSupported(m.Type()) {
   885  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
   886  			continue
   887  		}
   888  		s := g.funcSummary(nil, m)
   889  		g.objcdoc(doc.Member(m.Name()))
   890  		g.Printf("- %s;\n", s.asMethod(g))
   891  	}
   892  	g.Printf("@end\n")
   893  }
   894  
   895  func (g *ObjcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) {
   896  	summary := makeIfaceSummary(t)
   897  	if !summary.implementable {
   898  		g.genInterfaceInterface(obj, summary, false)
   899  		return
   900  	}
   901  	g.Printf("@protocol %s%s <NSObject>\n", g.namePrefix, obj.Name())
   902  	for _, m := range makeIfaceSummary(t).callable {
   903  		if !g.isSigSupported(m.Type()) {
   904  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
   905  			continue
   906  		}
   907  		s := g.funcSummary(nil, m)
   908  		g.Printf("- %s;\n", s.asMethod(g))
   909  	}
   910  	g.Printf("@end\n")
   911  }
   912  
   913  func (g *ObjcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool {
   914  	summary := makeIfaceSummary(t)
   915  
   916  	// @implementation Interface -- similar to what genStructM does.
   917  	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
   918  	g.Printf("}\n")
   919  	g.Printf("\n")
   920  	g.Printf("- (instancetype)initWithRef:(id)ref {\n")
   921  	g.Indent()
   922  	if isErrorType(obj.Type()) {
   923  		g.Printf("if (self) {\n")
   924  		g.Printf("	__ref = ref;\n")
   925  		g.Printf("	self = [super initWithDomain:@\"go\" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}];\n")
   926  		g.Printf("}\n")
   927  	} else {
   928  		g.Printf("self = [super init];\n")
   929  		g.Printf("if (self) { __ref = ref; }\n")
   930  	}
   931  	g.Printf("return self;\n")
   932  	g.Outdent()
   933  	g.Printf("}\n")
   934  	g.Printf("\n")
   935  
   936  	for _, m := range summary.callable {
   937  		if !g.isSigSupported(m.Type()) {
   938  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
   939  			continue
   940  		}
   941  		s := g.funcSummary(nil, m)
   942  		g.Printf("- %s {\n", s.asMethod(g))
   943  		g.Indent()
   944  		g.genFunc(s, obj.Name())
   945  		g.Outdent()
   946  		g.Printf("}\n\n")
   947  	}
   948  	g.Printf("@end\n")
   949  	g.Printf("\n")
   950  
   951  	return summary.implementable
   952  }
   953  
   954  func (g *ObjcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) {
   955  	oName := obj.Name()
   956  	s := g.funcSummary(nil, m)
   957  	g.genInterfaceMethodSignature(m, oName, false, g.paramName)
   958  	g.Indent()
   959  	g.Printf("@autoreleasepool {\n")
   960  	g.Indent()
   961  	g.Printf("%s* o = go_seq_objc_from_refnum(refnum);\n", g.refTypeBase(obj.Type()))
   962  	for _, p := range s.params {
   963  		g.genRead("_"+p.name, p.name, p.typ, modeTransient)
   964  	}
   965  
   966  	// call method
   967  	for _, p := range s.retParams {
   968  		if isErrorType(p.typ) {
   969  			g.Printf("NSError* %s = nil;\n", p.name)
   970  		} else {
   971  			g.Printf("%s %s;\n", g.objcType(p.typ), p.name)
   972  		}
   973  	}
   974  
   975  	if isErrorType(obj.Type()) && m.Name() == "Error" {
   976  		// As a special case, ObjC NSErrors are passed to Go pretending to implement the Go error interface.
   977  		// They don't actually have an Error method, so calls to to it needs to be rerouted.
   978  		g.Printf("%s = [o localizedDescription];\n", s.retParams[0].name)
   979  	} else {
   980  		if s.ret == "void" {
   981  			g.Printf("[o %s];\n", s.callMethod(g))
   982  		} else if !s.returnsVal() {
   983  			g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g))
   984  		} else {
   985  			g.Printf("%s = [o %s];\n", s.retParams[0].name, s.callMethod(g))
   986  		}
   987  	}
   988  
   989  	if len(s.retParams) > 0 {
   990  		if len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ) {
   991  			p := s.retParams[0]
   992  			g.genWrite(p.name, p.typ, modeRetained)
   993  			g.Printf("return _%s;\n", p.name)
   994  		} else {
   995  			var rets []string
   996  			for _, p := range s.retParams {
   997  				if isErrorType(p.typ) {
   998  					g.Printf("NSError *_%s = nil;\n", p.name)
   999  					if !s.returnsVal() {
  1000  						g.Printf("if (!returnVal) {\n")
  1001  					} else {
  1002  						g.Printf("if (%s != nil) {\n", p.name)
  1003  					}
  1004  					g.Indent()
  1005  					g.Printf("_%[1]s = %[1]s;\n", p.name)
  1006  					g.Outdent()
  1007  					g.Printf("}\n")
  1008  					g.genWrite("_"+p.name, p.typ, modeRetained)
  1009  					rets = append(rets, "__"+p.name)
  1010  				} else {
  1011  					g.genWrite(p.name, p.typ, modeRetained)
  1012  					rets = append(rets, "_"+p.name)
  1013  				}
  1014  			}
  1015  			if len(rets) > 1 {
  1016  				g.Printf("cproxy%s_%s_%s_return _sres = {\n", g.pkgPrefix, oName, m.Name())
  1017  				g.Printf("  %s\n", strings.Join(rets, ", "))
  1018  				g.Printf("};\n")
  1019  				g.Printf("return _sres;\n")
  1020  			} else {
  1021  				g.Printf("return %s;\n", rets[0])
  1022  			}
  1023  		}
  1024  	}
  1025  	g.Outdent()
  1026  	g.Printf("}\n")
  1027  	g.Outdent()
  1028  	g.Printf("}\n\n")
  1029  }
  1030  
  1031  // genRelease cleans up arguments that weren't copied in genWrite.
  1032  func (g *ObjcGen) genRelease(varName string, t types.Type, mode varMode) {
  1033  	switch t := t.(type) {
  1034  	case *types.Slice:
  1035  		switch e := t.Elem().(type) {
  1036  		case *types.Basic:
  1037  			switch e.Kind() {
  1038  			case types.Uint8: // Byte.
  1039  				if mode == modeTransient {
  1040  					// If the argument was not mutable, go_seq_from_objc_bytearray created a copy.
  1041  					// Free it here.
  1042  					g.Printf("if (![%s isKindOfClass:[NSMutableData class]]) {\n", varName)
  1043  					g.Printf("  free(_%s.ptr);\n", varName)
  1044  					g.Printf("}\n")
  1045  				}
  1046  			}
  1047  		}
  1048  	}
  1049  }
  1050  
  1051  func (g *ObjcGen) genStructH(obj *types.TypeName, t *types.Struct) {
  1052  	doc := g.docs[obj.Name()]
  1053  	g.objcdoc(doc.Doc())
  1054  	g.Printf("@interface %s%s : ", g.namePrefix, obj.Name())
  1055  	oinf := g.ostructs[obj]
  1056  	var prots []string
  1057  	if oinf != nil {
  1058  		for _, sup := range oinf.supers {
  1059  			if !sup.Protocol {
  1060  				g.Printf(sup.Name)
  1061  			} else {
  1062  				prots = append(prots, sup.Name)
  1063  			}
  1064  		}
  1065  	} else {
  1066  		g.Printf("NSObject")
  1067  		prots = append(prots, "goSeqRefInterface")
  1068  	}
  1069  	pT := types.NewPointer(obj.Type())
  1070  	for _, iface := range g.allIntf {
  1071  		p := iface.obj.Pkg()
  1072  		if g.Pkg != nil && g.Pkg != p {
  1073  			// To avoid header include cycles, only declare implementation of interfaces
  1074  			// from imported packages. TODO(elias.naur): Include every interface that
  1075  			// doesn't introduce an include cycle.
  1076  			found := false
  1077  			for _, imp := range g.Pkg.Imports() {
  1078  				if imp == p {
  1079  					found = true
  1080  					break
  1081  				}
  1082  			}
  1083  			if !found {
  1084  				continue
  1085  			}
  1086  		}
  1087  		obj := iface.obj
  1088  		if types.AssignableTo(pT, obj.Type()) {
  1089  			n := fmt.Sprintf("%s%s", g.namePrefixOf(obj.Pkg()), obj.Name())
  1090  			prots = append(prots, n)
  1091  		}
  1092  	}
  1093  
  1094  	if len(prots) > 0 {
  1095  		g.Printf(" <%s>", strings.Join(prots, ", "))
  1096  	}
  1097  	g.Printf(" {\n")
  1098  	g.Printf("}\n")
  1099  	g.Printf("@property(strong, readonly) id _ref;\n")
  1100  	g.Printf("\n")
  1101  	g.Printf("- (instancetype)initWithRef:(id)ref;\n")
  1102  	cons := g.constructors[obj]
  1103  	if oinf == nil {
  1104  		for _, f := range cons {
  1105  			if !g.isSigSupported(f.Type()) {
  1106  				g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj.Name(), f.Name())
  1107  				continue
  1108  			}
  1109  			g.genInitH(obj, f)
  1110  		}
  1111  	}
  1112  	if oinf != nil || len(cons) == 0 {
  1113  		g.Printf("- (instancetype)init;\n")
  1114  	}
  1115  
  1116  	// accessors to exported fields.
  1117  	for _, f := range exportedFields(t) {
  1118  		if t := f.Type(); !g.isSupported(t) {
  1119  			g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t)
  1120  			continue
  1121  		}
  1122  		name, typ := f.Name(), g.objcFieldType(f.Type())
  1123  		g.objcdoc(doc.Member(f.Name()))
  1124  		g.Printf("- (%s)%s;\n", typ, objcNameReplacer(lowerFirst(name)))
  1125  		g.Printf("- (void)set%s:(%s)v;\n", name, typ)
  1126  	}
  1127  
  1128  	// exported methods
  1129  	for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) {
  1130  		if !g.isSigSupported(m.Type()) {
  1131  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
  1132  			continue
  1133  		}
  1134  		s := g.funcSummary(obj, m)
  1135  		g.objcdoc(doc.Member(m.Name()))
  1136  		g.Printf("- %s;\n", s.asMethod(g))
  1137  	}
  1138  	g.Printf("@end\n")
  1139  }
  1140  
  1141  func (g *ObjcGen) objcdoc(doc string) {
  1142  	if doc == "" {
  1143  		return
  1144  	}
  1145  	g.Printf("/**\n * %s */\n", doc)
  1146  }
  1147  
  1148  func (g *ObjcGen) genStructM(obj *types.TypeName, t *types.Struct) {
  1149  	fields := exportedFields(t)
  1150  	methods := exportedMethodSet(types.NewPointer(obj.Type()))
  1151  
  1152  	g.Printf("\n")
  1153  	oinf := g.ostructs[obj]
  1154  	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
  1155  	g.Printf("}\n\n")
  1156  	g.Printf("- (instancetype)initWithRef:(id)ref {\n")
  1157  	g.Indent()
  1158  	g.Printf("self = [super init];\n")
  1159  	g.Printf("if (self) { __ref = ref; }\n")
  1160  	g.Printf("return self;\n")
  1161  	g.Outdent()
  1162  	g.Printf("}\n\n")
  1163  	cons := g.constructors[obj]
  1164  	if oinf == nil {
  1165  		for _, f := range cons {
  1166  			if !g.isSigSupported(f.Type()) {
  1167  				g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj, f.Name())
  1168  				continue
  1169  			}
  1170  			g.genInitM(obj, f)
  1171  		}
  1172  	}
  1173  	if oinf != nil || len(cons) == 0 {
  1174  		g.Printf("- (instancetype)init {\n")
  1175  		g.Indent()
  1176  		g.Printf("self = [super init];\n")
  1177  		g.Printf("if (self) {\n")
  1178  		g.Indent()
  1179  		g.Printf("__ref = go_seq_from_refnum(new_%s_%s());\n", g.pkgPrefix, obj.Name())
  1180  		g.Outdent()
  1181  		g.Printf("}\n")
  1182  		g.Printf("return self;\n")
  1183  		g.Outdent()
  1184  		g.Printf("}\n\n")
  1185  	}
  1186  
  1187  	for _, f := range fields {
  1188  		if !g.isSupported(f.Type()) {
  1189  			g.Printf("// skipped unsupported field %s with type %s\n\n", f.Name(), f.Type())
  1190  			continue
  1191  		}
  1192  		g.genGetter(obj.Name(), f)
  1193  		g.genSetter(obj.Name(), f)
  1194  	}
  1195  
  1196  	for _, m := range methods {
  1197  		if !g.isSigSupported(m.Type()) {
  1198  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
  1199  			continue
  1200  		}
  1201  		s := g.funcSummary(obj, m)
  1202  		g.Printf("- %s {\n", s.asMethod(g))
  1203  		g.Indent()
  1204  		g.genFunc(s, obj.Name())
  1205  		g.Outdent()
  1206  		g.Printf("}\n\n")
  1207  	}
  1208  	g.Printf("@end\n\n")
  1209  }
  1210  
  1211  func (g *ObjcGen) genInitH(obj *types.TypeName, f *types.Func) {
  1212  	s := g.funcSummary(obj, f)
  1213  	doc := g.docs[f.Name()]
  1214  	g.objcdoc(doc.Doc())
  1215  	g.Printf("- (instancetype)%s%s;\n", s.initName, s.asInitSignature(g))
  1216  }
  1217  
  1218  func (g *ObjcGen) genInitM(obj *types.TypeName, f *types.Func) {
  1219  	s := g.funcSummary(obj, f)
  1220  	g.Printf("- (instancetype)%s%s {\n", s.initName, s.asInitSignature(g))
  1221  	g.Indent()
  1222  	g.Printf("self = [super init];\n")
  1223  	g.Printf("if (!self) return nil;\n")
  1224  	for _, p := range s.params {
  1225  		g.genWrite(p.name, p.typ, modeTransient)
  1226  	}
  1227  	// Constructors always return a mandatory *T and an optional error
  1228  	if len(s.retParams) == 1 {
  1229  		g.Printf("%s refnum = ", g.cgoType(s.retParams[0].typ))
  1230  	} else {
  1231  		g.Printf("struct proxy%s__%s_return res = ", g.pkgPrefix, s.goname)
  1232  	}
  1233  	g.Printf("proxy%s__%s(", g.pkgPrefix, s.goname)
  1234  	for i, p := range s.params {
  1235  		if i > 0 {
  1236  			g.Printf(", ")
  1237  		}
  1238  		g.Printf("_%s", p.name)
  1239  	}
  1240  	g.Printf(");\n")
  1241  	for _, p := range s.params {
  1242  		g.genRelease(p.name, p.typ, modeTransient)
  1243  	}
  1244  	if len(s.retParams) == 2 {
  1245  		g.Printf("int32_t refnum = res.r0;\n")
  1246  		g.Printf("GoSeqRef *_err = go_seq_from_refnum(res.r1);\n")
  1247  	}
  1248  	g.Printf("__ref = go_seq_from_refnum(refnum);\n")
  1249  	if len(s.retParams) == 2 {
  1250  		g.Printf("if (_err != NULL)\n")
  1251  		g.Printf("	return nil;\n")
  1252  	}
  1253  	g.Printf("return self;\n")
  1254  	g.Outdent()
  1255  	g.Printf("}\n\n")
  1256  }
  1257  
  1258  func (g *ObjcGen) errorf(format string, args ...interface{}) {
  1259  	g.err = append(g.err, fmt.Errorf(format, args...))
  1260  }
  1261  
  1262  func (g *ObjcGen) refTypeBase(typ types.Type) string {
  1263  	switch typ := typ.(type) {
  1264  	case *types.Pointer:
  1265  		if _, ok := typ.Elem().(*types.Named); ok {
  1266  			return g.objcType(typ.Elem())
  1267  		}
  1268  	case *types.Named:
  1269  		n := typ.Obj()
  1270  		if isObjcType(typ) {
  1271  			return g.wrapMap[n.Name()].Name
  1272  		}
  1273  		if isErrorType(typ) || g.validPkg(n.Pkg()) {
  1274  			switch typ.Underlying().(type) {
  1275  			case *types.Interface, *types.Struct:
  1276  				return g.namePrefixOf(n.Pkg()) + n.Name()
  1277  			}
  1278  		}
  1279  	}
  1280  
  1281  	// fallback to whatever objcType returns. This must not happen.
  1282  	return g.objcType(typ)
  1283  }
  1284  
  1285  func (g *ObjcGen) objcFieldType(t types.Type) string {
  1286  	if isErrorType(t) {
  1287  		return "NSError*"
  1288  	}
  1289  	return g.objcType(t)
  1290  }
  1291  
  1292  func (g *ObjcGen) objcType(typ types.Type) string {
  1293  	if isErrorType(typ) {
  1294  		return "NSError*"
  1295  	}
  1296  
  1297  	switch typ := typ.(type) {
  1298  	case *types.Basic:
  1299  		switch typ.Kind() {
  1300  		case types.Bool, types.UntypedBool:
  1301  			return "BOOL"
  1302  		case types.Int:
  1303  			return "long"
  1304  		case types.Int8:
  1305  			return "int8_t"
  1306  		case types.Int16:
  1307  			return "int16_t"
  1308  		case types.Int32, types.UntypedRune: // types.Rune
  1309  			return "int32_t"
  1310  		case types.Int64, types.UntypedInt:
  1311  			return "int64_t"
  1312  		case types.Uint8:
  1313  			// byte is an alias of uint8, and the alias is lost.
  1314  			return "byte"
  1315  		case types.Uint16:
  1316  			return "uint16_t"
  1317  		case types.Uint32:
  1318  			return "uint32_t"
  1319  		case types.Uint64:
  1320  			return "uint64_t"
  1321  		case types.Float32:
  1322  			return "float"
  1323  		case types.Float64, types.UntypedFloat:
  1324  			return "double"
  1325  		case types.String, types.UntypedString:
  1326  			return "NSString*"
  1327  		default:
  1328  			g.errorf("unsupported type: %s", typ)
  1329  			return "TODO"
  1330  		}
  1331  	case *types.Slice:
  1332  		elem := g.objcType(typ.Elem())
  1333  		// Special case: NSData seems to be a better option for byte slice.
  1334  		if elem == "byte" {
  1335  			return "NSData*"
  1336  		}
  1337  		// TODO(hyangah): support other slice types: NSArray or CFArrayRef.
  1338  		// Investigate the performance implication.
  1339  		g.errorf("unsupported type: %s", typ)
  1340  		return "TODO"
  1341  	case *types.Pointer:
  1342  		if _, ok := typ.Elem().(*types.Named); ok {
  1343  			return g.objcType(typ.Elem()) + "*"
  1344  		}
  1345  		g.errorf("unsupported pointer to type: %s", typ)
  1346  		return "TODO"
  1347  	case *types.Named:
  1348  		n := typ.Obj()
  1349  		if isObjcType(typ) {
  1350  			w := g.wrapMap[n.Name()]
  1351  			return w.ObjcType()
  1352  		}
  1353  		if !isErrorType(typ) && !g.validPkg(n.Pkg()) {
  1354  			g.errorf("type %s is in package %s, which is not bound", n.Name(), n.Pkg().Name())
  1355  			return "TODO"
  1356  		}
  1357  		switch t := typ.Underlying().(type) {
  1358  		case *types.Interface:
  1359  			if makeIfaceSummary(t).implementable {
  1360  				return "id<" + g.namePrefixOf(n.Pkg()) + n.Name() + ">"
  1361  			} else {
  1362  				return g.namePrefixOf(n.Pkg()) + n.Name() + "*"
  1363  			}
  1364  		case *types.Struct:
  1365  			return g.namePrefixOf(n.Pkg()) + n.Name()
  1366  		}
  1367  		g.errorf("unsupported, named type %s", typ)
  1368  		return "TODO"
  1369  	default:
  1370  		g.errorf("unsupported type: %#+v, %s", typ, typ)
  1371  		return "TODO"
  1372  	}
  1373  }
  1374  
  1375  // embeddedObjcTypes returns the possible empty list of Objc types embedded
  1376  // in the given struct type.
  1377  func embeddedObjcTypes(t *types.Struct) []string {
  1378  	typeSet := make(map[string]struct{})
  1379  	var typs []string
  1380  	for i := 0; i < t.NumFields(); i++ {
  1381  		f := t.Field(i)
  1382  		if !f.Exported() {
  1383  			continue
  1384  		}
  1385  		if ft := f.Type(); isObjcType(ft) {
  1386  			name := ft.(*types.Named).Obj().Name()
  1387  			if _, exists := typeSet[name]; !exists {
  1388  				typeSet[name] = struct{}{}
  1389  				typs = append(typs, name)
  1390  			}
  1391  		}
  1392  	}
  1393  	return typs
  1394  }
  1395  
  1396  func isObjcType(t types.Type) bool {
  1397  	return typePkgFirstElem(t) == "ObjC"
  1398  }
  1399  
  1400  var objcNameReplacer = newNameSanitizer([]string{
  1401  	"bool", "bycopy", "byref", "char", "const", "double", "float",
  1402  	"id", "in", "init", "inout", "int", "long", "nil", "oneway",
  1403  	"out", "self", "short", "signed", "super", "unsigned", "void",
  1404  	"volatile"})
  1405  
  1406  const (
  1407  	objcPreamble = `// Objective-C API for talking to %[1]s Go package.
  1408  //   gobind %[2]s %[3]s
  1409  //
  1410  // File is generated by gobind. Do not edit.
  1411  
  1412  `
  1413  )