diff --git a/Makefile b/Makefile index 85ad6e2..8e720a0 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ generate: root build .root/src/$(PKG)/tests/snake.go \ .root/src/$(PKG)/tests/data.go \ .root/src/$(PKG)/tests/omitempty.go \ - .root/src/$(PKG)/tests/nothing.go + .root/src/$(PKG)/tests/nothing.go \ + .root/src/$(PKG)/tests/named_type.go .root/bin/easyjson -all .root/src/$(PKG)/tests/data.go .root/bin/easyjson -all .root/src/$(PKG)/tests/nothing.go @@ -30,6 +31,7 @@ generate: root build .root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go .root/bin/easyjson -build_tags=use_easyjson .root/src/$(PKG)/benchmark/data.go .root/bin/easyjson .root/src/$(PKG)/tests/nested_easy.go + .root/bin/easyjson .root/src/$(PKG)/tests/named_type.go test: generate root go test \ diff --git a/gen/generator.go b/gen/generator.go index c5c9103..db232d8 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -255,14 +255,41 @@ func (g *Generator) getType(t reflect.Type) string { } if t.Name() == "" || t.PkgPath() == "" { + if t.Kind() == reflect.Struct { + // the fields of an anonymous struct can have named types, + // and t.String() will not be sufficient because it does not + // remove the package name when it matches g.pkgPath. + // so we convert by hand + nf := t.NumField() + lines := make([]string, 0, nf) + for i := 0; i < nf; i++ { + f := t.Field(i) + line := f.Name + " " + g.getType(f.Type) + t := f.Tag + if t != "" { + line += " " + escapeTag(t) + } + lines = append(lines, line) + } + return strings.Join([]string{"struct { ", strings.Join(lines, "; "), " }"}, "") + } return t.String() } else if t.PkgPath() == g.pkgPath { return t.Name() } - // TODO: unnamed structs. return g.pkgAlias(t.PkgPath()) + "." + t.Name() } +// escape a struct field tag string back to source code +func escapeTag(tag reflect.StructTag) string { + t := string(tag) + if strings.ContainsRune(t, '`') { + // there are ` in the string; we can't use ` to enclose the string + return strconv.Quote(t) + } + return "`" + t + "`" +} + // uniqueVarName returns a file-unique name that can be used for generated variables. func (g *Generator) uniqueVarName() string { g.varCounter++ diff --git a/tests/basic_test.go b/tests/basic_test.go index 5798ee4..4e7c20c 100644 --- a/tests/basic_test.go +++ b/tests/basic_test.go @@ -36,6 +36,7 @@ var testCases = []struct { {&deepNestValue, deepNestString}, {&IntsValue, IntsString}, {&mapStringStringValue, mapStringStringString}, + {&namedTypeValue, namedTypeValueString}, } func TestMarshal(t *testing.T) { diff --git a/tests/named_type.go b/tests/named_type.go new file mode 100644 index 0000000..0ff8dfe --- /dev/null +++ b/tests/named_type.go @@ -0,0 +1,22 @@ +package tests + +//easyjson:json +type NamedType struct { + Inner struct { + // easyjson is mistakenly naming the type of this field 'tests.MyString' in the generated output + // something about a named type inside an anonmymous type is triggering this bug + Field MyString `tag:"value"` + Field2 int "tag:\"value with ` in it\"" + } +} + +type MyString string + +var namedTypeValue NamedType + +func init() { + namedTypeValue.Inner.Field = "test" + namedTypeValue.Inner.Field2 = 123 +} + +var namedTypeValueString = `{"Inner":{"Field":"test","Field2":123}}`