Skip to content

Commit 68d82d6

Browse files
committed
Handle types that implement json.Marshaler interface
Fixes #9
1 parent a1a85f0 commit 68d82d6

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

errchkjson.go

+23-3
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func (e *errchkjson) jsonSafe(t types.Type, level int, seenTypes map[types.Type]
154154
return nil
155155
}
156156

157-
if types.Implements(t, textMarshalerInterface()) {
157+
if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
158158
return fmt.Errorf("unsafe type `%s` found", t.String())
159159
}
160160

@@ -247,7 +247,7 @@ func (e *errchkjson) jsonSafe(t types.Type, level int, seenTypes map[types.Type]
247247
}
248248

249249
func jsonSafeMapKey(t types.Type) error {
250-
if types.Implements(t, textMarshalerInterface()) {
250+
if types.Implements(t, textMarshalerInterface()) || types.Implements(t, jsonMarshalerInterface()) {
251251
return fmt.Errorf("unsafe type `%s` as map key found", t.String())
252252
}
253253
switch ut := t.Underlying().(type) {
@@ -268,7 +268,7 @@ func jsonSafeMapKey(t types.Type) error {
268268
}
269269
}
270270

271-
// Construct *types.Interface for interface TextMarshaler
271+
// Construct *types.Interface for interface encoding.TextMarshaler
272272
// type TextMarshaler interface {
273273
// MarshalText() (text []byte, err error)
274274
// }
@@ -287,3 +287,23 @@ func textMarshalerInterface() *types.Interface {
287287

288288
return textMarshalerInterface
289289
}
290+
291+
// Construct *types.Interface for interface json.Marshaler
292+
// type Marshaler interface {
293+
// MarshalJSON() ([]byte, error)
294+
// }
295+
//
296+
func jsonMarshalerInterface() *types.Interface {
297+
textMarshalerInterface := types.NewInterfaceType([]*types.Func{
298+
types.NewFunc(token.NoPos, nil, "MarshalJSON", types.NewSignature(
299+
nil, nil, types.NewTuple(
300+
types.NewVar(token.NoPos, nil, "",
301+
types.NewSlice(
302+
types.Universe.Lookup("byte").Type())),
303+
types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("error").Type())),
304+
false)),
305+
}, nil)
306+
textMarshalerInterface.Complete()
307+
308+
return textMarshalerInterface
309+
}

testdata/src/nosafe/a.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import (
1010

1111
type marshalText struct{}
1212

13-
func (mt marshalText) MarshalText() ([]byte, error) {
13+
func (_ marshalText) MarshalText() ([]byte, error) {
1414
return []byte(`mt`), nil
1515
}
1616

1717
var _ encoding.TextMarshaler = marshalText(struct{}{})
1818

19+
type marshalJSON struct{}
20+
21+
func (_ marshalJSON) MarshalJSON() ([]byte, error) {
22+
return []byte(`mj`), nil
23+
}
24+
25+
var _ json.Marshaler = marshalJSON(struct{}{})
26+
1927
// JSONMarshalSafeTypesWithNoSafe contains a multitude of test cases to marshal different combinations of types to JSON,
2028
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
2129
func JSONMarshalSafeTypesWithNoSafe() {
@@ -266,6 +274,8 @@ type (
266274
Stringer fmt.Stringer
267275
Mt marshalText
268276
MapMarshalTextString map[marshalText]string
277+
Mj marshalJSON
278+
MapMarshalJSONString map[marshalJSON]string
269279

270280
C128 complex128
271281
C128Ptr *complex128
@@ -301,6 +311,8 @@ func JSONMarshalSafeStructWithUnexportedFieldsWithNoSafe() {
301311
stringer fmt.Stringer // unsafe unexported
302312
mt marshalText // unsafe unexported
303313
mapMarshalTextString map[marshalText]string // unsafe unexported
314+
mj marshalJSON // unsafe unexported
315+
mapMarshalJSONString map[marshalJSON]string // unsafe unexported
304316
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
305317
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported
306318

@@ -366,6 +378,8 @@ func JSONMarshalSafeStructWithOmittedFieldsWithNoSafe() {
366378
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
367379
Mt marshalText `json:"-"` // unsafe exported but omitted
368380
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
381+
Mj marshalJSON `json:"-"` // unsafe exported but omitted
382+
MapMarshalJSONString map[marshalJSON]string `json:"-"` // unsafe exported but omitted
369383
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
370384
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
371385

@@ -506,6 +520,16 @@ func JSONMarshalUnsafeTypes() {
506520
_, _ = json.Marshal(mapMarshalTextString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalText` as map key found"
507521
_, err = json.Marshal(mapMarshalTextString) // err is checked
508522
_ = err
523+
524+
var mj marshalJSON
525+
_, _ = json.Marshal(mj) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalJSON` found"
526+
_, err = json.Marshal(mj) // err is checked
527+
_ = err
528+
529+
var mapMarshalJSONString map[marshalJSON]string
530+
_, _ = json.Marshal(mapMarshalJSONString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `nosafe.marshalJSON` as map key found"
531+
_, err = json.Marshal(mapMarshalJSONString) // err is checked
532+
_ = err
509533
}
510534

511535
// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,

testdata/src/standard/a.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import (
1010

1111
type marshalText struct{}
1212

13-
func (mt marshalText) MarshalText() ([]byte, error) {
13+
func (_ marshalText) MarshalText() ([]byte, error) {
1414
return []byte(`mt`), nil
1515
}
1616

1717
var _ encoding.TextMarshaler = marshalText(struct{}{})
1818

19+
type marshalJSON struct{}
20+
21+
func (_ marshalJSON) MarshalJSON() ([]byte, error) {
22+
return []byte(`mj`), nil
23+
}
24+
25+
var _ json.Marshaler = marshalJSON(struct{}{})
26+
1927
// JSONMarshalSafeTypes contains a multitude of test cases to marshal different combinations of types to JSON,
2028
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
2129
func JSONMarshalSafeTypes() {
@@ -266,6 +274,8 @@ type (
266274
Stringer fmt.Stringer
267275
Mt marshalText
268276
MapMarshalTextString map[marshalText]string
277+
Mj marshalJSON
278+
MapMarshalJSONString map[marshalJSON]string
269279

270280
C128 complex128
271281
C128Ptr *complex128
@@ -301,6 +311,8 @@ func JSONMarshalSafeStructWithUnexportedFields() {
301311
stringer fmt.Stringer // unsafe unexported
302312
mt marshalText // unsafe unexported
303313
mapMarshalTextString map[marshalText]string // unsafe unexported
314+
mj marshalJSON // unsafe unexported
315+
mapMarshalJSONString map[marshalJSON]string // unsafe unexported
304316
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
305317
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported
306318

@@ -366,6 +378,8 @@ func JSONMarshalSafeStructWithOmittedFields() {
366378
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
367379
Mt marshalText `json:"-"` // unsafe exported but omitted
368380
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
381+
Mj marshalJSON `json:"-"` // unsafe exported but omitted
382+
MapMarshalJSONString map[marshalJSON]string `json:"-"` // unsafe exported but omitted
369383
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
370384
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
371385

@@ -506,6 +520,16 @@ func JSONMarshalUnsafeTypes() {
506520
_, _ = json.Marshal(mapMarshalTextString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalText` as map key found"
507521
_, err = json.Marshal(mapMarshalTextString) // err is checked
508522
_ = err
523+
524+
var mj marshalJSON
525+
_, _ = json.Marshal(mj) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalJSON` found"
526+
_, err = json.Marshal(mj) // err is checked
527+
_ = err
528+
529+
var mapMarshalJSONString map[marshalJSON]string
530+
_, _ = json.Marshal(mapMarshalJSONString) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `standard.marshalJSON` as map key found"
531+
_, err = json.Marshal(mapMarshalJSONString) // err is checked
532+
_ = err
509533
}
510534

511535
// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,

0 commit comments

Comments
 (0)