From e99a906c3a3ac5959fa4b8d08f90dd5f75d3b27c Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 7 Sep 2016 16:02:52 +0200 Subject: [PATCH] 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 --- bind/gen.go | 43 ++++++++++++++++++++++++++ bind/genjava.go | 45 +++++----------------------- bind/genobjc.go | 39 +++++++----------------- bind/testdata/keywords.objc.h.golden | 40 ++++++++++++------------- bind/testdata/keywords.objc.m.golden | 40 ++++++++++++------------- 5 files changed, 101 insertions(+), 106 deletions(-) diff --git a/bind/gen.go b/bind/gen.go index dcf3a9a..8d482d7 100644 --- a/bind/gen.go +++ b/bind/gen.go @@ -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) + } +} diff --git a/bind/genjava.go b/bind/genjava.go index bf9f77d..a36333d 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -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") } diff --git a/bind/genobjc.go b/bind/genobjc.go index f067c03..4a936bf 100644 --- a/bind/genobjc.go +++ b/bind/genobjc.go @@ -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. diff --git a/bind/testdata/keywords.objc.h.golden b/bind/testdata/keywords.objc.h.golden index 1672b7e..df4c914 100644 --- a/bind/testdata/keywords.objc.h.golden +++ b/bind/testdata/keywords.objc.h.golden @@ -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 diff --git a/bind/testdata/keywords.objc.m.golden b/bind/testdata/keywords.objc.m.golden index c115f8c..d4f9d73 100644 --- a/bind/testdata/keywords.objc.m.golden +++ b/bind/testdata/keywords.objc.m.golden @@ -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_]; } }