Merge pull request #264 from goccy/feature/fix-indirect

Fix encoding of indirect layout structure
This commit is contained in:
Masaaki Goshima 2021-07-05 21:57:16 +09:00 committed by GitHub
commit 0a7e5d9001
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 3 deletions

View File

@ -2004,3 +2004,32 @@ func TestInterfaceWithPointer(t *testing.T) {
}
assertEq(t, "interface{}", string(expected), string(actual))
}
func TestIssue263(t *testing.T) {
type Foo struct {
A []string `json:"a"`
B int `json:"b"`
}
type MyStruct struct {
Foo *Foo `json:"foo,omitempty"`
}
s := MyStruct{
Foo: &Foo{
A: []string{"ls -lah"},
B: 0,
},
}
expected, err := stdjson.Marshal(s)
if err != nil {
t.Fatal(err)
}
actual, err := json.Marshal(s)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(expected, actual) {
t.Fatalf("expected:[%s] but got:[%s]", string(expected), string(actual))
}
}

View File

@ -1440,8 +1440,10 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
// if parent is indirect type, set child indirect property to true
valueCode.Flags |= IndirectFlags
} else {
// if parent is not indirect type and child have only one field, set child indirect property to false
if i == 0 && valueCode.NextField != nil && valueCode.NextField.Op == OpStructEnd {
// if parent is not indirect type, set child indirect property to false.
// but if parent's indirect is false and isPtr is true, then indirect must be true.
// Do this only if indirectConversion is enabled at the end of compileStruct.
if i == 0 {
valueCode.Flags &= ^IndirectFlags
}
}
@ -1544,7 +1546,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
delete(ctx.structTypeToCompiledCode, typeptr)
if !disableIndirectConversion && (head.Flags&IndirectFlags == 0) && isPtr {
head.Flags |= IndirectFlags
headCode := head
for strings.Contains(headCode.Op.String(), "Head") {
headCode.Flags |= IndirectFlags
headCode = headCode.Next
}
}
return ret, nil

View File

@ -631,6 +631,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1}},
},
// HeadIntNotRootMultiFields
{
name: "HeadIntNotRootMultiFields",
data: struct {
A struct {
A int `json:"a"`
B int `json:"b"`
}
}{A: struct {
A int `json:"a"`
B int `json:"b"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootOmitEmptyMultiFields",
data: struct {
A struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}
}{A: struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootStringMultiFields",
data: struct {
A struct {
A int `json:"a,string"`
B int `json:"b,string"`
}
}{A: struct {
A int `json:"a,string"`
B int `json:"b,string"`
}{A: -1, B: 1}},
},
{
name: "HeadIntNotRootStringOmitEmptyMultiFields",
data: struct {
A struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}
}{A: struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}{A: -1, B: 1}},
},
// HeadIntPtrNotRoot
{
name: "HeadIntPtrNotRoot",
@ -791,6 +841,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1})},
},
// PtrHeadIntNotRootMultiFields
{
name: "PtrHeadIntNotRootMultiFields",
data: struct {
A *struct {
A int `json:"a"`
B int `json:"b"`
}
}{A: &(struct {
A int `json:"a"`
B int `json:"b"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootOmitEmptyMultiFields",
data: struct {
A *struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}
}{A: &(struct {
A int `json:"a,omitempty"`
B int `json:"b,omitempty"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootStringMultiFields",
data: struct {
A *struct {
A int `json:"a,string"`
B int `json:"b,string"`
}
}{A: &(struct {
A int `json:"a,string"`
B int `json:"b,string"`
}{A: -1, B: 1})},
},
{
name: "PtrHeadIntNotRootStringOmitEmptyMultiFields",
data: struct {
A *struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}
}{A: &(struct {
A int `json:"a,string,omitempty"`
B int `json:"b,string,omitempty"`
}{A: -1, B: 1})},
},
// PtrHeadIntPtrNotRoot
{
name: "PtrHeadIntPtrNotRoot",