github.com/coming-chat/gomobile@v0.0.0-20220601074111-56995f7d7aba/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 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* _Nullable" 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 )