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