bind: support types with the same title name as their packages

If a Go struct or interface has the same name as its package class,
append an underscore to the generated Java class name.

Fixes golang/go#23327.

Change-Id: Ib680af35c956801073a0effb510a3ed9bbb8b9d1
Reviewed-on: https://go-review.googlesource.com/87656
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/bind/genjava.go b/bind/genjava.go
index dd3cf18..8991466 100644
--- a/bind/genjava.go
+++ b/bind/genjava.go
@@ -205,10 +205,10 @@
 func (g *JavaGen) ClassNames() []string {
 	var names []string
 	for _, s := range g.structs {
-		names = append(names, s.obj.Name())
+		names = append(names, g.javaTypeName(s.obj.Name()))
 	}
 	for _, iface := range g.interfaces {
-		names = append(names, iface.obj.Name())
+		names = append(names, g.javaTypeName(iface.obj.Name()))
 	}
 	return names
 }
@@ -242,7 +242,7 @@
 	if g.Pkg != nil {
 		pkgPath = g.Pkg.Path()
 	}
-	n := s.obj.Name()
+	n := g.javaTypeName(s.obj.Name())
 	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), n, g.gobindOpts(), pkgPath)
 
 	fields := exportedFields(s.t)
@@ -254,7 +254,7 @@
 		impls = append(impls, "Seq.GoObject")
 		for _, cls := range jinf.supers {
 			if cls.Interface {
-				impls = append(impls, cls.Name)
+				impls = append(impls, g.javaTypeName(cls.Name))
 			}
 		}
 	} else {
@@ -266,7 +266,12 @@
 		if types.AssignableTo(pT, iface.obj.Type()) {
 			n := iface.obj.Name()
 			if p := iface.obj.Pkg(); p != g.Pkg {
+				if n == JavaClassName(p) {
+					n = n + "_"
+				}
 				n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
+			} else {
+				n = g.javaTypeName(n)
 			}
 			impls = append(impls, n)
 		}
@@ -277,7 +282,7 @@
 	g.Printf("public final class %s", n)
 	if jinf != nil {
 		if jinf.extends != nil {
-			g.Printf(" extends %s", jinf.extends.Name)
+			g.Printf(" extends %s", g.javaTypeName(jinf.extends.Name))
 		}
 	}
 	if len(impls) > 0 {
@@ -350,6 +355,16 @@
 	g.Printf("}\n\n")
 }
 
+// javaTypeName returns the class name of a given Go type name. If
+// the type name clashes with the package class name, an underscore is
+// appended.
+func (g *JavaGen) javaTypeName(n string) string {
+	if n == JavaClassName(g.Pkg) {
+		return n + "_"
+	}
+	return n
+}
+
 func (g *JavaGen) javadoc(doc string) {
 	if doc == "" {
 		return
@@ -514,7 +529,7 @@
 	if g.Pkg != nil {
 		pkgPath = g.Pkg.Path()
 	}
-	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), iface.obj.Name(), g.gobindOpts(), pkgPath)
+	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.javaTypeName(iface.obj.Name()), g.gobindOpts(), pkgPath)
 
 	var exts []string
 	numM := iface.t.NumMethods()
@@ -523,14 +538,19 @@
 		if other.t.NumMethods() < numM && types.AssignableTo(iface.t, other.t) {
 			n := other.obj.Name()
 			if p := other.obj.Pkg(); p != g.Pkg {
+				if n == JavaClassName(p) {
+					n = n + "_"
+				}
 				n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
+			} else {
+				n = g.javaTypeName(n)
 			}
 			exts = append(exts, n)
 		}
 	}
 	doc := g.docs[iface.obj.Name()]
 	g.javadoc(doc.Doc())
-	g.Printf("public interface %s", iface.obj.Name())
+	g.Printf("public interface %s", g.javaTypeName(iface.obj.Name()))
 	if len(exts) > 0 {
 		g.Printf(" extends %s", strings.Join(exts, ", "))
 	}
@@ -675,10 +695,14 @@
 			break
 		}
 		// TODO(crawshaw): more checking here
+		clsName := n.Name()
 		if nPkg != g.Pkg {
-			return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), n.Name())
+			if clsName == JavaClassName(nPkg) {
+				clsName += "_"
+			}
+			return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), clsName)
 		} else {
-			return n.Name()
+			return g.javaTypeName(clsName)
 		}
 	default:
 		g.errorf("unsupported javaType: %#+v, %s\n", T, T)
@@ -713,10 +737,10 @@
 		if proxy {
 			g.Printf(g.className())
 			// 0024 is the mangled form of $, for naming inner classes.
-			g.Printf("_00024")
-			g.Printf("proxy")
+			g.Printf("_00024proxy%s", sName)
+		} else {
+			g.Printf(java.JNIMangle(g.javaTypeName(sName)))
 		}
-		g.Printf("%s", sName)
 	} else {
 		g.Printf(g.className())
 	}
@@ -1037,9 +1061,10 @@
 		g.Printf("// skipped field %s with unsupported type: %T\n\n", o.Name(), t)
 		return
 	}
+	n := java.JNIMangle(g.javaTypeName(o.Name()))
 	// setter
 	g.Printf("JNIEXPORT void JNICALL\n")
-	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), o.Name(), f.Name(), g.jniType(f.Type()))
+	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), n, f.Name(), g.jniType(f.Type()))
 	g.Indent()
 	g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
 	g.genJavaToC("v", f.Type(), modeRetained)
@@ -1050,7 +1075,7 @@
 
 	// getter
 	g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type()))
-	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), o.Name(), f.Name())
+	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), n, f.Name())
 	g.Indent()
 	g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
 	g.Printf("%s r0 = ", g.cgoType(f.Type()))
@@ -1066,9 +1091,10 @@
 		g.Printf("// skipped variable %s with unsupported type: %T\n\n", o.Name(), t)
 		return
 	}
+	n := java.JNIMangle(g.javaTypeName(o.Name()))
 	// setter
 	g.Printf("JNIEXPORT void JNICALL\n")
-	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), g.className(), o.Name(), g.jniType(o.Type()))
+	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), g.className(), n, g.jniType(o.Type()))
 	g.Indent()
 	g.genJavaToC("v", o.Type(), modeRetained)
 	g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name())
@@ -1078,7 +1104,7 @@
 
 	// getter
 	g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type()))
-	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), g.className(), o.Name())
+	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), g.className(), n)
 	g.Indent()
 	g.Printf("%s r0 = ", g.cgoType(o.Type()))
 	g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name())
@@ -1096,7 +1122,7 @@
 	res := sig.Results()
 
 	g.Printf("JNIEXPORT jobject JNICALL\n")
-	g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), sName, java.JNIMangle("__"+f.Name()))
+	g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__"+f.Name()))
 	params := sig.Params()
 	for i := 0; i < params.Len(); i++ {
 		v := params.At(i)
@@ -1402,7 +1428,7 @@
 		}
 		g.errorf("unsupported pointer to type: %s", T)
 	case *types.Named:
-		return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + T.Obj().Name() + ";"
+		return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + g.javaTypeName(T.Obj().Name()) + ";"
 	default:
 		g.errorf("unsupported jniType: %#+v, %s\n", T, T)
 	}
@@ -1456,7 +1482,7 @@
 				continue
 			}
 		}
-		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+s.obj.Name())
+		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+g.javaTypeName(s.obj.Name()))
 		g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name())
 		g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(Lgo/Seq$Ref;)V\");\n", g.pkgPrefix, s.obj.Name())
 	}
@@ -1472,7 +1498,7 @@
 			g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n")
 			continue
 		}
-		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+iface.obj.Name())
+		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+g.javaTypeName(iface.obj.Name()))
 		for _, m := range iface.summary.callable {
 			if !g.isSigSupported(m.Type()) {
 				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
@@ -1510,7 +1536,7 @@
 		}
 		if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) {
 			g.Printf("JNIEXPORT jobject JNICALL\n")
-			g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), sName, java.JNIMangle("__New"))
+			g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__New"))
 			g.Indent()
 			g.Printf("int32_t refnum = new_%s_%s();\n", g.pkgPrefix, sName)
 			// Pass no proxy class so that the Seq.Ref is returned instead.
@@ -1578,7 +1604,7 @@
 		if isErrorType(iface.obj.Type()) {
 			g.Printf(" extends Exception")
 		}
-		g.Printf(" implements Seq.Proxy, %s {\n", n)
+		g.Printf(" implements Seq.Proxy, %s {\n", g.javaTypeName(n))
 		g.Indent()
 		g.genProxyImpl("proxy" + n)
 		g.Printf("proxy%s(Seq.Ref ref) { this.ref = ref; }\n\n", n)
diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java
index 36f3169..ccaa813 100644
--- a/bind/java/SeqTest.java
+++ b/bind/java/SeqTest.java
@@ -588,4 +588,13 @@
   public void testTags() {
     assertEquals("Constant from a tagged file", 42, Testpkg.TaggedConst);
   }
+
+  public void testClassNameWithPackageName() {
+    testpkg.Testpkg_ o = new secondpkg.Secondpkg_();
+    secondpkg.Secondpkg_ o2 = Secondpkg.newSecondpkg();
+    o2.m();
+    o2.setV("hi");
+    assertEquals(o2.getV(), "hi");
+    Testpkg.clashingParameterFromOtherPackage(o2);
+  }
 }
diff --git a/bind/testdata/interfaces.go b/bind/testdata/interfaces.go
index 0eaa99a..9e2da3a 100644
--- a/bind/testdata/interfaces.go
+++ b/bind/testdata/interfaces.go
@@ -62,3 +62,8 @@
 // not bound
 func F() seven  { return seven{} }
 func G(u seven) {}
+
+// Interfaces is an interface with the same name as its package.
+type Interfaces interface {
+	SomeMethod()
+}
diff --git a/bind/testdata/interfaces.go.golden b/bind/testdata/interfaces.go.golden
index 16baa81..a4700d6 100644
--- a/bind/testdata/interfaces.go.golden
+++ b/bind/testdata/interfaces.go.golden
@@ -112,6 +112,21 @@
 	return _res
 }
 
+//export proxyinterfaces_Interfaces_SomeMethod
+func proxyinterfaces_Interfaces_SomeMethod(refnum C.int32_t) {
+	ref := _seq.FromRefNum(int32(refnum))
+	v := ref.Get().(interfaces.Interfaces)
+	v.SomeMethod()
+}
+
+type proxyinterfaces_Interfaces _seq.Ref
+
+func (p *proxyinterfaces_Interfaces) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }
+
+func (p *proxyinterfaces_Interfaces) SomeMethod() {
+	C.cproxyinterfaces_Interfaces_SomeMethod(C.int32_t(p.Bind_proxy_refnum__()))
+}
+
 //export proxyinterfaces_LargerI_AnotherFunc
 func proxyinterfaces_LargerI_AnotherFunc(refnum C.int32_t) {
 	ref := _seq.FromRefNum(int32(refnum))
diff --git a/bind/testdata/interfaces.java.c.golden b/bind/testdata/interfaces.java.c.golden
index 7c31204..0f11d5d 100644
--- a/bind/testdata/interfaces.java.c.golden
+++ b/bind/testdata/interfaces.java.c.golden
@@ -24,6 +24,9 @@
 jclass proxy_class_interfaces_I3;
 jmethodID proxy_class_interfaces_I3_cons;
 static jmethodID mid_I3_F;
+jclass proxy_class_interfaces_Interfaces;
+jmethodID proxy_class_interfaces_Interfaces_cons;
+static jmethodID mid_Interfaces_SomeMethod;
 jclass proxy_class_interfaces_LargerI;
 jmethodID proxy_class_interfaces_LargerI_cons;
 static jmethodID mid_LargerI_AnotherFunc;
@@ -68,6 +71,12 @@
     clazz = (*env)->FindClass(env, "interfaces/I3");
     mid_I3_F = (*env)->GetMethodID(env, clazz, "f", "()Linterfaces/I1;");
     
+    clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyInterfaces");
+    proxy_class_interfaces_Interfaces = (*env)->NewGlobalRef(env, clazz);
+    proxy_class_interfaces_Interfaces_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
+    clazz = (*env)->FindClass(env, "interfaces/Interfaces_");
+    mid_Interfaces_SomeMethod = (*env)->GetMethodID(env, clazz, "someMethod", "()V");
+    
     clazz = (*env)->FindClass(env, "interfaces/Interfaces$proxyLargerI");
     proxy_class_interfaces_LargerI = (*env)->NewGlobalRef(env, clazz);
     proxy_class_interfaces_LargerI_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
@@ -191,6 +200,19 @@
 }
 
 JNIEXPORT void JNICALL
+Java_interfaces_Interfaces_00024proxyInterfaces_someMethod(JNIEnv* env, jobject __this__) {
+    int32_t o = go_seq_to_refnum_go(env, __this__);
+    proxyinterfaces_Interfaces_SomeMethod(o);
+}
+
+void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum) {
+    JNIEnv *env = go_seq_push_local_frame(0);
+    jobject o = go_seq_from_refnum(env, refnum, proxy_class_interfaces_Interfaces, proxy_class_interfaces_Interfaces_cons);
+    (*env)->CallVoidMethod(env, o, mid_Interfaces_SomeMethod);
+    go_seq_pop_local_frame(env);
+}
+
+JNIEXPORT void JNICALL
 Java_interfaces_Interfaces_00024proxyLargerI_anotherFunc(JNIEnv* env, jobject __this__) {
     int32_t o = go_seq_to_refnum_go(env, __this__);
     proxyinterfaces_LargerI_AnotherFunc(o);
diff --git a/bind/testdata/interfaces.java.golden b/bind/testdata/interfaces.java.golden
index 6b95947..87402b7 100644
--- a/bind/testdata/interfaces.java.golden
+++ b/bind/testdata/interfaces.java.golden
@@ -73,6 +73,22 @@
     
 }
 
+// Java class interfaces.Interfaces_ is a proxy for talking to a Go program.
+//   gobind -lang=java interfaces
+//
+// File is generated by gobind. Do not edit.
+package interfaces;
+
+import go.Seq;
+
+/**
+ * Interfaces is an interface with the same name as its package.
+ */
+public interface Interfaces_ {
+    public void someMethod();
+    
+}
+
 // Java class interfaces.LargerI is a proxy for talking to a Go program.
 //   gobind -lang=java interfaces
 //
@@ -199,6 +215,19 @@
         
         public native I1 f();
     }
+    private static final class proxyInterfaces implements Seq.Proxy, Interfaces_ {
+        private final Seq.Ref ref;
+        
+        @Override public final int incRefnum() {
+              int refnum = ref.refnum;
+              Seq.incGoRef(refnum);
+              return refnum;
+        }
+        
+        proxyInterfaces(Seq.Ref ref) { this.ref = ref; }
+        
+        public native void someMethod();
+    }
     private static final class proxyLargerI implements Seq.Proxy, LargerI {
         private final Seq.Ref ref;
         
diff --git a/bind/testdata/interfaces.java.h.golden b/bind/testdata/interfaces.java.h.golden
index 05840e8..5d5f3f1 100644
--- a/bind/testdata/interfaces.java.h.golden
+++ b/bind/testdata/interfaces.java.h.golden
@@ -33,6 +33,11 @@
 
 int32_t cproxyinterfaces_I3_F(int32_t refnum);
 
+extern jclass proxy_class_interfaces_Interfaces;
+extern jmethodID proxy_class_interfaces_Interfaces_cons;
+
+void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum);
+
 extern jclass proxy_class_interfaces_LargerI;
 extern jmethodID proxy_class_interfaces_LargerI_cons;
 
diff --git a/bind/testdata/interfaces.objc.go.h.golden b/bind/testdata/interfaces.objc.go.h.golden
index 8452626..983de54 100644
--- a/bind/testdata/interfaces.objc.go.h.golden
+++ b/bind/testdata/interfaces.objc.go.h.golden
@@ -14,6 +14,8 @@
 
 int32_t cproxyinterfaces_I3_F(int32_t refnum);
 
+void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum);
+
 void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum);
 
 int32_t cproxyinterfaces_LargerI_Rand(int32_t refnum);
diff --git a/bind/testdata/interfaces.objc.h.golden b/bind/testdata/interfaces.objc.h.golden
index ca5c7a4..c54288e 100644
--- a/bind/testdata/interfaces.objc.h.golden
+++ b/bind/testdata/interfaces.objc.h.golden
@@ -18,6 +18,8 @@
 @protocol InterfacesI2;
 @protocol InterfacesI3;
 @class InterfacesI3;
+@protocol InterfacesInterfaces;
+@class InterfacesInterfaces;
 @protocol InterfacesLargerI;
 @class InterfacesLargerI;
 @protocol InterfacesSameI;
@@ -59,6 +61,10 @@
 - (InterfacesI1*)f;
 @end
 
+@protocol InterfacesInterfaces <NSObject>
+- (void)someMethod;
+@end
+
 @protocol InterfacesLargerI <NSObject>
 - (void)anotherFunc;
 - (int32_t)rand;
@@ -84,6 +90,8 @@
 
 @class InterfacesI3;
 
+@class InterfacesInterfaces;
+
 @class InterfacesLargerI;
 
 @class InterfacesSameI;
@@ -118,6 +126,17 @@
 - (InterfacesI1*)f;
 @end
 
+/**
+ * Interfaces is an interface with the same name as its package.
+ */
+@interface InterfacesInterfaces : NSObject <goSeqRefInterface, InterfacesInterfaces> {
+}
+@property(strong, readonly) id _ref;
+
+- (instancetype)initWithRef:(id)ref;
+- (void)someMethod;
+@end
+
 @interface InterfacesLargerI : NSObject <goSeqRefInterface, InterfacesLargerI> {
 }
 @property(strong, readonly) id _ref;
diff --git a/bind/testdata/interfaces.objc.m.golden b/bind/testdata/interfaces.objc.m.golden
index 7b5e1d9..54383df 100644
--- a/bind/testdata/interfaces.objc.m.golden
+++ b/bind/testdata/interfaces.objc.m.golden
@@ -116,6 +116,23 @@
 @end
 
 
+@implementation InterfacesInterfaces {
+}
+
+- (instancetype)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+- (void)someMethod {
+	int32_t refnum = go_seq_go_to_refnum(self._ref);
+	proxyinterfaces_Interfaces_SomeMethod(refnum);
+}
+
+@end
+
+
 @implementation InterfacesLargerI {
 }
 
@@ -287,6 +304,13 @@
 	}
 }
 
+void cproxyinterfaces_Interfaces_SomeMethod(int32_t refnum) {
+	@autoreleasepool {
+		InterfacesInterfaces* o = go_seq_objc_from_refnum(refnum);
+		[o someMethod];
+	}
+}
+
 void cproxyinterfaces_LargerI_AnotherFunc(int32_t refnum) {
 	@autoreleasepool {
 		InterfacesLargerI* o = go_seq_objc_from_refnum(refnum);
diff --git a/bind/testdata/structs.go b/bind/testdata/structs.go
index 2505062..5974bdc 100644
--- a/bind/testdata/structs.go
+++ b/bind/testdata/structs.go
@@ -38,3 +38,9 @@
 func (_ *S2) String() string {
 	return ""
 }
+
+// Structs is a struct with the same name as its package.
+type Structs struct{}
+
+func (_ *Structs) M() {
+}
diff --git a/bind/testdata/structs.go.golden b/bind/testdata/structs.go.golden
index 49e366f..817ec5d 100644
--- a/bind/testdata/structs.go.golden
+++ b/bind/testdata/structs.go.golden
@@ -102,6 +102,18 @@
 	return C.int32_t(_seq.ToRefNum(new(structs.S2)))
 }
 
+//export proxystructs_Structs_M
+func proxystructs_Structs_M(refnum C.int32_t) {
+	ref := _seq.FromRefNum(int32(refnum))
+	v := ref.Get().(*structs.Structs)
+	v.M()
+}
+
+//export new_structs_Structs
+func new_structs_Structs() C.int32_t {
+	return C.int32_t(_seq.ToRefNum(new(structs.Structs)))
+}
+
 //export proxystructs_I_M
 func proxystructs_I_M(refnum C.int32_t) {
 	ref := _seq.FromRefNum(int32(refnum))
diff --git a/bind/testdata/structs.java.c.golden b/bind/testdata/structs.java.c.golden
index 52ca312..0934a11 100644
--- a/bind/testdata/structs.java.c.golden
+++ b/bind/testdata/structs.java.c.golden
@@ -16,6 +16,8 @@
 jmethodID proxy_class_structs_S_cons;
 jclass proxy_class_structs_S2;
 jmethodID proxy_class_structs_S2_cons;
+jclass proxy_class_structs_Structs;
+jmethodID proxy_class_structs_Structs_cons;
 
 JNIEXPORT void JNICALL
 Java_structs_Structs__1init(JNIEnv *env, jclass _unused) {
@@ -26,6 +28,9 @@
     clazz = (*env)->FindClass(env, "structs/S2");
     proxy_class_structs_S2 = (*env)->NewGlobalRef(env, clazz);
     proxy_class_structs_S2_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
+    clazz = (*env)->FindClass(env, "structs/Structs_");
+    proxy_class_structs_Structs = (*env)->NewGlobalRef(env, clazz);
+    proxy_class_structs_Structs_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
     clazz = (*env)->FindClass(env, "structs/Structs$proxyI");
     proxy_class_structs_I = (*env)->NewGlobalRef(env, clazz);
     proxy_class_structs_I_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
@@ -126,6 +131,18 @@
     return _r0;
 }
 
+JNIEXPORT jobject JNICALL
+Java_structs_Structs_1__1_1New(JNIEnv *env, jclass clazz) {
+    int32_t refnum = new_structs_Structs();
+    return go_seq_from_refnum(env, refnum, NULL, NULL);
+}
+
+JNIEXPORT void JNICALL
+Java_structs_Structs_1_m(JNIEnv* env, jobject __this__) {
+    int32_t o = go_seq_to_refnum_go(env, __this__);
+    proxystructs_Structs_M(o);
+}
+
 JNIEXPORT void JNICALL
 Java_structs_Structs_00024proxyI_m(JNIEnv* env, jobject __this__) {
     int32_t o = go_seq_to_refnum_go(env, __this__);
diff --git a/bind/testdata/structs.java.golden b/bind/testdata/structs.java.golden
index 9f5009e..e1aed3f 100644
--- a/bind/testdata/structs.java.golden
+++ b/bind/testdata/structs.java.golden
@@ -106,6 +106,51 @@
     }
 }
 
+// Java class structs.Structs_ is a proxy for talking to a Go program.
+//   gobind -lang=java structs
+//
+// File is generated by gobind. Do not edit.
+package structs;
+
+import go.Seq;
+
+public final class Structs_ implements Seq.Proxy, I {
+    static { Structs.touch(); }
+    
+    private final Seq.Ref ref;
+    
+    @Override public final int incRefnum() {
+          int refnum = ref.refnum;
+          Seq.incGoRef(refnum);
+          return refnum;
+    }
+    
+    Structs_(Seq.Ref ref) { this.ref = ref; }
+    
+    public Structs_() { this.ref = __New(); }
+    
+    private static native Seq.Ref __New();
+    
+    public native void m();
+    @Override public boolean equals(Object o) {
+        if (o == null || !(o instanceof Structs_)) {
+            return false;
+        }
+        Structs_ that = (Structs_)o;
+        return true;
+    }
+    
+    @Override public int hashCode() {
+        return java.util.Arrays.hashCode(new Object[] {});
+    }
+    
+    @Override public String toString() {
+        StringBuilder b = new StringBuilder();
+        b.append("Structs_").append("{");
+        return b.append("}").toString();
+    }
+}
+
 // Java class structs.I is a proxy for talking to a Go program.
 //   gobind -lang=java structs
 //
diff --git a/bind/testdata/structs.java.h.golden b/bind/testdata/structs.java.h.golden
index b80a847..4c84d34 100644
--- a/bind/testdata/structs.java.h.golden
+++ b/bind/testdata/structs.java.h.golden
@@ -17,4 +17,6 @@
 extern jmethodID proxy_class_structs_S_cons;
 extern jclass proxy_class_structs_S2;
 extern jmethodID proxy_class_structs_S2_cons;
+extern jclass proxy_class_structs_Structs;
+extern jmethodID proxy_class_structs_Structs_cons;
 #endif
diff --git a/bind/testdata/structs.objc.h.golden b/bind/testdata/structs.objc.h.golden
index 0ba8eab..3522f1e 100644
--- a/bind/testdata/structs.objc.h.golden
+++ b/bind/testdata/structs.objc.h.golden
@@ -12,6 +12,7 @@
 
 @class StructsS;
 @class StructsS2;
+@class StructsStructs;
 @protocol StructsI;
 @class StructsI;
 
@@ -43,6 +44,18 @@
 - (NSString*)string;
 @end
 
+/**
+ * Structs is a struct with the same name as its package.
+ */
+@interface StructsStructs : NSObject <goSeqRefInterface, StructsI> {
+}
+@property(strong, readonly) id _ref;
+
+- (instancetype)initWithRef:(id)ref;
+- (instancetype)init;
+- (void)m;
+@end
+
 FOUNDATION_EXPORT StructsS* StructsIdentity(StructsS* s);
 
 FOUNDATION_EXPORT StructsS* StructsIdentityWithError(StructsS* s, NSError** error);
diff --git a/bind/testdata/structs.objc.m.golden b/bind/testdata/structs.objc.m.golden
index 3d28302..87b1da8 100644
--- a/bind/testdata/structs.objc.m.golden
+++ b/bind/testdata/structs.objc.m.golden
@@ -123,6 +123,32 @@
 @end
 
 
+
+@implementation StructsStructs {
+}
+
+- (instancetype)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+- (instancetype)init {
+	self = [super init];
+	if (self) {
+		__ref = go_seq_from_refnum(new_structs_Structs());
+	}
+	return self;
+}
+
+- (void)m {
+	int32_t refnum = go_seq_go_to_refnum(self._ref);
+	proxystructs_Structs_M(refnum);
+}
+
+@end
+
+
 @implementation StructsI {
 }
 
diff --git a/bind/testpkg/secondpkg/secondpkg.go b/bind/testpkg/secondpkg/secondpkg.go
index 94f3e31..b7e7cd5 100644
--- a/bind/testpkg/secondpkg/secondpkg.go
+++ b/bind/testpkg/secondpkg/secondpkg.go
@@ -31,3 +31,14 @@
 func Hello() string {
 	return HelloString
 }
+
+type Secondpkg struct {
+	V string
+}
+
+func (_ *Secondpkg) M() {
+}
+
+func NewSecondpkg() *Secondpkg {
+	return new(Secondpkg)
+}
diff --git a/bind/testpkg/testpkg.go b/bind/testpkg/testpkg.go
index f0cda07..8ebbcd3 100644
--- a/bind/testpkg/testpkg.go
+++ b/bind/testpkg/testpkg.go
@@ -606,3 +606,8 @@
 		panic(fmt.Errorf("got %v, expected EPIPE", err))
 	}
 }
+
+// Testpkg is an empty interface with the same name as its package.
+type Testpkg interface{}
+
+func ClashingParameterFromOtherPackage(_ *secondpkg.Secondpkg) {}