Fix indirect layout

This commit is contained in:
Masaaki Goshima 2021-07-05 20:30:35 +09:00
parent 36a91cc8e8
commit 902856929d
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)) 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 // if parent is indirect type, set child indirect property to true
valueCode.Flags |= IndirectFlags valueCode.Flags |= IndirectFlags
} else { } else {
// if parent is not indirect type and child have only one field, set child indirect property to false // if parent is not indirect type, set child indirect property to false.
if i == 0 && valueCode.NextField != nil && valueCode.NextField.Op == OpStructEnd { // 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 valueCode.Flags &= ^IndirectFlags
} }
} }
@ -1544,7 +1546,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
delete(ctx.structTypeToCompiledCode, typeptr) delete(ctx.structTypeToCompiledCode, typeptr)
if !disableIndirectConversion && (head.Flags&IndirectFlags == 0) && isPtr { 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 return ret, nil

View File

@ -631,6 +631,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1}}, }{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 // HeadIntPtrNotRoot
{ {
name: "HeadIntPtrNotRoot", name: "HeadIntPtrNotRoot",
@ -791,6 +841,56 @@ func TestCoverInt(t *testing.T) {
}{A: -1})}, }{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 // PtrHeadIntPtrNotRoot
{ {
name: "PtrHeadIntPtrNotRoot", name: "PtrHeadIntPtrNotRoot",