github.com/danbrough/mobile@v0.0.3-beta03/bind/genjava.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package bind
     6  
     7  import (
     8  	"fmt"
     9  	"go/constant"
    10  	"go/types"
    11  	"html"
    12  	"math"
    13  	"reflect"
    14  	"regexp"
    15  	"strings"
    16  
    17  	"github.com/danbrough/mobile/internal/importers/java"
    18  )
    19  
    20  // TODO(crawshaw): disallow basic android java type names in exported symbols.
    21  // TODO(crawshaw): consider introducing Java functions for casting to and from interfaces at runtime.
    22  
    23  type JavaGen struct {
    24  	// JavaPkg is the Java package prefix for the generated classes. The prefix is prepended to the Go
    25  	// package name to create the full Java package name.
    26  	JavaPkg string
    27  
    28  	*Generator
    29  
    30  	jstructs map[*types.TypeName]*javaClassInfo
    31  	clsMap   map[string]*java.Class
    32  	// Constructors is a map from Go struct types to a list
    33  	// of exported constructor functions for the type, on the form
    34  	// func New<Type>(...) *Type
    35  	constructors map[*types.TypeName][]*types.Func
    36  }
    37  
    38  type javaClassInfo struct {
    39  	// The Java class this class extends.
    40  	extends *java.Class
    41  	// All Java classes and interfaces this class extends and implements.
    42  	supers  []*java.Class
    43  	methods map[string]*java.FuncSet
    44  	// Does the class need a default no-arg constructor
    45  	genNoargCon bool
    46  }
    47  
    48  // Init intializes the embedded Generator and initializes the Java class information
    49  // needed to generate structs that extend Java classes and interfaces.
    50  func (g *JavaGen) Init(classes []*java.Class) {
    51  	g.Generator.Init()
    52  	g.clsMap = make(map[string]*java.Class)
    53  	for _, cls := range classes {
    54  		g.clsMap[cls.Name] = cls
    55  	}
    56  	g.jstructs = make(map[*types.TypeName]*javaClassInfo)
    57  	g.constructors = make(map[*types.TypeName][]*types.Func)
    58  	for _, s := range g.structs {
    59  		classes := embeddedJavaClasses(s.t)
    60  		if len(classes) == 0 {
    61  			continue
    62  		}
    63  		inf := &javaClassInfo{
    64  			methods:     make(map[string]*java.FuncSet),
    65  			genNoargCon: true, // java.lang.Object has a no-arg constructor
    66  		}
    67  		for _, n := range classes {
    68  			cls := g.clsMap[n]
    69  			for _, fs := range cls.AllMethods {
    70  				hasMeth := false
    71  				for _, f := range fs.Funcs {
    72  					if !f.Final {
    73  						hasMeth = true
    74  					}
    75  				}
    76  				if hasMeth {
    77  					inf.methods[fs.GoName] = fs
    78  				}
    79  			}
    80  			inf.supers = append(inf.supers, cls)
    81  			if !cls.Interface {
    82  				if inf.extends != nil {
    83  					g.errorf("%s embeds more than one Java class; only one is allowed.", s.obj)
    84  				}
    85  				if cls.Final {
    86  					g.errorf("%s embeds final Java class %s", s.obj, cls.Name)
    87  				}
    88  				inf.extends = cls
    89  				inf.genNoargCon = cls.HasNoArgCon
    90  			}
    91  		}
    92  		g.jstructs[s.obj] = inf
    93  	}
    94  	for _, f := range g.funcs {
    95  		if t := g.constructorType(f); t != nil {
    96  			jinf := g.jstructs[t]
    97  			if jinf != nil {
    98  				sig := f.Type().(*types.Signature)
    99  				jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0
   100  			}
   101  			g.constructors[t] = append(g.constructors[t], f)
   102  		}
   103  	}
   104  }
   105  
   106  func (j *javaClassInfo) toJavaType(T types.Type) *java.Type {
   107  	switch T := T.(type) {
   108  	case *types.Basic:
   109  		var kind java.TypeKind
   110  		switch T.Kind() {
   111  		case types.Bool, types.UntypedBool:
   112  			kind = java.Boolean
   113  		case types.Uint8:
   114  			kind = java.Byte
   115  		case types.Int16:
   116  			kind = java.Short
   117  		case types.Int32, types.UntypedRune: // types.Rune
   118  			kind = java.Int
   119  		case types.Int64, types.UntypedInt:
   120  			kind = java.Long
   121  		case types.Float32:
   122  			kind = java.Float
   123  		case types.Float64, types.UntypedFloat:
   124  			kind = java.Double
   125  		case types.String, types.UntypedString:
   126  			kind = java.String
   127  		default:
   128  			return nil
   129  		}
   130  		return &java.Type{Kind: kind}
   131  	case *types.Slice:
   132  		switch e := T.Elem().(type) {
   133  		case *types.Basic:
   134  			switch e.Kind() {
   135  			case types.Uint8: // Byte.
   136  				return &java.Type{Kind: java.Array, Elem: &java.Type{Kind: java.Byte}}
   137  			}
   138  		}
   139  		return nil
   140  	case *types.Named:
   141  		if isJavaType(T) {
   142  			return &java.Type{Kind: java.Object, Class: classNameFor(T)}
   143  		}
   144  	}
   145  	return nil
   146  }
   147  
   148  // lookupMethod searches the Java class descriptor for a method
   149  // that matches the Go method.
   150  func (j *javaClassInfo) lookupMethod(m *types.Func, hasThis bool) *java.Func {
   151  	jm := j.methods[m.Name()]
   152  	if jm == nil {
   153  		// If an exact match is not found, try the method with trailing underscores
   154  		// stripped. This way, name clashes can be avoided when overriding multiple
   155  		// overloaded methods from Go.
   156  		base := strings.TrimRight(m.Name(), "_")
   157  		jm = j.methods[base]
   158  		if jm == nil {
   159  			return nil
   160  		}
   161  	}
   162  	// A name match was found. Now use the parameter and return types to locate
   163  	// the correct variant.
   164  	sig := m.Type().(*types.Signature)
   165  	params := sig.Params()
   166  	// Convert Go parameter types to their Java counterparts, if possible.
   167  	var jparams []*java.Type
   168  	i := 0
   169  	if hasThis {
   170  		i = 1
   171  	}
   172  	for ; i < params.Len(); i++ {
   173  		jparams = append(jparams, j.toJavaType(params.At(i).Type()))
   174  	}
   175  	var ret *java.Type
   176  	var throws bool
   177  	if results := sig.Results(); results.Len() > 0 {
   178  		ret = j.toJavaType(results.At(0).Type())
   179  		if results.Len() > 1 {
   180  			throws = isErrorType(results.At(1).Type())
   181  		}
   182  	}
   183  loop:
   184  	for _, f := range jm.Funcs {
   185  		if len(f.Params) != len(jparams) {
   186  			continue
   187  		}
   188  		if throws != (f.Throws != "") {
   189  			continue
   190  		}
   191  		if !reflect.DeepEqual(ret, f.Ret) {
   192  			continue
   193  		}
   194  		for i, p := range f.Params {
   195  			if !reflect.DeepEqual(p, jparams[i]) {
   196  				continue loop
   197  			}
   198  		}
   199  		return f
   200  	}
   201  	return nil
   202  }
   203  
   204  // ClassNames returns the list of names of the generated Java classes and interfaces.
   205  func (g *JavaGen) ClassNames() []string {
   206  	var names []string
   207  	for _, s := range g.structs {
   208  		names = append(names, g.javaTypeName(s.obj.Name()))
   209  	}
   210  	for _, iface := range g.interfaces {
   211  		names = append(names, g.javaTypeName(iface.obj.Name()))
   212  	}
   213  	return names
   214  }
   215  
   216  func (g *JavaGen) GenClass(idx int) error {
   217  	ns := len(g.structs)
   218  	if idx < ns {
   219  		s := g.structs[idx]
   220  		g.genStruct(s)
   221  	} else {
   222  		iface := g.interfaces[idx-ns]
   223  		g.genInterface(iface)
   224  	}
   225  	if len(g.err) > 0 {
   226  		return g.err
   227  	}
   228  	return nil
   229  }
   230  
   231  func (g *JavaGen) genProxyImpl(name string) {
   232  	g.Printf("private final int refnum;\n\n")
   233  	g.Printf("@Override public final int incRefnum() {\n")
   234  	g.Printf("      Seq.incGoRef(refnum, this);\n")
   235  	g.Printf("      return refnum;\n")
   236  	g.Printf("}\n\n")
   237  }
   238  
   239  func (g *JavaGen) genStruct(s structInfo) {
   240  	pkgPath := ""
   241  	if g.Pkg != nil {
   242  		pkgPath = g.Pkg.Path()
   243  	}
   244  	n := g.javaTypeName(s.obj.Name())
   245  	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), n, g.gobindOpts(), pkgPath)
   246  
   247  	fields := exportedFields(s.t)
   248  	methods := exportedMethodSet(types.NewPointer(s.obj.Type()))
   249  
   250  	var impls []string
   251  	jinf := g.jstructs[s.obj]
   252  	if jinf != nil {
   253  		impls = append(impls, "Seq.GoObject")
   254  		for _, cls := range jinf.supers {
   255  			if cls.Interface {
   256  				impls = append(impls, g.javaTypeName(cls.Name))
   257  			}
   258  		}
   259  	} else {
   260  		impls = append(impls, "Seq.Proxy")
   261  	}
   262  
   263  	pT := types.NewPointer(s.obj.Type())
   264  	for _, iface := range g.allIntf {
   265  		if types.AssignableTo(pT, iface.obj.Type()) {
   266  			n := iface.obj.Name()
   267  			if p := iface.obj.Pkg(); p != g.Pkg {
   268  				if n == JavaClassName(p) {
   269  					n = n + "_"
   270  				}
   271  				n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
   272  			} else {
   273  				n = g.javaTypeName(n)
   274  			}
   275  			impls = append(impls, n)
   276  		}
   277  	}
   278  
   279  	doc := g.docs[n]
   280  	//g.javadoc(doc.Doc())
   281  	g.javadoc(strings.ReplaceAll(doc.Doc(), "*", "(star)"))
   282  	g.Printf("public final class %s", n)
   283  	if jinf != nil {
   284  		if jinf.extends != nil {
   285  			g.Printf(" extends %s", g.javaTypeName(jinf.extends.Name))
   286  		}
   287  	}
   288  	if len(impls) > 0 {
   289  		g.Printf(" implements %s", strings.Join(impls, ", "))
   290  	}
   291  	g.Printf(" {\n")
   292  	g.Indent()
   293  
   294  	g.Printf("static { %s.touch(); }\n\n", g.className())
   295  	g.genProxyImpl(n)
   296  	cons := g.constructors[s.obj]
   297  	for _, f := range cons {
   298  		if !g.isConsSigSupported(f.Type()) {
   299  			g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name())
   300  			continue
   301  		}
   302  		g.genConstructor(f, n, jinf != nil)
   303  	}
   304  	if jinf == nil || jinf.genNoargCon {
   305  		// constructor for Go instantiated instances.
   306  		g.Printf("%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n)
   307  		if len(cons) == 0 {
   308  			// Generate default no-arg constructor
   309  			g.Printf("public %s() { this.refnum = __New(); Seq.trackGoRef(refnum, this); }\n\n", n)
   310  			g.Printf("private static native int __New();\n\n")
   311  		}
   312  	}
   313  
   314  	for _, f := range fields {
   315  		if t := f.Type(); !g.isSupported(t) {
   316  			g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t)
   317  			continue
   318  		}
   319  
   320  		fdoc := doc.Member(f.Name())
   321  		g.javadoc(fdoc)
   322  		g.Printf("public final native %s get%s();\n", g.javaType(f.Type()), f.Name())
   323  		g.javadoc(fdoc)
   324  		g.Printf("public final native void set%s(%s v);\n\n", f.Name(), g.javaType(f.Type()))
   325  	}
   326  
   327  	var isStringer bool
   328  	for _, m := range methods {
   329  		if !g.isSigSupported(m.Type()) {
   330  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name())
   331  			continue
   332  		}
   333  		g.javadoc(doc.Member(m.Name()))
   334  		var jm *java.Func
   335  		hasThis := false
   336  		if jinf != nil {
   337  			hasThis = g.hasThis(n, m)
   338  			jm = jinf.lookupMethod(m, hasThis)
   339  			if jm != nil {
   340  				g.Printf("@Override ")
   341  			}
   342  		}
   343  		g.Printf("public native ")
   344  		g.genFuncSignature(m, jm, hasThis)
   345  		t := m.Type().(*types.Signature)
   346  		isStringer = isStringer || (m.Name() == "String" && t.Params().Len() == 0 && t.Results().Len() == 1 &&
   347  			types.Identical(t.Results().At(0).Type(), types.Typ[types.String]))
   348  	}
   349  
   350  	if jinf == nil {
   351  		g.genObjectMethods(n, fields, isStringer)
   352  	}
   353  
   354  	g.Outdent()
   355  	g.Printf("}\n\n")
   356  }
   357  
   358  // isConsSigSupported reports whether the generators can handle a given
   359  // constructor signature.
   360  func (g *JavaGen) isConsSigSupported(t types.Type) bool {
   361  	if !g.isSigSupported(t) {
   362  		return false
   363  	}
   364  	// Skip constructors taking a single int32 argument
   365  	// since they clash with the proxy constructors that
   366  	// take a refnum.
   367  	params := t.(*types.Signature).Params()
   368  	if params.Len() != 1 {
   369  		return true
   370  	}
   371  	if t, ok := params.At(0).Type().(*types.Basic); ok {
   372  		switch t.Kind() {
   373  		case types.Int32, types.Uint32:
   374  			return false
   375  		}
   376  	}
   377  	return true
   378  }
   379  
   380  // javaTypeName returns the class name of a given Go type name. If
   381  // the type name clashes with the package class name, an underscore is
   382  // appended.
   383  func (g *JavaGen) javaTypeName(n string) string {
   384  	if n == JavaClassName(g.Pkg) {
   385  		return n + "_"
   386  	}
   387  	return n
   388  }
   389  
   390  func (g *JavaGen) javadoc(doc string) {
   391  	if doc == "" {
   392  		return
   393  	}
   394  	// JavaDoc expects HTML-escaped documentation.
   395  	g.Printf("/**\n * %s */\n", html.EscapeString(doc))
   396  }
   397  
   398  // hasThis reports whether a method has an implicit "this" parameter.
   399  func (g *JavaGen) hasThis(sName string, m *types.Func) bool {
   400  	sig := m.Type().(*types.Signature)
   401  	params := sig.Params()
   402  	if params.Len() == 0 {
   403  		return false
   404  	}
   405  	v := params.At(0)
   406  	if v.Name() != "this" {
   407  		return false
   408  	}
   409  	t, ok := v.Type().(*types.Named)
   410  	if !ok {
   411  		return false
   412  	}
   413  	obj := t.Obj()
   414  	pkg := obj.Pkg()
   415  	if pkgFirstElem(pkg) != "Java" {
   416  		return false
   417  	}
   418  	clsName := classNameFor(t)
   419  	exp := g.javaPkgName(g.Pkg) + "." + sName
   420  	if clsName != exp {
   421  		g.errorf("the type %s of the `this` argument to method %s.%s is not %s", clsName, sName, m.Name(), exp)
   422  		return false
   423  	}
   424  	return true
   425  }
   426  
   427  func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) {
   428  	g.javadoc(g.docs[f.Name()].Doc())
   429  	g.Printf("public %s(", n)
   430  	g.genFuncArgs(f, nil, false)
   431  	g.Printf(") {\n")
   432  	g.Indent()
   433  	sig := f.Type().(*types.Signature)
   434  	params := sig.Params()
   435  	if jcls {
   436  		g.Printf("super(")
   437  		for i := 0; i < params.Len(); i++ {
   438  			if i > 0 {
   439  				g.Printf(", ")
   440  			}
   441  			g.Printf(g.paramName(params, i))
   442  		}
   443  		g.Printf(");\n")
   444  	}
   445  	g.Printf("this.refnum = ")
   446  	g.Printf("__%s(", f.Name())
   447  	for i := 0; i < params.Len(); i++ {
   448  		if i > 0 {
   449  			g.Printf(", ")
   450  		}
   451  		g.Printf(g.paramName(params, i))
   452  	}
   453  	g.Printf(");\n")
   454  	g.Printf("Seq.trackGoRef(refnum, this);\n")
   455  	g.Outdent()
   456  	g.Printf("}\n\n")
   457  	g.Printf("private static native int __%s(", f.Name())
   458  	g.genFuncArgs(f, nil, false)
   459  	g.Printf(");\n\n")
   460  }
   461  
   462  // genFuncArgs generated Java function arguments declaration for the function f.
   463  // If the supplied overridden java function is supplied, genFuncArgs omits the implicit
   464  // this argument.
   465  func (g *JavaGen) genFuncArgs(f *types.Func, jm *java.Func, hasThis bool) {
   466  	sig := f.Type().(*types.Signature)
   467  	params := sig.Params()
   468  	first := 0
   469  	if hasThis {
   470  		// Skip the implicit this argument to the Go method
   471  		first = 1
   472  	}
   473  	for i := first; i < params.Len(); i++ {
   474  		if i > first {
   475  			g.Printf(", ")
   476  		}
   477  		v := params.At(i)
   478  		name := g.paramName(params, i)
   479  		jt := g.javaType(v.Type())
   480  		g.Printf("%s %s", jt, name)
   481  	}
   482  }
   483  
   484  func (g *JavaGen) genObjectMethods(n string, fields []*types.Var, isStringer bool) {
   485  	g.Printf("@Override public boolean equals(Object o) {\n")
   486  	g.Indent()
   487  	g.Printf("if (o == null || !(o instanceof %s)) {\n    return false;\n}\n", n)
   488  	g.Printf("%s that = (%s)o;\n", n, n)
   489  	for _, f := range fields {
   490  		if t := f.Type(); !g.isSupported(t) {
   491  			g.Printf("// skipped field %s.%s with unsupported type: %s\n\n", n, f.Name(), t)
   492  			continue
   493  		}
   494  		nf := f.Name()
   495  		g.Printf("%s this%s = get%s();\n", g.javaType(f.Type()), nf, nf)
   496  		g.Printf("%s that%s = that.get%s();\n", g.javaType(f.Type()), nf, nf)
   497  		if isJavaPrimitive(f.Type()) {
   498  			g.Printf("if (this%s != that%s) {\n    return false;\n}\n", nf, nf)
   499  		} else {
   500  			g.Printf("if (this%s == null) {\n", nf)
   501  			g.Indent()
   502  			g.Printf("if (that%s != null) {\n    return false;\n}\n", nf)
   503  			g.Outdent()
   504  			g.Printf("} else if (!this%s.equals(that%s)) {\n    return false;\n}\n", nf, nf)
   505  		}
   506  	}
   507  	g.Printf("return true;\n")
   508  	g.Outdent()
   509  	g.Printf("}\n\n")
   510  
   511  	g.Printf("@Override public int hashCode() {\n")
   512  	g.Printf("    return java.util.Arrays.hashCode(new Object[] {")
   513  	idx := 0
   514  	for _, f := range fields {
   515  		if t := f.Type(); !g.isSupported(t) {
   516  			continue
   517  		}
   518  		if idx > 0 {
   519  			g.Printf(", ")
   520  		}
   521  		idx++
   522  		g.Printf("get%s()", f.Name())
   523  	}
   524  	g.Printf("});\n")
   525  	g.Printf("}\n\n")
   526  
   527  	g.Printf("@Override public String toString() {\n")
   528  	g.Indent()
   529  	if isStringer {
   530  		g.Printf("return string();\n")
   531  	} else {
   532  		g.Printf("StringBuilder b = new StringBuilder();\n")
   533  		g.Printf(`b.append("%s").append("{");`, n)
   534  		g.Printf("\n")
   535  		for _, f := range fields {
   536  			if t := f.Type(); !g.isSupported(t) {
   537  				continue
   538  			}
   539  			n := f.Name()
   540  			g.Printf(`b.append("%s:").append(get%s()).append(",");`, n, n)
   541  			g.Printf("\n")
   542  		}
   543  		g.Printf(`return b.append("}").toString();`)
   544  		g.Printf("\n")
   545  	}
   546  	g.Outdent()
   547  	g.Printf("}\n")
   548  }
   549  
   550  func (g *JavaGen) genInterface(iface interfaceInfo) {
   551  	pkgPath := ""
   552  	if g.Pkg != nil {
   553  		pkgPath = g.Pkg.Path()
   554  	}
   555  	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.javaTypeName(iface.obj.Name()), g.gobindOpts(), pkgPath)
   556  
   557  	var exts []string
   558  	numM := iface.t.NumMethods()
   559  	for _, other := range g.allIntf {
   560  		// Only extend interfaces with fewer methods to avoid circular references
   561  		if other.t.NumMethods() < numM && types.AssignableTo(iface.t, other.t) {
   562  			n := other.obj.Name()
   563  			if p := other.obj.Pkg(); p != g.Pkg {
   564  				if n == JavaClassName(p) {
   565  					n = n + "_"
   566  				}
   567  				n = fmt.Sprintf("%s.%s", g.javaPkgName(p), n)
   568  			} else {
   569  				n = g.javaTypeName(n)
   570  			}
   571  			exts = append(exts, n)
   572  		}
   573  	}
   574  	doc := g.docs[iface.obj.Name()]
   575  	g.javadoc(doc.Doc())
   576  	g.Printf("public interface %s", g.javaTypeName(iface.obj.Name()))
   577  	if len(exts) > 0 {
   578  		g.Printf(" extends %s", strings.Join(exts, ", "))
   579  	}
   580  	g.Printf(" {\n")
   581  	g.Indent()
   582  
   583  	for _, m := range iface.summary.callable {
   584  		if !g.isSigSupported(m.Type()) {
   585  			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
   586  			continue
   587  		}
   588  		g.javadoc(doc.Member(m.Name()))
   589  		g.Printf("public ")
   590  		g.genFuncSignature(m, nil, false)
   591  	}
   592  
   593  	g.Printf("\n")
   594  
   595  	g.Outdent()
   596  	g.Printf("}\n\n")
   597  }
   598  
   599  func isJavaPrimitive(T types.Type) bool {
   600  	b, ok := T.(*types.Basic)
   601  	if !ok {
   602  		return false
   603  	}
   604  	switch b.Kind() {
   605  	case types.Bool, types.Uint8, types.Float32, types.Float64,
   606  		types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
   607  		return true
   608  	}
   609  	return false
   610  }
   611  
   612  // jniType returns a string that can be used as a JNI type.
   613  func (g *JavaGen) jniType(T types.Type) string {
   614  	switch T := T.(type) {
   615  	case *types.Basic:
   616  		switch T.Kind() {
   617  		case types.Bool, types.UntypedBool:
   618  			return "jboolean"
   619  		case types.Int:
   620  			return "jlong"
   621  		case types.Int8:
   622  			return "jbyte"
   623  		case types.Int16:
   624  			return "jshort"
   625  		case types.Int32, types.UntypedRune: // types.Rune
   626  			return "jint"
   627  		case types.Int64, types.UntypedInt:
   628  			return "jlong"
   629  		case types.Uint8: // types.Byte
   630  			// TODO(crawshaw): Java bytes are signed, so this is
   631  			// questionable, but vital.
   632  			return "jbyte"
   633  		// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
   634  		case types.Float32:
   635  			return "jfloat"
   636  		case types.Float64, types.UntypedFloat:
   637  			return "jdouble"
   638  		case types.String, types.UntypedString:
   639  			return "jstring"
   640  		default:
   641  			g.errorf("unsupported basic type: %s", T)
   642  			return "TODO"
   643  		}
   644  	case *types.Slice:
   645  		return "jbyteArray"
   646  
   647  	case *types.Pointer:
   648  		if _, ok := T.Elem().(*types.Named); ok {
   649  			return g.jniType(T.Elem())
   650  		}
   651  		g.errorf("unsupported pointer to type: %s", T)
   652  	case *types.Named:
   653  		return "jobject"
   654  	default:
   655  		g.errorf("unsupported jniType: %#+v, %s\n", T, T)
   656  	}
   657  	return "TODO"
   658  }
   659  
   660  func (g *JavaGen) javaBasicType(T *types.Basic) string {
   661  	switch T.Kind() {
   662  	case types.Bool, types.UntypedBool:
   663  		return "boolean"
   664  	case types.Int:
   665  		return "long"
   666  	case types.Int8:
   667  		return "byte"
   668  	case types.Int16:
   669  		return "short"
   670  	case types.Int32, types.UntypedRune: // types.Rune
   671  		return "int"
   672  	case types.Int64, types.UntypedInt:
   673  		return "long"
   674  	case types.Uint8: // types.Byte
   675  		// TODO(crawshaw): Java bytes are signed, so this is
   676  		// questionable, but vital.
   677  		return "byte"
   678  	// TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64:
   679  	case types.Float32:
   680  		return "float"
   681  	case types.Float64, types.UntypedFloat:
   682  		return "double"
   683  	case types.String, types.UntypedString:
   684  		return "String"
   685  	default:
   686  		g.errorf("unsupported basic type: %s", T)
   687  		return "TODO"
   688  	}
   689  }
   690  
   691  // javaType returns a string that can be used as a Java type.
   692  func (g *JavaGen) javaType(T types.Type) string {
   693  	if isErrorType(T) {
   694  		// The error type is usually translated into an exception in
   695  		// Java, however the type can be exposed in other ways, such
   696  		// as an exported field.
   697  		return "java.lang.Exception"
   698  	} else if isJavaType(T) {
   699  		return classNameFor(T)
   700  	}
   701  	switch T := T.(type) {
   702  	case *types.Basic:
   703  		return g.javaBasicType(T)
   704  	case *types.Slice:
   705  		elem := g.javaType(T.Elem())
   706  		return elem + "[]"
   707  
   708  	case *types.Pointer:
   709  		if _, ok := T.Elem().(*types.Named); ok {
   710  			return g.javaType(T.Elem())
   711  		}
   712  		g.errorf("unsupported pointer to type: %s", T)
   713  	case *types.Named:
   714  		n := T.Obj()
   715  		nPkg := n.Pkg()
   716  		if !isErrorType(T) && !g.validPkg(nPkg) {
   717  			g.errorf("type %s is in %s, which is not bound", n.Name(), nPkg)
   718  			break
   719  		}
   720  		// TODO(crawshaw): more checking here
   721  		clsName := n.Name()
   722  		if nPkg != g.Pkg {
   723  			if clsName == JavaClassName(nPkg) {
   724  				clsName += "_"
   725  			}
   726  			return fmt.Sprintf("%s.%s", g.javaPkgName(nPkg), clsName)
   727  		} else {
   728  			return g.javaTypeName(clsName)
   729  		}
   730  	default:
   731  		g.errorf("unsupported javaType: %#+v, %s\n", T, T)
   732  	}
   733  	return "TODO"
   734  }
   735  
   736  func (g *JavaGen) genJNIFuncSignature(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) {
   737  	sig := o.Type().(*types.Signature)
   738  	res := sig.Results()
   739  
   740  	var ret string
   741  	switch res.Len() {
   742  	case 2:
   743  		ret = g.jniType(res.At(0).Type())
   744  	case 1:
   745  		if isErrorType(res.At(0).Type()) {
   746  			ret = "void"
   747  		} else {
   748  			ret = g.jniType(res.At(0).Type())
   749  		}
   750  	case 0:
   751  		ret = "void"
   752  	default:
   753  		g.errorf("too many result values: %s", o)
   754  		return
   755  	}
   756  
   757  	g.Printf("JNIEXPORT %s JNICALL\n", ret)
   758  	g.Printf("Java_%s_", g.jniPkgName())
   759  	if sName != "" {
   760  		if proxy {
   761  			g.Printf(java.JNIMangle(g.className()))
   762  			// 0024 is the mangled form of $, for naming inner classes.
   763  			g.Printf("_00024proxy%s", sName)
   764  		} else {
   765  			g.Printf(java.JNIMangle(g.javaTypeName(sName)))
   766  		}
   767  	} else {
   768  		g.Printf(java.JNIMangle(g.className()))
   769  	}
   770  	g.Printf("_")
   771  	if jm != nil {
   772  		g.Printf(jm.JNIName)
   773  	} else {
   774  		oName := javaNameReplacer(lowerFirst(o.Name()))
   775  		g.Printf(java.JNIMangle(oName))
   776  	}
   777  	g.Printf("(JNIEnv* env, ")
   778  	if sName != "" {
   779  		g.Printf("jobject __this__")
   780  	} else {
   781  		g.Printf("jclass _clazz")
   782  	}
   783  	params := sig.Params()
   784  	i := 0
   785  	if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
   786  		// Skip the implicit this argument, if any.
   787  		i = 1
   788  	}
   789  	for ; i < params.Len(); i++ {
   790  		g.Printf(", ")
   791  		v := sig.Params().At(i)
   792  		name := g.paramName(params, i)
   793  		jt := g.jniType(v.Type())
   794  		g.Printf("%s %s", jt, name)
   795  	}
   796  	g.Printf(")")
   797  }
   798  
   799  func (g *JavaGen) jniPkgName() string {
   800  	return strings.Replace(java.JNIMangle(g.javaPkgName(g.Pkg)), ".", "_", -1)
   801  }
   802  
   803  var javaLetterDigitRE = regexp.MustCompile(`[0-9a-zA-Z$_]`)
   804  
   805  func (g *JavaGen) paramName(params *types.Tuple, pos int) string {
   806  	name := basicParamName(params, pos)
   807  	if !javaLetterDigitRE.MatchString(name) {
   808  		name = fmt.Sprintf("p%d", pos)
   809  	}
   810  	return javaNameReplacer(name)
   811  }
   812  
   813  func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) {
   814  	sig := o.Type().(*types.Signature)
   815  	res := sig.Results()
   816  
   817  	var returnsError bool
   818  	var ret string
   819  	switch res.Len() {
   820  	case 2:
   821  		if !isErrorType(res.At(1).Type()) {
   822  			g.errorf("second result value must be of type error: %s", o)
   823  			return
   824  		}
   825  		returnsError = true
   826  		ret = g.javaType(res.At(0).Type())
   827  	case 1:
   828  		if isErrorType(res.At(0).Type()) {
   829  			returnsError = true
   830  			ret = "void"
   831  		} else {
   832  			ret = g.javaType(res.At(0).Type())
   833  		}
   834  	case 0:
   835  		ret = "void"
   836  	default:
   837  		g.errorf("too many result values: %s", o)
   838  		return
   839  	}
   840  
   841  	g.Printf("%s ", ret)
   842  	if jm != nil {
   843  		g.Printf(jm.Name)
   844  	} else {
   845  		g.Printf(javaNameReplacer(lowerFirst(o.Name())))
   846  	}
   847  	g.Printf("(")
   848  	g.genFuncArgs(o, jm, hasThis)
   849  	g.Printf(")")
   850  	if returnsError {
   851  		if jm != nil {
   852  			if jm.Throws == "" {
   853  				g.errorf("%s declares an error return value but the overriden method does not throw", o)
   854  				return
   855  			}
   856  			g.Printf(" throws %s", jm.Throws)
   857  		} else {
   858  			g.Printf(" throws Exception")
   859  		}
   860  	}
   861  	g.Printf(";\n")
   862  }
   863  
   864  func (g *JavaGen) genVar(o *types.Var) {
   865  	if t := o.Type(); !g.isSupported(t) {
   866  		g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t)
   867  		return
   868  	}
   869  	jType := g.javaType(o.Type())
   870  
   871  	doc := g.docs[o.Name()].Doc()
   872  	// setter
   873  	g.javadoc(doc)
   874  	g.Printf("public static native void set%s(%s v);\n", o.Name(), jType)
   875  
   876  	// getter
   877  	g.javadoc(doc)
   878  	g.Printf("public static native %s get%s();\n\n", jType, o.Name())
   879  }
   880  
   881  // genCRetClear clears the result value from a JNI call if an exception was
   882  // raised.
   883  func (g *JavaGen) genCRetClear(varName string, t types.Type, exc string) {
   884  	g.Printf("if (%s != NULL) {\n", exc)
   885  	g.Indent()
   886  	switch t := t.(type) {
   887  	case *types.Basic:
   888  		switch t.Kind() {
   889  		case types.String:
   890  			g.Printf("%s = NULL;\n", varName)
   891  		default:
   892  			g.Printf("%s = 0;\n", varName)
   893  		}
   894  	case *types.Slice, *types.Named, *types.Pointer:
   895  		g.Printf("%s = NULL;\n", varName)
   896  	}
   897  	g.Outdent()
   898  	g.Printf("}\n")
   899  }
   900  
   901  func (g *JavaGen) genJavaToC(varName string, t types.Type, mode varMode) {
   902  	switch t := t.(type) {
   903  	case *types.Basic:
   904  		switch t.Kind() {
   905  		case types.String:
   906  			g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", varName, varName)
   907  		default:
   908  			g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
   909  		}
   910  	case *types.Slice:
   911  		switch e := t.Elem().(type) {
   912  		case *types.Basic:
   913  			switch e.Kind() {
   914  			case types.Uint8: // Byte.
   915  				g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, toCFlag(mode == modeRetained))
   916  			default:
   917  				g.errorf("unsupported type: %s", t)
   918  			}
   919  		default:
   920  			g.errorf("unsupported type: %s", t)
   921  		}
   922  	case *types.Named:
   923  		switch u := t.Underlying().(type) {
   924  		case *types.Interface:
   925  			g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName)
   926  		default:
   927  			g.errorf("unsupported named type: %s / %T", u, u)
   928  		}
   929  	case *types.Pointer:
   930  		g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName)
   931  	default:
   932  		g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName)
   933  	}
   934  }
   935  
   936  func (g *JavaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) {
   937  	switch t := t.(type) {
   938  	case *types.Basic:
   939  		switch t.Kind() {
   940  		case types.String:
   941  			g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName)
   942  		case types.Bool:
   943  			g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName)
   944  		default:
   945  			g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName)
   946  		}
   947  	case *types.Slice:
   948  		switch e := t.Elem().(type) {
   949  		case *types.Basic:
   950  			switch e.Kind() {
   951  			case types.Uint8: // Byte.
   952  				g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, toCFlag(mode == modeRetained))
   953  			default:
   954  				g.errorf("unsupported type: %s", t)
   955  			}
   956  		default:
   957  			g.errorf("unsupported type: %s", t)
   958  		}
   959  	case *types.Pointer:
   960  		// TODO(crawshaw): test *int
   961  		// TODO(crawshaw): test **Generator
   962  		switch t := t.Elem().(type) {
   963  		case *types.Named:
   964  			g.genFromRefnum(toName, fromName, t, t.Obj())
   965  		default:
   966  			g.errorf("unsupported type %s", t)
   967  		}
   968  	case *types.Named:
   969  		switch t.Underlying().(type) {
   970  		case *types.Interface, *types.Pointer:
   971  			g.genFromRefnum(toName, fromName, t, t.Obj())
   972  		default:
   973  			g.errorf("unsupported, direct named type %s", t)
   974  		}
   975  	default:
   976  		g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName)
   977  	}
   978  }
   979  
   980  func (g *JavaGen) genFromRefnum(toName, fromName string, t types.Type, o *types.TypeName) {
   981  	oPkg := o.Pkg()
   982  	isJava := isJavaType(o.Type())
   983  	if !isErrorType(o.Type()) && !g.validPkg(oPkg) && !isJava {
   984  		g.errorf("type %s is defined in package %s, which is not bound", t, oPkg)
   985  		return
   986  	}
   987  	p := pkgPrefix(oPkg)
   988  	g.Printf("jobject %s = go_seq_from_refnum(env, %s, ", toName, fromName)
   989  	if isJava {
   990  		g.Printf("NULL, NULL")
   991  	} else {
   992  		g.Printf("proxy_class_%s_%s, proxy_class_%s_%s_cons", p, o.Name(), p, o.Name())
   993  	}
   994  	g.Printf(");\n")
   995  }
   996  
   997  func (g *JavaGen) gobindOpts() string {
   998  	opts := []string{"-lang=java"}
   999  	if g.JavaPkg != "" {
  1000  		opts = append(opts, "-javapkg="+g.JavaPkg)
  1001  	}
  1002  	return strings.Join(opts, " ")
  1003  }
  1004  
  1005  var javaNameReplacer = newNameSanitizer([]string{
  1006  	"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
  1007  	"class", "const", "continue", "default", "do", "double", "else", "enum",
  1008  	"extends", "final", "finally", "float", "for", "goto", "if", "implements",
  1009  	"import", "instanceof", "int", "interface", "long", "native", "new", "package",
  1010  	"private", "protected", "public", "return", "short", "static", "strictfp",
  1011  	"super", "switch", "synchronized", "this", "throw", "throws", "transient",
  1012  	"try", "void", "volatile", "while", "false", "null", "true"})
  1013  
  1014  func (g *JavaGen) javaPkgName(pkg *types.Package) string {
  1015  	return JavaPkgName(g.JavaPkg, pkg)
  1016  }
  1017  
  1018  // JavaPkgName returns the Java package name for a Go package
  1019  // given a pkg prefix. If the prefix is empty, "go" is used
  1020  // instead.
  1021  func JavaPkgName(pkgPrefix string, pkg *types.Package) string {
  1022  	if pkg == nil {
  1023  		return "go"
  1024  	}
  1025  	s := javaNameReplacer(pkg.Name())
  1026  	if pkgPrefix == "" {
  1027  		return s
  1028  	}
  1029  	return pkgPrefix + "." + s
  1030  }
  1031  
  1032  func (g *JavaGen) className() string {
  1033  	return JavaClassName(g.Pkg)
  1034  }
  1035  
  1036  // JavaClassName returns the name of the Java class that
  1037  // contains Go package level identifiers.
  1038  func JavaClassName(pkg *types.Package) string {
  1039  	if pkg == nil {
  1040  		return "Universe"
  1041  	}
  1042  	return javaNameReplacer(strings.Title(pkg.Name()))
  1043  }
  1044  
  1045  func (g *JavaGen) genConst(o *types.Const) {
  1046  	if _, ok := o.Type().(*types.Basic); !ok || !g.isSupported(o.Type()) {
  1047  		g.Printf("// skipped const %s with unsupported type: %s\n\n", o.Name(), o.Type())
  1048  		return
  1049  	}
  1050  	// TODO(hyangah): should const names use upper cases + "_"?
  1051  	// TODO(hyangah): check invalid names.
  1052  	jType := g.javaType(o.Type())
  1053  	val := o.Val().ExactString()
  1054  	switch b := o.Type().(*types.Basic); b.Kind() {
  1055  	case types.Int64, types.UntypedInt:
  1056  		i, exact := constant.Int64Val(o.Val())
  1057  		if !exact {
  1058  			g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType)
  1059  			return
  1060  		}
  1061  		val = fmt.Sprintf("%dL", i)
  1062  
  1063  	case types.Float32:
  1064  		f, _ := constant.Float32Val(o.Val())
  1065  		val = fmt.Sprintf("%gf", f)
  1066  
  1067  	case types.Float64, types.UntypedFloat:
  1068  		f, _ := constant.Float64Val(o.Val())
  1069  		if math.IsInf(f, 0) || math.Abs(f) > math.MaxFloat64 {
  1070  			g.errorf("const value %s for %s cannot be represented as %s", val, o.Name(), jType)
  1071  			return
  1072  		}
  1073  		val = fmt.Sprintf("%g", f)
  1074  	}
  1075  	g.javadoc(g.docs[o.Name()].Doc())
  1076  	g.Printf("public static final %s %s = %s;\n", g.javaType(o.Type()), o.Name(), val)
  1077  }
  1078  
  1079  func (g *JavaGen) genJNIField(o *types.TypeName, f *types.Var) {
  1080  	if t := f.Type(); !g.isSupported(t) {
  1081  		g.Printf("// skipped field %s with unsupported type: %s\n\n", o.Name(), t)
  1082  		return
  1083  	}
  1084  	n := java.JNIMangle(g.javaTypeName(o.Name()))
  1085  	// setter
  1086  	g.Printf("JNIEXPORT void JNICALL\n")
  1087  	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jobject this, %s v) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()), g.jniType(f.Type()))
  1088  	g.Indent()
  1089  	g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
  1090  	g.genJavaToC("v", f.Type(), modeRetained)
  1091  	g.Printf("proxy%s_%s_%s_Set(o, _v);\n", g.pkgPrefix, o.Name(), f.Name())
  1092  	g.genRelease("v", f.Type(), modeRetained)
  1093  	g.Outdent()
  1094  	g.Printf("}\n\n")
  1095  
  1096  	// getter
  1097  	g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(f.Type()))
  1098  	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jobject this) {\n", g.jniPkgName(), n, java.JNIMangle(f.Name()))
  1099  	g.Indent()
  1100  	g.Printf("int32_t o = go_seq_to_refnum_go(env, this);\n")
  1101  	g.Printf("%s r0 = ", g.cgoType(f.Type()))
  1102  	g.Printf("proxy%s_%s_%s_Get(o);\n", g.pkgPrefix, o.Name(), f.Name())
  1103  	g.genCToJava("_r0", "r0", f.Type(), modeRetained)
  1104  	g.Printf("return _r0;\n")
  1105  	g.Outdent()
  1106  	g.Printf("}\n\n")
  1107  }
  1108  
  1109  func (g *JavaGen) genJNIVar(o *types.Var) {
  1110  	if t := o.Type(); !g.isSupported(t) {
  1111  		g.Printf("// skipped variable %s with unsupported type: %s\n\n", o.Name(), t)
  1112  		return
  1113  	}
  1114  	n := java.JNIMangle(g.javaTypeName(o.Name()))
  1115  	// setter
  1116  	g.Printf("JNIEXPORT void JNICALL\n")
  1117  	g.Printf("Java_%s_%s_set%s(JNIEnv *env, jclass clazz, %s v) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n, g.jniType(o.Type()))
  1118  	g.Indent()
  1119  	g.genJavaToC("v", o.Type(), modeRetained)
  1120  	g.Printf("var_set%s_%s(_v);\n", g.pkgPrefix, o.Name())
  1121  	g.genRelease("v", o.Type(), modeRetained)
  1122  	g.Outdent()
  1123  	g.Printf("}\n\n")
  1124  
  1125  	// getter
  1126  	g.Printf("JNIEXPORT %s JNICALL\n", g.jniType(o.Type()))
  1127  	g.Printf("Java_%s_%s_get%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.className()), n)
  1128  	g.Indent()
  1129  	g.Printf("%s r0 = ", g.cgoType(o.Type()))
  1130  	g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name())
  1131  	g.genCToJava("_r0", "r0", o.Type(), modeRetained)
  1132  	g.Printf("return _r0;\n")
  1133  	g.Outdent()
  1134  	g.Printf("}\n\n")
  1135  }
  1136  
  1137  func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) {
  1138  	if !g.isConsSigSupported(f.Type()) {
  1139  		return
  1140  	}
  1141  	sig := f.Type().(*types.Signature)
  1142  	res := sig.Results()
  1143  
  1144  	g.Printf("JNIEXPORT jint JNICALL\n")
  1145  	g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__"+f.Name()))
  1146  	params := sig.Params()
  1147  	for i := 0; i < params.Len(); i++ {
  1148  		v := params.At(i)
  1149  		jt := g.jniType(v.Type())
  1150  		g.Printf(", %s %s", jt, g.paramName(params, i))
  1151  	}
  1152  	g.Printf(") {\n")
  1153  	g.Indent()
  1154  	for i := 0; i < params.Len(); i++ {
  1155  		name := g.paramName(params, i)
  1156  		g.genJavaToC(name, params.At(i).Type(), modeTransient)
  1157  	}
  1158  	// Constructors always return a mandatory *T and an optional error
  1159  	if res.Len() == 1 {
  1160  		g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name())
  1161  	} else {
  1162  		g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name())
  1163  	}
  1164  	for i := 0; i < params.Len(); i++ {
  1165  		if i > 0 {
  1166  			g.Printf(", ")
  1167  		}
  1168  		g.Printf("_%s", g.paramName(params, i))
  1169  	}
  1170  	g.Printf(");\n")
  1171  	for i := 0; i < params.Len(); i++ {
  1172  		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
  1173  	}
  1174  	// Extract multi returns and handle errors
  1175  	if res.Len() == 2 {
  1176  		g.Printf("int32_t refnum = res.r0;\n")
  1177  		g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained)
  1178  		g.Printf("go_seq_maybe_throw_exception(env, _err);\n")
  1179  	}
  1180  	g.Printf("return refnum;\n")
  1181  	g.Outdent()
  1182  	g.Printf("}\n\n")
  1183  }
  1184  
  1185  func (g *JavaGen) genJNIFunc(o *types.Func, sName string, jm *java.Func, proxy, isjava bool) {
  1186  	if !g.isSigSupported(o.Type()) {
  1187  		n := o.Name()
  1188  		if sName != "" {
  1189  			n = sName + "." + n
  1190  		}
  1191  		g.Printf("// skipped function %s with unsupported parameter or return types\n\n", n)
  1192  		return
  1193  	}
  1194  	g.genJNIFuncSignature(o, sName, jm, proxy, isjava)
  1195  
  1196  	g.Printf(" {\n")
  1197  	g.Indent()
  1198  	g.genJNIFuncBody(o, sName, jm, isjava)
  1199  	g.Outdent()
  1200  	g.Printf("}\n\n")
  1201  }
  1202  
  1203  func (g *JavaGen) genJNIFuncBody(o *types.Func, sName string, jm *java.Func, isjava bool) {
  1204  	sig := o.Type().(*types.Signature)
  1205  	res := sig.Results()
  1206  	if sName != "" {
  1207  		g.Printf("int32_t o = go_seq_to_refnum_go(env, __this__);\n")
  1208  	}
  1209  	params := sig.Params()
  1210  	first := 0
  1211  	if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
  1212  		// Start after the implicit this argument.
  1213  		first = 1
  1214  		g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0))
  1215  	}
  1216  	for i := first; i < params.Len(); i++ {
  1217  		name := g.paramName(params, i)
  1218  		g.genJavaToC(name, params.At(i).Type(), modeTransient)
  1219  	}
  1220  	resPrefix := ""
  1221  	if res.Len() > 0 {
  1222  		if res.Len() == 1 {
  1223  			g.Printf("%s r0 = ", g.cgoType(res.At(0).Type()))
  1224  		} else {
  1225  			resPrefix = "res."
  1226  			g.Printf("struct proxy%s_%s_%s_return res = ", g.pkgPrefix, sName, o.Name())
  1227  		}
  1228  	}
  1229  	g.Printf("proxy%s_%s_%s(", g.pkgPrefix, sName, o.Name())
  1230  	if sName != "" {
  1231  		g.Printf("o")
  1232  	}
  1233  	// Pass all arguments, including the implicit this argument.
  1234  	for i := 0; i < params.Len(); i++ {
  1235  		if i > 0 || sName != "" {
  1236  			g.Printf(", ")
  1237  		}
  1238  		g.Printf("_%s", g.paramName(params, i))
  1239  	}
  1240  	g.Printf(");\n")
  1241  	for i := first; i < params.Len(); i++ {
  1242  		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
  1243  	}
  1244  	for i := 0; i < res.Len(); i++ {
  1245  		tn := fmt.Sprintf("_r%d", i)
  1246  		t := res.At(i).Type()
  1247  		g.genCToJava(tn, fmt.Sprintf("%sr%d", resPrefix, i), t, modeRetained)
  1248  	}
  1249  	// Go backwards so that any exception is thrown before
  1250  	// the return.
  1251  	for i := res.Len() - 1; i >= 0; i-- {
  1252  		t := res.At(i).Type()
  1253  		if !isErrorType(t) {
  1254  			g.Printf("return _r%d;\n", i)
  1255  		} else {
  1256  			g.Printf("go_seq_maybe_throw_exception(env, _r%d);\n", i)
  1257  		}
  1258  	}
  1259  }
  1260  
  1261  // genRelease cleans up arguments that weren't copied in genJavaToC.
  1262  func (g *JavaGen) genRelease(varName string, t types.Type, mode varMode) {
  1263  	switch t := t.(type) {
  1264  	case *types.Basic:
  1265  	case *types.Slice:
  1266  		switch e := t.Elem().(type) {
  1267  		case *types.Basic:
  1268  			switch e.Kind() {
  1269  			case types.Uint8: // Byte.
  1270  				if mode == modeTransient {
  1271  					g.Printf("go_seq_release_byte_array(env, %s, _%s.ptr);\n", varName, varName)
  1272  				}
  1273  			}
  1274  		}
  1275  	}
  1276  }
  1277  
  1278  func (g *JavaGen) genMethodInterfaceProxy(oName string, m *types.Func) {
  1279  	if !g.isSigSupported(m.Type()) {
  1280  		g.Printf("// skipped method %s with unsupported parameter or return types\n\n", oName)
  1281  		return
  1282  	}
  1283  	sig := m.Type().(*types.Signature)
  1284  	params := sig.Params()
  1285  	res := sig.Results()
  1286  	g.genInterfaceMethodSignature(m, oName, false, g.paramName)
  1287  	g.Indent()
  1288  	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len())
  1289  	g.Printf("jobject o = go_seq_from_refnum(env, refnum, proxy_class_%s_%s, proxy_class_%s_%s_cons);\n", g.pkgPrefix, oName, g.pkgPrefix, oName)
  1290  	for i := 0; i < params.Len(); i++ {
  1291  		pn := g.paramName(params, i)
  1292  		g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient)
  1293  	}
  1294  	if res.Len() > 0 && !isErrorType(res.At(0).Type()) {
  1295  		t := res.At(0).Type()
  1296  		g.Printf("%s res = (*env)->Call%sMethod(env, o, ", g.jniType(t), g.jniCallType(t))
  1297  	} else {
  1298  		g.Printf("(*env)->CallVoidMethod(env, o, ")
  1299  	}
  1300  	g.Printf("mid_%s_%s", oName, m.Name())
  1301  	for i := 0; i < params.Len(); i++ {
  1302  		g.Printf(", _%s", g.paramName(params, i))
  1303  	}
  1304  	g.Printf(");\n")
  1305  	var retName string
  1306  	if res.Len() > 0 {
  1307  		t := res.At(0).Type()
  1308  		if res.Len() == 2 || isErrorType(t) {
  1309  			g.Printf("jobject exc = go_seq_get_exception(env);\n")
  1310  			errType := types.Universe.Lookup("error").Type()
  1311  			g.genJavaToC("exc", errType, modeRetained)
  1312  			retName = "_exc"
  1313  		}
  1314  		if !isErrorType(t) {
  1315  			if res.Len() == 2 {
  1316  				g.genCRetClear("res", t, "exc")
  1317  			}
  1318  			g.genJavaToC("res", t, modeRetained)
  1319  			retName = "_res"
  1320  		}
  1321  
  1322  		if res.Len() > 1 {
  1323  			g.Printf("cproxy%s_%s_%s_return sres = {\n", g.pkgPrefix, oName, m.Name())
  1324  			g.Printf("	_res, _exc\n")
  1325  			g.Printf("};\n")
  1326  			retName = "sres"
  1327  		}
  1328  	}
  1329  	g.Printf("go_seq_pop_local_frame(env);\n")
  1330  	if retName != "" {
  1331  		g.Printf("return %s;\n", retName)
  1332  	}
  1333  	g.Outdent()
  1334  	g.Printf("}\n\n")
  1335  }
  1336  
  1337  func (g *JavaGen) GenH() error {
  1338  	pkgPath := ""
  1339  	if g.Pkg != nil {
  1340  		pkgPath = g.Pkg.Path()
  1341  	}
  1342  	g.Printf(hPreamble, g.gobindOpts(), pkgPath, g.className())
  1343  	for _, iface := range g.interfaces {
  1344  		g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name())
  1345  		g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name())
  1346  		g.Printf("\n")
  1347  		for _, m := range iface.summary.callable {
  1348  			if !g.isSigSupported(m.Type()) {
  1349  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
  1350  				continue
  1351  			}
  1352  			g.genInterfaceMethodSignature(m, iface.obj.Name(), true, g.paramName)
  1353  			g.Printf("\n")
  1354  		}
  1355  	}
  1356  	for _, s := range g.structs {
  1357  		g.Printf("extern jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name())
  1358  		g.Printf("extern jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name())
  1359  	}
  1360  	g.Printf("#endif\n")
  1361  	if len(g.err) > 0 {
  1362  		return g.err
  1363  	}
  1364  	return nil
  1365  }
  1366  
  1367  func (g *JavaGen) jniCallType(t types.Type) string {
  1368  	switch t := t.(type) {
  1369  	case *types.Basic:
  1370  		switch t.Kind() {
  1371  		case types.Bool, types.UntypedBool:
  1372  			return "Boolean"
  1373  		case types.Int:
  1374  			return "Long"
  1375  		case types.Int8, types.Uint8: // types.Byte
  1376  			return "Byte"
  1377  		case types.Int16:
  1378  			return "Short"
  1379  		case types.Int32, types.UntypedRune: // types.Rune
  1380  			return "Int"
  1381  		case types.Int64, types.UntypedInt:
  1382  			return "Long"
  1383  		case types.Float32:
  1384  			return "Float"
  1385  		case types.Float64, types.UntypedFloat:
  1386  			return "Double"
  1387  		case types.String, types.UntypedString:
  1388  			return "Object"
  1389  		default:
  1390  			g.errorf("unsupported basic type: %s", t)
  1391  		}
  1392  	case *types.Slice:
  1393  		return "Object"
  1394  	case *types.Pointer:
  1395  		if _, ok := t.Elem().(*types.Named); ok {
  1396  			return g.jniCallType(t.Elem())
  1397  		}
  1398  		g.errorf("unsupported pointer to type: %s", t)
  1399  	case *types.Named:
  1400  		return "Object"
  1401  	default:
  1402  		return "Object"
  1403  	}
  1404  	return "TODO"
  1405  }
  1406  
  1407  func (g *JavaGen) jniClassSigPrefix(pkg *types.Package) string {
  1408  	return strings.Replace(g.javaPkgName(pkg), ".", "/", -1) + "/"
  1409  }
  1410  
  1411  func (g *JavaGen) jniSigType(T types.Type) string {
  1412  	if isErrorType(T) {
  1413  		return "Ljava/lang/Exception;"
  1414  	}
  1415  	switch T := T.(type) {
  1416  	case *types.Basic:
  1417  		switch T.Kind() {
  1418  		case types.Bool, types.UntypedBool:
  1419  			return "Z"
  1420  		case types.Int:
  1421  			return "J"
  1422  		case types.Int8:
  1423  			return "B"
  1424  		case types.Int16:
  1425  			return "S"
  1426  		case types.Int32, types.UntypedRune: // types.Rune
  1427  			return "I"
  1428  		case types.Int64, types.UntypedInt:
  1429  			return "J"
  1430  		case types.Uint8: // types.Byte
  1431  			return "B"
  1432  		case types.Float32:
  1433  			return "F"
  1434  		case types.Float64, types.UntypedFloat:
  1435  			return "D"
  1436  		case types.String, types.UntypedString:
  1437  			return "Ljava/lang/String;"
  1438  		default:
  1439  			g.errorf("unsupported basic type: %s", T)
  1440  			return "TODO"
  1441  		}
  1442  	case *types.Slice:
  1443  		return "[" + g.jniSigType(T.Elem())
  1444  	case *types.Pointer:
  1445  		if _, ok := T.Elem().(*types.Named); ok {
  1446  			return g.jniSigType(T.Elem())
  1447  		}
  1448  		g.errorf("unsupported pointer to type: %s", T)
  1449  	case *types.Named:
  1450  		return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + g.javaTypeName(T.Obj().Name()) + ";"
  1451  	default:
  1452  		g.errorf("unsupported jniType: %#+v, %s\n", T, T)
  1453  	}
  1454  	return "TODO"
  1455  }
  1456  
  1457  func (g *JavaGen) GenC() error {
  1458  	var pkgName, pkgPath string
  1459  	if g.Pkg != nil {
  1460  		pkgName = g.Pkg.Name()
  1461  		pkgPath = g.Pkg.Path()
  1462  	} else {
  1463  		pkgName = "universe"
  1464  	}
  1465  	g.Printf(cPreamble, g.gobindOpts(), pkgPath)
  1466  	g.Printf("#include %q\n", pkgName+".h")
  1467  	if g.Pkg != nil {
  1468  		for _, pkg := range g.Pkg.Imports() {
  1469  			if g.validPkg(pkg) {
  1470  				g.Printf("#include \"%s.h\"\n", pkg.Name())
  1471  			}
  1472  		}
  1473  	}
  1474  	g.Printf("\n")
  1475  
  1476  	for _, iface := range g.interfaces {
  1477  		g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, iface.obj.Name())
  1478  		g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, iface.obj.Name())
  1479  		for _, m := range iface.summary.callable {
  1480  			if !g.isSigSupported(m.Type()) {
  1481  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
  1482  				continue
  1483  			}
  1484  			g.Printf("static jmethodID mid_%s_%s;\n", iface.obj.Name(), m.Name())
  1485  		}
  1486  	}
  1487  	for _, s := range g.structs {
  1488  		g.Printf("jclass proxy_class_%s_%s;\n", g.pkgPrefix, s.obj.Name())
  1489  		g.Printf("jmethodID proxy_class_%s_%s_cons;\n", g.pkgPrefix, s.obj.Name())
  1490  	}
  1491  	g.Printf("\n")
  1492  	g.Printf("JNIEXPORT void JNICALL\n")
  1493  	g.Printf("Java_%s_%s__1init(JNIEnv *env, jclass _unused) {\n", g.jniPkgName(), java.JNIMangle(g.className()))
  1494  	g.Indent()
  1495  	g.Printf("jclass clazz;\n")
  1496  	for _, s := range g.structs {
  1497  		if jinf, ok := g.jstructs[s.obj]; ok {
  1498  			// Leave the class and constructor NULL for Java classes with no
  1499  			// default constructor.
  1500  			if !jinf.genNoargCon {
  1501  				continue
  1502  			}
  1503  		}
  1504  		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(s.obj.Pkg())+g.javaTypeName(s.obj.Name()))
  1505  		g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, s.obj.Name())
  1506  		g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, s.obj.Name())
  1507  	}
  1508  	for _, iface := range g.interfaces {
  1509  		pkg := iface.obj.Pkg()
  1510  		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+JavaClassName(pkg)+"$proxy"+iface.obj.Name())
  1511  		g.Printf("proxy_class_%s_%s = (*env)->NewGlobalRef(env, clazz);\n", g.pkgPrefix, iface.obj.Name())
  1512  		g.Printf("proxy_class_%s_%s_cons = (*env)->GetMethodID(env, clazz, \"<init>\", \"(I)V\");\n", g.pkgPrefix, iface.obj.Name())
  1513  		if isErrorType(iface.obj.Type()) {
  1514  			// As a special case, Java Exceptions are passed to Go pretending to implement the Go error interface.
  1515  			// To complete the illusion, use the Throwable.getMessage method for proxied calls to the error.Error method.
  1516  			g.Printf("clazz = (*env)->FindClass(env, \"java/lang/Throwable\");\n")
  1517  			g.Printf("mid_error_Error = (*env)->GetMethodID(env, clazz, \"getMessage\", \"()Ljava/lang/String;\");\n")
  1518  			continue
  1519  		}
  1520  		g.Printf("clazz = (*env)->FindClass(env, %q);\n", g.jniClassSigPrefix(pkg)+g.javaTypeName(iface.obj.Name()))
  1521  		for _, m := range iface.summary.callable {
  1522  			if !g.isSigSupported(m.Type()) {
  1523  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
  1524  				continue
  1525  			}
  1526  			sig := m.Type().(*types.Signature)
  1527  			res := sig.Results()
  1528  			retSig := "V"
  1529  			if res.Len() > 0 {
  1530  				if t := res.At(0).Type(); !isErrorType(t) {
  1531  					retSig = g.jniSigType(t)
  1532  				}
  1533  			}
  1534  			var jniParams string
  1535  			params := sig.Params()
  1536  			for i := 0; i < params.Len(); i++ {
  1537  				jniParams += g.jniSigType(params.At(i).Type())
  1538  			}
  1539  			g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n",
  1540  				iface.obj.Name(), m.Name(), javaNameReplacer(lowerFirst(m.Name())), jniParams, retSig)
  1541  		}
  1542  		g.Printf("\n")
  1543  	}
  1544  	g.Outdent()
  1545  	g.Printf("}\n\n")
  1546  	for _, f := range g.funcs {
  1547  		g.genJNIFunc(f, "", nil, false, false)
  1548  	}
  1549  	for _, s := range g.structs {
  1550  		sName := s.obj.Name()
  1551  		cons := g.constructors[s.obj]
  1552  		jinf := g.jstructs[s.obj]
  1553  		for _, f := range cons {
  1554  			g.genJNIConstructor(f, sName)
  1555  		}
  1556  		if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) {
  1557  			g.Printf("JNIEXPORT jint JNICALL\n")
  1558  			g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), java.JNIMangle(g.javaTypeName(sName)), java.JNIMangle("__New"))
  1559  			g.Indent()
  1560  			g.Printf("return new_%s_%s();\n", g.pkgPrefix, sName)
  1561  			g.Outdent()
  1562  			g.Printf("}\n\n")
  1563  		}
  1564  
  1565  		for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) {
  1566  			var jm *java.Func
  1567  			if jinf != nil {
  1568  				jm = jinf.lookupMethod(m, g.hasThis(s.obj.Name(), m))
  1569  			}
  1570  			g.genJNIFunc(m, sName, jm, false, jinf != nil)
  1571  		}
  1572  		for _, f := range exportedFields(s.t) {
  1573  			g.genJNIField(s.obj, f)
  1574  		}
  1575  	}
  1576  	for _, iface := range g.interfaces {
  1577  		for _, m := range iface.summary.callable {
  1578  			g.genJNIFunc(m, iface.obj.Name(), nil, true, false)
  1579  			g.genMethodInterfaceProxy(iface.obj.Name(), m)
  1580  		}
  1581  	}
  1582  	for _, v := range g.vars {
  1583  		g.genJNIVar(v)
  1584  	}
  1585  	if len(g.err) > 0 {
  1586  		return g.err
  1587  	}
  1588  	return nil
  1589  }
  1590  
  1591  func (g *JavaGen) GenJava() error {
  1592  	pkgPath := ""
  1593  	if g.Pkg != nil {
  1594  		pkgPath = g.Pkg.Path()
  1595  	}
  1596  	g.Printf(javaPreamble, g.javaPkgName(g.Pkg), g.className(), g.gobindOpts(), pkgPath)
  1597  
  1598  	g.Printf("public abstract class %s {\n", g.className())
  1599  	g.Indent()
  1600  	g.Printf("static {\n")
  1601  	g.Indent()
  1602  	g.Printf("Seq.touch(); // for loading the native library\n")
  1603  	if g.Pkg != nil {
  1604  		for _, p := range g.Pkg.Imports() {
  1605  			if g.validPkg(p) {
  1606  				g.Printf("%s.%s.touch();\n", g.javaPkgName(p), JavaClassName(p))
  1607  			}
  1608  		}
  1609  	}
  1610  	g.Printf("_init();\n")
  1611  	g.Outdent()
  1612  	g.Printf("}\n\n")
  1613  	g.Printf("private %s() {} // uninstantiable\n\n", g.className())
  1614  	g.Printf("// touch is called from other bound packages to initialize this package\n")
  1615  	g.Printf("public static void touch() {}\n\n")
  1616  	g.Printf("private static native void _init();\n\n")
  1617  
  1618  	for _, iface := range g.interfaces {
  1619  		n := iface.obj.Name()
  1620  		g.Printf("private static final class proxy%s", n)
  1621  		if isErrorType(iface.obj.Type()) {
  1622  			g.Printf(" extends Exception")
  1623  		}
  1624  		g.Printf(" implements Seq.Proxy, %s {\n", g.javaTypeName(n))
  1625  		g.Indent()
  1626  		g.genProxyImpl("proxy" + n)
  1627  		g.Printf("proxy%s(int refnum) { this.refnum = refnum; Seq.trackGoRef(refnum, this); }\n\n", n)
  1628  
  1629  		if isErrorType(iface.obj.Type()) {
  1630  			g.Printf("@Override public String getMessage() { return error(); }\n\n")
  1631  		}
  1632  		for _, m := range iface.summary.callable {
  1633  			if !g.isSigSupported(m.Type()) {
  1634  				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", n, m.Name())
  1635  				continue
  1636  			}
  1637  			g.Printf("public native ")
  1638  			g.genFuncSignature(m, nil, false)
  1639  		}
  1640  
  1641  		g.Outdent()
  1642  		g.Printf("}\n")
  1643  	}
  1644  
  1645  	g.Printf("\n")
  1646  
  1647  	for _, c := range g.constants {
  1648  		g.genConst(c)
  1649  	}
  1650  	g.Printf("\n")
  1651  	for _, v := range g.vars {
  1652  		g.genVar(v)
  1653  	}
  1654  	for _, f := range g.funcs {
  1655  		if !g.isSigSupported(f.Type()) {
  1656  			g.Printf("// skipped function %s with unsupported parameter or return types\n\n", f.Name())
  1657  			continue
  1658  		}
  1659  		g.javadoc(g.docs[f.Name()].Doc())
  1660  		g.Printf("public static native ")
  1661  		g.genFuncSignature(f, nil, false)
  1662  	}
  1663  
  1664  	g.Outdent()
  1665  	g.Printf("}\n")
  1666  
  1667  	if len(g.err) > 0 {
  1668  		return g.err
  1669  	}
  1670  	return nil
  1671  }
  1672  
  1673  // embeddedJavaClasses returns the possible empty list of Java types embedded
  1674  // in the given struct type.
  1675  func embeddedJavaClasses(t *types.Struct) []string {
  1676  	clsSet := make(map[string]struct{})
  1677  	var classes []string
  1678  	for i := 0; i < t.NumFields(); i++ {
  1679  		f := t.Field(i)
  1680  		if !f.Exported() {
  1681  			continue
  1682  		}
  1683  		if t := f.Type(); isJavaType(t) {
  1684  			cls := classNameFor(t)
  1685  			if _, exists := clsSet[cls]; !exists {
  1686  				clsSet[cls] = struct{}{}
  1687  				classes = append(classes, cls)
  1688  			}
  1689  		}
  1690  	}
  1691  	return classes
  1692  }
  1693  
  1694  func classNameFor(t types.Type) string {
  1695  	obj := t.(*types.Named).Obj()
  1696  	pkg := obj.Pkg()
  1697  	return strings.Replace(pkg.Path()[len("Java/"):], "/", ".", -1) + "." + obj.Name()
  1698  }
  1699  
  1700  func isJavaType(t types.Type) bool {
  1701  	return typePkgFirstElem(t) == "Java"
  1702  }
  1703  
  1704  const (
  1705  	javaPreamble = gobindPreamble + `// Java class %[1]s.%[2]s is a proxy for talking to a Go program.
  1706  //
  1707  //   autogenerated by gobind %[3]s %[4]s
  1708  //go:build  linux || windows 
  1709  //+build linux, windows 
  1710  package %[1]s;
  1711  
  1712  import go.Seq;
  1713  
  1714  `
  1715  	cPreamble = gobindPreamble + `// JNI functions for the Go <=> Java bridge.
  1716  //
  1717  //   autogenerated by gobind %[1]s %[2]s
  1718  #ifdef __GOBIND_ANDROID__
  1719  #include <android/log.h>
  1720  #endif 
  1721  #include <stdint.h>
  1722  #include "seq_support.h"
  1723  #include "_cgo_export.h"
  1724  `
  1725  
  1726  	hPreamble = gobindPreamble + `// JNI function headers for the Go <=> Java bridge.
  1727  //
  1728  //   autogenerated by gobind %[1]s %[2]s
  1729  
  1730  #ifndef __%[3]s_H__
  1731  #define __%[3]s_H__
  1732  
  1733  #include <jni.h>
  1734  
  1735  `
  1736  )