forked from mirror/go-json
Add nilcheck property
This commit is contained in:
parent
d3b031cef2
commit
249c4da6dd
|
@ -609,123 +609,228 @@ func TestCoverMarshalJSON(t *testing.T) {
|
|||
}{A: nil, B: nil, C: nil},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONZeroMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFields",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a"`
|
||||
B coverMarshalJSON `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a,omitempty"`
|
||||
B coverMarshalJSON `json:"b,omitempty"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFieldsString",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a,string"`
|
||||
B coverMarshalJSON `json:"b,string"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONZeroMultiFields",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a"`
|
||||
B coverPtrMarshalJSON `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONZeroMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a,omitempty"`
|
||||
B coverPtrMarshalJSON `json:"b,omitempty"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONZeroMultiFieldsString",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a,string"`
|
||||
B coverPtrMarshalJSON `json:"b,string"`
|
||||
}{},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFields",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a"`
|
||||
B coverMarshalJSON `json:"b"`
|
||||
}{A: coverMarshalJSON{}, B: coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a,omitempty"`
|
||||
B coverMarshalJSON `json:"b,omitempty"`
|
||||
}{A: coverMarshalJSON{}, B: coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFieldsString",
|
||||
data: &struct {
|
||||
A coverMarshalJSON `json:"a,string"`
|
||||
B coverMarshalJSON `json:"b,string"`
|
||||
}{A: coverMarshalJSON{}, B: coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONMultiFields",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a"`
|
||||
B coverPtrMarshalJSON `json:"b"`
|
||||
}{A: coverPtrMarshalJSON{}, B: coverPtrMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a,omitempty"`
|
||||
B coverPtrMarshalJSON `json:"b,omitempty"`
|
||||
}{A: coverPtrMarshalJSON{}, B: coverPtrMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONMultiFieldsString",
|
||||
data: &struct {
|
||||
A coverPtrMarshalJSON `json:"a,string"`
|
||||
B coverPtrMarshalJSON `json:"b,string"`
|
||||
}{A: coverPtrMarshalJSON{}, B: coverPtrMarshalJSON{}},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONPtrMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFields",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a"`
|
||||
B *coverMarshalJSON `json:"b"`
|
||||
}{A: &coverMarshalJSON{}, B: &coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a,omitempty"`
|
||||
B *coverMarshalJSON `json:"b,omitempty"`
|
||||
}{A: &coverMarshalJSON{}, B: &coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFieldsString",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a,string"`
|
||||
B *coverMarshalJSON `json:"b,string"`
|
||||
}{A: &coverMarshalJSON{}, B: &coverMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrMultiFields",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a"`
|
||||
B *coverPtrMarshalJSON `json:"b"`
|
||||
}{A: &coverPtrMarshalJSON{}, B: &coverPtrMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a,omitempty"`
|
||||
B *coverPtrMarshalJSON `json:"b,omitempty"`
|
||||
}{A: &coverPtrMarshalJSON{}, B: &coverPtrMarshalJSON{}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrMultiFieldsString",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a,string"`
|
||||
B *coverPtrMarshalJSON `json:"b,string"`
|
||||
}{A: &coverPtrMarshalJSON{}, B: &coverPtrMarshalJSON{}},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONPtrNilMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFields",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a"`
|
||||
B *coverMarshalJSON `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a,omitempty"`
|
||||
B *coverMarshalJSON `json:"b,omitempty"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFieldsString",
|
||||
data: &struct {
|
||||
A *coverMarshalJSON `json:"a,string"`
|
||||
B *coverMarshalJSON `json:"b,string"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrNilMultiFields",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a"`
|
||||
B *coverPtrMarshalJSON `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrNilMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a,omitempty"`
|
||||
B *coverPtrMarshalJSON `json:"b,omitempty"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONPtrNilMultiFieldsString",
|
||||
data: &struct {
|
||||
A *coverPtrMarshalJSON `json:"a,string"`
|
||||
B *coverPtrMarshalJSON `json:"b,string"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONNilMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFields",
|
||||
data: (*struct {
|
||||
A coverMarshalJSON `json:"a"`
|
||||
B coverMarshalJSON `json:"b"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFieldsOmitEmpty",
|
||||
data: (*struct {
|
||||
A coverMarshalJSON `json:"a,omitempty"`
|
||||
B coverMarshalJSON `json:"b,omitempty"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFieldsString",
|
||||
data: (*struct {
|
||||
A coverMarshalJSON `json:"a,string"`
|
||||
B coverMarshalJSON `json:"b,string"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONNilMultiFields",
|
||||
data: (*struct {
|
||||
A coverPtrMarshalJSON `json:"a"`
|
||||
B coverPtrMarshalJSON `json:"b"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONNilMultiFieldsOmitEmpty",
|
||||
data: (*struct {
|
||||
A coverPtrMarshalJSON `json:"a,omitempty"`
|
||||
B coverPtrMarshalJSON `json:"b,omitempty"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadPtrMarshalJSONNilMultiFieldsString",
|
||||
data: (*struct {
|
||||
A coverPtrMarshalJSON `json:"a,string"`
|
||||
B coverPtrMarshalJSON `json:"b,string"`
|
||||
})(nil),
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
// PtrHeadMarshalJSONZeroMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFields",
|
||||
data: &struct {
|
||||
A [2]int `json:"a"`
|
||||
B [2]int `json:"b"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A [2]int `json:"a,omitempty"`
|
||||
B [2]int `json:"b,omitempty"`
|
||||
}{},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONZeroMultiFieldsString",
|
||||
data: &struct {
|
||||
A [2]int `json:"a,string"`
|
||||
B [2]int `json:"b,string"`
|
||||
}{},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFields",
|
||||
data: &struct {
|
||||
A [2]int `json:"a"`
|
||||
B [2]int `json:"b"`
|
||||
}{A: [2]int{-1}, B: [2]int{1}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A [2]int `json:"a,omitempty"`
|
||||
B [2]int `json:"b,omitempty"`
|
||||
}{A: [2]int{-1}, B: [2]int{1}},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONMultiFieldsString",
|
||||
data: &struct {
|
||||
A [2]int `json:"a,string"`
|
||||
B [2]int `json:"b,string"`
|
||||
}{A: [2]int{-1}, B: [2]int{1}},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONPtrMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFields",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a"`
|
||||
B *[2]int `json:"b"`
|
||||
}{A: arrayptr([2]int{-1}), B: arrayptr([2]int{-2})},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a,omitempty"`
|
||||
B *[2]int `json:"b,omitempty"`
|
||||
}{A: arrayptr([2]int{-1}), B: arrayptr([2]int{-2})},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrMultiFieldsString",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a,string"`
|
||||
B *[2]int `json:"b,string"`
|
||||
}{A: arrayptr([2]int{-1}), B: arrayptr([2]int{-2})},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONPtrNilMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFields",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a"`
|
||||
B *[2]int `json:"b"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFieldsOmitEmpty",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a,omitempty"`
|
||||
B *[2]int `json:"b,omitempty"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONPtrNilMultiFieldsString",
|
||||
data: &struct {
|
||||
A *[2]int `json:"a,string"`
|
||||
B *[2]int `json:"b,string"`
|
||||
}{A: nil, B: nil},
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONNilMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFields",
|
||||
data: (*struct {
|
||||
A [2]int `json:"a"`
|
||||
B [2]int `json:"b"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFieldsOmitEmpty",
|
||||
data: (*struct {
|
||||
A [2]int `json:"a,omitempty"`
|
||||
B [2]int `json:"b,omitempty"`
|
||||
})(nil),
|
||||
},
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFieldsString",
|
||||
data: (*struct {
|
||||
A [2]int `json:"a,string"`
|
||||
B [2]int `json:"b,string"`
|
||||
})(nil),
|
||||
},
|
||||
|
||||
// PtrHeadMarshalJSONNilMultiFields
|
||||
{
|
||||
name: "PtrHeadMarshalJSONNilMultiFields",
|
||||
|
|
|
@ -1231,6 +1231,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
fieldNum := typ.NumField()
|
||||
indirect := ifaceIndir(typ)
|
||||
fieldIdx := 0
|
||||
disableIndirectConversion := false
|
||||
var (
|
||||
head *opcode
|
||||
code *opcode
|
||||
|
@ -1263,6 +1264,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
fieldOpcodeIndex := ctx.opcodeIndex
|
||||
fieldPtrIndex := ctx.ptrIndex
|
||||
ctx.incIndex()
|
||||
nilcheck := indirect
|
||||
var valueCode *opcode
|
||||
if i == 0 && fieldNum == 1 && isPtr && rtype_ptrTo(fieldType).Implements(marshalJSONType) && !fieldType.Implements(marshalJSONType) {
|
||||
// *struct{ field implementedMarshalJSONType } => struct { field *implementedMarshalJSONType }
|
||||
|
@ -1273,8 +1275,17 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
return nil, err
|
||||
}
|
||||
valueCode = code
|
||||
nilcheck = false
|
||||
indirect = false
|
||||
isPtr = false
|
||||
disableIndirectConversion = true
|
||||
} else if isPtr && fieldNum > 1 && fieldType.Kind() != reflect.Ptr && !fieldType.Implements(marshalJSONType) && rtype_ptrTo(fieldType).Implements(marshalJSONType) {
|
||||
ctx.typ = rtype_ptrTo(fieldType)
|
||||
code, err := encodeCompileMarshalJSON(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nilcheck = false
|
||||
valueCode = code
|
||||
} else {
|
||||
code, err := encodeCompile(ctx.withType(fieldType), i == 0 && isPtr)
|
||||
if err != nil {
|
||||
|
@ -1301,6 +1312,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
key := fmt.Sprintf(`"%s":`, tag.key)
|
||||
escapedKey := fmt.Sprintf(`%s:`, string(encodeEscapedString([]byte{}, tag.key)))
|
||||
valueCode.indirect = indirect
|
||||
valueCode.nilcheck = nilcheck
|
||||
fieldCode := &opcode{
|
||||
typ: valueCode.typ,
|
||||
displayIdx: fieldOpcodeIndex,
|
||||
|
@ -1314,6 +1326,7 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
displayKey: tag.key,
|
||||
offset: field.Offset,
|
||||
indirect: indirect,
|
||||
nilcheck: nilcheck,
|
||||
}
|
||||
if fieldIdx == 0 {
|
||||
fieldCode.headIdx = fieldCode.idx
|
||||
|
@ -1373,8 +1386,8 @@ func encodeCompileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error)
|
|||
|
||||
delete(ctx.structTypeToCompiledCode, typeptr)
|
||||
|
||||
if !code.indirect && isPtr {
|
||||
code.indirect = true
|
||||
if !disableIndirectConversion && !head.indirect && isPtr {
|
||||
head.indirect = true
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
|
|
@ -20,6 +20,7 @@ type opcode struct {
|
|||
anonymousKey bool // whether anonymous key
|
||||
root bool // whether root
|
||||
indirect bool // whether indirect or not
|
||||
nilcheck bool // whether needs to nilcheck or not
|
||||
rshiftNum uint8 // use to take bit for judging whether negative integer or not
|
||||
mask uint64 // mask for number
|
||||
indent int // indent number
|
||||
|
@ -93,6 +94,7 @@ func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
|
|||
anonymousKey: c.anonymousKey,
|
||||
root: c.root,
|
||||
indirect: c.indirect,
|
||||
nilcheck: c.nilcheck,
|
||||
indent: c.indent,
|
||||
idx: c.idx,
|
||||
headIdx: c.headIdx,
|
||||
|
|
|
@ -3234,7 +3234,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
}
|
||||
b = append(b, '{')
|
||||
b = append(b, code.key...)
|
||||
if p == 0 || code.indirect && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
bb, err := encodeMarshalJSON(b, ptrToInterface(code, p+code.offset))
|
||||
|
@ -3264,7 +3264,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
if p == 0 || code.indirect && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||
if p == 0 || code.nilcheck && code.typ.Kind() == reflect.Ptr && ptrToPtr(p) == 0 {
|
||||
code = code.nextField
|
||||
} else {
|
||||
b = append(b, code.key...)
|
||||
|
@ -4093,7 +4093,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
p := load(ctxptr, code.headIdx)
|
||||
b = append(b, code.key...)
|
||||
p += code.offset
|
||||
if code.typ.Kind() == reflect.Ptr && p != 0 && ptrToPtr(p) == 0 {
|
||||
if code.nilcheck && code.typ.Kind() == reflect.Ptr && p != 0 && ptrToPtr(p) == 0 {
|
||||
b = encodeNull(b)
|
||||
} else {
|
||||
v := ptrToInterface(code, p)
|
||||
|
@ -4108,7 +4108,7 @@ func encodeRun(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt Enco
|
|||
case opStructFieldOmitEmptyMarshalJSON:
|
||||
ptr := load(ctxptr, code.headIdx)
|
||||
p := ptr + code.offset
|
||||
if code.typ.Kind() == reflect.Ptr && p != 0 && ptrToPtr(p) == 0 {
|
||||
if code.nilcheck && code.typ.Kind() == reflect.Ptr && p != 0 && ptrToPtr(p) == 0 {
|
||||
code = code.nextField
|
||||
break
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue