bind: generate wrappers for generated ObjC types

This is the Objective-C equivalent of CL 34776, generating reverse
wrappers for generated ObjC types. The implementation follows the same
strategy as the Java implementation: use the Go ast package to find
exported structs with embedded Objective-C types and synthesize their
types as if they were imported through clang.

In turn, the handling of the implicit "self" parameter changes in the
same way as well: the type of self parameters must be the wrapped type
for the generated type. For example:

func (d *GoNSDate) Description(self Foundation.NSDate) string

becomes

import gopkg "ObjC/Objcpkg"

func (d *GoNSDate) Description(self gopkg.GoNSDate) string

Change-Id: I26f838b06a622864be463f81dbb4dcae76f70f20
Reviewed-on: https://go-review.googlesource.com/34780
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/bind_test.go b/bind/bind_test.go
index 9fe39a0..5864319 100644
--- a/bind/bind_test.go
+++ b/bind/bind_test.go
@@ -179,14 +179,7 @@
 	}
 }
 
-func genObjcPackages(t *testing.T, dir string, types []*objc.Named, buf *bytes.Buffer) *ObjcWrapper {
-	cg := &ObjcWrapper{
-		Printer: &Printer{
-			IndentEach: []byte("\t"),
-			Buf:        buf,
-		},
-	}
-	cg.Init(types)
+func genObjcPackages(t *testing.T, dir string, cg *ObjcWrapper) {
 	pkgBase := filepath.Join(dir, "src", "ObjC")
 	if err := os.MkdirAll(pkgBase, 0700); err != nil {
 		t.Fatal(err)
@@ -197,16 +190,16 @@
 			t.Fatal(err)
 		}
 		pkgFile := filepath.Join(pkgDir, "package.go")
-		buf.Reset()
+		cg.Buf.Reset()
 		cg.GenPackage(i)
-		if err := ioutil.WriteFile(pkgFile, buf.Bytes(), 0600); err != nil {
+		if err := ioutil.WriteFile(pkgFile, cg.Buf.Bytes(), 0600); err != nil {
 			t.Fatal(err)
 		}
 	}
-	buf.Reset()
+	cg.Buf.Reset()
 	cg.GenInterfaces()
 	clsFile := filepath.Join(pkgBase, "interfaces.go")
-	if err := ioutil.WriteFile(clsFile, buf.Bytes(), 0600); err != nil {
+	if err := ioutil.WriteFile(clsFile, cg.Buf.Bytes(), 0600); err != nil {
 		t.Fatal(err)
 	}
 
@@ -220,7 +213,6 @@
 	if out, err := cmd.CombinedOutput(); err != nil {
 		t.Fatalf("failed to go install the generated ObjC wrappers: %v: %s", err, string(out))
 	}
-	return cg
 }
 
 func genJavaPackages(t *testing.T, dir string, cg *ClassGen) {
@@ -422,7 +414,18 @@
 			t.Fatal(err)
 		}
 		defer os.RemoveAll(tmpGopath)
-		cg := genObjcPackages(t, tmpGopath, types, &buf)
+		cg := &ObjcWrapper{
+			Printer: &Printer{
+				IndentEach: []byte("\t"),
+				Buf:        &buf,
+			},
+		}
+		var genNames []string
+		for _, emb := range refs.Embedders {
+			genNames = append(genNames, emb.Name)
+		}
+		cg.Init(types, genNames)
+		genObjcPackages(t, tmpGopath, cg)
 		pkg := typeCheck(t, filename, tmpGopath)
 		cg.GenGo()
 		testGenGo(t, filename, &buf, pkg)
diff --git a/bind/genobjc.go b/bind/genobjc.go
index d374974..32ec399 100644
--- a/bind/genobjc.go
+++ b/bind/genobjc.go
@@ -51,7 +51,9 @@
 	for _, w := range wrappers {
 		g.wrapMap[w.GoName] = w
 		if _, exists := modMap[w.Module]; !exists {
-			g.modules = append(g.modules, w.Module)
+			if !w.Generated {
+				g.modules = append(g.modules, w.Module)
+			}
 			modMap[w.Module] = struct{}{}
 		}
 	}
@@ -412,19 +414,20 @@
 	name string
 }
 
-func (g *ObjcGen) funcSummary(oinf *objcClassInfo, obj *types.Func) *funcSummary {
-	sig := obj.Type().(*types.Signature)
-	s := &funcSummary{goname: obj.Name(), sig: sig}
+func (g *ObjcGen) funcSummary(obj *types.TypeName, f *types.Func) *funcSummary {
+	sig := f.Type().(*types.Signature)
+	s := &funcSummary{goname: f.Name(), sig: sig}
 	var om *objc.Func
 	var sigElems []string
+	oinf := g.ostructs[obj]
 	if oinf != nil {
-		om = oinf.methods[obj.Name()]
+		om = oinf.methods[f.Name()]
 	}
 	if om != nil {
 		sigElems = strings.Split(om.Sig, ":")
 		s.name = sigElems[0]
 	} else {
-		s.name = obj.Name()
+		s.name = f.Name()
 	}
 	params := sig.Params()
 	first := 0
@@ -433,20 +436,16 @@
 			v := params.At(0)
 			if v.Name() == "self" {
 				t := v.Type()
-				if isObjcType(t) {
-					s.hasself = true
-					first = 1
-					ot := g.wrapMap[t.(*types.Named).Obj().Name()]
-					found := false
-					for _, sup := range oinf.supers {
-						if ot == sup {
-							found = true
-							break
+				if t, ok := t.(*types.Named); ok {
+					if pkg := t.Obj().Pkg(); pkgFirstElem(pkg) == "ObjC" {
+						s.hasself = true
+						module := pkg.Path()[len("ObjC/"):]
+						typName := module + "." + t.Obj().Name()
+						exp := g.namePrefix + "." + obj.Name()
+						if typName != exp {
+							g.errorf("the type %s of the `this` argument to method %s is not %s", typName, f.Name(), exp)
 						}
 					}
-					if !found {
-						g.errorf("the type %s of the `this` argument to method %s is not a super class of the enclosing struct", ot.Name, obj.Name())
-					}
 				}
 			}
 		}
@@ -501,7 +500,7 @@
 		}
 
 		if !isErrorType(res.At(1).Type()) {
-			g.errorf("second result value must be of type error: %s", obj)
+			g.errorf("second result value must be of type error: %s", f)
 			return nil
 		}
 		s.retParams = append(s.retParams, paramInfo{
@@ -510,7 +509,7 @@
 		})
 	default:
 		// TODO(hyangah): relax the constraint on multiple return params.
-		g.errorf("too many result values: %s", obj)
+		g.errorf("too many result values: %s", f)
 		return nil
 	}
 
@@ -534,14 +533,18 @@
 
 func (s *funcSummary) asMethod(g *ObjcGen) string {
 	var params []string
-	for i, p := range s.params {
+	skip := 0
+	if s.hasself {
+		skip = 1
+	}
+	for i, p := range s.params[skip:] {
 		var key string
 		if i != 0 {
 			key = p.name
 		}
 		params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ), p.name))
 	}
-	skip := 0
+	skip = 0
 	if s.returnsVal() {
 		skip = 1
 	}
@@ -743,13 +746,15 @@
 }
 
 func (g *ObjcGen) genFunc(s *funcSummary, objName string) {
+	skip := 0
 	if objName != "" {
 		g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
 		if s.hasself {
-			g.genRefWrite("self")
+			skip = 1
+			g.Printf("int32_t _self = go_seq_to_refnum(self);\n")
 		}
 	}
-	for _, p := range s.params {
+	for _, p := range s.params[skip:] {
 		g.genWrite(p.name, p.typ, modeTransient)
 	}
 	resPrefix := ""
@@ -768,7 +773,7 @@
 			g.Printf(", _self")
 		}
 	}
-	for i, p := range s.params {
+	for i, p := range s.params[skip:] {
 		if i > 0 || objName != "" {
 			g.Printf(", ")
 		}
@@ -782,7 +787,7 @@
 	for i, r := range s.retParams {
 		g.genRead("_"+r.name, fmt.Sprintf("%sr%d", resPrefix, i), r.typ, modeRetained)
 	}
-	skip := 0
+	skip = 0
 	if s.returnsVal() {
 		skip = 1
 	}
@@ -1045,7 +1050,7 @@
 			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
 			continue
 		}
-		s := g.funcSummary(g.ostructs[obj], m)
+		s := g.funcSummary(obj, m)
 		g.Printf("- %s;\n", objcNameReplacer(lowerFirst(s.asMethod(g))))
 	}
 	g.Printf("@end\n")
@@ -1094,7 +1099,7 @@
 			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
 			continue
 		}
-		s := g.funcSummary(g.ostructs[obj], m)
+		s := g.funcSummary(obj, m)
 		g.Printf("- %s {\n", s.asMethod(g))
 		g.Indent()
 		g.genFunc(s, obj.Name())
diff --git a/bind/genobjcw.go b/bind/genobjcw.go
index 99f8f14..b277f77 100644
--- a/bind/genobjcw.go
+++ b/bind/genobjcw.go
@@ -26,10 +26,18 @@
 		// For each module/name Go package path, the ObjC type
 		// with static functions or constants.
 		typePkgs map[string]*objc.Named
+		// supers is the map of types that need Super methods.
+		supers map[string]struct{}
 	}
 )
 
-func (g *ObjcWrapper) Init(types []*objc.Named) {
+// Init initializes the ObjC types wrapper generator. Types is the
+// list of types to wrap, genNames the list of generated type names.
+func (g *ObjcWrapper) Init(types []*objc.Named, genNames []string) {
+	g.supers = make(map[string]struct{})
+	for _, s := range genNames {
+		g.supers[s] = struct{}{}
+	}
 	g.types = types
 	g.imported = make(map[string]*objc.Named)
 	g.modMap = make(map[string][]*objc.Named)
@@ -39,8 +47,10 @@
 		g.imported[n.GoName] = n
 		typePkg := n.Module + "/" + n.GoName
 		g.typePkgs[typePkg] = n
-		if _, exists := g.modMap[n.Module]; !exists {
-			g.modules = append(g.modules, n.Module)
+		if !n.Generated {
+			if _, exists := g.modMap[n.Module]; !exists {
+				g.modules = append(g.modules, n.Module)
+			}
 		}
 		g.modMap[n.Module] = append(g.modMap[n.Module], n)
 		if _, exists := pkgSet[n.Module]; !exists {
@@ -68,7 +78,7 @@
 			}
 			g.genCFuncDecl("cproxy", n.GoName, f)
 			g.genCFuncBody(n, f, false)
-			if !n.Protocol {
+			if _, exists := g.supers[n.GoName]; exists {
 				g.genCFuncDecl("csuper", n.GoName, f)
 				g.genCFuncBody(n, f, true)
 			}
@@ -99,7 +109,7 @@
 	if super {
 		g.Printf("struct objc_super _super = {\n")
 		g.Printf("	.receiver = _this,\n")
-		g.Printf("	.super_class = [%s class],\n", n.Name)
+		g.Printf("	.super_class = class_getSuperclass([%s class]),\n", n.Name)
 		g.Printf("};\n")
 	}
 	retType := "void"
@@ -123,7 +133,7 @@
 		switch f.Ret.Kind {
 		case objc.String, objc.Bool, objc.Data, objc.Int, objc.Uint, objc.Short, objc.Ushort, objc.Char, objc.Float, objc.Double, objc.Class, objc.Protocol:
 		default:
-			// If support struct is added, objc_msgSend_stret must be used
+			// If support for struct results is added, objc_msgSend_stret must be used
 			panic("unsupported type kind - use objc_msgSend_stret?")
 		}
 	}
@@ -214,6 +224,19 @@
 	for _, m := range g.modules {
 		g.Printf("@import %s;\n", m)
 	}
+	// Include header files for generated types
+	for _, n := range g.pkgNames {
+		hasGen := false
+		for _, t := range g.modMap[n] {
+			if t.Generated {
+				hasGen = true
+				break
+			}
+		}
+		if hasGen {
+			g.Printf("#import %q\n", n+".objc.h")
+		}
+	}
 	for _, tn := range []string{"int", "nstring", "nbyteslice", "long", "unsigned long", "short", "unsigned short", "bool", "char", "unsigned char", "float", "double"} {
 		sn := strings.Replace(tn, " ", "_", -1)
 		g.Printf("typedef struct ret_%s {\n", sn)
@@ -230,7 +253,7 @@
 			g.Printf("extern ")
 			g.genCFuncDecl("cproxy", n.GoName, f)
 			g.Printf(";\n")
-			if !n.Protocol {
+			if _, exists := g.supers[n.GoName]; exists {
 				g.Printf("extern ")
 				g.genCFuncDecl("csuper", n.GoName, f)
 				g.Printf(";\n")
@@ -341,7 +364,7 @@
 		g.genFuncDecl(false, f)
 		g.genFuncBody(n, f, "cproxy")
 	}
-	if !n.Protocol {
+	if _, exists := g.supers[n.GoName]; exists {
 		g.Printf("func (p *proxy_class_%s) Super() ObjC.%s {\n", n.GoName, n.Module+"_"+n.GoName)
 		g.Printf("  return &super_%s{p}\n", n.GoName)
 		g.Printf("}\n\n")
@@ -557,7 +580,7 @@
 		g.genFuncDecl(true, f)
 		g.Printf("\n")
 	}
-	if !n.Protocol {
+	if _, exists := g.supers[n.GoName]; exists {
 		g.Printf("Super() %s\n", n.Module+"_"+n.GoName)
 	}
 	g.Outdent()
diff --git a/bind/testdata/objc.go.golden b/bind/testdata/objc.go.golden
index eaa3ce7..c03ecf1 100644
--- a/bind/testdata/objc.go.golden
+++ b/bind/testdata/objc.go.golden
@@ -6,15 +6,12 @@
 const Dummy = 0
 
 type Foundation_NSString interface {
-	Super() Foundation_NSString
 }
 
 type Foundation_NSDate interface {
-	Super() Foundation_NSDate
 }
 
 type Foundation_NSObjectC interface {
-	Super() Foundation_NSObjectC
 }
 
 // File is generated by gobind. Do not edit.
@@ -42,12 +39,6 @@
 
 func (p *proxy_class_NSString) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
 
-func (p *proxy_class_NSString) Super() ObjC.Foundation_NSString {
-  return &super_NSString{p}
-}
-
-type super_NSString struct {*proxy_class_NSString}
-
 func init() {
 }
 
@@ -55,12 +46,6 @@
 
 func (p *proxy_class_NSDate) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
 
-func (p *proxy_class_NSDate) Super() ObjC.Foundation_NSDate {
-  return &super_NSDate{p}
-}
-
-type super_NSDate struct {*proxy_class_NSDate}
-
 func init() {
 }
 
@@ -68,12 +53,6 @@
 
 func (p *proxy_class_NSObjectC) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
 
-func (p *proxy_class_NSObjectC) Super() ObjC.Foundation_NSObjectC {
-  return &super_NSObjectC{p}
-}
-
-type super_NSObjectC struct {*proxy_class_NSObjectC}
-
 // Package gomobile_bind is an autogenerated binder stub for package objc.
 //   gobind -lang=go objc
 //
@@ -96,24 +75,14 @@
 // suppress the error if seq ends up unused
 var _ = _seq.FromRefNum
 
-// skipped method D.Super with unsupported parameter or return types
-
 type proxyobjc_D _seq.Ref
 
 func (p *proxyobjc_D) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
 
-// skipped method D.Super with unsupported parameter or result types
-// skipped method O.Super with unsupported parameter or return types
-
 type proxyobjc_O _seq.Ref
 
 func (p *proxyobjc_O) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
 
-// skipped method O.Super with unsupported parameter or result types
-// skipped method S.Super with unsupported parameter or return types
-
 type proxyobjc_S _seq.Ref
 
 func (p *proxyobjc_S) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
-
-// skipped method S.Super with unsupported parameter or result types
diff --git a/bind/testdata/objcw.go.golden b/bind/testdata/objcw.go.golden
index 056a784..f0f237b 100644
--- a/bind/testdata/objcw.go.golden
+++ b/bind/testdata/objcw.go.golden
@@ -8,13 +8,11 @@
 type Foundation_NSDate interface {
 	Hash() (uint)
 	Description() (string)
-	Super() Foundation_NSDate
 }
 
 type Foundation_NSObjectC interface {
 	Hash() (uint)
 	Description() (string)
-	Super() Foundation_NSObjectC
 }
 
 type Foundation_NSObjectP interface {
@@ -25,19 +23,34 @@
 type Foundation_NSSet interface {
 	Hash() (uint)
 	Description() (string)
-	Super() Foundation_NSSet
 }
 
 type UIKit_UIResponder interface {
 	Hash() (uint)
 	Description() (string)
-	Super() UIKit_UIResponder
 }
 
 type UIKit_UIPressesEvent interface {
 	Hash() (uint)
 	Description() (string)
-	Super() UIKit_UIPressesEvent
+}
+
+type Objc_GoNSDate interface {
+	Hash() (uint)
+	Description() (string)
+	Super() Objc_GoNSDate
+}
+
+type Objc_GoNSObject interface {
+	Hash() (uint)
+	Description() (string)
+	Super() Objc_GoNSObject
+}
+
+type Objc_GoUIResponder interface {
+	Hash() (uint)
+	Description() (string)
+	Super() Objc_GoUIResponder
 }
 
 // File is generated by gobind. Do not edit.
@@ -77,24 +90,6 @@
 	return _res
 }
 
-func (p *proxy_class_NSDate) Super() ObjC.Foundation_NSDate {
-  return &super_NSDate{p}
-}
-
-type super_NSDate struct {*proxy_class_NSDate}
-
-func (p *super_NSDate) Hash() (uint) {
-	res := C.csuper_NSDate_Hash(C.int(p.Bind_proxy_refnum__()))
-	_res := uint(res)
-	return _res
-}
-
-func (p *super_NSDate) Description() (string) {
-	res := C.csuper_NSDate_Description(C.int(p.Bind_proxy_refnum__()))
-	_res := decodeString(res)
-	return _res
-}
-
 func init() {
 }
 
@@ -114,24 +109,6 @@
 	return _res
 }
 
-func (p *proxy_class_NSObjectC) Super() ObjC.Foundation_NSObjectC {
-  return &super_NSObjectC{p}
-}
-
-type super_NSObjectC struct {*proxy_class_NSObjectC}
-
-func (p *super_NSObjectC) Hash() (uint) {
-	res := C.csuper_NSObjectC_Hash(C.int(p.Bind_proxy_refnum__()))
-	_res := uint(res)
-	return _res
-}
-
-func (p *super_NSObjectC) Description() (string) {
-	res := C.csuper_NSObjectC_Description(C.int(p.Bind_proxy_refnum__()))
-	_res := decodeString(res)
-	return _res
-}
-
 func init() {
 }
 
@@ -170,24 +147,6 @@
 	return _res
 }
 
-func (p *proxy_class_NSSet) Super() ObjC.Foundation_NSSet {
-  return &super_NSSet{p}
-}
-
-type super_NSSet struct {*proxy_class_NSSet}
-
-func (p *super_NSSet) Hash() (uint) {
-	res := C.csuper_NSSet_Hash(C.int(p.Bind_proxy_refnum__()))
-	_res := uint(res)
-	return _res
-}
-
-func (p *super_NSSet) Description() (string) {
-	res := C.csuper_NSSet_Description(C.int(p.Bind_proxy_refnum__()))
-	_res := decodeString(res)
-	return _res
-}
-
 func init() {
 }
 
@@ -207,24 +166,6 @@
 	return _res
 }
 
-func (p *proxy_class_UIResponder) Super() ObjC.UIKit_UIResponder {
-  return &super_UIResponder{p}
-}
-
-type super_UIResponder struct {*proxy_class_UIResponder}
-
-func (p *super_UIResponder) Hash() (uint) {
-	res := C.csuper_UIResponder_Hash(C.int(p.Bind_proxy_refnum__()))
-	_res := uint(res)
-	return _res
-}
-
-func (p *super_UIResponder) Description() (string) {
-	res := C.csuper_UIResponder_Description(C.int(p.Bind_proxy_refnum__()))
-	_res := decodeString(res)
-	return _res
-}
-
 func init() {
 }
 
@@ -244,20 +185,113 @@
 	return _res
 }
 
-func (p *proxy_class_UIPressesEvent) Super() ObjC.UIKit_UIPressesEvent {
-  return &super_UIPressesEvent{p}
+func init() {
 }
 
-type super_UIPressesEvent struct {*proxy_class_UIPressesEvent}
+type proxy_class_GoNSDate _seq.Ref
 
-func (p *super_UIPressesEvent) Hash() (uint) {
-	res := C.csuper_UIPressesEvent_Hash(C.int(p.Bind_proxy_refnum__()))
+func (p *proxy_class_GoNSDate) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
+
+func (p *proxy_class_GoNSDate) Hash() (uint) {
+	res := C.cproxy_GoNSDate_Hash(C.int(p.Bind_proxy_refnum__()))
 	_res := uint(res)
 	return _res
 }
 
-func (p *super_UIPressesEvent) Description() (string) {
-	res := C.csuper_UIPressesEvent_Description(C.int(p.Bind_proxy_refnum__()))
+func (p *proxy_class_GoNSDate) Description() (string) {
+	res := C.cproxy_GoNSDate_Description(C.int(p.Bind_proxy_refnum__()))
+	_res := decodeString(res)
+	return _res
+}
+
+func (p *proxy_class_GoNSDate) Super() ObjC.Objc_GoNSDate {
+  return &super_GoNSDate{p}
+}
+
+type super_GoNSDate struct {*proxy_class_GoNSDate}
+
+func (p *super_GoNSDate) Hash() (uint) {
+	res := C.csuper_GoNSDate_Hash(C.int(p.Bind_proxy_refnum__()))
+	_res := uint(res)
+	return _res
+}
+
+func (p *super_GoNSDate) Description() (string) {
+	res := C.csuper_GoNSDate_Description(C.int(p.Bind_proxy_refnum__()))
+	_res := decodeString(res)
+	return _res
+}
+
+func init() {
+}
+
+type proxy_class_GoNSObject _seq.Ref
+
+func (p *proxy_class_GoNSObject) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
+
+func (p *proxy_class_GoNSObject) Hash() (uint) {
+	res := C.cproxy_GoNSObject_Hash(C.int(p.Bind_proxy_refnum__()))
+	_res := uint(res)
+	return _res
+}
+
+func (p *proxy_class_GoNSObject) Description() (string) {
+	res := C.cproxy_GoNSObject_Description(C.int(p.Bind_proxy_refnum__()))
+	_res := decodeString(res)
+	return _res
+}
+
+func (p *proxy_class_GoNSObject) Super() ObjC.Objc_GoNSObject {
+  return &super_GoNSObject{p}
+}
+
+type super_GoNSObject struct {*proxy_class_GoNSObject}
+
+func (p *super_GoNSObject) Hash() (uint) {
+	res := C.csuper_GoNSObject_Hash(C.int(p.Bind_proxy_refnum__()))
+	_res := uint(res)
+	return _res
+}
+
+func (p *super_GoNSObject) Description() (string) {
+	res := C.csuper_GoNSObject_Description(C.int(p.Bind_proxy_refnum__()))
+	_res := decodeString(res)
+	return _res
+}
+
+func init() {
+}
+
+type proxy_class_GoUIResponder _seq.Ref
+
+func (p *proxy_class_GoUIResponder) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
+
+func (p *proxy_class_GoUIResponder) Hash() (uint) {
+	res := C.cproxy_GoUIResponder_Hash(C.int(p.Bind_proxy_refnum__()))
+	_res := uint(res)
+	return _res
+}
+
+func (p *proxy_class_GoUIResponder) Description() (string) {
+	res := C.cproxy_GoUIResponder_Description(C.int(p.Bind_proxy_refnum__()))
+	_res := decodeString(res)
+	return _res
+}
+
+func (p *proxy_class_GoUIResponder) Super() ObjC.Objc_GoUIResponder {
+  return &super_GoUIResponder{p}
+}
+
+type super_GoUIResponder struct {*proxy_class_GoUIResponder}
+
+func (p *super_GoUIResponder) Hash() (uint) {
+	res := C.csuper_GoUIResponder_Hash(C.int(p.Bind_proxy_refnum__()))
+	_res := uint(res)
+	return _res
+}
+
+func (p *super_GoUIResponder) Description() (string) {
+	res := C.csuper_GoUIResponder_Description(C.int(p.Bind_proxy_refnum__()))
 	_res := decodeString(res)
 	return _res
 }
diff --git a/bind/testpkg/objcpkg/classes.go b/bind/testpkg/objcpkg/classes.go
index 7fd761f..d90a294 100644
--- a/bind/testpkg/objcpkg/classes.go
+++ b/bind/testpkg/objcpkg/classes.go
@@ -6,6 +6,7 @@
 
 import (
 	"ObjC/Foundation"
+	gopkg "ObjC/Objcpkg"
 	"ObjC/UIKit"
 )
 
@@ -18,11 +19,11 @@
 	Foundation.NSDate
 }
 
-func (d *GoNSDate) Hash(self Foundation.NSDate) int {
+func (d *GoNSDate) Hash(self gopkg.GoNSDate) int {
 	return Hash
 }
 
-func (d *GoNSDate) Description(self Foundation.NSDate) string {
+func (d *GoNSDate) Description(self gopkg.GoNSDate) string {
 	// Test self call
 	if h := self.Hash(); h != Hash {
 		panic("hash mismatch")
@@ -30,7 +31,7 @@
 	return DescriptionStr
 }
 
-func (d *GoNSDate) GetSelf(self Foundation.NSDate) Foundation.NSDate {
+func (d *GoNSDate) GetSelf(self gopkg.GoNSDate) Foundation.NSDate {
 	return self
 }
 
@@ -44,7 +45,7 @@
 	UseSelf bool
 }
 
-func (o *GoNSObject) Description(self Foundation.NSObjectC) string {
+func (o *GoNSObject) Description(self gopkg.GoNSObject) string {
 	if o.UseSelf {
 		return DescriptionStr
 	} else {
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index e9a685b..1256265 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -311,7 +311,11 @@
 			Buf:        &buf,
 		},
 	}
-	g.Init(types)
+	var genNames []string
+	for _, emb := range refs.Embedders {
+		genNames = append(genNames, emb.Name)
+	}
+	g.Init(types, genNames)
 	for i, name := range g.Packages() {
 		pkgDir := filepath.Join(pkgGen, "src", "ObjC", name)
 		if err := os.MkdirAll(pkgDir, 0700); err != nil {
diff --git a/internal/importers/objc/objc.go b/internal/importers/objc/objc.go
index 517ae08..a202d15 100644
--- a/internal/importers/objc/objc.go
+++ b/internal/importers/objc/objc.go
@@ -45,6 +45,9 @@
 	// declarations.
 	funcMap  map[string]struct{}
 	Protocol bool
+	// Generated is true if the type is wrapper of a
+	// generated Go struct.
+	Generated bool
 }
 
 // Super denotes a super class or protocol.
@@ -111,6 +114,10 @@
 	modMap := make(map[string]struct{})
 	typeNames := make(map[string][]string)
 	typeSet := make(map[string]struct{})
+	genMods := make(map[string]struct{})
+	for _, emb := range refs.Embedders {
+		genMods[initialUpper(emb.Pkg)] = struct{}{}
+	}
 	for _, ref := range refs.Refs {
 		var module, name string
 		if idx := strings.Index(ref.Pkg, "/"); idx != -1 {
@@ -128,8 +135,11 @@
 			typeSet[fullName] = struct{}{}
 		}
 		if _, exists := modMap[module]; !exists {
-			modMap[module] = struct{}{}
-			modules = append(modules, module)
+			// Include the module only if it is generated.
+			if _, exists := genMods[module]; !exists {
+				modMap[module] = struct{}{}
+				modules = append(modules, module)
+			}
 		}
 	}
 	var allTypes []*Named
@@ -141,6 +151,30 @@
 		}
 		allTypes = append(allTypes, types...)
 	}
+	// Embedders refer to every exported Go struct that will have its class
+	// generated. Allow Go code to reverse bind to those classes by synthesizing
+	// their descriptors.
+	for _, emb := range refs.Embedders {
+		module := initialUpper(emb.Pkg)
+		named := &Named{
+			Name:      module + emb.Name,
+			GoName:    emb.Name,
+			Module:    module,
+			Generated: true,
+		}
+		for _, ref := range emb.Refs {
+			t, exists := typeMap[ref.Name]
+			if !exists {
+				return nil, fmt.Errorf("type not found: %q", ref.Name)
+			}
+			named.Supers = append(named.Supers, Super{
+				Name:     t.Name,
+				Protocol: t.Protocol,
+			})
+		}
+		typeMap[emb.Name] = named
+		allTypes = append(allTypes, named)
+	}
 	for _, t := range allTypes {
 		fillAllMethods(t, typeMap)
 	}