From af33c478461d9d790e46e65ba2fdc9214a42988a Mon Sep 17 00:00:00 2001 From: Nao Yonashiro Date: Tue, 26 Apr 2022 14:16:28 +0900 Subject: [PATCH] fix: determining embedded structs was wrong fix #362 --- decode_test.go | 15 +++++++++++++++ internal/decoder/compile.go | 9 +++++++++ internal/encoder/code.go | 16 ++++++++++++++-- internal/runtime/struct_field.go | 6 +++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/decode_test.go b/decode_test.go index f7c4074..93b7f41 100644 --- a/decode_test.go +++ b/decode_test.go @@ -3944,3 +3944,18 @@ func TestIssue364(t *testing.T) { t.Errorf("unexpected result: %v", v.Description) } } + +func TestIssue362(t *testing.T) { + type AliasedPrimitive int + type Combiner struct { + SomeField int + AliasedPrimitive + } + originalCombiner := Combiner{AliasedPrimitive: 7} + b, err := json.Marshal(originalCombiner) + assertErr(t, err) + newCombiner := Combiner{} + err = json.Unmarshal(b, &newCombiner) + assertErr(t, err) + assertEq(t, "TestEmbeddedPrimitiveAlias", originalCombiner, newCombiner) +} diff --git a/internal/decoder/compile.go b/internal/decoder/compile.go index bf17d1b..f13b43b 100644 --- a/internal/decoder/compile.go +++ b/internal/decoder/compile.go @@ -394,6 +394,15 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo allFields = append(allFields, fieldSet) } } + } else { + fieldSet := &structFieldSet{ + dec: dec, + offset: field.Offset, + isTaggedKey: tag.IsTaggedKey, + key: field.Name, + keyLen: int64(len(field.Name)), + } + allFields = append(allFields, fieldSet) } } else { if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) { diff --git a/internal/encoder/code.go b/internal/encoder/code.go index a00e38a..a886480 100644 --- a/internal/encoder/code.go +++ b/internal/encoder/code.go @@ -2,6 +2,7 @@ package encoder import ( "fmt" + "reflect" "unsafe" "github.com/goccy/go-json/internal/runtime" @@ -383,7 +384,7 @@ func (c *StructCode) Kind() CodeKind { } func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode { - if field.isAnonymous { + if isEmbeddedStruct(field) { return c.lastAnonymousFieldCode(firstField) } lastField := firstField @@ -436,7 +437,7 @@ func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { } if isEndField { endField := fieldCodes.Last() - if field.isAnonymous { + if isEmbeddedStruct(field) { firstField.End = endField lastField := c.lastAnonymousFieldCode(firstField) lastField.NextField = endField @@ -1003,3 +1004,14 @@ func convertPtrOp(code *Opcode) OpType { } return code.Op } + +func isEmbeddedStruct(field *StructFieldCode) bool { + if !field.isAnonymous { + return false + } + t := field.typ + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + return t.Kind() == reflect.Struct +} diff --git a/internal/runtime/struct_field.go b/internal/runtime/struct_field.go index c321180..eba4257 100644 --- a/internal/runtime/struct_field.go +++ b/internal/runtime/struct_field.go @@ -13,7 +13,11 @@ func getTag(field reflect.StructField) string { func IsIgnoredStructField(field reflect.StructField) bool { if field.PkgPath != "" { if field.Anonymous { - if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct { + t := field.Type + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if !field.IsExported() && t.Kind() != reflect.Struct { return true } } else {