github.com/F4RD1N/gomobile@v1.0.1/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/F4RD1N/gomobile/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 summary := makeIfaceSummary(t) 898 if !summary.implementable { 899 g.genInterfaceInterface(obj, summary, false) 900 return 901 } 902 g.Printf("@protocol %s%s <NSObject>\n", g.namePrefix, obj.Name()) 903 for _, m := range makeIfaceSummary(t).callable { 904 if !g.isSigSupported(m.Type()) { 905 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 906 continue 907 } 908 s := g.funcSummary(nil, m) 909 g.Printf("- %s;\n", s.asMethod(g)) 910 } 911 g.Printf("@end\n") 912 } 913 914 func (g *ObjcGen) genInterfaceM(obj *types.TypeName, t *types.Interface) bool { 915 summary := makeIfaceSummary(t) 916 917 // @implementation Interface -- similar to what genStructM does. 918 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 919 g.Printf("}\n") 920 g.Printf("\n") 921 g.Printf("- (nonnull instancetype)initWithRef:(id)ref {\n") 922 g.Indent() 923 if isErrorType(obj.Type()) { 924 g.Printf("if (self) {\n") 925 g.Printf(" __ref = ref;\n") 926 g.Printf(" self = [super initWithDomain:@\"go\" code:1 userInfo:@{NSLocalizedDescriptionKey: [self error]}];\n") 927 g.Printf("}\n") 928 } else { 929 g.Printf("self = [super init];\n") 930 g.Printf("if (self) { __ref = ref; }\n") 931 } 932 g.Printf("return self;\n") 933 g.Outdent() 934 g.Printf("}\n") 935 g.Printf("\n") 936 937 for _, m := range summary.callable { 938 if !g.isSigSupported(m.Type()) { 939 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 940 continue 941 } 942 s := g.funcSummary(nil, m) 943 g.Printf("- %s {\n", s.asMethod(g)) 944 g.Indent() 945 g.genFunc(s, obj.Name()) 946 g.Outdent() 947 g.Printf("}\n\n") 948 } 949 g.Printf("@end\n") 950 g.Printf("\n") 951 952 return summary.implementable 953 } 954 955 func (g *ObjcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) { 956 oName := obj.Name() 957 s := g.funcSummary(nil, m) 958 g.genInterfaceMethodSignature(m, oName, false, g.paramName) 959 g.Indent() 960 g.Printf("@autoreleasepool {\n") 961 g.Indent() 962 g.Printf("%s* o = go_seq_objc_from_refnum(refnum);\n", g.refTypeBase(obj.Type())) 963 for _, p := range s.params { 964 g.genRead("_"+p.name, p.name, p.typ, modeTransient) 965 } 966 967 // call method 968 for _, p := range s.retParams { 969 if isErrorType(p.typ) { 970 g.Printf("NSError* %s = nil;\n", p.name) 971 } else { 972 g.Printf("%s %s;\n", g.objcType(p.typ), p.name) 973 } 974 } 975 976 if isErrorType(obj.Type()) && m.Name() == "Error" { 977 // As a special case, ObjC NSErrors are passed to Go pretending to implement the Go error interface. 978 // They don't actually have an Error method, so calls to to it needs to be rerouted. 979 g.Printf("%s = [o localizedDescription];\n", s.retParams[0].name) 980 } else { 981 if s.ret == "void" { 982 g.Printf("[o %s];\n", s.callMethod(g)) 983 } else if !s.returnsVal() { 984 g.Printf("%s returnVal = [o %s];\n", s.ret, s.callMethod(g)) 985 } else { 986 g.Printf("%s = [o %s];\n", s.retParams[0].name, s.callMethod(g)) 987 } 988 } 989 990 if len(s.retParams) > 0 { 991 if len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ) { 992 p := s.retParams[0] 993 g.genWrite(p.name, p.typ, modeRetained) 994 g.Printf("return _%s;\n", p.name) 995 } else { 996 var rets []string 997 for _, p := range s.retParams { 998 if isErrorType(p.typ) { 999 g.Printf("NSError *_%s = nil;\n", p.name) 1000 if !s.returnsVal() { 1001 g.Printf("if (!returnVal) {\n") 1002 } else { 1003 g.Printf("if (%s != nil) {\n", p.name) 1004 } 1005 g.Indent() 1006 g.Printf("_%[1]s = %[1]s;\n", p.name) 1007 g.Outdent() 1008 g.Printf("}\n") 1009 g.genWrite("_"+p.name, p.typ, modeRetained) 1010 rets = append(rets, "__"+p.name) 1011 } else { 1012 g.genWrite(p.name, p.typ, modeRetained) 1013 rets = append(rets, "_"+p.name) 1014 } 1015 } 1016 if len(rets) > 1 { 1017 g.Printf("cproxy%s_%s_%s_return _sres = {\n", g.pkgPrefix, oName, m.Name()) 1018 g.Printf(" %s\n", strings.Join(rets, ", ")) 1019 g.Printf("};\n") 1020 g.Printf("return _sres;\n") 1021 } else { 1022 g.Printf("return %s;\n", rets[0]) 1023 } 1024 } 1025 } 1026 g.Outdent() 1027 g.Printf("}\n") 1028 g.Outdent() 1029 g.Printf("}\n\n") 1030 } 1031 1032 // genRelease cleans up arguments that weren't copied in genWrite. 1033 func (g *ObjcGen) genRelease(varName string, t types.Type, mode varMode) { 1034 switch t := t.(type) { 1035 case *types.Slice: 1036 switch e := t.Elem().(type) { 1037 case *types.Basic: 1038 switch e.Kind() { 1039 case types.Uint8: // Byte. 1040 if mode == modeTransient { 1041 // If the argument was not mutable, go_seq_from_objc_bytearray created a copy. 1042 // Free it here. 1043 g.Printf("if (![%s isKindOfClass:[NSMutableData class]]) {\n", varName) 1044 g.Printf(" free(_%s.ptr);\n", varName) 1045 g.Printf("}\n") 1046 } 1047 } 1048 } 1049 } 1050 } 1051 1052 func (g *ObjcGen) genStructH(obj *types.TypeName, t *types.Struct) { 1053 doc := g.docs[obj.Name()] 1054 g.objcdoc(doc.Doc()) 1055 g.Printf("@interface %s%s : ", g.namePrefix, obj.Name()) 1056 oinf := g.ostructs[obj] 1057 var prots []string 1058 if oinf != nil { 1059 for _, sup := range oinf.supers { 1060 if !sup.Protocol { 1061 g.Printf(sup.Name) 1062 } else { 1063 prots = append(prots, sup.Name) 1064 } 1065 } 1066 } else { 1067 g.Printf("NSObject") 1068 prots = append(prots, "goSeqRefInterface") 1069 } 1070 pT := types.NewPointer(obj.Type()) 1071 for _, iface := range g.allIntf { 1072 p := iface.obj.Pkg() 1073 if g.Pkg != nil && g.Pkg != p { 1074 // To avoid header include cycles, only declare implementation of interfaces 1075 // from imported packages. TODO(elias.naur): Include every interface that 1076 // doesn't introduce an include cycle. 1077 found := false 1078 for _, imp := range g.Pkg.Imports() { 1079 if imp == p { 1080 found = true 1081 break 1082 } 1083 } 1084 if !found { 1085 continue 1086 } 1087 } 1088 obj := iface.obj 1089 if types.AssignableTo(pT, obj.Type()) { 1090 n := fmt.Sprintf("%s%s", g.namePrefixOf(obj.Pkg()), obj.Name()) 1091 prots = append(prots, n) 1092 } 1093 } 1094 1095 if len(prots) > 0 { 1096 g.Printf(" <%s>", strings.Join(prots, ", ")) 1097 } 1098 g.Printf(" {\n") 1099 g.Printf("}\n") 1100 g.Printf("@property(strong, readonly) _Nonnull id _ref;\n") 1101 g.Printf("\n") 1102 g.Printf("- (nonnull instancetype)initWithRef:(_Nonnull id)ref;\n") 1103 cons := g.constructors[obj] 1104 if oinf == nil { 1105 for _, f := range cons { 1106 if !g.isSigSupported(f.Type()) { 1107 g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj.Name(), f.Name()) 1108 continue 1109 } 1110 g.genInitH(obj, f) 1111 } 1112 } 1113 if oinf != nil || len(cons) == 0 { 1114 // default constructor won't return nil 1115 g.Printf("- (nonnull instancetype)init;\n") 1116 } 1117 1118 // accessors to exported fields. 1119 for _, f := range exportedFields(t) { 1120 if t := f.Type(); !g.isSupported(t) { 1121 g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", obj.Name(), f.Name(), t) 1122 continue 1123 } 1124 name, typ := f.Name(), g.objcType(f.Type()) 1125 g.objcdoc(doc.Member(f.Name())) 1126 1127 // properties are atomic by default so explicitly say otherwise 1128 g.Printf("@property (nonatomic) %s %s;\n", typ, objcNameReplacer(lowerFirst(name))) 1129 } 1130 1131 // exported methods 1132 for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) { 1133 if !g.isSigSupported(m.Type()) { 1134 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 1135 continue 1136 } 1137 s := g.funcSummary(obj, m) 1138 g.objcdoc(doc.Member(m.Name())) 1139 g.Printf("- %s;\n", s.asMethod(g)) 1140 } 1141 g.Printf("@end\n") 1142 } 1143 1144 func (g *ObjcGen) objcdoc(doc string) { 1145 if doc == "" { 1146 return 1147 } 1148 g.Printf("/**\n * %s */\n", doc) 1149 } 1150 1151 func (g *ObjcGen) genStructM(obj *types.TypeName, t *types.Struct) { 1152 fields := exportedFields(t) 1153 methods := exportedMethodSet(types.NewPointer(obj.Type())) 1154 1155 g.Printf("\n") 1156 oinf := g.ostructs[obj] 1157 g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name()) 1158 g.Printf("}\n\n") 1159 g.Printf("- (nonnull instancetype)initWithRef:(_Nonnull id)ref {\n") 1160 g.Indent() 1161 g.Printf("self = [super init];\n") 1162 g.Printf("if (self) { __ref = ref; }\n") 1163 g.Printf("return self;\n") 1164 g.Outdent() 1165 g.Printf("}\n\n") 1166 cons := g.constructors[obj] 1167 if oinf == nil { 1168 for _, f := range cons { 1169 if !g.isSigSupported(f.Type()) { 1170 g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", obj, f.Name()) 1171 continue 1172 } 1173 g.genInitM(obj, f) 1174 } 1175 } 1176 if oinf != nil || len(cons) == 0 { 1177 g.Printf("- (nonnull instancetype)init {\n") 1178 g.Indent() 1179 g.Printf("self = [super init];\n") 1180 g.Printf("if (self) {\n") 1181 g.Indent() 1182 g.Printf("__ref = go_seq_from_refnum(new_%s_%s());\n", g.pkgPrefix, obj.Name()) 1183 g.Outdent() 1184 g.Printf("}\n") 1185 g.Printf("return self;\n") 1186 g.Outdent() 1187 g.Printf("}\n\n") 1188 } 1189 1190 for _, f := range fields { 1191 if !g.isSupported(f.Type()) { 1192 g.Printf("// skipped unsupported field %s with type %s\n\n", f.Name(), f.Type()) 1193 continue 1194 } 1195 g.genGetter(obj.Name(), f) 1196 g.genSetter(obj.Name(), f) 1197 } 1198 1199 for _, m := range methods { 1200 if !g.isSigSupported(m.Type()) { 1201 g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name()) 1202 continue 1203 } 1204 s := g.funcSummary(obj, m) 1205 g.Printf("- %s {\n", s.asMethod(g)) 1206 g.Indent() 1207 g.genFunc(s, obj.Name()) 1208 g.Outdent() 1209 g.Printf("}\n\n") 1210 } 1211 g.Printf("@end\n\n") 1212 } 1213 1214 func (g *ObjcGen) genInitH(obj *types.TypeName, f *types.Func) { 1215 s := g.funcSummary(obj, f) 1216 doc := g.docs[f.Name()] 1217 g.objcdoc(doc.Doc()) 1218 1219 // custom inits can return nil in Go so make them nullable 1220 g.Printf("- (nullable instancetype)%s%s;\n", s.initName, s.asInitSignature(g)) 1221 } 1222 1223 func (g *ObjcGen) genInitM(obj *types.TypeName, f *types.Func) { 1224 s := g.funcSummary(obj, f) 1225 g.Printf("- (instancetype)%s%s {\n", s.initName, s.asInitSignature(g)) 1226 g.Indent() 1227 g.Printf("self = [super init];\n") 1228 g.Printf("if (!self) return nil;\n") 1229 for _, p := range s.params { 1230 g.genWrite(p.name, p.typ, modeTransient) 1231 } 1232 // Constructors always return a mandatory *T and an optional error 1233 if len(s.retParams) == 1 { 1234 g.Printf("%s refnum = ", g.cgoType(s.retParams[0].typ)) 1235 } else { 1236 g.Printf("struct proxy%s__%s_return res = ", g.pkgPrefix, s.goname) 1237 } 1238 g.Printf("proxy%s__%s(", g.pkgPrefix, s.goname) 1239 for i, p := range s.params { 1240 if i > 0 { 1241 g.Printf(", ") 1242 } 1243 g.Printf("_%s", p.name) 1244 } 1245 g.Printf(");\n") 1246 for _, p := range s.params { 1247 g.genRelease(p.name, p.typ, modeTransient) 1248 } 1249 if len(s.retParams) == 2 { 1250 g.Printf("int32_t refnum = res.r0;\n") 1251 g.Printf("GoSeqRef *_err = go_seq_from_refnum(res.r1);\n") 1252 } 1253 g.Printf("__ref = go_seq_from_refnum(refnum);\n") 1254 if len(s.retParams) == 2 { 1255 g.Printf("if (_err != NULL)\n") 1256 g.Printf(" return nil;\n") 1257 } 1258 g.Printf("return self;\n") 1259 g.Outdent() 1260 g.Printf("}\n\n") 1261 } 1262 1263 func (g *ObjcGen) errorf(format string, args ...interface{}) { 1264 g.err = append(g.err, fmt.Errorf(format, args...)) 1265 } 1266 1267 func (g *ObjcGen) refTypeBase(typ types.Type) string { 1268 switch typ := typ.(type) { 1269 case *types.Pointer: 1270 if _, ok := typ.Elem().(*types.Named); ok { 1271 return g.objcType(typ.Elem()) 1272 } 1273 case *types.Named: 1274 n := typ.Obj() 1275 if isObjcType(typ) { 1276 return g.wrapMap[n.Name()].Name 1277 } 1278 if isErrorType(typ) || g.validPkg(n.Pkg()) { 1279 switch typ.Underlying().(type) { 1280 case *types.Interface, *types.Struct: 1281 return g.namePrefixOf(n.Pkg()) + n.Name() 1282 } 1283 } 1284 } 1285 1286 // fallback to whatever objcType returns. This must not happen. 1287 return g.objcType(typ) 1288 } 1289 1290 func (g *ObjcGen) objcParamType(t types.Type) string { 1291 1292 switch typ := t.(type) { 1293 case *types.Basic: 1294 switch typ.Kind() { 1295 case types.String, types.UntypedString: 1296 return "NSString* _Nullable" 1297 } 1298 } 1299 1300 return g.objcType(t) 1301 1302 } 1303 1304 func (g *ObjcGen) objcType(typ types.Type) string { 1305 1306 if isErrorType(typ) { 1307 return "NSError* _Nullable" 1308 } 1309 1310 switch typ := typ.(type) { 1311 case *types.Basic: 1312 switch typ.Kind() { 1313 case types.Bool, types.UntypedBool: 1314 return "BOOL" 1315 case types.Int: 1316 return "long" 1317 case types.Int8: 1318 return "int8_t" 1319 case types.Int16: 1320 return "int16_t" 1321 case types.Int32, types.UntypedRune: // types.Rune 1322 return "int32_t" 1323 case types.Int64, types.UntypedInt: 1324 return "int64_t" 1325 case types.Uint8: 1326 // byte is an alias of uint8, and the alias is lost. 1327 return "byte" 1328 case types.Uint16: 1329 return "uint16_t" 1330 case types.Uint32: 1331 return "uint32_t" 1332 case types.Uint64: 1333 return "uint64_t" 1334 case types.Float32: 1335 return "float" 1336 case types.Float64, types.UntypedFloat: 1337 return "double" 1338 case types.String, types.UntypedString: 1339 return "NSString* _Nonnull" 1340 default: 1341 g.errorf("unsupported type: %s", typ) 1342 return "TODO" 1343 } 1344 case *types.Slice: 1345 elem := g.objcType(typ.Elem()) 1346 // Special case: NSData seems to be a better option for byte slice. 1347 if elem == "byte" { 1348 return "NSData* _Nullable" 1349 } 1350 // TODO(hyangah): support other slice types: NSArray or CFArrayRef. 1351 // Investigate the performance implication. 1352 g.errorf("unsupported type: %s", typ) 1353 return "TODO" 1354 case *types.Pointer: 1355 if _, ok := typ.Elem().(*types.Named); ok { 1356 return g.objcType(typ.Elem()) + "* _Nullable" 1357 } 1358 g.errorf("unsupported pointer to type: %s", typ) 1359 return "TODO" 1360 case *types.Named: 1361 n := typ.Obj() 1362 if isObjcType(typ) { 1363 w := g.wrapMap[n.Name()] 1364 return w.ObjcType() 1365 } 1366 if !isErrorType(typ) && !g.validPkg(n.Pkg()) { 1367 g.errorf("type %s is in package %s, which is not bound", n.Name(), n.Pkg().Name()) 1368 return "TODO" 1369 } 1370 switch t := typ.Underlying().(type) { 1371 case *types.Interface: 1372 if makeIfaceSummary(t).implementable { 1373 return "id<" + g.namePrefixOf(n.Pkg()) + n.Name() + "> _Nullable" 1374 } else { 1375 return g.namePrefixOf(n.Pkg()) + n.Name() + "* _Nullable" 1376 } 1377 case *types.Struct: 1378 return g.namePrefixOf(n.Pkg()) + n.Name() 1379 } 1380 g.errorf("unsupported, named type %s", typ) 1381 return "TODO" 1382 default: 1383 g.errorf("unsupported type: %#+v, %s", typ, typ) 1384 return "TODO" 1385 } 1386 } 1387 1388 // embeddedObjcTypes returns the possible empty list of Objc types embedded 1389 // in the given struct type. 1390 func embeddedObjcTypes(t *types.Struct) []string { 1391 typeSet := make(map[string]struct{}) 1392 var typs []string 1393 for i := 0; i < t.NumFields(); i++ { 1394 f := t.Field(i) 1395 if !f.Exported() { 1396 continue 1397 } 1398 if ft := f.Type(); isObjcType(ft) { 1399 name := ft.(*types.Named).Obj().Name() 1400 if _, exists := typeSet[name]; !exists { 1401 typeSet[name] = struct{}{} 1402 typs = append(typs, name) 1403 } 1404 } 1405 } 1406 return typs 1407 } 1408 1409 func isObjcType(t types.Type) bool { 1410 return typePkgFirstElem(t) == "ObjC" 1411 } 1412 1413 var objcNameReplacer = newNameSanitizer([]string{ 1414 "bool", "bycopy", "byref", "char", "const", "double", "float", 1415 "id", "in", "init", "inout", "int", "long", "nil", "oneway", 1416 "out", "self", "short", "signed", "super", "unsigned", "void", 1417 "volatile"}) 1418 1419 const ( 1420 objcPreamble = `// Objective-C API for talking to %[1]s Go package. 1421 // gobind %[2]s %[3]s 1422 // 1423 // File is generated by gobind. Do not edit. 1424 1425 ` 1426 )