bind: param name replacement for invalid unicode names

The are three generators that currently call this method:
    A  -> B
(1) go -> java
(2) go -> objective-c
(3) go -> go

As discussed below, we only substitute for invalid unicode characters
in case (1).

**Case 1**
Go:
From golang.org/ref/spec:
Identifiers name program entities such as variables and types.
An identifier is a sequence of one or more letters and digits(unicode_digit).
The first character in an identifier must be a letter(unicode_letter | "_" ).

Java:
From https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.8
`The "Java letters" include uppercase and lowercase ASCII Latin letters
A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons,
the ASCII underscore (_, or \u005f) and dollar sign ($, or \u0024). The $
character should be used only in mechanically generated source code or,
rarely, to access pre-existing names on legacy systems.`

Therefore, Go's identifiers are checked in case they break these Java rules.

**Case 2**
There is no objective-c standard specification for valid identifiers.
From some testing it seems that Go and objective-c have identical
valid identifier rules.

**Case 3**
Requires no checking.

Change-Id: I881810eb9355af6a418727ace32cb6ce4266b2a0
Reviewed-on: https://go-review.googlesource.com/14044
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/gen.go b/bind/gen.go
index 7d4ad65..1878142 100644
--- a/bind/gen.go
+++ b/bind/gen.go
@@ -266,7 +266,7 @@
 	return "TODO"
 }
 
-func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool) {
+func (g *Generator) genInterfaceMethodSignature(m *types.Func, iName string, header bool, g_paramName func(*types.Tuple, int) string) {
 	sig := m.Type().(*types.Signature)
 	params := sig.Params()
 	res := sig.Results()
@@ -293,7 +293,7 @@
 	g.Printf("cproxy%s_%s_%s(int32_t refnum", g.pkgPrefix, iName, m.Name())
 	for i := 0; i < params.Len(); i++ {
 		t := params.At(i).Type()
-		g.Printf(", %s %s", g.cgoType(t), paramName(params, i))
+		g.Printf(", %s %s", g.cgoType(t), g_paramName(params, i))
 	}
 	g.Printf(")")
 	if header {
@@ -360,10 +360,9 @@
 
 var paramRE = regexp.MustCompile(`^p[0-9]*$`)
 
-// paramName replaces incompatible name with a p0-pN name.
+// basicParamName replaces incompatible name with a p0-pN name.
 // Missing names, or existing names of the form p[0-9] are incompatible.
-// TODO(crawshaw): Replace invalid unicode names.
-func paramName(params *types.Tuple, pos int) string {
+func basicParamName(params *types.Tuple, pos int) string {
 	name := params.At(pos).Name()
 	if name == "" || name[0] == '_' || paramRE.MatchString(name) {
 		name = fmt.Sprintf("p%d", pos)
diff --git a/bind/gengo.go b/bind/gengo.go
index ec26ffc..9bbba4d 100644
--- a/bind/gengo.go
+++ b/bind/gengo.go
@@ -40,7 +40,7 @@
 	params := sig.Params()
 	for i := 0; i < params.Len(); i++ {
 		p := params.At(i)
-		pn := "param_" + paramName(params, i)
+		pn := "param_" + g.paramName(params, i)
 		g.genRead("_"+pn, pn, p.Type(), modeTransient)
 	}
 
@@ -64,7 +64,7 @@
 		if i > 0 {
 			g.Printf(", ")
 		}
-		g.Printf("_param_%s", paramName(params, i))
+		g.Printf("_param_%s", g.paramName(params, i))
 	}
 	g.Printf(")\n")
 
@@ -152,7 +152,7 @@
 			g.Printf(", ")
 		}
 		p := params.At(i)
-		g.Printf("param_%s C.%s", paramName(params, i), g.cgoType(p.Type()))
+		g.Printf("param_%s C.%s", g.paramName(params, i), g.cgoType(p.Type()))
 	}
 	g.Printf(") ")
 	res := sig.Results()
@@ -169,6 +169,10 @@
 	g.Printf("{\n")
 }
 
+func (g *goGen) paramName(params *types.Tuple, pos int) string {
+	return basicParamName(params, pos)
+}
+
 func (g *goGen) genFunc(o *types.Func) {
 	if !g.isSigSupported(o.Type()) {
 		g.Printf("// skipped function %s with unsupported parameter or result types\n", o.Name())
@@ -314,7 +318,7 @@
 			if i > 0 {
 				g.Printf(", ")
 			}
-			g.Printf("param_%s %s", paramName(params, i), g.typeString(params.At(i).Type()))
+			g.Printf("param_%s %s", g.paramName(params, i), g.typeString(params.At(i).Type()))
 		}
 		g.Printf(") ")
 
@@ -327,7 +331,7 @@
 		g.Indent()
 
 		for i := 0; i < params.Len(); i++ {
-			pn := "param_" + paramName(params, i)
+			pn := "param_" + g.paramName(params, i)
 			g.genWrite("_"+pn, pn, params.At(i).Type(), modeTransient)
 		}
 
@@ -336,7 +340,7 @@
 		}
 		g.Printf("C.cproxy%s_%s_%s(C.int32_t(p.Bind_proxy_refnum__())", g.pkgPrefix, obj.Name(), m.Name())
 		for i := 0; i < params.Len(); i++ {
-			g.Printf(", _param_%s", paramName(params, i))
+			g.Printf(", _param_%s", g.paramName(params, i))
 		}
 		g.Printf(")\n")
 		var retName string
diff --git a/bind/genjava.go b/bind/genjava.go
index 3fb71e0..99ab7aa 100644
--- a/bind/genjava.go
+++ b/bind/genjava.go
@@ -9,6 +9,7 @@
 	"go/constant"
 	"go/types"
 	"math"
+	"regexp"
 	"strings"
 
 	"golang.org/x/mobile/internal/importers/java"
@@ -274,7 +275,7 @@
 			if i > 0 {
 				g.Printf(", ")
 			}
-			g.Printf(paramName(params, i))
+			g.Printf(g.paramName(params, i))
 		}
 		g.Printf(");\n")
 	}
@@ -284,7 +285,7 @@
 		if i > 0 {
 			g.Printf(", ")
 		}
-		g.Printf(paramName(params, i))
+		g.Printf(g.paramName(params, i))
 	}
 	g.Printf(");\n")
 	g.Outdent()
@@ -310,7 +311,7 @@
 			g.Printf(", ")
 		}
 		v := params.At(i)
-		name := paramName(params, i)
+		name := g.paramName(params, i)
 		jt := g.javaType(v.Type())
 		g.Printf("%s %s", jt, name)
 	}
@@ -615,7 +616,7 @@
 	for ; i < params.Len(); i++ {
 		g.Printf(", ")
 		v := sig.Params().At(i)
-		name := paramName(params, i)
+		name := g.paramName(params, i)
 		jt := g.jniType(v.Type())
 		g.Printf("%s %s", jt, name)
 	}
@@ -626,6 +627,16 @@
 	return strings.Replace(g.javaPkgName(g.Pkg), ".", "_", -1)
 }
 
+var javaLetterDigitRE = regexp.MustCompile(`[0-9a-zA-Z$_]`)
+
+func (g *JavaGen) paramName(params *types.Tuple, pos int) string {
+	name := basicParamName(params, pos)
+	if !javaLetterDigitRE.MatchString(name) {
+		name = fmt.Sprintf("p%d", pos)
+	}
+	return name
+}
+
 func (g *JavaGen) genFuncSignature(o *types.Func, jm *java.Func, hasThis bool) {
 	sig := o.Type().(*types.Signature)
 	res := sig.Results()
@@ -928,12 +939,12 @@
 	for i := 0; i < params.Len(); i++ {
 		v := params.At(i)
 		jt := g.jniType(v.Type())
-		g.Printf(", %s %s", jt, paramName(params, i))
+		g.Printf(", %s %s", jt, g.paramName(params, i))
 	}
 	g.Printf(") {\n")
 	g.Indent()
 	for i := 0; i < params.Len(); i++ {
-		name := paramName(params, i)
+		name := g.paramName(params, i)
 		g.genJavaToC(name, params.At(i).Type(), modeTransient)
 	}
 	// Constructors always have one result parameter, a *T.
@@ -942,11 +953,11 @@
 		if i > 0 {
 			g.Printf(", ")
 		}
-		g.Printf("_%s", paramName(params, i))
+		g.Printf("_%s", g.paramName(params, i))
 	}
 	g.Printf(");\n")
 	for i := 0; i < params.Len(); i++ {
-		g.genRelease(paramName(params, i), params.At(i).Type(), modeTransient)
+		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
 	}
 	// Pass no proxy class so that the Seq.Ref is returned instead.
 	g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n")
@@ -989,10 +1000,10 @@
 	if isjava && params.Len() > 0 && params.At(0).Name() == "this" {
 		// Start after the implicit this argument.
 		first = 1
-		g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", paramName(params, 0))
+		g.Printf("int32_t _%s = go_seq_to_refnum(env, __this__);\n", g.paramName(params, 0))
 	}
 	for i := first; i < params.Len(); i++ {
-		name := paramName(params, i)
+		name := g.paramName(params, i)
 		g.genJavaToC(name, params.At(i).Type(), modeTransient)
 	}
 	resPrefix := ""
@@ -1013,11 +1024,11 @@
 		if i > 0 || sName != "" {
 			g.Printf(", ")
 		}
-		g.Printf("_%s", paramName(params, i))
+		g.Printf("_%s", g.paramName(params, i))
 	}
 	g.Printf(");\n")
 	for i := first; i < params.Len(); i++ {
-		g.genRelease(paramName(params, i), params.At(i).Type(), modeTransient)
+		g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient)
 	}
 	for i := 0; i < res.Len(); i++ {
 		tn := fmt.Sprintf("_r%d", i)
@@ -1061,12 +1072,12 @@
 	sig := m.Type().(*types.Signature)
 	params := sig.Params()
 	res := sig.Results()
-	g.genInterfaceMethodSignature(m, oName, false)
+	g.genInterfaceMethodSignature(m, oName, false, g.paramName)
 	g.Indent()
 	g.Printf("JNIEnv *env = go_seq_push_local_frame(%d);\n", params.Len())
 	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)
 	for i := 0; i < params.Len(); i++ {
-		pn := paramName(params, i)
+		pn := g.paramName(params, i)
 		g.genCToJava("_"+pn, pn, params.At(i).Type(), modeTransient)
 	}
 	if res.Len() > 0 && !isErrorType(res.At(0).Type()) {
@@ -1077,7 +1088,7 @@
 	}
 	g.Printf("mid_%s_%s", oName, m.Name())
 	for i := 0; i < params.Len(); i++ {
-		g.Printf(", _%s", paramName(params, i))
+		g.Printf(", _%s", g.paramName(params, i))
 	}
 	g.Printf(");\n")
 	var retName string
@@ -1127,7 +1138,7 @@
 				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", iface.obj.Name(), m.Name())
 				continue
 			}
-			g.genInterfaceMethodSignature(m, iface.obj.Name(), true)
+			g.genInterfaceMethodSignature(m, iface.obj.Name(), true, g.paramName)
 			g.Printf("\n")
 		}
 	}
diff --git a/bind/genobjc.go b/bind/genobjc.go
index b1ab0ff..9d3f9e9 100644
--- a/bind/genobjc.go
+++ b/bind/genobjc.go
@@ -64,7 +64,7 @@
 				g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", i.obj.Name(), m.Name())
 				continue
 			}
-			g.genInterfaceMethodSignature(m, i.obj.Name(), true)
+			g.genInterfaceMethodSignature(m, i.obj.Name(), true, g.paramName)
 			g.Printf("\n")
 		}
 	}
@@ -366,7 +366,7 @@
 		p := params.At(i)
 		v := paramInfo{
 			typ:  p.Type(),
-			name: paramName(params, i),
+			name: g.paramName(params, i),
 		}
 		s.params = append(s.params, v)
 	}
@@ -479,6 +479,10 @@
 	return len(s.retParams) == 1 && !isErrorType(s.retParams[0].typ)
 }
 
+func (g *objcGen) paramName(params *types.Tuple, pos int) string {
+	return basicParamName(params, pos)
+}
+
 func (g *objcGen) genFuncH(obj *types.Func) {
 	if !g.isSigSupported(obj.Type()) {
 		g.Printf("// skipped function %s with unsupported parameter or return types\n\n", obj.Name())
@@ -776,7 +780,7 @@
 func (g *objcGen) genInterfaceMethodProxy(obj *types.TypeName, m *types.Func) {
 	oName := obj.Name()
 	s := g.funcSummary(m)
-	g.genInterfaceMethodSignature(m, oName, false)
+	g.genInterfaceMethodSignature(m, oName, false, g.paramName)
 	g.Indent()
 	g.Printf("@autoreleasepool {\n")
 	g.Indent()
diff --git a/bind/testdata/issue10788.go b/bind/testdata/issue10788.go
index e5c6a12..af48721 100644
--- a/bind/testdata/issue10788.go
+++ b/bind/testdata/issue10788.go
@@ -10,5 +10,5 @@
 
 type TestInterface interface {
 	DoSomeWork(s *TestStruct)
-	MultipleUnnamedParams(_ int, p0 string, _ int64)
+	MultipleUnnamedParams(_ int, p0 string, 日本 int64)
 }
diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden
index 1d3652a..a6ef182 100644
--- a/bind/testdata/issue10788.go.golden
+++ b/bind/testdata/issue10788.go.golden
@@ -52,13 +52,13 @@
 }
 
 //export proxyissue10788_TestInterface_MultipleUnnamedParams
-func proxyissue10788_TestInterface_MultipleUnnamedParams(refnum C.int32_t, param_p0 C.nint, param_p1 C.nstring, param_p2 C.int64_t) {
+func proxyissue10788_TestInterface_MultipleUnnamedParams(refnum C.int32_t, param_p0 C.nint, param_p1 C.nstring, param_日本 C.int64_t) {
 	ref := _seq.FromRefNum(int32(refnum))
 	v := ref.Get().(issue10788.TestInterface)
 	_param_p0 := int(param_p0)
 	_param_p1 := decodeString(param_p1)
-	_param_p2 := int64(param_p2)
-	v.MultipleUnnamedParams(_param_p0, _param_p1, _param_p2)
+	_param_日本 := int64(param_日本)
+	v.MultipleUnnamedParams(_param_p0, _param_p1, _param_日本)
 }
 
 type proxyissue10788_TestInterface _seq.Ref
@@ -75,9 +75,9 @@
 	C.cproxyissue10788_TestInterface_DoSomeWork(C.int32_t(p.Bind_proxy_refnum__()), _param_s)
 }
 
-func (p *proxyissue10788_TestInterface) MultipleUnnamedParams(param_p0 int, param_p1 string, param_p2 int64) {
+func (p *proxyissue10788_TestInterface) MultipleUnnamedParams(param_p0 int, param_p1 string, param_日本 int64) {
 	_param_p0 := C.nint(param_p0)
 	_param_p1 := encodeString(param_p1)
-	_param_p2 := C.int64_t(param_p2)
-	C.cproxyissue10788_TestInterface_MultipleUnnamedParams(C.int32_t(p.Bind_proxy_refnum__()), _param_p0, _param_p1, _param_p2)
+	_param_日本 := C.int64_t(param_日本)
+	C.cproxyissue10788_TestInterface_MultipleUnnamedParams(C.int32_t(p.Bind_proxy_refnum__()), _param_p0, _param_p1, _param_日本)
 }
diff --git a/bind/testdata/issue10788.objc.go.h.golden b/bind/testdata/issue10788.objc.go.h.golden
index 5c480a8..28f3c46 100644
--- a/bind/testdata/issue10788.objc.go.h.golden
+++ b/bind/testdata/issue10788.objc.go.h.golden
@@ -10,6 +10,6 @@
 #include <objc/objc.h>
 void cproxyissue10788_TestInterface_DoSomeWork(int32_t refnum, int32_t s);
 
-void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2);
+void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t 日本);
 
 #endif
diff --git a/bind/testdata/issue10788.objc.h.golden b/bind/testdata/issue10788.objc.h.golden
index 25c2e7d..5bb4a39 100644
--- a/bind/testdata/issue10788.objc.h.golden
+++ b/bind/testdata/issue10788.objc.h.golden
@@ -24,7 +24,7 @@
 
 @protocol GoIssue10788TestInterface
 - (void)doSomeWork:(GoIssue10788TestStruct*)s;
-- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 p2:(int64_t)p2;
+- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 日本:(int64_t)日本;
 @end
 
 @class GoIssue10788TestInterface;
@@ -35,7 +35,7 @@
 
 - (instancetype)initWithRef:(id)ref;
 - (void)doSomeWork:(GoIssue10788TestStruct*)s;
-- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 p2:(int64_t)p2;
+- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 日本:(int64_t)日本;
 @end
 
 #endif
diff --git a/bind/testdata/issue10788.objc.m.golden b/bind/testdata/issue10788.objc.m.golden
index 80fc8a5..5d99e1f 100644
--- a/bind/testdata/issue10788.objc.m.golden
+++ b/bind/testdata/issue10788.objc.m.golden
@@ -54,12 +54,12 @@
 	proxyissue10788_TestInterface_DoSomeWork(refnum, _s);
 }
 
-- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 p2:(int64_t)p2 {
+- (void)multipleUnnamedParams:(long)p0 p1:(NSString*)p1 日本:(int64_t)日本 {
 	int32_t refnum = go_seq_go_to_refnum(self._ref);
 	nint _p0 = (nint)p0;
 	nstring _p1 = go_seq_from_objc_string(p1);
-	int64_t _p2 = (int64_t)p2;
-	proxyissue10788_TestInterface_MultipleUnnamedParams(refnum, _p0, _p1, _p2);
+	int64_t _日本 = (int64_t)日本;
+	proxyissue10788_TestInterface_MultipleUnnamedParams(refnum, _p0, _p1, _日本);
 }
 
 @end
@@ -81,13 +81,13 @@
 	}
 }
 
-void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t p2) {
+void cproxyissue10788_TestInterface_MultipleUnnamedParams(int32_t refnum, nint p0, nstring p1, int64_t 日本) {
 	@autoreleasepool {
 		GoIssue10788TestInterface* o = go_seq_objc_from_refnum(refnum);
 		long _p0 = (long)p0;
 		NSString *_p1 = go_seq_to_objc_string(p1);
-		int64_t _p2 = (int64_t)p2;
-		[o multipleUnnamedParams:_p0 p1:_p1 p2:_p2];
+		int64_t _日本 = (int64_t)日本;
+		[o multipleUnnamedParams:_p0 p1:_p1 日本:_日本];
 	}
 }