From 4f4272d70b878b7e496cc4696333bd6bdd54e5da Mon Sep 17 00:00:00 2001 From: "Hyang-Ah (Hana) Kim" Date: Tue, 12 May 2015 09:44:08 -0400 Subject: [PATCH] bind: fix Java code generation that takes reference type params. Also fixes a parameter name handling problem when processing a function signature that omits parameter names. Fixes golang/go#10788. Change-Id: I65273d330bbf3a836ec9e4ffb691927970d795d8 Reviewed-on: https://go-review.googlesource.com/9926 Reviewed-by: Alan Donovan --- bind/bind_test.go | 1 + bind/gengo.go | 4 +- bind/genjava.go | 14 +-- bind/java/SeqTest.java | 19 ++++ bind/java/testpkg/testpkg.go | 5 + bind/testdata/issue10788.go | 14 +++ bind/testdata/issue10788.go.golden | 83 +++++++++++++++ bind/testdata/issue10788.java.golden | 149 +++++++++++++++++++++++++++ 8 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 bind/testdata/issue10788.go create mode 100644 bind/testdata/issue10788.go.golden create mode 100644 bind/testdata/issue10788.java.golden diff --git a/bind/bind_test.go b/bind/bind_test.go index efd92af..fd28e0c 100644 --- a/bind/bind_test.go +++ b/bind/bind_test.go @@ -24,6 +24,7 @@ var tests = []string{ "testdata/basictypes.go", "testdata/structs.go", "testdata/interfaces.go", + "testdata/issue10788.go", } var fset = token.NewFileSet() diff --git a/bind/gengo.go b/bind/gengo.go index 6d2dca2..c9fc952 100644 --- a/bind/gengo.go +++ b/bind/gengo.go @@ -47,7 +47,7 @@ func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) - g.genRead("param_"+p.Name(), "in", p.Type()) + g.genRead("param_"+paramName(params, i), "in", p.Type()) } res := sig.Results() @@ -76,7 +76,7 @@ func (g *goGen) genFuncBody(o *types.Func, selectorLHS string) { if i > 0 { g.Printf(", ") } - g.Printf("param_%s", params.At(i).Name()) + g.Printf("param_%s", paramName(params, i)) } g.Printf(")\n") diff --git a/bind/genjava.go b/bind/genjava.go index c6b23a6..236d4d1 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -168,10 +168,12 @@ func (g *javaGen) genInterfaceStub(o *types.TypeName, m *types.Interface) { g.Indent() sig := f.Type().(*types.Signature) - for i := 0; i < sig.Params().Len(); i++ { + params := sig.Params() + for i := 0; i < params.Len(); i++ { p := sig.Params().At(i) jt := g.javaType(p.Type()) - g.Printf("%s param_%s = in.read%s;\n", jt, p.Name(), seqRead(p.Type())) + g.Printf("%s param_%s;\n", jt, paramName(params, i)) + g.genRead("param_"+paramName(params, i), "in", p.Type()) } res := sig.Results() @@ -193,11 +195,11 @@ func (g *javaGen) genInterfaceStub(o *types.TypeName, m *types.Interface) { } g.Printf("this.%s(", f.Name()) - for i := 0; i < sig.Params().Len(); i++ { + for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") } - g.Printf("param_%s", sig.Params().At(i).Name()) + g.Printf("param_%s", paramName(params, i)) } g.Printf(");\n") @@ -388,7 +390,7 @@ var paramRE = regexp.MustCompile(`^p[0-9]+$`) // TODO(crawshaw): Replace invalid unicode names. func paramName(params *types.Tuple, pos int) string { name := params.At(pos).Name() - if name == "" || paramRE.MatchString(name) { + if name == "" || name == "_" || paramRE.MatchString(name) { name = fmt.Sprintf("p%d", pos) } return name @@ -476,7 +478,7 @@ func (g *javaGen) genFunc(o *types.Func, method bool) { params := sig.Params() for i := 0; i < params.Len(); i++ { p := params.At(i) - g.Printf("_in.write%s;\n", seqWrite(p.Type(), p.Name())) + g.Printf("_in.write%s;\n", seqWrite(p.Type(), paramName(params, i))) } g.Printf("Seq.send(DESCRIPTOR, CALL_%s, _in, _out);\n", o.Name()) if resultType != nil { diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java index 9a518e0..6ad1986 100644 --- a/bind/java/SeqTest.java +++ b/bind/java/SeqTest.java @@ -137,6 +137,10 @@ public class SeqTest extends AndroidTestCase { return Testpkg.New(); } + public String StoString(Testpkg.S s) { + return s.String(); + } + public long V() { return 1234; } @@ -187,6 +191,14 @@ public class SeqTest extends AndroidTestCase { Testpkg.S s = Testpkg.CallS(obj); } + public void testInterfaceMethodTakesStructPointer() { + final AnI obj = new AnI(); + Testpkg.S s = Testpkg.CallS(obj); + String got = obj.StoString(s); + String want = s.String(); + assertEquals("Want AnI.StoString(s) to call s's String", want, got); + } + public void testInterfaceMethodReturnsInt() { final AnI obj = new AnI(); assertEquals("Values must match", 1234, Testpkg.CallV(obj)); @@ -231,4 +243,11 @@ public class SeqTest extends AndroidTestCase { System.gc(); System.runFinalization(); } + + public void testUnnamedParams() { + final String msg = "1234567"; + assertEquals("Want the length of \"1234567\" passed after unnamed params", + 7, Testpkg.UnnamedParams(10, 20, msg)); + } + } diff --git a/bind/java/testpkg/testpkg.go b/bind/java/testpkg/testpkg.go index 5fb72ab..5b0c260 100644 --- a/bind/java/testpkg/testpkg.go +++ b/bind/java/testpkg/testpkg.go @@ -23,6 +23,7 @@ type I interface { VE() (int, error) I() I S() *S + StoString(*S) string String() string } @@ -119,3 +120,7 @@ func AppendToString(str string, someBytes []byte) []byte { fmt.Printf("str=%q (len=%d), someBytes=%v (len=%d)\n", str, len(str), someBytes, len(someBytes)) return append(a, someBytes...) } + +func UnnamedParams(_, _ int, p0 string) int { + return len(p0) +} diff --git a/bind/testdata/issue10788.go b/bind/testdata/issue10788.go new file mode 100644 index 0000000..e5c6a12 --- /dev/null +++ b/bind/testdata/issue10788.go @@ -0,0 +1,14 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue10788 + +type TestStruct struct { + Value string +} + +type TestInterface interface { + DoSomeWork(s *TestStruct) + MultipleUnnamedParams(_ int, p0 string, _ int64) +} diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden new file mode 100644 index 0000000..d258675 --- /dev/null +++ b/bind/testdata/issue10788.go.golden @@ -0,0 +1,83 @@ +// Package go_issue10788 is an autogenerated binder stub for package issue10788. +// gobind -lang=go issue10788 +// +// File is generated by gobind. Do not edit. +package go_issue10788 + +import ( + "golang.org/x/mobile/bind/seq" + "issue10788" +) + +const ( + proxyTestInterfaceDescriptor = "go.issue10788.TestInterface" + proxyTestInterfaceDoSomeWorkCode = 0x10a + proxyTestInterfaceMultipleUnnamedParamsCode = 0x20a +) + +func proxyTestInterfaceDoSomeWork(out, in *seq.Buffer) { + ref := in.ReadRef() + v := ref.Get().(issue10788.TestInterface) + // Must be a Go object + param_s_ref := in.ReadRef() + param_s := param_s_ref.Get().(*issue10788.TestStruct) + v.DoSomeWork(param_s) +} + +func proxyTestInterfaceMultipleUnnamedParams(out, in *seq.Buffer) { + ref := in.ReadRef() + v := ref.Get().(issue10788.TestInterface) + param_p0 := in.ReadInt() + param_p1 := in.ReadString() + param_p2 := in.ReadInt64() + v.MultipleUnnamedParams(param_p0, param_p1, param_p2) +} + +func init() { + seq.Register(proxyTestInterfaceDescriptor, proxyTestInterfaceDoSomeWorkCode, proxyTestInterfaceDoSomeWork) + seq.Register(proxyTestInterfaceDescriptor, proxyTestInterfaceMultipleUnnamedParamsCode, proxyTestInterfaceMultipleUnnamedParams) +} + +type proxyTestInterface seq.Ref + +func (p *proxyTestInterface) DoSomeWork(s *issue10788.TestStruct) { + in := new(seq.Buffer) + in.WriteGoRef(s) + seq.Transact((*seq.Ref)(p), proxyTestInterfaceDoSomeWorkCode, in) +} + +func (p *proxyTestInterface) MultipleUnnamedParams(p0 int, p1 string, p2 int64) { + in := new(seq.Buffer) + in.WriteInt(p0) + in.WriteString(p1) + in.WriteInt64(p2) + seq.Transact((*seq.Ref)(p), proxyTestInterfaceMultipleUnnamedParamsCode, in) +} + +const ( + proxyTestStructDescriptor = "go.issue10788.TestStruct" + proxyTestStructValueGetCode = 0x00f + proxyTestStructValueSetCode = 0x01f +) + +type proxyTestStruct seq.Ref + +func proxyTestStructValueSet(out, in *seq.Buffer) { + ref := in.ReadRef() + v := in.ReadString() + ref.Get().(*issue10788.TestStruct).Value = v +} + +func proxyTestStructValueGet(out, in *seq.Buffer) { + ref := in.ReadRef() + v := ref.Get().(*issue10788.TestStruct).Value + out.WriteString(v) +} + +func init() { + seq.Register(proxyTestStructDescriptor, proxyTestStructValueSetCode, proxyTestStructValueSet) + seq.Register(proxyTestStructDescriptor, proxyTestStructValueGetCode, proxyTestStructValueGet) +} + +func init() { +} diff --git a/bind/testdata/issue10788.java.golden b/bind/testdata/issue10788.java.golden new file mode 100644 index 0000000..3cae243 --- /dev/null +++ b/bind/testdata/issue10788.java.golden @@ -0,0 +1,149 @@ +// Java Package issue10788 is a proxy for talking to a Go program. +// gobind -lang=java issue10788 +// +// File is generated by gobind. Do not edit. +package go.issue10788; + +import go.Seq; + +public abstract class Issue10788 { + private Issue10788() {} // uninstantiable + + public interface TestInterface extends go.Seq.Object { + public void DoSomeWork(TestStruct s); + + public void MultipleUnnamedParams(long p0, String p1, long p2); + + public static abstract class Stub implements TestInterface { + static final String DESCRIPTOR = "go.issue10788.TestInterface"; + + private final go.Seq.Ref ref; + public Stub() { + ref = go.Seq.createRef(this); + } + + public go.Seq.Ref ref() { return ref; } + + public void call(int code, go.Seq in, go.Seq out) { + switch (code) { + case Proxy.CALL_DoSomeWork: { + TestStruct param_s; + param_s = new TestStruct(in.readRef()); + this.DoSomeWork(param_s); + return; + } + case Proxy.CALL_MultipleUnnamedParams: { + long param_p0; + param_p0 = in.readInt(); + String param_p1; + param_p1 = in.readString(); + long param_p2; + param_p2 = in.readInt64(); + this.MultipleUnnamedParams(param_p0, param_p1, param_p2); + return; + } + default: + throw new RuntimeException("unknown code: "+ code); + } + } + } + + static final class Proxy implements TestInterface { + static final String DESCRIPTOR = Stub.DESCRIPTOR; + + private go.Seq.Ref ref; + + Proxy(go.Seq.Ref ref) { this.ref = ref; } + + public go.Seq.Ref ref() { return ref; } + + public void call(int code, go.Seq in, go.Seq out) { + throw new RuntimeException("cycle: cannot call proxy"); + } + + public void DoSomeWork(TestStruct s) { + go.Seq _in = new go.Seq(); + go.Seq _out = new go.Seq(); + _in.writeRef(ref); + _in.writeRef(s.ref()); + Seq.send(DESCRIPTOR, CALL_DoSomeWork, _in, _out); + } + + public void MultipleUnnamedParams(long p0, String p1, long p2) { + go.Seq _in = new go.Seq(); + go.Seq _out = new go.Seq(); + _in.writeRef(ref); + _in.writeInt(p0); + _in.writeString(p1); + _in.writeInt64(p2); + Seq.send(DESCRIPTOR, CALL_MultipleUnnamedParams, _in, _out); + } + + static final int CALL_DoSomeWork = 0x10a; + static final int CALL_MultipleUnnamedParams = 0x20a; + } + } + + public static final class TestStruct implements go.Seq.Object { + private static final String DESCRIPTOR = "go.issue10788.TestStruct"; + private static final int FIELD_Value_GET = 0x00f; + private static final int FIELD_Value_SET = 0x01f; + + private go.Seq.Ref ref; + + private TestStruct(go.Seq.Ref ref) { this.ref = ref; } + + public go.Seq.Ref ref() { return ref; } + + public void call(int code, go.Seq in, go.Seq out) { + throw new RuntimeException("internal error: cycle: cannot call concrete proxy"); + } + + public String getValue() { + Seq in = new Seq(); + Seq out = new Seq(); + in.writeRef(ref); + Seq.send(DESCRIPTOR, FIELD_Value_GET, in, out); + return out.readString(); + } + + public void setValue(String v) { + Seq in = new Seq(); + Seq out = new Seq(); + in.writeRef(ref); + in.writeString(v); + Seq.send(DESCRIPTOR, FIELD_Value_SET, in, out); + } + + @Override public boolean equals(Object o) { + if (o == null || !(o instanceof TestStruct)) { + return false; + } + TestStruct that = (TestStruct)o; + String thisValue = getValue(); + String thatValue = that.getValue(); + if (thisValue == null) { + if (thatValue != null) { + return false; + } + } else if (!thisValue.equals(thatValue)) { + return false; + } + return true; + } + + @Override public int hashCode() { + return java.util.Arrays.hashCode(new Object[] {getValue()}); + } + + @Override public String toString() { + StringBuilder b = new StringBuilder(); + b.append("TestStruct").append("{"); + b.append("Value:").append(getValue()).append(","); + return b.append("}").toString(); + } + + } + + private static final String DESCRIPTOR = "issue10788"; +}