Skip to content

Commit

Permalink
bind: Fix setter name generation for ObjC
Browse files Browse the repository at this point in the history
The generation for getters and setters of Go
exported fields that followed the accroynyms
rule, i.e. for a field named `OSName` the
resulting getter and settere were `osName` and
`setOSName` respectively, however the Obj-C rules
defined here:

  * https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

expected for the names to be the following: `osName`
and `setOsName`.

This commit updates setter name generation by capitalizing
the field name and leaves the getter name unchaged, this
also updates the golden files.

Fix golang/go#32008
  • Loading branch information
triztian committed Aug 2, 2019
1 parent d2bd2a2 commit 50acf06
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
23 changes: 23 additions & 0 deletions bind/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,29 @@ func TestLowerFirst(t *testing.T) {
}
}

func Test_objcCapitalize(t *testing.T) {
testCases := []struct {
in, want string
}{
{"", ""},
{"hello", "Hello"},
{"helloGopher", "HelloGopher"},
{"ID", "Id"},
{"IDOrName", "IdOrName"},
{"OSName", "OsName"},
{"a00name", "A00name"},

{"γειαΣας", "ΓειαΣας"},
}

for _, tc := range testCases {
if got := objcCapitalize(tc.in); got != tc.want {
t.Errorf("capitalize(%q) = %q; want %q", tc.in, got, tc.want)
}
}

}

// Test that typeName work for anonymous qualified fields.
func TestSelectorExprTypeName(t *testing.T) {
e, err := parser.ParseExprFrom(fset, "", "struct { bytes.Buffer }", 0)
Expand Down
44 changes: 43 additions & 1 deletion bind/genobjc.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"go/types"
"math"
"strings"
"unicode"
"unicode/utf8"

"golang.org/x/mobile/internal/importers/objc"
)
Expand Down Expand Up @@ -668,7 +670,7 @@ func (g *ObjcGen) genGetter(oName string, f *types.Var) {
func (g *ObjcGen) genSetter(oName string, f *types.Var) {
t := f.Type()

g.Printf("- (void)set%s:(%s)v {\n", f.Name(), g.objcType(t))
g.Printf("- (void)set%s:(%s)v {\n", objcCapitalize(f.Name()), g.objcType(t))
g.Indent()
g.Printf("int32_t refnum = go_seq_go_to_refnum(self._ref);\n")
g.genWrite("v", f.Type(), modeRetained)
Expand Down Expand Up @@ -1410,6 +1412,46 @@ func isObjcType(t types.Type) bool {
return typePkgFirstElem(t) == "ObjC"
}

// objcCapitalize ...
func objcCapitalize(s string) string {
switch utf8.RuneCount([]byte(s)) {
case 0:
return s

case 1:
r, _ := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r))

default:
var sb strings.Builder
sb.Grow(len(s))

// title case first
r, n := utf8.DecodeRuneInString(s)
sb.WriteRune(unicode.ToTitle(r))
s = s[n:]

// lower case second
r, n = utf8.DecodeRuneInString(s)
sb.WriteRune(unicode.ToLower(r))
s = s[n:]

// just copy the rest
for len(s) > 0 {
r, n = utf8.DecodeRuneInString(s)
if r == utf8.RuneError {
return sb.String()
}

sb.WriteRune(r)

s = s[n:]
}

return sb.String()
}
}

var objcNameReplacer = newNameSanitizer([]string{
"bool", "bycopy", "byref", "char", "const", "double", "float",
"id", "in", "init", "inout", "int", "long", "nil", "oneway",
Expand Down
2 changes: 1 addition & 1 deletion bind/testdata/doc.objc.m.golden
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
return _r0;
}

- (void)setSF:(NSString* _Nonnull)v {
- (void)setSf:(NSString* _Nonnull)v {
int32_t refnum = go_seq_go_to_refnum(self._ref);
nstring _v = go_seq_from_objc_string(v);
proxydoc_S_SF_Set(refnum, _v);
Expand Down

0 comments on commit 50acf06

Please sign in to comment.