internal,bind: resolve overloaded methods at runtime
Before this CL, calling overloaded methods on reverse bound Java classes and interfaces involved confusing and ugly name mangling. If a set of methods with the same name differed only in argument count, the mangling was simply adding the argument count to the name: func F() func F1(int32) But if two or more methods had the same number of arguments, the type had to be appended: func (...) F() int32 func (...) F1(int32) (int32, error) func (...) F__I(int32, int32) func (...) F__JLjava_util_concurrent_TimeUnit_2(int64, concurrent.TimeUnit) This CL sacrifices a bit of type safety and performance to regain the convenience and simplicity of Go by resolving overloaded method dispatch at runtime. Overloaded Java methods are combined to one Go method that, when invoked, determines the correct Java method variant at runtime. The signature of the Go method is compatible with every Java method with that name. For the example above, the single Go method becomes the most general func (...) F(...interface{}) (interface{}, error) The method is variadic to cover function with a varying number of arguments, and it returns interface{} to cover int32, int64 and no argument. Finally, it returns an error to cover the variant that returns an error. The generator tries to be specific; for example func G1(int32) int32 func G2(int32, int32) int32 becomes func G(int32, ...int32) int32 Overriding Java methods in Go is changed to use the Go parameter types to determine to correct Java method. To avoid name clashes when overriding multiple overloaded methods, trailing underscores in the method name are ignored when matching Java methods. See the Get methods of GoFuture in bind/testpkg/javapkg for an example. Change-Id: I6ac3e024141daa8fc2c35187865c5d7a63368094 Reviewed-on: https://go-review.googlesource.com/35186 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
1aa9ad5c48
commit
3884e8cb98
|
@ -7,6 +7,7 @@ package bind
|
|||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
@ -49,6 +50,15 @@ func (g *ClassGen) isSupported(t *java.Type) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (g *ClassGen) isFuncSetSupported(fs *java.FuncSet) bool {
|
||||
for _, f := range fs.Funcs {
|
||||
if g.isFuncSupported(f) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *ClassGen) isFuncSupported(f *java.Func) bool {
|
||||
for _, a := range f.Params {
|
||||
if !g.isSupported(a) {
|
||||
|
@ -62,6 +72,11 @@ func (g *ClassGen) isFuncSupported(f *java.Func) bool {
|
|||
}
|
||||
|
||||
func (g *ClassGen) goType(t *java.Type, local bool) string {
|
||||
if t == nil {
|
||||
// interface{} is used for parameters types for overloaded methods
|
||||
// where no common ancestor type exists.
|
||||
return "interface{}"
|
||||
}
|
||||
switch t.Kind {
|
||||
case java.Int:
|
||||
return "int32"
|
||||
|
@ -153,13 +168,16 @@ func (g *ClassGen) GenPackage(idx int) {
|
|||
g.Printf("var (\n")
|
||||
g.Indent()
|
||||
// Functions
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
loop:
|
||||
for _, fs := range cls.Funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if f.Public && g.isFuncSupported(f) {
|
||||
g.Printf("%s func", fs.GoName)
|
||||
g.genFuncDecl(false, fs)
|
||||
g.Printf("\n")
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
g.Printf("%s func", f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.Printf("\n")
|
||||
}
|
||||
g.Printf("// Cast takes a proxy for a Java object and converts it to a %s proxy.\n", cls.Name)
|
||||
g.Printf("// Cast panics if the argument is not a proxy or if the underlying object does\n")
|
||||
|
@ -209,17 +227,19 @@ func (g *ClassGen) GenH() {
|
|||
}
|
||||
g.Printf("\n")
|
||||
for _, cls := range g.classes {
|
||||
for _, f := range cls.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
||||
g.Printf(";\n")
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
for _, fs := range cls.AllMethods {
|
||||
for _, f := range fs.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCMethodDecl("csuper", cls.JNIName, f)
|
||||
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
||||
g.Printf(";\n")
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("extern ")
|
||||
g.genCMethodDecl("csuper", cls.JNIName, f)
|
||||
g.Printf(";\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,17 +255,21 @@ func (g *ClassGen) GenC() {
|
|||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("static jclass sclass_%s;\n", cls.JNIName)
|
||||
}
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
for _, fs := range cls.Funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
}
|
||||
g.Printf("static jmethodID m_s_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
}
|
||||
for _, f := range cls.AllMethods {
|
||||
if g.isFuncSupported(f) {
|
||||
g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
for _, fs := range cls.AllMethods {
|
||||
for _, f := range fs.Funcs {
|
||||
if g.isFuncSupported(f) {
|
||||
g.Printf("static jmethodID m_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("static jmethodID sm_%s_%s;\n", cls.JNIName, f.JNIName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,22 +287,26 @@ func (g *ClassGen) GenC() {
|
|||
g.Printf("sclass_%s = (*env)->GetSuperclass(env, clazz);\n", cls.JNIName)
|
||||
g.Printf("sclass_%s = (*env)->NewGlobalRef(env, sclass_%s);\n", cls.JNIName, cls.JNIName)
|
||||
}
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName)
|
||||
if f.Constructor {
|
||||
g.Printf("go_seq_get_method_id(clazz, \"<init>\", %q);\n", f.Desc)
|
||||
} else {
|
||||
g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc)
|
||||
for _, fs := range cls.Funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("m_s_%s_%s = ", cls.JNIName, f.JNIName)
|
||||
if f.Constructor {
|
||||
g.Printf("go_seq_get_method_id(clazz, \"<init>\", %q);\n", f.Desc)
|
||||
} else {
|
||||
g.Printf("go_seq_get_static_method_id(clazz, %q, %q);\n", f.Name, f.Desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range cls.AllMethods {
|
||||
if g.isFuncSupported(f) {
|
||||
g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc)
|
||||
for _, fs := range cls.AllMethods {
|
||||
for _, f := range fs.Funcs {
|
||||
if g.isFuncSupported(f) {
|
||||
g.Printf("m_%s_%s = go_seq_get_method_id(clazz, %q, %q);\n", cls.JNIName, f.JNIName, f.Name, f.Desc)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.Printf("sm_%s_%s = go_seq_get_method_id(sclass_%s, %q, %q);\n", cls.JNIName, f.JNIName, cls.JNIName, f.Name, f.Desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -287,15 +315,17 @@ func (g *ClassGen) GenC() {
|
|||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
for _, cls := range g.classes {
|
||||
for _, f := range cls.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
||||
g.genCMethodBody(cls, f, false)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.genCMethodDecl("csuper", cls.JNIName, f)
|
||||
g.genCMethodBody(cls, f, true)
|
||||
for _, fs := range cls.AllMethods {
|
||||
for _, f := range fs.Funcs {
|
||||
if !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.genCMethodDecl("cproxy", cls.JNIName, f)
|
||||
g.genCMethodBody(cls, f, false)
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
g.genCMethodDecl("csuper", cls.JNIName, f)
|
||||
g.genCMethodBody(cls, f, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,76 +395,84 @@ func initialUpper(s string) string {
|
|||
return string(unicode.ToUpper(r)) + s[n:]
|
||||
}
|
||||
|
||||
func (g *ClassGen) genFuncDecl(local bool, f *java.Func) {
|
||||
func (g *ClassGen) genFuncDecl(local bool, fs *java.FuncSet) {
|
||||
g.Printf("(")
|
||||
for i, a := range f.Params {
|
||||
for i, a := range fs.Params {
|
||||
if i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("a%d %s", i, g.goType(a, local))
|
||||
g.Printf("a%d ", i)
|
||||
if i == len(fs.Params)-1 && fs.Variadic {
|
||||
g.Printf("...")
|
||||
}
|
||||
g.Printf(g.goType(a, local))
|
||||
}
|
||||
g.Printf(")")
|
||||
if f.Throws != "" {
|
||||
if f.Ret != nil {
|
||||
g.Printf(" (%s, error)", g.goType(f.Ret, local))
|
||||
if fs.Throws {
|
||||
if fs.HasRet {
|
||||
g.Printf(" (%s, error)", g.goType(fs.Ret, local))
|
||||
} else {
|
||||
g.Printf(" error")
|
||||
}
|
||||
} else if f.Ret != nil {
|
||||
g.Printf(" %s", g.goType(f.Ret, local))
|
||||
} else if fs.HasRet {
|
||||
g.Printf(" %s", g.goType(fs.Ret, local))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ClassGen) genC(cls *java.Class) {
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
for _, fs := range cls.Funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.genCFuncDecl(cls.JNIName, f)
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params))
|
||||
for i, a := range f.Params {
|
||||
g.genCToJava(fmt.Sprintf("a%d", i), a)
|
||||
}
|
||||
if f.Constructor {
|
||||
g.Printf("jobject res = (*env)->NewObject(env")
|
||||
} else if f.Ret != nil {
|
||||
g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType())
|
||||
} else {
|
||||
g.Printf("(*env)->CallStaticVoidMethod(env")
|
||||
}
|
||||
g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
|
||||
for i := range f.Params {
|
||||
g.Printf(", _a%d", i)
|
||||
}
|
||||
g.Printf(");\n")
|
||||
g.Printf("jobject _exc = go_seq_get_exception(env);\n")
|
||||
g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
|
||||
if f.Ret != nil {
|
||||
g.genCRetClear("res", f.Ret, "_exc")
|
||||
g.genJavaToC("res", f.Ret)
|
||||
}
|
||||
g.Printf("go_seq_pop_local_frame(env);\n")
|
||||
if f.Ret != nil {
|
||||
g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
|
||||
g.Printf("return __res;\n")
|
||||
} else {
|
||||
g.Printf("return _exc_ref;\n")
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
g.genCFuncDecl(cls.JNIName, f)
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", len(f.Params))
|
||||
for i, a := range f.Params {
|
||||
g.genCToJava(fmt.Sprintf("a%d", i), a)
|
||||
}
|
||||
if f.Constructor {
|
||||
g.Printf("jobject res = (*env)->NewObject(env")
|
||||
} else if f.Ret != nil {
|
||||
g.Printf("%s res = (*env)->CallStatic%sMethod(env", f.Ret.JNIType(), f.Ret.JNICallType())
|
||||
} else {
|
||||
g.Printf("(*env)->CallStaticVoidMethod(env")
|
||||
}
|
||||
g.Printf(", class_%s, m_s_%s_%s", cls.JNIName, cls.JNIName, f.JNIName)
|
||||
for i := range f.Params {
|
||||
g.Printf(", _a%d", i)
|
||||
}
|
||||
g.Printf(");\n")
|
||||
g.Printf("jobject _exc = go_seq_get_exception(env);\n")
|
||||
g.Printf("int32_t _exc_ref = go_seq_to_refnum(env, _exc);\n")
|
||||
if f.Ret != nil {
|
||||
g.genCRetClear("res", f.Ret, "_exc")
|
||||
g.genJavaToC("res", f.Ret)
|
||||
}
|
||||
g.Printf("go_seq_pop_local_frame(env);\n")
|
||||
if f.Ret != nil {
|
||||
g.Printf("ret_%s __res = {_res, _exc_ref};\n", f.Ret.CType())
|
||||
g.Printf("return __res;\n")
|
||||
} else {
|
||||
g.Printf("return _exc_ref;\n")
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ClassGen) genH(cls *java.Class) {
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
for _, fs := range cls.Funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
continue
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCFuncDecl(cls.JNIName, f)
|
||||
g.Printf(";\n")
|
||||
}
|
||||
g.Printf("extern ")
|
||||
g.genCFuncDecl(cls.JNIName, f)
|
||||
g.Printf(";\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,13 +518,20 @@ func (g *ClassGen) genGo(cls *java.Class) {
|
|||
g.Printf(" return\n")
|
||||
g.Printf("}\n")
|
||||
g.Printf("class_%s = clazz\n", cls.JNIName)
|
||||
for _, f := range cls.Funcs {
|
||||
if !f.Public || !g.isFuncSupported(f) {
|
||||
for _, fs := range cls.Funcs {
|
||||
var supported bool
|
||||
for _, f := range fs.Funcs {
|
||||
if f.Public && g.isFuncSupported(f) {
|
||||
supported = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !supported {
|
||||
continue
|
||||
}
|
||||
g.Printf("%s.%s = func", cls.PkgName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(cls, f, "cproxy_s", true)
|
||||
g.Printf("%s.%s = func", cls.PkgName, fs.GoName)
|
||||
g.genFuncDecl(false, fs)
|
||||
g.genFuncBody(cls, fs, "cproxy_s", true)
|
||||
}
|
||||
g.Printf("%s.Cast = func(v interface{}) Java.%s {\n", cls.PkgName, goClsName(cls.Name))
|
||||
g.Indent()
|
||||
|
@ -503,13 +548,13 @@ func (g *ClassGen) genGo(cls *java.Class) {
|
|||
g.Printf("}\n\n")
|
||||
g.Printf("type proxy_class_%s _seq.Ref\n\n", cls.JNIName)
|
||||
g.Printf("func (p *proxy_class_%s) Bind_proxy_refnum__() int32 { return (*_seq.Ref)(p).Bind_IncNum() }\n\n", cls.JNIName)
|
||||
for _, f := range cls.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
for _, fs := range cls.AllMethods {
|
||||
if !g.isFuncSetSupported(fs) {
|
||||
continue
|
||||
}
|
||||
g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(cls, f, "cproxy", false)
|
||||
g.Printf("func (p *proxy_class_%s) %s", cls.JNIName, fs.GoName)
|
||||
g.genFuncDecl(false, fs)
|
||||
g.genFuncBody(cls, fs, "cproxy", false)
|
||||
}
|
||||
if cls.Throwable {
|
||||
g.Printf("func (p *proxy_class_%s) Error() string {\n", cls.JNIName)
|
||||
|
@ -521,54 +566,145 @@ func (g *ClassGen) genGo(cls *java.Class) {
|
|||
g.Printf(" return &super_%s{p}\n", cls.JNIName)
|
||||
g.Printf("}\n\n")
|
||||
g.Printf("type super_%s struct {*proxy_class_%[1]s}\n\n", cls.JNIName)
|
||||
for _, f := range cls.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
for _, fs := range cls.AllMethods {
|
||||
if !g.isFuncSetSupported(fs) {
|
||||
continue
|
||||
}
|
||||
g.Printf("func (p *super_%s) %s", cls.JNIName, f.GoName)
|
||||
g.genFuncDecl(false, f)
|
||||
g.genFuncBody(cls, f, "csuper", false)
|
||||
g.Printf("func (p *super_%s) %s", cls.JNIName, fs.GoName)
|
||||
g.genFuncDecl(false, fs)
|
||||
g.genFuncBody(cls, fs, "csuper", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ClassGen) genFuncBody(cls *java.Class, f *java.Func, prefix string, static bool) {
|
||||
// genFuncBody generated a Go function body for a FuncSet. It resolves overloading dynamically,
|
||||
// by inspecting the number of arguments (if the FuncSet contains varying parameter counts),
|
||||
// and their types.
|
||||
func (g *ClassGen) genFuncBody(cls *java.Class, fs *java.FuncSet, prefix string, static bool) {
|
||||
maxp := len(fs.Funcs[0].Params)
|
||||
minp := maxp
|
||||
// sort the function variants into argument sizes.
|
||||
buckets := make(map[int][]*java.Func)
|
||||
for _, f := range fs.Funcs {
|
||||
n := len(f.Params)
|
||||
if n < minp {
|
||||
minp = n
|
||||
} else if n > maxp {
|
||||
maxp = n
|
||||
}
|
||||
buckets[n] = append(buckets[n], f)
|
||||
}
|
||||
g.Printf(" {\n")
|
||||
g.Indent()
|
||||
for i, a := range f.Params {
|
||||
g.genWrite(fmt.Sprintf("a%d", i), a, modeTransient)
|
||||
if fs.Variadic {
|
||||
// Switch over the number of arguments.
|
||||
g.Printf("switch %d + len(a%d) {\n", minp, minp)
|
||||
}
|
||||
g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName)
|
||||
if !static {
|
||||
g.Printf("C.jint(p.Bind_proxy_refnum__())")
|
||||
}
|
||||
for i := range f.Params {
|
||||
if !static || i > 0 {
|
||||
g.Printf(", ")
|
||||
for i := minp; i <= maxp; i++ {
|
||||
funcs := buckets[i]
|
||||
if len(funcs) == 0 {
|
||||
continue
|
||||
}
|
||||
if fs.Variadic {
|
||||
g.Printf("case %d:\n", i)
|
||||
g.Indent()
|
||||
}
|
||||
for _, f := range funcs {
|
||||
if len(funcs) > 1 {
|
||||
g.Printf("{\n")
|
||||
g.Indent()
|
||||
}
|
||||
var argNames []string
|
||||
var preds []string
|
||||
for i, a := range f.Params {
|
||||
var ct *java.Type
|
||||
var argName string
|
||||
if i >= minp {
|
||||
argName = fmt.Sprintf("a%d[%d]", minp, i-minp)
|
||||
ct = fs.Params[minp]
|
||||
} else {
|
||||
argName = fmt.Sprintf("a%d", i)
|
||||
ct = fs.Params[i]
|
||||
}
|
||||
if !reflect.DeepEqual(ct, a) {
|
||||
g.Printf("_a%d, ok%d := %s.(%s)\n", i, i, argName, g.goType(a, false))
|
||||
argName = fmt.Sprintf("_a%d", i)
|
||||
preds = append(preds, fmt.Sprintf("ok%d", i))
|
||||
}
|
||||
argNames = append(argNames, argName)
|
||||
}
|
||||
if len(preds) > 0 {
|
||||
g.Printf("if %s {\n", strings.Join(preds, " && "))
|
||||
g.Indent()
|
||||
}
|
||||
for i, a := range f.Params {
|
||||
g.genWrite(fmt.Sprintf("__a%d", i), argNames[i], a, modeTransient)
|
||||
}
|
||||
g.Printf("res := C.%s_%s_%s(", prefix, cls.JNIName, f.JNIName)
|
||||
if !static {
|
||||
g.Printf("C.jint(p.Bind_proxy_refnum__())")
|
||||
}
|
||||
for i := range f.Params {
|
||||
if !static || i > 0 {
|
||||
g.Printf(", ")
|
||||
}
|
||||
g.Printf("__a%d", i)
|
||||
}
|
||||
g.Printf(")\n")
|
||||
g.genFuncRet(fs, f)
|
||||
if len(preds) > 0 {
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
}
|
||||
if len(funcs) > 1 {
|
||||
g.Outdent()
|
||||
g.Printf("}\n")
|
||||
}
|
||||
}
|
||||
if fs.Variadic {
|
||||
g.Outdent()
|
||||
}
|
||||
g.Printf("_a%d", i)
|
||||
}
|
||||
g.Printf(")\n")
|
||||
g.genFuncRet(f)
|
||||
if fs.Variadic {
|
||||
g.Printf("}\n")
|
||||
}
|
||||
if fs.Variadic || len(fs.Funcs) > 1 {
|
||||
g.Printf("panic(\"no overloaded method found for %s.%s that matched the arguments\")\n", cls.Name, fs.Name)
|
||||
}
|
||||
g.Outdent()
|
||||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
func (g *ClassGen) genFuncRet(f *java.Func) {
|
||||
func (g *ClassGen) genFuncRet(fs *java.FuncSet, f *java.Func) {
|
||||
if f.Ret != nil {
|
||||
g.genRead("_res", "res.res", f.Ret, modeRetained)
|
||||
g.genRefRead("_exc", "res.exc", "error", "proxy_error", true)
|
||||
} else {
|
||||
g.genRefRead("_exc", "res", "error", "proxy_error", true)
|
||||
}
|
||||
if f.Throws == "" {
|
||||
if !fs.Throws {
|
||||
g.Printf("if (_exc != nil) { panic(_exc) }\n")
|
||||
if f.Ret != nil {
|
||||
g.Printf("return _res\n")
|
||||
if fs.HasRet {
|
||||
if f.Ret != nil {
|
||||
g.Printf("return _res\n")
|
||||
} else {
|
||||
// The variant doesn't return a value, but the common
|
||||
// signature does. Use nil as a placeholder return value.
|
||||
g.Printf("return nil\n")
|
||||
}
|
||||
} else if fs.Variadic || len(fs.Funcs) > 1 {
|
||||
// If there are overloaded variants, return here to avoid the fallback
|
||||
// panic generated in genFuncBody.
|
||||
g.Printf("return\n")
|
||||
}
|
||||
} else {
|
||||
if f.Ret != nil {
|
||||
g.Printf("return _res, _exc\n")
|
||||
if fs.HasRet {
|
||||
if f.Ret != nil {
|
||||
g.Printf("return _res, _exc\n")
|
||||
} else {
|
||||
// As above, use a nil placeholder return value.
|
||||
g.Printf("return nil, _exc\n")
|
||||
}
|
||||
} else {
|
||||
g.Printf("return _exc\n")
|
||||
}
|
||||
|
@ -612,26 +748,26 @@ func (g *ClassGen) genRefRead(to, from string, intfName, proxyName string, hasPr
|
|||
g.Printf("}\n")
|
||||
}
|
||||
|
||||
func (g *ClassGen) genWrite(v string, t *java.Type, mode varMode) {
|
||||
func (g *ClassGen) genWrite(dst, v string, t *java.Type, mode varMode) {
|
||||
switch t.Kind {
|
||||
case java.Int, java.Short, java.Char, java.Byte, java.Long, java.Float, java.Double:
|
||||
g.Printf("_%s := C.%s(%s)\n", v, t.CType(), v)
|
||||
g.Printf("%s := C.%s(%s)\n", dst, t.CType(), v)
|
||||
case java.Boolean:
|
||||
g.Printf("_%s := C.jboolean(C.JNI_FALSE)\n", v)
|
||||
g.Printf("%s := C.jboolean(C.JNI_FALSE)\n", dst)
|
||||
g.Printf("if %s {\n", v)
|
||||
g.Printf(" _%s = C.jboolean(C.JNI_TRUE)\n", v)
|
||||
g.Printf(" %s = C.jboolean(C.JNI_TRUE)\n", dst)
|
||||
g.Printf("}\n")
|
||||
case java.String:
|
||||
g.Printf("_%s := encodeString(%s)\n", v, v)
|
||||
g.Printf("%s := encodeString(%s)\n", dst, v)
|
||||
case java.Array:
|
||||
if t.Elem.Kind != java.Byte {
|
||||
panic("unsupported array type")
|
||||
}
|
||||
g.Printf("_%s := fromSlice(%s, %v)\n", v, v, mode == modeRetained)
|
||||
g.Printf("%s := fromSlice(%s, %v)\n", dst, v, mode == modeRetained)
|
||||
case java.Object:
|
||||
g.Printf("var _%s C.jint = _seq.NullRefNum\n", v)
|
||||
g.Printf("var %s C.jint = _seq.NullRefNum\n", dst)
|
||||
g.Printf("if %s != nil {\n", v)
|
||||
g.Printf(" _%s = C.jint(_seq.ToRefNum(%s))\n", v, v)
|
||||
g.Printf(" %s = C.jint(_seq.ToRefNum(%s))\n", dst, v)
|
||||
g.Printf("}\n")
|
||||
default:
|
||||
panic("invalid kind")
|
||||
|
@ -698,12 +834,12 @@ func (g *ClassGen) genInterface(cls *java.Class) {
|
|||
g.Printf("type %s interface {\n", goClsName(cls.Name))
|
||||
g.Indent()
|
||||
// Methods
|
||||
for _, f := range cls.AllMethods {
|
||||
if !g.isFuncSupported(f) {
|
||||
for _, fs := range cls.AllMethods {
|
||||
if !g.isFuncSetSupported(fs) {
|
||||
continue
|
||||
}
|
||||
g.Printf(f.GoName)
|
||||
g.genFuncDecl(true, f)
|
||||
g.Printf(fs.GoName)
|
||||
g.genFuncDecl(true, fs)
|
||||
g.Printf("\n")
|
||||
}
|
||||
if _, ok := g.supers[cls.Name]; ok {
|
||||
|
|
172
bind/genjava.go
172
bind/genjava.go
|
@ -9,6 +9,7 @@ import (
|
|||
"go/constant"
|
||||
"go/types"
|
||||
"math"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
|
@ -38,7 +39,7 @@ type javaClassInfo struct {
|
|||
extends *java.Class
|
||||
// All Java classes and interfaces this class extends and implements.
|
||||
supers []*java.Class
|
||||
methods map[string]*java.Func
|
||||
methods map[string]*java.FuncSet
|
||||
// Does the class need a default no-arg constructor
|
||||
genNoargCon bool
|
||||
}
|
||||
|
@ -59,16 +60,21 @@ func (g *JavaGen) Init(classes []*java.Class) {
|
|||
continue
|
||||
}
|
||||
inf := &javaClassInfo{
|
||||
methods: make(map[string]*java.Func),
|
||||
methods: make(map[string]*java.FuncSet),
|
||||
genNoargCon: true, // java.lang.Object has a no-arg constructor
|
||||
}
|
||||
for _, n := range classes {
|
||||
cls := g.clsMap[n]
|
||||
for _, f := range cls.AllMethods {
|
||||
if f.Final {
|
||||
continue
|
||||
for _, fs := range cls.AllMethods {
|
||||
hasMeth := false
|
||||
for _, f := range fs.Funcs {
|
||||
if !f.Final {
|
||||
hasMeth = true
|
||||
}
|
||||
}
|
||||
if hasMeth {
|
||||
inf.methods[fs.GoName] = fs
|
||||
}
|
||||
inf.methods[f.GoName] = f
|
||||
}
|
||||
inf.supers = append(inf.supers, cls)
|
||||
if !cls.Interface {
|
||||
|
@ -96,6 +102,104 @@ func (g *JavaGen) Init(classes []*java.Class) {
|
|||
}
|
||||
}
|
||||
|
||||
func (j *javaClassInfo) toJavaType(T types.Type) *java.Type {
|
||||
switch T := T.(type) {
|
||||
case *types.Basic:
|
||||
var kind java.TypeKind
|
||||
switch T.Kind() {
|
||||
case types.Bool, types.UntypedBool:
|
||||
kind = java.Boolean
|
||||
case types.Uint8:
|
||||
kind = java.Byte
|
||||
case types.Int16:
|
||||
kind = java.Short
|
||||
case types.Int32, types.UntypedRune: // types.Rune
|
||||
kind = java.Int
|
||||
case types.Int64, types.UntypedInt:
|
||||
kind = java.Long
|
||||
case types.Float32:
|
||||
kind = java.Float
|
||||
case types.Float64, types.UntypedFloat:
|
||||
kind = java.Double
|
||||
case types.String, types.UntypedString:
|
||||
kind = java.String
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return &java.Type{Kind: kind}
|
||||
case *types.Slice:
|
||||
switch e := T.Elem().(type) {
|
||||
case *types.Basic:
|
||||
switch e.Kind() {
|
||||
case types.Uint8: // Byte.
|
||||
return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *types.Named:
|
||||
if isJavaType(T) {
|
||||
return &java.Type{Kind: java.Object, Class: classNameFor(T)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lookupMethod searches the Java class descriptor for a method
|
||||
// that matches the Go method.
|
||||
func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func {
|
||||
jm := j.methods[m.Name()]
|
||||
if jm == nil {
|
||||
// If an exact match is not found, try the method with trailing underscores
|
||||
// stripped. This way, name clashes can be avoided when overriding multiple
|
||||
// overloaded methods from Go.
|
||||
base := strings.TrimRight(m.Name(), "_")
|
||||
jm = j.methods[base]
|
||||
if jm == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// A name match was found. Now use the parameter and return types to locate
|
||||
// the correct variant.
|
||||
sig := m.Type().(*types.Signature)
|
||||
params := sig.Params()
|
||||
// Convert Go parameter types to their Java counterparts, if possible.
|
||||
var jparams []*java.Type
|
||||
i := 0
|
||||
if hasThis {
|
||||
i = 1
|
||||
}
|
||||
for ; i < params.Len(); i++ {
|
||||
jparams = append(jparams, j.toJavaType(params.At(i).Type()))
|
||||
}
|
||||
var ret *java.Type
|
||||
var throws bool
|
||||
if results := sig.Results(); results.Len() > 0 {
|
||||
ret = j.toJavaType(results.At(0).Type())
|
||||
if results.Len() > 1 {
|
||||
throws = isErrorType(results.At(1).Type())
|
||||
}
|
||||
}
|
||||
loop:
|
||||
for _, f := range jm.Funcs {
|
||||
if len(f.Params) != len(jparams) {
|
||||
continue
|
||||
}
|
||||
if throws != (f.Throws != "") {
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(ret, f.Ret) {
|
||||
continue
|
||||
}
|
||||
for i, p := range f.Params {
|
||||
if !reflect.DeepEqual(p, jparams[i]) {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClassNames returns the list of names of the generated Java classes and interfaces.
|
||||
func (g *JavaGen) ClassNames() []string {
|
||||
var names []string
|
||||
|
@ -217,32 +321,11 @@ func (g *JavaGen) genStruct(s structInfo) {
|
|||
var jm *java.Func
|
||||
hasThis := false
|
||||
if jinf != nil {
|
||||
jm = jinf.methods[m.Name()]
|
||||
hasThis = g.hasThis(n, m)
|
||||
jm = jinf.lookupMethod(m, hasThis)
|
||||
if jm != nil {
|
||||
g.Printf("@Override ")
|
||||
}
|
||||
// Check the implicit this argument, if any
|
||||
sig := m.Type().(*types.Signature)
|
||||
params := sig.Params()
|
||||
if params.Len() > 0 {
|
||||
v := params.At(0)
|
||||
if v.Name() == "this" {
|
||||
t := v.Type()
|
||||
if t, ok := t.(*types.Named); ok {
|
||||
obj := t.Obj()
|
||||
pkg := obj.Pkg()
|
||||
if pkgFirstElem(pkg) == "Java" {
|
||||
clsName := classNameFor(t)
|
||||
exp := g.javaPkgName(g.Pkg) + "." + s.obj.Name()
|
||||
if clsName != exp {
|
||||
g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, n, m.Name(), exp)
|
||||
continue
|
||||
}
|
||||
hasThis = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.Printf("public native ")
|
||||
g.genFuncSignature(m, jm, hasThis)
|
||||
|
@ -259,6 +342,35 @@ func (g *JavaGen) genStruct(s structInfo) {
|
|||
g.Printf("}\n\n")
|
||||
}
|
||||
|
||||
// hasThis returns whether a method has an implicit "this" parameter.
|
||||
func (g *JavaGen) hasThis(sName string, m *types.Func) bool {
|
||||
sig := m.Type().(*types.Signature)
|
||||
params := sig.Params()
|
||||
if params.Len() == 0 {
|
||||
return false
|
||||
}
|
||||
v := params.At(0)
|
||||
if v.Name() != "this" {
|
||||
return false
|
||||
}
|
||||
t, ok := v.Type().(*types.Named)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
obj := t.Obj()
|
||||
pkg := obj.Pkg()
|
||||
if pkgFirstElem(pkg) != "Java" {
|
||||
return false
|
||||
}
|
||||
clsName := classNameFor(t)
|
||||
exp := g.javaPkgName(g.Pkg) + "." + sName
|
||||
if clsName != exp {
|
||||
g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) {
|
||||
g.Printf("public %s(", n)
|
||||
g.genFuncArgs(f, nil, false)
|
||||
|
@ -1386,7 +1498,7 @@ func (g *JavaGen) GenC() error {
|
|||
for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) {
|
||||
var jm *java.Func
|
||||
if jinf != nil {
|
||||
jm = jinf.methods[m.Name()]
|
||||
jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m))
|
||||
}
|
||||
g.genJNIFunc(m, sName, jm, false, jinf != nil)
|
||||
}
|
||||
|
|
|
@ -36,12 +36,13 @@ type Future struct {
|
|||
concurrent.Future
|
||||
}
|
||||
|
||||
func (_ *Future) Get() lang.Object {
|
||||
return nil
|
||||
func (_ *Future) Get() (lang.Object, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *Future) Get2(_ int64, _ concurrent.TimeUnit) lang.Object {
|
||||
return nil
|
||||
// Use a trailing underscore to override multiple overloaded methods.
|
||||
func (_ *Future) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
|
@ -51,7 +52,7 @@ type Object struct {
|
|||
func innerClassTypes() {
|
||||
// java.util.Spliterators.iterator use inner class types
|
||||
// for the return value as well as parameters.
|
||||
Spliterators.Iterator_Ljava_util_Spliterator_00024OfInt_2(nil)
|
||||
Spliterators.Iterator(nil)
|
||||
}
|
||||
|
||||
func returnType() {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,13 +8,33 @@ static jclass class_java_lang_Runnable;
|
|||
static jmethodID m_java_lang_Runnable_run;
|
||||
static jclass class_java_io_InputStream;
|
||||
static jmethodID m_java_io_InputStream_read__;
|
||||
static jmethodID m_java_io_InputStream_read___3B;
|
||||
static jmethodID m_java_io_InputStream_read___3BII;
|
||||
static jclass class_java_util_concurrent_Future;
|
||||
static jmethodID m_java_util_concurrent_Future_get__;
|
||||
static jmethodID m_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2;
|
||||
static jclass class_java_lang_Object;
|
||||
static jclass class_java_util_concurrent_TimeUnit;
|
||||
static jclass class_java_util_Spliterators;
|
||||
static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2;
|
||||
static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2;
|
||||
static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2;
|
||||
static jmethodID m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2;
|
||||
ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL);
|
||||
jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = NULL;
|
||||
}
|
||||
jint _res = go_seq_to_refnum(env, res);
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL);
|
||||
|
@ -30,6 +50,36 @@ ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024O
|
|||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL);
|
||||
jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = NULL;
|
||||
}
|
||||
jint _res = go_seq_to_refnum(env, res);
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
jobject _a0 = go_seq_from_refnum(env, a0, NULL, NULL);
|
||||
jobject res = (*env)->CallStaticObjectMethod(env, class_java_util_Spliterators, m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = NULL;
|
||||
}
|
||||
jint _res = go_seq_to_refnum(env, res);
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
static jclass class_java_lang_System;
|
||||
static jmethodID m_s_java_lang_System_console;
|
||||
ret_jint cproxy_s_java_lang_System_console() {
|
||||
|
@ -56,19 +106,29 @@ static jclass class_java_InputStream;
|
|||
static jclass sclass_java_InputStream;
|
||||
static jmethodID m_java_InputStream_read__;
|
||||
static jmethodID sm_java_InputStream_read__;
|
||||
static jmethodID m_java_InputStream_read___3B;
|
||||
static jmethodID sm_java_InputStream_read___3B;
|
||||
static jmethodID m_java_InputStream_read___3BII;
|
||||
static jmethodID sm_java_InputStream_read___3BII;
|
||||
static jclass class_java_Object;
|
||||
static jclass sclass_java_Object;
|
||||
static jclass class_java_Runnable;
|
||||
static jclass sclass_java_Runnable;
|
||||
static jmethodID m_java_Runnable_run;
|
||||
static jmethodID sm_java_Runnable_run;
|
||||
static jclass class_java_util_Iterator;
|
||||
static jclass class_java_util_Spliterator;
|
||||
static jclass class_java_util_PrimitiveIterator_OfInt;
|
||||
static jclass class_java_util_Spliterator_OfInt;
|
||||
static jclass class_java_util_PrimitiveIterator_OfLong;
|
||||
static jclass class_java_util_Spliterator_OfLong;
|
||||
static jclass class_java_util_PrimitiveIterator_OfDouble;
|
||||
static jclass class_java_util_Spliterator_OfDouble;
|
||||
static jclass class_java_io_Console;
|
||||
static jmethodID m_java_io_Console_flush;
|
||||
|
||||
void init_proxies() {
|
||||
JNIEnv *env = go_seq_push_local_frame(14);
|
||||
JNIEnv *env = go_seq_push_local_frame(20);
|
||||
jclass clazz;
|
||||
clazz = (*env)->FindClass(env, "java/lang/Runnable");
|
||||
class_java_lang_Runnable = (*env)->NewGlobalRef(env, clazz);
|
||||
|
@ -76,6 +136,8 @@ void init_proxies() {
|
|||
clazz = (*env)->FindClass(env, "java/io/InputStream");
|
||||
class_java_io_InputStream = (*env)->NewGlobalRef(env, clazz);
|
||||
m_java_io_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I");
|
||||
m_java_io_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I");
|
||||
m_java_io_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I");
|
||||
clazz = (*env)->FindClass(env, "java/util/concurrent/Future");
|
||||
class_java_util_concurrent_Future = (*env)->NewGlobalRef(env, clazz);
|
||||
m_java_util_concurrent_Future_get__ = go_seq_get_method_id(clazz, "get", "()Ljava/lang/Object;");
|
||||
|
@ -86,7 +148,10 @@ void init_proxies() {
|
|||
class_java_util_concurrent_TimeUnit = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/Spliterators");
|
||||
class_java_util_Spliterators = (*env)->NewGlobalRef(env, clazz);
|
||||
m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator;)Ljava/util/Iterator;");
|
||||
m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfInt;)Ljava/util/PrimitiveIterator$OfInt;");
|
||||
m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfLong;)Ljava/util/PrimitiveIterator$OfLong;");
|
||||
m_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2 = go_seq_get_static_method_id(clazz, "iterator", "(Ljava/util/Spliterator$OfDouble;)Ljava/util/PrimitiveIterator$OfDouble;");
|
||||
clazz = (*env)->FindClass(env, "java/lang/System");
|
||||
class_java_lang_System = (*env)->NewGlobalRef(env, clazz);
|
||||
m_s_java_lang_System_console = go_seq_get_static_method_id(clazz, "console", "()Ljava/io/Console;");
|
||||
|
@ -104,6 +169,10 @@ void init_proxies() {
|
|||
sclass_java_InputStream = (*env)->NewGlobalRef(env, sclass_java_InputStream);
|
||||
m_java_InputStream_read__ = go_seq_get_method_id(clazz, "read", "()I");
|
||||
sm_java_InputStream_read__ = go_seq_get_method_id(sclass_java_InputStream, "read", "()I");
|
||||
m_java_InputStream_read___3B = go_seq_get_method_id(clazz, "read", "([B)I");
|
||||
sm_java_InputStream_read___3B = go_seq_get_method_id(sclass_java_InputStream, "read", "([B)I");
|
||||
m_java_InputStream_read___3BII = go_seq_get_method_id(clazz, "read", "([BII)I");
|
||||
sm_java_InputStream_read___3BII = go_seq_get_method_id(sclass_java_InputStream, "read", "([BII)I");
|
||||
clazz = (*env)->FindClass(env, "java/Object");
|
||||
class_java_Object = (*env)->NewGlobalRef(env, clazz);
|
||||
sclass_java_Object = (*env)->GetSuperclass(env, clazz);
|
||||
|
@ -114,10 +183,22 @@ void init_proxies() {
|
|||
sclass_java_Runnable = (*env)->NewGlobalRef(env, sclass_java_Runnable);
|
||||
m_java_Runnable_run = go_seq_get_method_id(clazz, "run", "()V");
|
||||
sm_java_Runnable_run = go_seq_get_method_id(sclass_java_Runnable, "run", "()V");
|
||||
clazz = (*env)->FindClass(env, "java/util/Iterator");
|
||||
class_java_util_Iterator = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/Spliterator");
|
||||
class_java_util_Spliterator = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfInt");
|
||||
class_java_util_PrimitiveIterator_OfInt = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/Spliterator$OfInt");
|
||||
class_java_util_Spliterator_OfInt = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfLong");
|
||||
class_java_util_PrimitiveIterator_OfLong = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/Spliterator$OfLong");
|
||||
class_java_util_Spliterator_OfLong = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/PrimitiveIterator$OfDouble");
|
||||
class_java_util_PrimitiveIterator_OfDouble = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/util/Spliterator$OfDouble");
|
||||
class_java_util_Spliterator_OfDouble = (*env)->NewGlobalRef(env, clazz);
|
||||
clazz = (*env)->FindClass(env, "java/io/Console");
|
||||
class_java_io_Console = (*env)->NewGlobalRef(env, clazz);
|
||||
m_java_io_Console_flush = go_seq_get_method_id(clazz, "flush", "()V");
|
||||
|
@ -151,6 +232,42 @@ ret_jint cproxy_java_io_InputStream_read__(jint this) {
|
|||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(2);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3B, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_java_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) {
|
||||
JNIEnv *env = go_seq_push_local_frame(4);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint _a1 = a1;
|
||||
jint _a2 = a2;
|
||||
jint res = (*env)->CallIntMethod(env, _this, m_java_io_InputStream_read___3BII, _a0, _a1, _a2);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_java_util_concurrent_Future_get__(jint this) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
// Must be a Java object
|
||||
|
@ -285,6 +402,78 @@ ret_jint csuper_java_InputStream_read__(jint this) {
|
|||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(2);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3B, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint csuper_java_InputStream_read___3B(jint this, nbyteslice a0) {
|
||||
JNIEnv *env = go_seq_push_local_frame(2);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3B, _a0);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint cproxy_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) {
|
||||
JNIEnv *env = go_seq_push_local_frame(4);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint _a1 = a1;
|
||||
jint _a2 = a2;
|
||||
jint res = (*env)->CallIntMethod(env, _this, m_java_InputStream_read___3BII, _a0, _a1, _a2);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
ret_jint csuper_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2) {
|
||||
JNIEnv *env = go_seq_push_local_frame(4);
|
||||
// Must be a Java object
|
||||
jobject _this = go_seq_from_refnum(env, this, NULL, NULL);
|
||||
jbyteArray _a0 = go_seq_to_java_bytearray(env, a0, 0);
|
||||
jint _a1 = a1;
|
||||
jint _a2 = a2;
|
||||
jint res = (*env)->CallNonvirtualIntMethod(env, _this, sclass_java_InputStream, sm_java_InputStream_read___3BII, _a0, _a1, _a2);
|
||||
jobject _exc = go_seq_get_exception(env);
|
||||
int32_t _exc_ref = go_seq_to_refnum(env, _exc);
|
||||
if (_exc != NULL) {
|
||||
res = 0;
|
||||
}
|
||||
jint _res = res;
|
||||
go_seq_pop_local_frame(env);
|
||||
ret_jint __res = {_res, _exc_ref};
|
||||
return __res;
|
||||
}
|
||||
|
||||
jint cproxy_java_Runnable_run(jint this) {
|
||||
JNIEnv *env = go_seq_push_local_frame(1);
|
||||
// Must be a Java object
|
||||
|
@ -368,8 +557,10 @@ Java_java_Future__1_1New(JNIEnv *env, jclass clazz) {
|
|||
JNIEXPORT jobject JNICALL
|
||||
Java_java_Future_get__(JNIEnv* env, jobject __this__) {
|
||||
int32_t o = go_seq_to_refnum_go(env, __this__);
|
||||
int32_t r0 = proxyjava_Future_Get(o);
|
||||
jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL);
|
||||
struct proxyjava_Future_Get_return res = proxyjava_Future_Get(o);
|
||||
jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL);
|
||||
jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons);
|
||||
go_seq_maybe_throw_exception(env, _r1);
|
||||
return _r0;
|
||||
}
|
||||
|
||||
|
@ -378,8 +569,10 @@ Java_java_Future_get__JLjava_util_concurrent_TimeUnit_2(JNIEnv* env, jobject __t
|
|||
int32_t o = go_seq_to_refnum_go(env, __this__);
|
||||
int64_t _p0 = (int64_t)p0;
|
||||
int32_t _p1 = go_seq_to_refnum(env, p1);
|
||||
int32_t r0 = proxyjava_Future_Get2(o, _p0, _p1);
|
||||
jobject _r0 = go_seq_from_refnum(env, r0, NULL, NULL);
|
||||
struct proxyjava_Future_Get__return res = proxyjava_Future_Get_(o, _p0, _p1);
|
||||
jobject _r0 = go_seq_from_refnum(env, res.r0, NULL, NULL);
|
||||
jobject _r1 = go_seq_from_refnum(env, res.r1, proxy_class__error, proxy_class__error_cons);
|
||||
go_seq_maybe_throw_exception(env, _r1);
|
||||
return _r0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ public final class Future implements Seq.GoObject, java.util.concurrent.Future {
|
|||
public final native java.util.concurrent.Future getFuture();
|
||||
public final native void setFuture(java.util.concurrent.Future v);
|
||||
|
||||
@Override public native java.lang.Object get();
|
||||
@Override public native java.lang.Object get(long p0, java.util.concurrent.TimeUnit p1);
|
||||
@Override public native java.lang.Object get() throws java.lang.InterruptedException, java.util.concurrent.ExecutionException;
|
||||
@Override public native java.lang.Object get(long p0, java.util.concurrent.TimeUnit p1) throws java.lang.InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException;
|
||||
}
|
||||
|
||||
// Java class java.InputStream is a proxy for talking to a Go program.
|
||||
|
|
|
@ -48,6 +48,8 @@ typedef struct ret_nbyteslice {
|
|||
|
||||
extern jint cproxy_java_lang_Runnable_run(jint this);
|
||||
extern ret_jint cproxy_java_io_InputStream_read__(jint this);
|
||||
extern ret_jint cproxy_java_io_InputStream_read___3B(jint this, nbyteslice a0);
|
||||
extern ret_jint cproxy_java_io_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2);
|
||||
extern ret_jint cproxy_java_util_concurrent_Future_get__(jint this);
|
||||
extern ret_jint cproxy_java_util_concurrent_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1);
|
||||
extern ret_jint cproxy_java_Future_get__(jint this);
|
||||
|
@ -56,10 +58,17 @@ extern ret_jint cproxy_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint t
|
|||
extern ret_jint csuper_java_Future_get__JLjava_util_concurrent_TimeUnit_2(jint this, jlong a0, jint a1);
|
||||
extern ret_jint cproxy_java_InputStream_read__(jint this);
|
||||
extern ret_jint csuper_java_InputStream_read__(jint this);
|
||||
extern ret_jint cproxy_java_InputStream_read___3B(jint this, nbyteslice a0);
|
||||
extern ret_jint csuper_java_InputStream_read___3B(jint this, nbyteslice a0);
|
||||
extern ret_jint cproxy_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2);
|
||||
extern ret_jint csuper_java_InputStream_read___3BII(jint this, nbyteslice a0, jint a1, jint a2);
|
||||
extern jint cproxy_java_Runnable_run(jint this);
|
||||
extern jint csuper_java_Runnable_run(jint this);
|
||||
extern jint cproxy_java_io_Console_flush(jint this);
|
||||
extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_2(jint a0);
|
||||
extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfInt_2(jint a0);
|
||||
extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfLong_2(jint a0);
|
||||
extern ret_jint cproxy_s_java_util_Spliterators_iterator__Ljava_util_Spliterator_00024OfDouble_2(jint a0);
|
||||
extern ret_jint cproxy_s_java_lang_System_console();
|
||||
// JNI function headers for the Go <=> Java bridge.
|
||||
// gobind -lang=java classes
|
||||
|
|
|
@ -51,7 +51,7 @@ type GoInputStream struct {
|
|||
}
|
||||
|
||||
func (_ *GoInputStream) Read() (int32, error) {
|
||||
return 0, IOException.New_Ljava_lang_String_2(IOExceptionMessage)
|
||||
return 0, IOException.New(IOExceptionMessage)
|
||||
}
|
||||
|
||||
func NewGoInputStream() *GoInputStream {
|
||||
|
@ -66,12 +66,13 @@ func (_ *GoFuture) Cancel(_ bool) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (_ *GoFuture) Get() lang.Object {
|
||||
return nil
|
||||
func (_ *GoFuture) Get() (lang.Object, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *GoFuture) Get2(_ int64, _ concurrent.TimeUnit) lang.Object {
|
||||
return nil
|
||||
// Use a trailing underscore to override multiple overloaded methods.
|
||||
func (_ *GoFuture) Get_(_ int64, _ concurrent.TimeUnit) (lang.Object, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *GoFuture) IsCancelled() bool {
|
||||
|
@ -153,7 +154,8 @@ func NewJavaObject() lang.Object {
|
|||
}
|
||||
|
||||
func NewJavaInteger() lang.Integer {
|
||||
return Integer.New_I(42)
|
||||
i, _ := Integer.New(int32(42))
|
||||
return i
|
||||
}
|
||||
|
||||
type NoargConstructor struct {
|
||||
|
|
|
@ -30,7 +30,7 @@ func IntegerBytes() int {
|
|||
}
|
||||
|
||||
func IntegerValueOf(v int32) int32 {
|
||||
i := Integer.ValueOf_I(v)
|
||||
i, _ := Integer.ValueOf(v)
|
||||
return i.IntValue()
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ func IntegerDecode(v string) (int32, error) {
|
|||
}
|
||||
|
||||
func IntegerParseInt(v string, radix int32) (int32, error) {
|
||||
return Integer.ParseInt2(v, radix)
|
||||
return Integer.ParseInt(v, radix)
|
||||
}
|
||||
|
||||
func ProvokeRuntimeException() (err error) {
|
||||
|
|
|
@ -18,9 +18,9 @@ type MainActivity struct {
|
|||
app.AppCompatActivity
|
||||
}
|
||||
|
||||
func (a *MainActivity) OnCreate1(this gopkg.MainActivity, b os.Bundle) {
|
||||
this.Super().OnCreate1(b)
|
||||
db := DataBindingUtil.SetContentView2(this, rlayout.Activity_main)
|
||||
func (a *MainActivity) OnCreate(this gopkg.MainActivity, b os.Bundle) {
|
||||
this.Super().OnCreate(b)
|
||||
db := DataBindingUtil.SetContentView(this, rlayout.Activity_main)
|
||||
mainBind := ActivityMainBinding.Cast(db)
|
||||
mainBind.SetAct(this)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
@ -35,11 +36,15 @@ type Class struct {
|
|||
JNIName string
|
||||
// "Inner"
|
||||
PkgName string
|
||||
Funcs []*Func
|
||||
Methods []*Func
|
||||
Funcs []*FuncSet
|
||||
Methods []*FuncSet
|
||||
// funcMap maps function names.
|
||||
funcMap map[string]*FuncSet
|
||||
// FuncMap maps method names.
|
||||
methodMap map[string]*FuncSet
|
||||
// All methods, including methods from
|
||||
// supers.
|
||||
AllMethods []*Func
|
||||
AllMethods []*FuncSet
|
||||
Vars []*Var
|
||||
Supers []string
|
||||
Final bool
|
||||
|
@ -50,11 +55,34 @@ type Class struct {
|
|||
HasNoArgCon bool
|
||||
}
|
||||
|
||||
// FuncSet is the set of overloaded variants of a function.
|
||||
// If the function is not overloaded, its FuncSet contains
|
||||
// one entry.
|
||||
type FuncSet struct {
|
||||
Name string
|
||||
GoName string
|
||||
Funcs []*Func
|
||||
CommonSig
|
||||
}
|
||||
|
||||
// CommonSig is a signature compatible with every
|
||||
// overloaded variant of a FuncSet.
|
||||
type CommonSig struct {
|
||||
// Variadic is set if the signature covers variants
|
||||
// with varying number of parameters.
|
||||
Variadic bool
|
||||
// HasRet is true if at least one variant returns a
|
||||
// value.
|
||||
HasRet bool
|
||||
Throws bool
|
||||
Params []*Type
|
||||
Ret *Type
|
||||
}
|
||||
|
||||
// Func is a Java static function or method or constructor.
|
||||
type Func struct {
|
||||
FuncSig
|
||||
ArgDesc string
|
||||
GoName string
|
||||
// Mangled JNI name
|
||||
JNIName string
|
||||
Static bool
|
||||
|
@ -102,6 +130,13 @@ type Importer struct {
|
|||
clsMap map[string]*Class
|
||||
}
|
||||
|
||||
// funcRef is a reference to a Java function (static method).
|
||||
// It is used as a key to filter unused Java functions.
|
||||
type funcRef struct {
|
||||
clsName string
|
||||
goName string
|
||||
}
|
||||
|
||||
const (
|
||||
Int TypeKind = iota
|
||||
Boolean
|
||||
|
@ -167,10 +202,21 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) {
|
|||
}
|
||||
}
|
||||
}
|
||||
funcRefs := make(map[funcRef]struct{})
|
||||
for _, ref := range refs.Refs {
|
||||
pkgName := strings.Replace(ref.Pkg, "/", ".", -1)
|
||||
funcRefs[funcRef{pkgName, ref.Name}] = struct{}{}
|
||||
}
|
||||
classes, err := j.importClasses(names, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
j.filterReferences(classes, refs, funcRefs)
|
||||
supers, err := j.importReferencedClasses(classes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
j.filterReferences(supers, refs, funcRefs)
|
||||
// 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 class descriptors.
|
||||
|
@ -182,6 +228,7 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) {
|
|||
if _, exists := j.clsMap[n]; exists {
|
||||
continue
|
||||
}
|
||||
clsSet[n] = struct{}{}
|
||||
cls := &Class{
|
||||
Name: n,
|
||||
FindName: n,
|
||||
|
@ -199,52 +246,193 @@ func (j *Importer) Import(refs *importers.References) ([]*Class, error) {
|
|||
classes = append(classes, cls)
|
||||
j.clsMap[cls.Name] = cls
|
||||
}
|
||||
j.initClasses(classes, refs)
|
||||
// Include implicit classes that are used in parameter or return values.
|
||||
newClasses := classes
|
||||
for len(newClasses) > 0 {
|
||||
var impNames []string
|
||||
var impClasses []*Class
|
||||
for _, cls := range newClasses {
|
||||
for _, funcs := range [][]*Func{cls.Funcs, cls.AllMethods} {
|
||||
for _, f := range funcs {
|
||||
for _, cls := range classes {
|
||||
for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} {
|
||||
for _, fs := range fsets {
|
||||
for _, f := range fs.Funcs {
|
||||
names := j.implicitFuncTypes(f)
|
||||
for _, name := range names {
|
||||
if _, exists := clsSet[name]; exists {
|
||||
continue
|
||||
}
|
||||
clsSet[name] = struct{}{}
|
||||
if cls, exists := j.clsMap[name]; exists {
|
||||
impClasses = append(impClasses, cls)
|
||||
} else {
|
||||
impNames = append(impNames, name)
|
||||
}
|
||||
classes = append(classes, j.clsMap[name])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
imports, err := j.importClasses(impNames, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cls := range j.clsMap {
|
||||
j.fillFuncSigs(cls.Funcs)
|
||||
j.fillFuncSigs(cls.Methods)
|
||||
for _, m := range cls.Methods {
|
||||
j.fillSuperSigs(cls, m)
|
||||
}
|
||||
impClasses = append(impClasses, imports...)
|
||||
j.initClasses(impClasses, refs)
|
||||
classes = append(classes, impClasses...)
|
||||
newClasses = impClasses
|
||||
}
|
||||
for _, cls := range j.clsMap {
|
||||
j.fillAllMethods(cls)
|
||||
}
|
||||
// Include classes that appear as ancestor types for overloaded signatures.
|
||||
for _, cls := range classes {
|
||||
for _, funcs := range [][]*FuncSet{cls.Funcs, cls.AllMethods} {
|
||||
for _, f := range funcs {
|
||||
for _, p := range f.Params {
|
||||
if p == nil || p.Kind != Object {
|
||||
continue
|
||||
}
|
||||
if _, exists := clsSet[p.Class]; !exists {
|
||||
clsSet[p.Class] = struct{}{}
|
||||
classes = append(classes, j.clsMap[p.Class])
|
||||
}
|
||||
}
|
||||
if t := f.Ret; t != nil && t.Kind == Object {
|
||||
if _, exists := clsSet[t.Class]; !exists {
|
||||
clsSet[t.Class] = struct{}{}
|
||||
classes = append(classes, j.clsMap[t.Class])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, cls := range classes {
|
||||
j.fillJNINames(cls.Funcs)
|
||||
j.fillJNINames(cls.AllMethods)
|
||||
}
|
||||
j.fillThrowables(classes)
|
||||
return classes, nil
|
||||
}
|
||||
|
||||
func (j *Importer) initClasses(classes []*Class, refs *importers.References) {
|
||||
for _, cls := range classes {
|
||||
j.fillAllMethods(cls)
|
||||
func (j *Importer) fillJNINames(funcs []*FuncSet) {
|
||||
for _, fs := range funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
f.JNIName = JNIMangle(f.Name)
|
||||
if len(fs.Funcs) > 1 {
|
||||
f.JNIName += "__" + JNIMangle(f.ArgDesc)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, cls := range classes {
|
||||
j.mangleOverloads(cls.AllMethods)
|
||||
j.mangleOverloads(cls.Funcs)
|
||||
}
|
||||
|
||||
// commonType finds the most specific type common to t1 and t2.
|
||||
// If t1 and t2 are both Java classes, the most specific ancestor
|
||||
// class is returned.
|
||||
// Else if the types are equal, their type is returned.
|
||||
// Finally, nil is returned, indicating no common type.
|
||||
func commonType(clsMap map[string]*Class, t1, t2 *Type) *Type {
|
||||
if t1 == nil || t2 == nil {
|
||||
return nil
|
||||
}
|
||||
if reflect.DeepEqual(t1, t2) {
|
||||
return t1
|
||||
}
|
||||
if t1.Kind != Object || t2.Kind != Object {
|
||||
// The types are fundamentally incompatible
|
||||
return nil
|
||||
}
|
||||
superSet := make(map[string]struct{})
|
||||
supers := []string{t1.Class}
|
||||
for len(supers) > 0 {
|
||||
var newSupers []string
|
||||
for _, s := range supers {
|
||||
cls := clsMap[s]
|
||||
superSet[s] = struct{}{}
|
||||
newSupers = append(newSupers, cls.Supers...)
|
||||
}
|
||||
supers = newSupers
|
||||
}
|
||||
supers = []string{t2.Class}
|
||||
for len(supers) > 0 {
|
||||
var newSupers []string
|
||||
for _, s := range supers {
|
||||
if _, exists := superSet[s]; exists {
|
||||
return &Type{Kind: Object, Class: s}
|
||||
}
|
||||
cls := clsMap[s]
|
||||
newSupers = append(newSupers, cls.Supers...)
|
||||
}
|
||||
supers = newSupers
|
||||
}
|
||||
return &Type{Kind: Object, Class: "java.lang.Object"}
|
||||
}
|
||||
|
||||
// combineSigs finds the most specific function signature
|
||||
// that covers all its overload variants.
|
||||
// If a function has only one variant, its common signature
|
||||
// is the signature of that variant.
|
||||
func combineSigs(clsMap map[string]*Class, sigs ...CommonSig) CommonSig {
|
||||
var common CommonSig
|
||||
minp := len(sigs[0].Params)
|
||||
for i := 1; i < len(sigs); i++ {
|
||||
sig := sigs[i]
|
||||
n := len(sig.Params)
|
||||
common.Variadic = common.Variadic || sig.Variadic || n != minp
|
||||
if n < minp {
|
||||
minp = n
|
||||
}
|
||||
}
|
||||
for i, sig := range sigs {
|
||||
for j, p := range sig.Params {
|
||||
idx := j
|
||||
// If the common signature is variadic, combine all parameters in the
|
||||
// last parameter type of the shortest parameter list.
|
||||
if idx > minp {
|
||||
idx = minp
|
||||
}
|
||||
if idx < len(common.Params) {
|
||||
common.Params[idx] = commonType(clsMap, common.Params[idx], p)
|
||||
} else {
|
||||
common.Params = append(common.Params, p)
|
||||
}
|
||||
}
|
||||
common.Throws = common.Throws || sig.Throws
|
||||
common.HasRet = common.HasRet || sig.HasRet
|
||||
if i > 0 {
|
||||
common.Ret = commonType(clsMap, common.Ret, sig.Ret)
|
||||
} else {
|
||||
common.Ret = sig.Ret
|
||||
}
|
||||
}
|
||||
return common
|
||||
}
|
||||
|
||||
// fillSuperSigs combines methods signatures with super class signatures,
|
||||
// to preserve the assignability of classes to their super classes.
|
||||
//
|
||||
// For example, the class
|
||||
//
|
||||
// class A {
|
||||
// void f();
|
||||
// }
|
||||
//
|
||||
// is by itself represented by the Go interface
|
||||
//
|
||||
// type A interface {
|
||||
// f()
|
||||
// }
|
||||
//
|
||||
// However, if class
|
||||
//
|
||||
// class B extends A {
|
||||
// void f(int);
|
||||
// }
|
||||
//
|
||||
// is also imported, it will be represented as
|
||||
//
|
||||
// type B interface {
|
||||
// f(...int32)
|
||||
// }
|
||||
//
|
||||
// To make Go B assignable to Go A, the signature of A's f must
|
||||
// be updated to f(...int32) as well.
|
||||
func (j *Importer) fillSuperSigs(cls *Class, m *FuncSet) {
|
||||
for _, s := range cls.Supers {
|
||||
sup := j.clsMap[s]
|
||||
if sm, exists := sup.methodMap[m.GoName]; exists {
|
||||
sm.CommonSig = combineSigs(j.clsMap, sm.CommonSig, m.CommonSig)
|
||||
}
|
||||
j.fillSuperSigs(sup, m)
|
||||
}
|
||||
j.filterReferences(classes, refs)
|
||||
}
|
||||
|
||||
func (v *Var) Constant() bool {
|
||||
|
@ -377,20 +565,11 @@ func (t *Type) JNICallType() string {
|
|||
}
|
||||
}
|
||||
|
||||
func (j *Importer) filterReferences(classes []*Class, refs *importers.References) {
|
||||
refFuncs := make(map[[2]string]struct{})
|
||||
for _, ref := range refs.Refs {
|
||||
pkgName := strings.Replace(ref.Pkg, "/", ".", -1)
|
||||
cls := j.clsMap[pkgName]
|
||||
if cls == nil {
|
||||
continue
|
||||
}
|
||||
refFuncs[[...]string{pkgName, ref.Name}] = struct{}{}
|
||||
}
|
||||
func (j *Importer) filterReferences(classes []*Class, refs *importers.References, funcRefs map[funcRef]struct{}) {
|
||||
for _, cls := range classes {
|
||||
var filtered []*Func
|
||||
var filtered []*FuncSet
|
||||
for _, f := range cls.Funcs {
|
||||
if _, exists := refFuncs[[...]string{cls.Name, f.GoName}]; exists {
|
||||
if _, exists := funcRefs[funcRef{cls.Name, f.GoName}]; exists {
|
||||
filtered = append(filtered, f)
|
||||
}
|
||||
}
|
||||
|
@ -402,16 +581,10 @@ func (j *Importer) filterReferences(classes []*Class, refs *importers.References
|
|||
}
|
||||
}
|
||||
cls.Methods = filtered
|
||||
filtered = nil
|
||||
for _, m := range cls.AllMethods {
|
||||
if _, exists := refs.Names[m.GoName]; exists {
|
||||
filtered = append(filtered, m)
|
||||
}
|
||||
}
|
||||
cls.AllMethods = filtered
|
||||
}
|
||||
}
|
||||
|
||||
// importClasses imports the named classes from the classpaths of the Importer.
|
||||
func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*Class, error) {
|
||||
if len(names) == 0 {
|
||||
return nil, nil
|
||||
|
@ -442,31 +615,54 @@ func (j *Importer) importClasses(names []string, allowMissingClasses bool) ([]*C
|
|||
for _, name := range names {
|
||||
cls, err := j.scanClass(s, name)
|
||||
if err != nil {
|
||||
if allowMissingClasses && err == errClsNotFound {
|
||||
if err == errClsNotFound && allowMissingClasses {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
if err == errClsNotFound && name != "android.databinding.DataBindingComponent" {
|
||||
return nil, err
|
||||
}
|
||||
// The Android Databinding library generates android.databinding.DataBindingComponent
|
||||
// too late in the build process for the gobind plugin to import it. Synthesize a class
|
||||
// for it instead.
|
||||
cls = &Class{
|
||||
Name: name,
|
||||
FindName: name,
|
||||
Interface: true,
|
||||
PkgName: "databinding",
|
||||
JNIName: JNIMangle(name),
|
||||
}
|
||||
}
|
||||
classes = append(classes, cls)
|
||||
j.clsMap[name] = cls
|
||||
}
|
||||
return classes, nil
|
||||
}
|
||||
|
||||
// importReferencedClasses imports all implicit classes (super types, parameter and
|
||||
// return types) for the given classes not already imported.
|
||||
func (j *Importer) importReferencedClasses(classes []*Class) ([]*Class, error) {
|
||||
var allCls []*Class
|
||||
// Include methods from extended or implemented classes.
|
||||
unkCls := classes
|
||||
for {
|
||||
var unknown []string
|
||||
for _, cls := range unkCls {
|
||||
unknown = j.unknownSuperClasses(cls, unknown)
|
||||
set := make(map[string]struct{})
|
||||
for _, cls := range classes {
|
||||
j.unknownImplicitClasses(cls, set)
|
||||
}
|
||||
if len(unknown) == 0 {
|
||||
if len(set) == 0 {
|
||||
break
|
||||
}
|
||||
newCls, err := j.importClasses(unknown, false)
|
||||
var names []string
|
||||
for n := range set {
|
||||
names = append(names, n)
|
||||
}
|
||||
newCls, err := j.importClasses(names, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unkCls = newCls
|
||||
allCls = append(allCls, newCls...)
|
||||
classes = newCls
|
||||
}
|
||||
return classes, nil
|
||||
return allCls, nil
|
||||
}
|
||||
|
||||
func (j *Importer) implicitFuncTypes(f *Func) []string {
|
||||
|
@ -482,21 +678,43 @@ func (j *Importer) implicitFuncTypes(f *Func) []string {
|
|||
return unk
|
||||
}
|
||||
|
||||
func (j *Importer) unknownSuperClasses(cls *Class, unk []string) []string {
|
||||
loop:
|
||||
for _, n := range cls.Supers {
|
||||
if s, exists := j.clsMap[n]; exists {
|
||||
unk = j.unknownSuperClasses(s, unk)
|
||||
} else {
|
||||
for _, u := range unk {
|
||||
if u == n {
|
||||
continue loop
|
||||
func (j *Importer) unknownImplicitClasses(cls *Class, set map[string]struct{}) {
|
||||
for _, fsets := range [][]*FuncSet{cls.Funcs, cls.Methods} {
|
||||
for _, fs := range fsets {
|
||||
for _, f := range fs.Funcs {
|
||||
names := j.implicitFuncTypes(f)
|
||||
for _, name := range names {
|
||||
if _, exists := j.clsMap[name]; !exists {
|
||||
set[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
unk = append(unk, n)
|
||||
}
|
||||
}
|
||||
return unk
|
||||
for _, n := range cls.Supers {
|
||||
if s, exists := j.clsMap[n]; exists {
|
||||
j.unknownImplicitClasses(s, set)
|
||||
} else {
|
||||
set[n] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Importer) implicitFuncClasses(funcs []*FuncSet, impl []string) []string {
|
||||
var l []string
|
||||
for _, fs := range funcs {
|
||||
for _, f := range fs.Funcs {
|
||||
if rt := f.Ret; rt != nil && rt.Kind == Object {
|
||||
l = append(l, rt.Class)
|
||||
}
|
||||
for _, t := range f.Params {
|
||||
if t.Kind == Object {
|
||||
l = append(l, t.Class)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return impl
|
||||
}
|
||||
|
||||
func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) {
|
||||
|
@ -522,13 +740,6 @@ func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cls.Supers) == 0 {
|
||||
if name == "java.lang.Object" {
|
||||
cls.HasNoArgCon = true
|
||||
} else if !cls.Interface {
|
||||
cls.Supers = append(cls.Supers, "java.lang.Object")
|
||||
}
|
||||
}
|
||||
cls.JNIName = JNIMangle(cls.Name)
|
||||
clsElems := strings.Split(cls.Name, ".")
|
||||
cls.PkgName = clsElems[len(clsElems)-1]
|
||||
|
@ -606,18 +817,37 @@ func (j *Importer) scanClass(s *bufio.Scanner, name string) (*Class, error) {
|
|||
}
|
||||
}
|
||||
for _, f := range funcs {
|
||||
var m map[string]*FuncSet
|
||||
var l *[]*FuncSet
|
||||
goName := initialUpper(f.Name)
|
||||
if f.Static || f.Constructor {
|
||||
cls.Funcs = append(cls.Funcs, f)
|
||||
m = cls.funcMap
|
||||
l = &cls.Funcs
|
||||
} else {
|
||||
cls.Methods = append(cls.Methods, f)
|
||||
m = cls.methodMap
|
||||
l = &cls.Methods
|
||||
}
|
||||
fs, exists := m[goName]
|
||||
if !exists {
|
||||
fs = &FuncSet{
|
||||
Name: f.Name,
|
||||
GoName: goName,
|
||||
}
|
||||
m[goName] = fs
|
||||
*l = append(*l, fs)
|
||||
}
|
||||
fs.Funcs = append(fs.Funcs, f)
|
||||
}
|
||||
return cls, nil
|
||||
}
|
||||
|
||||
func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) {
|
||||
isRoot := name == "java.lang.Object"
|
||||
cls := &Class{
|
||||
Name: name,
|
||||
Name: name,
|
||||
funcMap: make(map[string]*FuncSet),
|
||||
methodMap: make(map[string]*FuncSet),
|
||||
HasNoArgCon: isRoot,
|
||||
}
|
||||
const (
|
||||
stMod = iota
|
||||
|
@ -625,6 +855,7 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) {
|
|||
stExt
|
||||
stImpl
|
||||
)
|
||||
superClsDecl := isRoot
|
||||
st := stMod
|
||||
var w []byte
|
||||
// if > 0, we're inside a generics declaration
|
||||
|
@ -641,6 +872,9 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) {
|
|||
case '<':
|
||||
gennest++
|
||||
case '{':
|
||||
if !superClsDecl && !cls.Interface {
|
||||
cls.Supers = append(cls.Supers, "java.lang.Object")
|
||||
}
|
||||
return cls, nil
|
||||
case ' ', ',':
|
||||
if gennest > 0 {
|
||||
|
@ -655,6 +889,7 @@ func (j *Importer) scanClassDecl(name string, decl string) (*Class, error) {
|
|||
}
|
||||
cls.FindName = w
|
||||
case stExt:
|
||||
superClsDecl = true
|
||||
cls.Supers = append(cls.Supers, w)
|
||||
case stImpl:
|
||||
if !cls.Interface {
|
||||
|
@ -800,68 +1035,61 @@ func (j *Importer) fillThrowableFor(cls, thrCls *Class) {
|
|||
}
|
||||
}
|
||||
|
||||
func commonSig(f *Func) CommonSig {
|
||||
return CommonSig{
|
||||
Params: f.Params,
|
||||
Ret: f.Ret,
|
||||
HasRet: f.Ret != nil,
|
||||
Throws: f.Throws != "",
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Importer) fillFuncSigs(funcs []*FuncSet) {
|
||||
for _, fs := range funcs {
|
||||
var sigs []CommonSig
|
||||
for _, f := range fs.Funcs {
|
||||
sigs = append(sigs, commonSig(f))
|
||||
}
|
||||
fs.CommonSig = combineSigs(j.clsMap, sigs...)
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Importer) fillAllMethods(cls *Class) {
|
||||
if len(cls.AllMethods) > 0 {
|
||||
return
|
||||
}
|
||||
if len(cls.Supers) == 0 {
|
||||
cls.AllMethods = cls.Methods
|
||||
return
|
||||
}
|
||||
for _, supName := range cls.Supers {
|
||||
super := j.clsMap[supName]
|
||||
j.fillAllMethods(super)
|
||||
}
|
||||
methods := make(map[FuncSig]struct{})
|
||||
var fsets []*FuncSet
|
||||
fsets = append(fsets, cls.Methods...)
|
||||
for _, supName := range cls.Supers {
|
||||
super := j.clsMap[supName]
|
||||
for _, f := range super.AllMethods {
|
||||
if _, exists := methods[f.FuncSig]; !exists {
|
||||
methods[f.FuncSig] = struct{}{}
|
||||
cls.AllMethods = append(cls.AllMethods, f)
|
||||
fsets = append(fsets, super.AllMethods...)
|
||||
}
|
||||
sigs := make(map[FuncSig]struct{})
|
||||
methods := make(map[string]*FuncSet)
|
||||
for _, fs := range fsets {
|
||||
clsFs, exists := methods[fs.Name]
|
||||
if !exists {
|
||||
clsFs = &FuncSet{
|
||||
Name: fs.Name,
|
||||
GoName: fs.GoName,
|
||||
CommonSig: fs.CommonSig,
|
||||
}
|
||||
cls.AllMethods = append(cls.AllMethods, clsFs)
|
||||
methods[fs.Name] = clsFs
|
||||
} else {
|
||||
// Combine the (overloaded) signature with the other variants.
|
||||
clsFs.CommonSig = combineSigs(j.clsMap, clsFs.CommonSig, fs.CommonSig)
|
||||
}
|
||||
}
|
||||
for _, f := range cls.Methods {
|
||||
if _, exists := methods[f.FuncSig]; !exists {
|
||||
cls.AllMethods = append(cls.AllMethods, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mangleOverloads assigns unique names to overloaded Java functions by appending
|
||||
// the argument count. If multiple methods have the same name and argument count,
|
||||
// the method signature is appended in JNI mangled form.
|
||||
func (j *Importer) mangleOverloads(allFuncs []*Func) {
|
||||
overloads := make(map[string][]*Func)
|
||||
for i, f := range allFuncs {
|
||||
// Name mangling is per class so copy the function first.
|
||||
f := *f
|
||||
allFuncs[i] = &f
|
||||
overloads[f.Name] = append(overloads[f.Name], &f)
|
||||
}
|
||||
for _, funcs := range overloads {
|
||||
for _, f := range funcs {
|
||||
f.GoName = initialUpper(f.Name)
|
||||
f.JNIName = JNIMangle(f.Name)
|
||||
}
|
||||
if len(funcs) == 1 {
|
||||
continue
|
||||
}
|
||||
lengths := make(map[int]int)
|
||||
for _, f := range funcs {
|
||||
f.JNIName += "__" + JNIMangle(f.ArgDesc)
|
||||
lengths[len(f.Params)]++
|
||||
}
|
||||
for _, f := range funcs {
|
||||
n := len(f.Params)
|
||||
if lengths[n] > 1 {
|
||||
f.GoName += "_" + JNIMangle(f.ArgDesc)
|
||||
for _, f := range fs.Funcs {
|
||||
if _, exists := sigs[f.FuncSig]; exists {
|
||||
continue
|
||||
}
|
||||
if n > 0 {
|
||||
f.GoName = fmt.Sprintf("%s%d", f.GoName, n)
|
||||
}
|
||||
sigs[f.FuncSig] = struct{}{}
|
||||
clsFs.Funcs = append(clsFs.Funcs, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,32 @@ func TestImport(t *testing.T) {
|
|||
tests := []struct {
|
||||
ref importers.PkgRef
|
||||
name string
|
||||
methods []*Func
|
||||
methods []*FuncSet
|
||||
}{
|
||||
{
|
||||
ref: importers.PkgRef{"java/lang/Object", "equals"},
|
||||
name: "java.lang.Object",
|
||||
methods: []*Func{
|
||||
&Func{FuncSig: FuncSig{Name: "equals", Desc: "(Ljava/lang/Object;)Z"}, ArgDesc: "Ljava/lang/Object;", GoName: "Equals", JNIName: "equals", Public: true, Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}},
|
||||
methods: []*FuncSet{
|
||||
&FuncSet{
|
||||
Name: "equals",
|
||||
GoName: "Equals",
|
||||
CommonSig: CommonSig{
|
||||
Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}, HasRet: true,
|
||||
},
|
||||
Funcs: []*Func{&Func{FuncSig: FuncSig{Name: "equals", Desc: "(Ljava/lang/Object;)Z"}, ArgDesc: "Ljava/lang/Object;", JNIName: "equals", Public: true, Params: []*Type{&Type{Kind: Object, Class: "java.lang.Object"}}, Ret: &Type{Kind: Boolean}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ref: importers.PkgRef{"java/lang/Runnable", "run"},
|
||||
name: "java.lang.Runnable",
|
||||
methods: []*Func{
|
||||
&Func{FuncSig: FuncSig{Name: "run", Desc: "()V"}, ArgDesc: "", GoName: "Run", JNIName: "run", Public: true, Abstract: true},
|
||||
methods: []*FuncSet{
|
||||
&FuncSet{
|
||||
Name: "run",
|
||||
GoName: "Run",
|
||||
CommonSig: CommonSig{},
|
||||
Funcs: []*Func{&Func{FuncSig: FuncSig{Name: "run", Desc: "()V"}, ArgDesc: "", JNIName: "run", Public: true, Abstract: true}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -56,7 +68,7 @@ func TestImport(t *testing.T) {
|
|||
}
|
||||
loop:
|
||||
for _, exp := range test.methods {
|
||||
for _, got := range cls.Methods {
|
||||
for _, got := range cls.AllMethods {
|
||||
if reflect.DeepEqual(exp, got) {
|
||||
continue loop
|
||||
}
|
||||
|
@ -65,3 +77,118 @@ func TestImport(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testClsMap() map[string]*Class {
|
||||
//
|
||||
// A--
|
||||
// / \ \
|
||||
// B C \
|
||||
// \ / \ \
|
||||
// D E F
|
||||
//
|
||||
return map[string]*Class{
|
||||
"A": &Class{},
|
||||
"B": &Class{
|
||||
Supers: []string{"A"},
|
||||
},
|
||||
"C": &Class{
|
||||
Supers: []string{"A"},
|
||||
},
|
||||
"D": &Class{
|
||||
Supers: []string{"B", "C"},
|
||||
},
|
||||
"E": &Class{
|
||||
Supers: []string{"C"},
|
||||
},
|
||||
"F": &Class{
|
||||
Supers: []string{"A"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommonTypes(t *testing.T) {
|
||||
clsMap := testClsMap()
|
||||
tests := [][3]*Type{
|
||||
{nil, nil, nil},
|
||||
{&Type{Kind: Int}, nil, nil},
|
||||
{&Type{Kind: Int}, &Type{Kind: Float}, nil},
|
||||
{&Type{Kind: Int}, &Type{Kind: Int}, &Type{Kind: Int}},
|
||||
{&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "D"}},
|
||||
{&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "E"}, &Type{Kind: Object, Class: "C"}},
|
||||
{&Type{Kind: Object, Class: "D"}, &Type{Kind: Object, Class: "F"}, &Type{Kind: Object, Class: "A"}},
|
||||
{&Type{Kind: Object, Class: "B"}, &Type{Kind: Object, Class: "E"}, &Type{Kind: Object, Class: "A"}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t1, t2, exp := test[0], test[1], test[2]
|
||||
got := commonType(clsMap, t1, t2)
|
||||
if !reflect.DeepEqual(got, exp) {
|
||||
t.Errorf("commonType(%+v, %+v) = %+v, expected %+v", t1, t2, got, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommonSig(t *testing.T) {
|
||||
tests := []struct {
|
||||
Sigs []CommonSig
|
||||
CommonSig
|
||||
}{
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{}, // f()
|
||||
},
|
||||
CommonSig: CommonSig{}, // f()
|
||||
},
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{Throws: true, HasRet: true, Ret: &Type{Kind: Int}}, // int f() throws
|
||||
},
|
||||
// int f() throws
|
||||
CommonSig: CommonSig{Throws: true, HasRet: true, Ret: &Type{Kind: Int}},
|
||||
},
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{}, // f()
|
||||
CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int)
|
||||
},
|
||||
CommonSig: CommonSig{ // f(int...)
|
||||
Variadic: true,
|
||||
Params: []*Type{&Type{Kind: Int}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int)
|
||||
CommonSig{Params: []*Type{&Type{Kind: Float}}}, // f(float)
|
||||
},
|
||||
CommonSig: CommonSig{ // f(interface{})
|
||||
Params: []*Type{nil},
|
||||
},
|
||||
},
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{Params: []*Type{&Type{Kind: Int}}}, // f(int)
|
||||
CommonSig{Params: []*Type{&Type{Kind: Int}, &Type{Kind: Int}}}, // f(int, int)
|
||||
},
|
||||
CommonSig: CommonSig{ // f(int, int...)
|
||||
Variadic: true,
|
||||
Params: []*Type{&Type{Kind: Int}, &Type{Kind: Int}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Sigs: []CommonSig{
|
||||
CommonSig{Params: []*Type{&Type{Kind: Object, Class: "A"}}}, // f(A)
|
||||
CommonSig{Params: []*Type{&Type{Kind: Object, Class: "B"}}}, // f(B)
|
||||
},
|
||||
CommonSig: CommonSig{ // f(A)
|
||||
Params: []*Type{&Type{Kind: Object, Class: "A"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
clsMap := testClsMap()
|
||||
for _, test := range tests {
|
||||
got := combineSigs(clsMap, test.Sigs...)
|
||||
if !reflect.DeepEqual(got, test.CommonSig) {
|
||||
t.Errorf("commonSig(%+v) = %+v, expected %+v", test.Sigs, got, test.CommonSig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue