bind: avoid ObjC reserved names

The new tests in CL 28494 exposed a bug: the ObjC generator does
not avoid reserved names and names with special meaning ("init").
Generalize the name sanitizer from the Java generator and use that.

Also, move the lowerFirst function to gen.go since it is now used
by both generators.

Change-Id: I25b7af2594b2ea136f05d2bab1cfdc66ba169859
Reviewed-on: https://go-review.googlesource.com/28592
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur 2016-09-07 16:02:52 +02:00
parent 7f59993615
commit e99a906c3a
5 changed files with 101 additions and 106 deletions

View File

@ -11,6 +11,9 @@ import (
"go/types"
"io"
"regexp"
"strings"
"unicode"
"unicode/utf8"
)
type (
@ -340,3 +343,43 @@ func constExactString(o *types.Const) string {
// TODO: warning?
return v.String()
}
func lowerFirst(s string) string {
if s == "" {
return ""
}
var conv []rune
for len(s) > 0 {
r, n := utf8.DecodeRuneInString(s)
if !unicode.IsUpper(r) {
if l := len(conv); l > 1 {
conv[l-1] = unicode.ToUpper(conv[l-1])
}
return string(conv) + s
}
conv = append(conv, unicode.ToLower(r))
s = s[n:]
}
return string(conv)
}
// newNameSanitizer returns a functions that replaces all dashes and dots
// with underscores, as well as avoiding reserved words by suffixing such
// identifiers with underscores.
func newNameSanitizer(res []string) func(s string) string {
reserved := make(map[string]bool)
for _, word := range res {
reserved[word] = true
}
symbols := strings.NewReplacer(
"-", "_",
".", "_",
)
return func(s string) string {
if reserved[s] {
return s + "_"
}
return symbols.Replace(s)
}
}

View File

@ -375,7 +375,7 @@ func (g *JavaGen) genJNIFuncSignature(o *types.Func, sName string, proxy bool) {
} else {
g.Printf(g.className())
}
oName := javaNameReplacer.Replace(lowerFirst(o.Name()))
oName := javaNameReplacer(lowerFirst(o.Name()))
if strings.HasSuffix(oName, "_") {
oName += "1" // JNI doesn't like methods ending with underscore, needs the _1 suffixing
}
@ -435,7 +435,7 @@ func (g *JavaGen) genFuncSignature(o *types.Func, static, header bool) {
if !header {
g.Printf("native ")
}
g.Printf("%s %s(", ret, javaNameReplacer.Replace(lowerFirst(o.Name())))
g.Printf("%s %s(", ret, javaNameReplacer(lowerFirst(o.Name())))
params := sig.Params()
for i := 0; i < params.Len(); i++ {
if i > 0 {
@ -564,51 +564,20 @@ func (g *JavaGen) gobindOpts() string {
return strings.Join(opts, " ")
}
var javaKeywordsAndReserves = []string{
var javaNameReplacer = newNameSanitizer([]string{
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
"class", "const", "continue", "default", "do", "double", "else", "enum",
"extends", "final", "finally", "float", "for", "goto", "if", "implements",
"import", "instanceof", "int", "interface", "long", "native", "new", "package",
"private", "protected", "public", "return", "short", "static", "strictfp",
"super", "switch", "synchronized", "this", "throw", "throws", "transient",
"try", "void", "volatile", "while", "false", "null", "true"}
// javaNameSanitizer replaces all dashes and dots with underscores, as well as
// avoiding all keywords and reserved words by suffixing such identifier with
// an underscore.
type javaNameSanitizer struct {
symbols *strings.Replacer
reserved map[string]bool
}
func newJavaNameSanitizer() *javaNameSanitizer {
reserved := make(map[string]bool)
for _, word := range javaKeywordsAndReserves {
reserved[word] = true
}
return &javaNameSanitizer{
symbols: strings.NewReplacer(
"-", "_",
".", "_",
),
reserved: reserved,
}
}
func (r *javaNameSanitizer) Replace(s string) string {
if r.reserved[s] {
return s + "_"
}
return r.symbols.Replace(s)
}
var javaNameReplacer = newJavaNameSanitizer()
"try", "void", "volatile", "while", "false", "null", "true"})
func (g *JavaGen) javaPkgName(pkg *types.Package) string {
if pkg == nil {
return "go"
}
s := javaNameReplacer.Replace(pkg.Name())
s := javaNameReplacer(pkg.Name())
if g.JavaPkg != "" {
return g.JavaPkg + "." + s
} else {
@ -624,7 +593,7 @@ func className(pkg *types.Package) string {
if pkg == nil {
return "Universe"
}
return javaNameReplacer.Replace(strings.Title(pkg.Name()))
return javaNameReplacer(strings.Title(pkg.Name()))
}
func (g *JavaGen) genConst(o *types.Const) {
@ -1048,7 +1017,7 @@ func (g *JavaGen) GenC() error {
jniParams += g.jniSigType(params.At(i).Type())
}
g.Printf("mid_%s_%s = (*env)->GetMethodID(env, clazz, %q, \"(%s)%s\");\n",
iface.obj.Name(), m.Name(), javaNameReplacer.Replace(lowerFirst(m.Name())), jniParams, retSig)
iface.obj.Name(), m.Name(), javaNameReplacer(lowerFirst(m.Name())), jniParams, retSig)
}
g.Printf("\n")
}

View File

@ -10,8 +10,6 @@ import (
"go/types"
"math"
"strings"
"unicode"
"unicode/utf8"
)
// TODO(hyangah): handle method name conflicts.
@ -162,7 +160,7 @@ func (g *objcGen) genH() error {
continue
}
objcType := g.objcType(obj.Type())
g.Printf("+ (%s) %s;\n", objcType, lowerFirst(obj.Name()))
g.Printf("+ (%s) %s;\n", objcType, objcNameReplacer(lowerFirst(obj.Name())))
g.Printf("+ (void) set%s:(%s)v;\n", obj.Name(), objcType)
g.Printf("\n")
}
@ -305,7 +303,7 @@ func (g *objcGen) genVarM(o *types.Var) {
g.Printf("}\n\n")
// getter
g.Printf("+ (%s) %s {\n", objcType, lowerFirst(o.Name()))
g.Printf("+ (%s) %s {\n", objcType, objcNameReplacer(lowerFirst(o.Name())))
g.Indent()
g.Printf("%s r0 = ", g.cgoType(o.Type()))
g.Printf("var_get%s_%s();\n", g.pkgPrefix, o.Name())
@ -470,7 +468,7 @@ func (s *funcSummary) asMethod(g *objcGen) string {
params = append(params, fmt.Sprintf("%s:(%s)%s", key, g.objcType(p.typ)+"*", p.name))
}
}
return fmt.Sprintf("(%s)%s%s", s.ret, lowerFirst(s.name), strings.Join(params, " "))
return fmt.Sprintf("(%s)%s%s", s.ret, objcNameReplacer(lowerFirst(s.name)), strings.Join(params, " "))
}
func (s *funcSummary) callMethod(g *objcGen) string {
@ -491,7 +489,7 @@ func (s *funcSummary) callMethod(g *objcGen) string {
params = append(params, fmt.Sprintf("%s:&%s", key, p.name))
}
}
return fmt.Sprintf("%s%s", lowerFirst(s.name), strings.Join(params, " "))
return fmt.Sprintf("%s%s", objcNameReplacer(lowerFirst(s.name)), strings.Join(params, " "))
}
func (s *funcSummary) returnsVal() bool {
@ -522,7 +520,7 @@ func (g *objcGen) genFuncM(obj *types.Func) {
func (g *objcGen) genGetter(oName string, f *types.Var) {
t := f.Type()
g.Printf("- (%s)%s {\n", g.objcType(t), lowerFirst(f.Name()))
g.Printf("- (%s)%s {\n", g.objcType(t), objcNameReplacer(lowerFirst(f.Name())))
g.Indent()
g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
g.Printf("%s r0 = ", g.cgoType(f.Type()))
@ -885,7 +883,7 @@ func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) {
continue
}
name, typ := f.Name(), g.objcFieldType(f.Type())
g.Printf("- (%s)%s;\n", typ, lowerFirst(name))
g.Printf("- (%s)%s;\n", typ, objcNameReplacer(lowerFirst(name)))
g.Printf("- (void)set%s:(%s)v;\n", name, typ)
}
@ -896,7 +894,7 @@ func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) {
continue
}
s := g.funcSummary(m)
g.Printf("- %s;\n", lowerFirst(s.asMethod(g)))
g.Printf("- %s;\n", objcNameReplacer(lowerFirst(s.asMethod(g))))
}
g.Printf("@end\n")
}
@ -1050,25 +1048,10 @@ func (g *objcGen) objcType(typ types.Type) string {
}
}
func lowerFirst(s string) string {
if s == "" {
return ""
}
var conv []rune
for len(s) > 0 {
r, n := utf8.DecodeRuneInString(s)
if !unicode.IsUpper(r) {
if l := len(conv); l > 1 {
conv[l-1] = unicode.ToUpper(conv[l-1])
}
return string(conv) + s
}
conv = append(conv, unicode.ToLower(r))
s = s[n:]
}
return string(conv)
}
var objcNameReplacer = newNameSanitizer([]string{
"void", "char", "short", "int", "long", "float", "double", "signed",
"unsigned", "id", "const", "volatile", "in", "out", "inout", "bycopy",
"byref", "oneway", "self", "super", "init"})
const (
objcPreamble = `// Objective-C API for talking to %[1]s Go package.

View File

@ -20,29 +20,29 @@
- (void)byte;
- (void)case;
- (void)catch;
- (void)char;
- (void)char_;
- (void)class;
- (void)const;
- (void)const_;
- (void)continue;
- (void)default;
- (void)do;
- (void)double;
- (void)double_;
- (void)else;
- (void)enum;
- (void)extends;
- (void)false;
- (void)final;
- (void)finally;
- (void)float;
- (void)float_;
- (void)for;
- (void)goto;
- (void)if;
- (void)implements;
- (void)import;
- (void)instanceof;
- (void)int;
- (void)int_;
- (void)interface;
- (void)long;
- (void)long_;
- (void)native;
- (void)new;
- (void)null;
@ -51,10 +51,10 @@
- (void)protected;
- (void)public;
- (void)return;
- (void)short;
- (void)short_;
- (void)static;
- (void)strictfp;
- (void)super;
- (void)super_;
- (void)switch;
- (void)synchronized;
- (void)this;
@ -63,8 +63,8 @@
- (void)transient;
- (void)true;
- (void)try;
- (void)void;
- (void)volatile;
- (void)void_;
- (void)volatile_;
- (void)while;
@end
@ -82,29 +82,29 @@
- (void)byte;
- (void)case;
- (void)catch;
- (void)char;
- (void)char_;
- (void)class;
- (void)const;
- (void)const_;
- (void)continue;
- (void)default;
- (void)do;
- (void)double;
- (void)double_;
- (void)else;
- (void)enum;
- (void)extends;
- (void)false;
- (void)final;
- (void)finally;
- (void)float;
- (void)float_;
- (void)for;
- (void)goto;
- (void)if;
- (void)implements;
- (void)import;
- (void)instanceof;
- (void)int;
- (void)int_;
- (void)interface;
- (void)long;
- (void)long_;
- (void)native;
- (void)new;
- (void)null;
@ -113,10 +113,10 @@
- (void)protected;
- (void)public;
- (void)return;
- (void)short;
- (void)short_;
- (void)static;
- (void)strictfp;
- (void)super;
- (void)super_;
- (void)switch;
- (void)synchronized;
- (void)this;
@ -125,8 +125,8 @@
- (void)transient;
- (void)true;
- (void)try;
- (void)void;
- (void)volatile;
- (void)void_;
- (void)volatile_;
- (void)while;
@end

View File

@ -54,7 +54,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Catch(refnum);
}
- (void)char {
- (void)char_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Char(refnum);
}
@ -64,7 +64,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Class(refnum);
}
- (void)const {
- (void)const_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Const(refnum);
}
@ -84,7 +84,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Do(refnum);
}
- (void)double {
- (void)double_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Double(refnum);
}
@ -119,7 +119,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Finally(refnum);
}
- (void)float {
- (void)float_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Float(refnum);
}
@ -154,7 +154,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Instanceof(refnum);
}
- (void)int {
- (void)int_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Int(refnum);
}
@ -164,7 +164,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Interface(refnum);
}
- (void)long {
- (void)long_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Long(refnum);
}
@ -209,7 +209,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Return(refnum);
}
- (void)short {
- (void)short_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Short(refnum);
}
@ -224,7 +224,7 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Strictfp(refnum);
}
- (void)super {
- (void)super_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Super(refnum);
}
@ -269,12 +269,12 @@ static NSString* errDomain = @"go.keywords";
proxykeywords_KeywordCaller_Try(refnum);
}
- (void)void {
- (void)void_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Void(refnum);
}
- (void)volatile {
- (void)volatile_ {
int32_t refnum = go_seq_go_to_refnum(self._ref);
proxykeywords_KeywordCaller_Volatile(refnum);
}
@ -340,7 +340,7 @@ void cproxykeywords_KeywordCaller_Catch(int32_t refnum) {
void cproxykeywords_KeywordCaller_Char(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o char];
[o char_];
}
}
@ -354,7 +354,7 @@ void cproxykeywords_KeywordCaller_Class(int32_t refnum) {
void cproxykeywords_KeywordCaller_Const(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o const];
[o const_];
}
}
@ -382,7 +382,7 @@ void cproxykeywords_KeywordCaller_Do(int32_t refnum) {
void cproxykeywords_KeywordCaller_Double(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o double];
[o double_];
}
}
@ -431,7 +431,7 @@ void cproxykeywords_KeywordCaller_Finally(int32_t refnum) {
void cproxykeywords_KeywordCaller_Float(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o float];
[o float_];
}
}
@ -480,7 +480,7 @@ void cproxykeywords_KeywordCaller_Instanceof(int32_t refnum) {
void cproxykeywords_KeywordCaller_Int(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o int];
[o int_];
}
}
@ -494,7 +494,7 @@ void cproxykeywords_KeywordCaller_Interface(int32_t refnum) {
void cproxykeywords_KeywordCaller_Long(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o long];
[o long_];
}
}
@ -557,7 +557,7 @@ void cproxykeywords_KeywordCaller_Return(int32_t refnum) {
void cproxykeywords_KeywordCaller_Short(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o short];
[o short_];
}
}
@ -578,7 +578,7 @@ void cproxykeywords_KeywordCaller_Strictfp(int32_t refnum) {
void cproxykeywords_KeywordCaller_Super(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o super];
[o super_];
}
}
@ -641,14 +641,14 @@ void cproxykeywords_KeywordCaller_Try(int32_t refnum) {
void cproxykeywords_KeywordCaller_Void(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o void];
[o void_];
}
}
void cproxykeywords_KeywordCaller_Volatile(int32_t refnum) {
@autoreleasepool {
GoKeywordsKeywordCaller* o = go_seq_objc_from_refnum(refnum);
[o volatile];
[o volatile_];
}
}