Skip to content

Commit 0a7e5d9

Browse files
authored
Merge pull request #264 from goccy/feature/fix-indirect
Fix encoding of indirect layout structure
2 parents 36a91cc + 9028569 commit 0a7e5d9

File tree

3 files changed

+138
-3
lines changed

3 files changed

+138
-3
lines changed

encode_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,3 +2004,32 @@ func TestInterfaceWithPointer(t *testing.T) {
20042004
}
20052005
assertEq(t, "interface{}", string(expected), string(actual))
20062006
}
2007+
2008+
func TestIssue263(t *testing.T) {
2009+
type Foo struct {
2010+
A []string `json:"a"`
2011+
B int `json:"b"`
2012+
}
2013+
2014+
type MyStruct struct {
2015+
Foo *Foo `json:"foo,omitempty"`
2016+
}
2017+
2018+
s := MyStruct{
2019+
Foo: &Foo{
2020+
A: []string{"ls -lah"},
2021+
B: 0,
2022+
},
2023+
}
2024+
expected, err := stdjson.Marshal(s)
2025+
if err != nil {
2026+
t.Fatal(err)
2027+
}
2028+
actual, err := json.Marshal(s)
2029+
if err != nil {
2030+
t.Fatal(err)
2031+
}
2032+
if !bytes.Equal(expected, actual) {
2033+
t.Fatalf("expected:[%s] but got:[%s]", string(expected), string(actual))
2034+
}
2035+
}

internal/encoder/compiler.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,8 +1440,10 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
14401440
// if parent is indirect type, set child indirect property to true
14411441
valueCode.Flags |= IndirectFlags
14421442
} else {
1443-
// if parent is not indirect type and child have only one field, set child indirect property to false
1444-
if i == 0 && valueCode.NextField != nil && valueCode.NextField.Op == OpStructEnd {
1443+
// if parent is not indirect type, set child indirect property to false.
1444+
// but if parent's indirect is false and isPtr is true, then indirect must be true.
1445+
// Do this only if indirectConversion is enabled at the end of compileStruct.
1446+
if i == 0 {
14451447
valueCode.Flags &= ^IndirectFlags
14461448
}
14471449
}
@@ -1544,7 +1546,11 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
15441546
delete(ctx.structTypeToCompiledCode, typeptr)
15451547

15461548
if !disableIndirectConversion && (head.Flags&IndirectFlags == 0) && isPtr {
1547-
head.Flags |= IndirectFlags
1549+
headCode := head
1550+
for strings.Contains(headCode.Op.String(), "Head") {
1551+
headCode.Flags |= IndirectFlags
1552+
headCode = headCode.Next
1553+
}
15481554
}
15491555

15501556
return ret, nil

test/cover/cover_int_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,56 @@ func TestCoverInt(t *testing.T) {
631631
}{A: -1}},
632632
},
633633

634+
// HeadIntNotRootMultiFields
635+
{
636+
name: "HeadIntNotRootMultiFields",
637+
data: struct {
638+
A struct {
639+
A int `json:"a"`
640+
B int `json:"b"`
641+
}
642+
}{A: struct {
643+
A int `json:"a"`
644+
B int `json:"b"`
645+
}{A: -1, B: 1}},
646+
},
647+
{
648+
name: "HeadIntNotRootOmitEmptyMultiFields",
649+
data: struct {
650+
A struct {
651+
A int `json:"a,omitempty"`
652+
B int `json:"b,omitempty"`
653+
}
654+
}{A: struct {
655+
A int `json:"a,omitempty"`
656+
B int `json:"b,omitempty"`
657+
}{A: -1, B: 1}},
658+
},
659+
{
660+
name: "HeadIntNotRootStringMultiFields",
661+
data: struct {
662+
A struct {
663+
A int `json:"a,string"`
664+
B int `json:"b,string"`
665+
}
666+
}{A: struct {
667+
A int `json:"a,string"`
668+
B int `json:"b,string"`
669+
}{A: -1, B: 1}},
670+
},
671+
{
672+
name: "HeadIntNotRootStringOmitEmptyMultiFields",
673+
data: struct {
674+
A struct {
675+
A int `json:"a,string,omitempty"`
676+
B int `json:"b,string,omitempty"`
677+
}
678+
}{A: struct {
679+
A int `json:"a,string,omitempty"`
680+
B int `json:"b,string,omitempty"`
681+
}{A: -1, B: 1}},
682+
},
683+
634684
// HeadIntPtrNotRoot
635685
{
636686
name: "HeadIntPtrNotRoot",
@@ -791,6 +841,56 @@ func TestCoverInt(t *testing.T) {
791841
}{A: -1})},
792842
},
793843

844+
// PtrHeadIntNotRootMultiFields
845+
{
846+
name: "PtrHeadIntNotRootMultiFields",
847+
data: struct {
848+
A *struct {
849+
A int `json:"a"`
850+
B int `json:"b"`
851+
}
852+
}{A: &(struct {
853+
A int `json:"a"`
854+
B int `json:"b"`
855+
}{A: -1, B: 1})},
856+
},
857+
{
858+
name: "PtrHeadIntNotRootOmitEmptyMultiFields",
859+
data: struct {
860+
A *struct {
861+
A int `json:"a,omitempty"`
862+
B int `json:"b,omitempty"`
863+
}
864+
}{A: &(struct {
865+
A int `json:"a,omitempty"`
866+
B int `json:"b,omitempty"`
867+
}{A: -1, B: 1})},
868+
},
869+
{
870+
name: "PtrHeadIntNotRootStringMultiFields",
871+
data: struct {
872+
A *struct {
873+
A int `json:"a,string"`
874+
B int `json:"b,string"`
875+
}
876+
}{A: &(struct {
877+
A int `json:"a,string"`
878+
B int `json:"b,string"`
879+
}{A: -1, B: 1})},
880+
},
881+
{
882+
name: "PtrHeadIntNotRootStringOmitEmptyMultiFields",
883+
data: struct {
884+
A *struct {
885+
A int `json:"a,string,omitempty"`
886+
B int `json:"b,string,omitempty"`
887+
}
888+
}{A: &(struct {
889+
A int `json:"a,string,omitempty"`
890+
B int `json:"b,string,omitempty"`
891+
}{A: -1, B: 1})},
892+
},
893+
794894
// PtrHeadIntPtrNotRoot
795895
{
796896
name: "PtrHeadIntPtrNotRoot",

0 commit comments

Comments
 (0)