Skip to content

Commit

Permalink
private/model/api: Update SDK code generation for colliding field nam…
Browse files Browse the repository at this point in the history
…es (aws#96)

Ports aws#1713 to the v2 SDK. Fixing the issue where API
field names could collide with SDK generated methods.

Fix aws#78
  • Loading branch information
jasdel authored Jan 15, 2018
1 parent ed4e5c9 commit 3a5dcd2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
2 changes: 2 additions & 0 deletions private/model/api/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func (a *API) Setup() {
if !a.NoRenameToplevelShapes {
a.renameToplevelShapes()
}

a.renameCollidingFields()
a.updateTopLevelShapeReferences()
a.createInputOutputShapes()
a.customizationPasses()
Expand Down
43 changes: 43 additions & 0 deletions private/model/api/passes.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,49 @@ func (a *API) renameExportable() {
}
}

// renameCollidingFields will rename any fields that uses an SDK or Golang
// specific name.
func (a *API) renameCollidingFields() {
for _, v := range a.Shapes {
namesWithSet := map[string]struct{}{}
for k, field := range v.MemberRefs {
if strings.HasPrefix(k, "Set") {
namesWithSet[k] = struct{}{}
}

if collides(k) {
renameCollidingField(k, v, field)
}
}

// checks if any field names collide with setters.
for name := range namesWithSet {
if field, ok := v.MemberRefs["Set"+name]; ok {
renameCollidingField(name, v, field)
}
}
}
}

// collides will return true if it is a name used by the SDK or Golang.
func collides(name string) bool {
switch name {
case "String",
"GoString",
"Validate":
return true
default:
return false
}
}

func renameCollidingField(name string, v *Shape, field *ShapeRef) {
newName := name + "_"
fmt.Printf("Shape %s's field %q renamed to %q\n", v.ShapeName, name, newName)
delete(v.MemberRefs, name)
v.MemberRefs[newName] = field
}

// createInputOutputShapes creates toplevel input/output shapes if they
// have not been defined in the API. This normalizes all APIs to always
// have an input and output structure in the signature.
Expand Down
47 changes: 45 additions & 2 deletions private/model/api/passes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
package api

import (
"reflect"
"testing"
)

func TestUniqueInputAndOutputs(t *testing.T) {
testCases := [][]struct {
cases := [][]struct {
expectedInput string
expectedOutput string
operation string
Expand Down Expand Up @@ -38,7 +39,7 @@ func TestUniqueInputAndOutputs(t *testing.T) {
},
}

for _, c := range testCases {
for _, c := range cases {
a := &API{
name: "FooService",
Operations: map[string]*Operation{},
Expand Down Expand Up @@ -92,3 +93,45 @@ func TestUniqueInputAndOutputs(t *testing.T) {

}
}

func TestCollidingFields(t *testing.T) {
cases := []struct {
api *API
expected []*Shapes
}{
{
&API{
name: "FooService",
Shapes: []*Shapes{
{
MemberRefs: map[string]*ShapeRef{
"String": &ShapeRef{},
"GoString": &ShapeRef{},
"Validate": &ShapeRef{},
"Foo": &ShapeRef{},
"SetFoo": &ShapeRef{},
},
},
},
},
[]*Shapes{
{
MemberRefs: map[string]*ShapeRef{
"String_": &ShapeRef{},
"GoString_": &ShapeRef{},
"Validate_": &ShapeRef{},
"Foo": &ShapeRef{},
"SetFoo_": &ShapeRef{},
},
},
},
},
}

for _, c := range testCases {
c.api.renameCollidingFields()
if !reflect.DeepEqual(c.api.Shapes, c.expected) {
t.Errorf("expected %v, but received %v", c.expected, c.api.Shapes)
}
}
}

0 comments on commit 3a5dcd2

Please sign in to comment.