Add errchkjson linter (#2362)

This commit is contained in:
Lucas Bremgartner 2021-11-26 23:25:59 +01:00 committed by GitHub
parent fc888cf0cb
commit 55358972d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1362 additions and 0 deletions

View File

@ -137,6 +137,24 @@ linters-settings:
- io.Copy(*bytes.Buffer)
- io.Copy(os.Stdout)
errchkjson:
# with check-error-free-encoding set to true, errchkjson does warn about errors
# from json encoding functions that are safe to be ignored,
# because they are not possible to happen (default false)
#
# if check-error-free-encoding is set to true and errcheck linter is enabled,
# it is recommended to add the following exceptions to prevent from false positives:
#
# linters-settings:
# errcheck:
# exclude-functions:
# - encoding/json.Marshal
# - encoding/json.MarshalIndent
# - (*encoding/json.Encoder).Encode
check-error-free-encoding: false
# if report-no-exported is true, encoding a struct without exported fields is reported as issue (default false)
report-no-exported: false
errorlint:
# Check whether fmt.Errorf uses the %w verb for formatting errors. See the readme for caveats
errorf: true

1
go.mod
View File

@ -16,6 +16,7 @@ require (
github.com/blizzy78/varnamelen v0.5.0
github.com/bombsimon/wsl/v3 v3.3.0
github.com/breml/bidichk v0.2.1
github.com/breml/errchkjson v0.2.0
github.com/butuzov/ireturn v0.1.1
github.com/charithe/durationcheck v0.0.9
github.com/daixiang0/gci v0.2.9

2
go.sum generated
View File

@ -108,6 +108,8 @@ github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxj
github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
github.com/breml/bidichk v0.2.1 h1:SRNtZuLdfkxtocj+xyHXKC1Uv3jVi6EPYx+NHSTNQvE=
github.com/breml/bidichk v0.2.1/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso=
github.com/breml/errchkjson v0.2.0 h1:5XK9tXXqahYiPHuJ5Asx9a5ucpASxLMxq3EvQyLb26c=
github.com/breml/errchkjson v0.2.0/go.mod h1:jZEATw/jF69cL1iy7//Yih8yp/mXp2CBoBr9GJwCAsY=
github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY=
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=

View File

@ -89,6 +89,7 @@ type LintersSettings struct {
Dogsled DogsledSettings
Dupl DuplSettings
Errcheck ErrcheckSettings
ErrChkJSON ErrChkJSONSettings
ErrorLint ErrorLintSettings
Exhaustive ExhaustiveSettings
ExhaustiveStruct ExhaustiveStructSettings
@ -165,6 +166,11 @@ type Cyclop struct {
SkipTests bool `mapstructure:"skip-tests"`
}
type ErrChkJSONSettings struct {
CheckErrorFreeEncoding bool `mapstructure:"check-error-free-encoding"`
ReportNoExported bool `mapstructure:"report-no-exported"`
}
type DepGuardSettings struct {
ListType string `mapstructure:"list-type"`
Packages []string

View File

@ -0,0 +1,33 @@
package golinters
import (
"github.com/breml/errchkjson"
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)
func NewErrChkJSONFuncName(cfg *config.ErrChkJSONSettings) *goanalysis.Linter {
a := errchkjson.NewAnalyzer()
cfgMap := map[string]map[string]interface{}{}
cfgMap[a.Name] = map[string]interface{}{
"omit-safe": true,
}
if cfg != nil {
cfgMap[a.Name] = map[string]interface{}{
"omit-safe": !cfg.CheckErrorFreeEncoding,
"report-no-exported": cfg.ReportNoExported,
}
}
return goanalysis.NewLinter(
"errchkjson",
"Checks types passed to the json encoding functions. "+
"Reports unsupported types and optionally reports occations, "+
"where the check for the returned error can be omitted.",
[]*analysis.Analyzer{a},
cfgMap,
).WithLoadMode(goanalysis.LoadModeTypesInfo)
}

View File

@ -102,6 +102,7 @@ func enableLinterConfigs(lcs []*linter.Config, isEnabled func(lc *linter.Config)
func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var bidichkCfg *config.BiDiChkSettings
var cyclopCfg *config.Cyclop
var errchkjsonCfg *config.ErrChkJSONSettings
var errorlintCfg *config.ErrorLintSettings
var exhaustiveCfg *config.ExhaustiveSettings
var exhaustiveStructCfg *config.ExhaustiveStructSettings
@ -129,6 +130,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
if m.cfg != nil {
bidichkCfg = &m.cfg.LintersSettings.BiDiChk
cyclopCfg = &m.cfg.LintersSettings.Cyclop
errchkjsonCfg = &m.cfg.LintersSettings.ErrChkJSON
errorlintCfg = &m.cfg.LintersSettings.ErrorLint
exhaustiveCfg = &m.cfg.LintersSettings.Exhaustive
exhaustiveStructCfg = &m.cfg.LintersSettings.ExhaustiveStruct
@ -548,6 +550,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("1.43.0").
WithPresets(linter.PresetBugs).
WithURL("https://github.com/breml/bidichk"),
linter.NewConfig(golinters.NewErrChkJSONFuncName(errchkjsonCfg)).
WithSince("1.44.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/breml/errchkjson"),
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
linter.NewConfig(golinters.NewNoLintLint()).

2
test/testdata/configs/errchkjson.yml vendored Normal file
View File

@ -0,0 +1,2 @@
issues:
max-issues-per-linter: 100

View File

@ -0,0 +1,5 @@
issues:
max-issues-per-linter: 100
linters-settings:
errchkjson:
check-error-free-encoding: true

View File

@ -0,0 +1,3 @@
linters-settings:
errchkjson:
report-no-exported: true

641
test/testdata/errchkjson.go vendored Normal file
View File

@ -0,0 +1,641 @@
// args: -Eerrchkjson
// config_path: testdata/configs/errchkjson.yml
package testdata
import (
"encoding"
"encoding/json"
"fmt"
"io/ioutil"
"unsafe"
)
type marshalText struct{}
func (mt marshalText) MarshalText() ([]byte, error) {
return []byte(`mt`), nil
}
var _ encoding.TextMarshaler = marshalText(struct{}{})
// JSONMarshalSafeTypesWithNoSafe contains a multitude of test cases to marshal different combinations of types to JSON,
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
func JSONMarshalSafeTypesWithNoSafe() {
var err error
_, _ = json.Marshal(nil) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
json.Marshal(nil) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(nil) // nil is safe and check-error-free-encoding is false
_ = err
_, _ = json.MarshalIndent(nil, "", " ") // ERROR "Error return value of `encoding/json.MarshalIndent` is not checked"
json.MarshalIndent(nil, "", " ") // ERROR "Error return value of `encoding/json.MarshalIndent` is not checked"
_, err = json.MarshalIndent(nil, "", " ") // nil is safe and check-error-free-encoding is false
_ = err
enc := json.NewEncoder(ioutil.Discard)
_ = enc.Encode(nil) // ERROR "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is not checked"
enc.Encode(nil) // ERROR "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is not checked"
err = enc.Encode(nil) // nil is safe and check-error-free-encoding is false
_ = err
var b bool
_, _ = json.Marshal(b) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(b) // bool is safe and check-error-free-encoding is false
_ = err
var i int
_, _ = json.Marshal(i) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(i) // int is safe and check-error-free-encoding is false
_ = err
var i8 int8
_, _ = json.Marshal(i8) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(i8) // int8 is safe and check-error-free-encoding is false
_ = err
var i16 int16
_, _ = json.Marshal(i16) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(i16) // int16 is safe and check-error-free-encoding is false
_ = err
var i32 int32
_, _ = json.Marshal(i32) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(i32) // int32 / rune is safe and check-error-free-encoding is false
_ = err
var i64 int64
_, _ = json.Marshal(i64) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(i64) // int64 is safe and check-error-free-encoding is false
_ = err
var ui uint
_, _ = json.Marshal(ui) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ui) // uint is safe and check-error-free-encoding is false
_ = err
var ui8 uint8
_, _ = json.Marshal(ui8) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ui8) // uint8 is safe and check-error-free-encoding is false
_ = err
var ui16 uint16
_, _ = json.Marshal(ui16) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ui16) // uint16 is safe and check-error-free-encoding is false
_ = err
var ui32 uint32
_, _ = json.Marshal(ui32) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ui32) // uint32 is safe and check-error-free-encoding is false
_ = err
var ui64 uint64
_, _ = json.Marshal(ui64) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ui64) // uint64 is safe and check-error-free-encoding is false
_ = err
var uiptr uintptr
_, _ = json.Marshal(uiptr) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(uiptr) // uintptr is safe and check-error-free-encoding is false
_ = err
var str string
_, _ = json.Marshal(str) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(str) // string is safe and check-error-free-encoding is false
_ = err
var strSlice []string
_, _ = json.Marshal(strSlice) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(strSlice) // []string is safe and check-error-free-encoding is false
_ = err
var intSlice []int
_, _ = json.Marshal(intSlice) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(intSlice) // []int is safe and check-error-free-encoding is false
_ = err
var boolSlice []bool
_, _ = json.Marshal(boolSlice) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(boolSlice) // []bool is safe and check-error-free-encoding is false
_ = err
var strArray [10]string
_, _ = json.Marshal(strArray) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(strArray) // [10]string is safe and check-error-free-encoding is false
_ = err
var intArray [10]int
_, _ = json.Marshal(intArray) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(intArray) // [10]int is safe and check-error-free-encoding is false
_ = err
var boolArray [10]bool
_, _ = json.Marshal(boolArray) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(boolArray) // [10]bool is safe and check-error-free-encoding is false
_ = err
var basicStruct struct {
Bool bool
Int int
Int8 int8
Int16 int16
Int32 int32 // also rune
Int64 int64
Uint uint
Uint8 uint8 // also byte
Uint16 uint16
Uint32 uint32
Uint64 uint64
Uintptr uintptr
String string
}
_, _ = json.Marshal(basicStruct) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(basicStruct) // struct containing only safe basic types is safe and check-error-free-encoding is false
_ = err
var ptrStruct struct {
Bool *bool
Int *int
Int8 *int8
Int16 *int16
Int32 *int32
Int64 *int64
Uint *uint
Uint8 *uint8
Uint16 *uint16
Uint32 *uint32
Uint64 *uint64
Uintptr *uintptr
String *string
}
_, _ = json.Marshal(ptrStruct) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(ptrStruct) // struct containing pointer to only safe basic types is safe and check-error-free-encoding is false
_ = err
var mapStrStr map[string]string
_, _ = json.Marshal(mapStrStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapStrStr) // map[string]string is safe and check-error-free-encoding is false
_ = err
var mapStrInt map[string]int
_, _ = json.Marshal(mapStrInt) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapStrInt) // map[string]int is safe and check-error-free-encoding is false
_ = err
var mapStrBool map[string]bool
_, _ = json.Marshal(mapStrBool) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapStrBool) // map[string]bool is safe and check-error-free-encoding is false
_ = err
var mapIntStr map[int]string
_, _ = json.Marshal(mapIntStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapIntStr) // map[int]string is safe and check-error-free-encoding is false
_ = err
var mapIntInt map[int]int
_, _ = json.Marshal(mapIntInt) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapIntInt) // map[int]int is safe and check-error-free-encoding is false
_ = err
var mapIntBool map[int]bool
_, _ = json.Marshal(mapIntBool) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(mapIntBool) // map[int]bool is safe and check-error-free-encoding is false
_ = err
type innerStruct struct {
Bool bool
Int int
String string
StrSlice []string
IntSlice []int
BoolSlice []bool
StrArray [10]string
IntArray [10]int
BoolArray [10]bool
MapStrStr map[string]string
MapStrInt map[string]int
MapStrBool map[string]bool
MapIntStr map[int]string
MapIntInt map[int]int
MapIntBool map[int]bool
}
var outerStruct struct {
Bool bool
Int int
String string
StrSlice []string
IntSlice []int
BoolSlice []bool
StrArray [10]string
IntArray [10]int
BoolArray [10]bool
MapStrStr map[string]string
MapStrInt map[string]int
MapStrBool map[string]bool
MapIntStr map[int]string
MapIntInt map[int]int
MapIntBool map[int]bool
InnerStruct innerStruct
}
_, _ = json.Marshal(outerStruct) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(outerStruct) // struct with only safe types is safe and check-error-free-encoding is false
_ = err
}
type (
structKey struct{ id int }
ExportedUnsafeAndInvalidStruct struct { // unsafe unexported but omitted
F64 float64
F64Ptr *float64
F64Slice []float64
F64Array [10]float64
MapStrF64 map[string]float64
MapEIStr map[interface{}]string
Number json.Number
NumberPtr *json.Number
NumberSlice []json.Number
MapNumberStr map[json.Number]string
Ei interface{}
Stringer fmt.Stringer
Mt marshalText
MapMarshalTextString map[marshalText]string
C128 complex128
C128Ptr *complex128
C128Slice []complex128
C128Array [10]complex128
MapBoolStr map[bool]string
MapF64Str map[float64]string
F func()
Ch chan struct{}
UnsafePtr unsafe.Pointer
MapStructStr map[structKey]string
}
)
// JSONMarshalSafeStructWithUnexportedFieldsWithNoSafe contains a struct with unexported, unsafe fields.
func JSONMarshalSaveStructWithUnexportedFieldsWithNoSafe() {
var err error
var unexportedInStruct struct {
Bool bool // safe exported
f64 float64 // unsafe unexported
f64Ptr *float64 // unsafe unexported
f64Slice []float64 // unsafe unexported
f64Array [10]float64 // unsafe unexported
mapStrF64 map[string]float64 // unsafe unexported
mapEIStr map[interface{}]string // unsafe unexported
number json.Number // unsafe unexported
numberPtr *json.Number // unsafe unexported
numberSlice []json.Number // unsafe unexported
mapNumberStr map[json.Number]string // unsafe unexported
ei interface{} // unsafe unexported
stringer fmt.Stringer // unsafe unexported
mt marshalText // unsafe unexported
mapMarshalTextString map[marshalText]string // unsafe unexported
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported
c128 complex128 // invalid unexported
c128Slice []complex128 // invalid unexported
c128Array [10]complex128 // invalid unexported
mapBoolStr map[bool]string // invalid unexported
mapF64Str map[float64]string // invalid unexported
f func() // invalid unexported
ch chan struct{} // invalid unexported
unsafePtr unsafe.Pointer // invalid unexported
mapStructStr map[structKey]string // invalid unexported
}
_ = unexportedInStruct.f64
_ = unexportedInStruct.f64Ptr
_ = unexportedInStruct.f64Slice
_ = unexportedInStruct.f64Array
_ = unexportedInStruct.mapStrF64
_ = unexportedInStruct.mapEIStr
_ = unexportedInStruct.number
_ = unexportedInStruct.numberPtr
_ = unexportedInStruct.numberSlice
_ = unexportedInStruct.mapNumberStr
_ = unexportedInStruct.ei
_ = unexportedInStruct.stringer
_ = unexportedInStruct.mt
_ = unexportedInStruct.mapMarshalTextString
_ = unexportedInStruct.unexportedStruct
_ = unexportedInStruct.unexportedStructPtr
_ = unexportedInStruct.c128
_ = unexportedInStruct.c128Slice
_ = unexportedInStruct.c128Array
_ = unexportedInStruct.mapBoolStr
_ = unexportedInStruct.mapF64Str
_ = unexportedInStruct.f
_ = unexportedInStruct.ch
_ = unexportedInStruct.unsafePtr
_ = unexportedInStruct.mapStructStr[structKey{1}]
_, _ = json.Marshal(unexportedInStruct) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(unexportedInStruct) // struct containing unsafe but unexported fields is safe
_ = err
}
// JSONMarshalSafeStructWithOmittedFieldsWithNoSafe contains a struct with omitted, unsafe fields.
func JSONMarshalSaveStructWithOmittedFieldsWithNoSafe() {
var err error
var omitInStruct struct {
Bool bool // safe exported
F64 float64 `json:"-"` // unsafe exported but omitted
F64Ptr *float64 `json:"-"` // unsafe exported but omitted
F64Slice []float64 `json:"-"` // unsafe exported but omitted
F64Array [10]float64 `json:"-"` // unsafe exported but omitted
MapStrF64 map[string]float64 `json:"-"` // unsafe exported but omitted
MapEIStr map[interface{}]string `json:"-"` // unsafe exported but omitted
Number json.Number `json:"-"` // unsafe exported but omitted
NumberPtr *json.Number `json:"-"` // unsafe exported but omitted
NumberSlice []json.Number `json:"-"` // unsafe exported but omitted
MapNumberStr map[json.Number]string `json:"-"` // unsafe exported but omitted
Ei interface{} `json:"-"` // unsafe exported but omitted
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
Mt marshalText `json:"-"` // unsafe exported but omitted
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
C128 complex128 `json:"-"` // invalid exported but omitted
C128Slice []complex128 `json:"-"` // invalid exported but omitted
C128Array [10]complex128 `json:"-"` // invalid exported but omitted
MapBoolStr map[bool]string `json:"-"` // invalid exported but omitted
MapF64Str map[float64]string `json:"-"` // invalid exported but omitted
F func() `json:"-"` // invalid exported but omitted
Ch chan struct{} `json:"-"` // invalid exported but omitted
UnsafePtr unsafe.Pointer `json:"-"` // invalid exported but omitted
MapStructStr map[structKey]string `json:"-"` // invalid exported but omitted
}
_ = omitInStruct.MapStructStr[structKey{1}]
_, _ = json.Marshal(omitInStruct) // ERROR "Error return value of `encoding/json.Marshal` is not checked"
_, err = json.Marshal(omitInStruct) // struct containing unsafe but omitted, exported fields is safe and check-error-free-encoding is false
_ = err
}
// JSONMarshalUnsafeTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that can potentially lead to json.Marshal returning an error.
func JSONMarshalUnsafeTypes() {
var err error
var f32 float32
json.Marshal(f32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, _ = json.Marshal(f32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32) // err is checked
_ = err
var f64 float64
_, _ = json.Marshal(f64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64) // err is checked
_ = err
var f32Slice []float32
_, _ = json.Marshal(f32Slice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32Slice) // err is checked
_ = err
var f64Slice []float64
_, _ = json.Marshal(f64Slice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64Slice) // err is checked
_ = err
var f32Array [10]float32
_, _ = json.Marshal(f32Array) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32Array) // err is checked
_ = err
var f64Array [10]float64
_, _ = json.Marshal(f64Array) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64Array) // err is checked
_ = err
var structPtrF32 struct {
F32 *float32
}
_, _ = json.Marshal(structPtrF32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(structPtrF32) // err is checked
_ = err
var structPtrF64 struct {
F64 *float64
}
_, _ = json.Marshal(structPtrF64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(structPtrF64) // err is checked
_ = err
var mapStrF32 map[string]float32
_, _ = json.Marshal(mapStrF32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(mapStrF32) // err is checked
_ = err
var mapStrF64 map[string]float64
_, _ = json.Marshal(mapStrF64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(mapStrF64) // err is checked
_ = err
var mapEIStr map[interface{}]string
_, _ = json.Marshal(mapEIStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` as map key found"
_, err = json.Marshal(mapEIStr) // err is checked
_ = err
var mapStringerStr map[fmt.Stringer]string
_, _ = json.Marshal(mapStringerStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `fmt.Stringer` as map key found"
_, err = json.Marshal(mapStringerStr) // err is checked
_ = err
var number json.Number
_, _ = json.Marshal(number) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(number) // err is checked
_ = err
var numberSlice []json.Number
_, _ = json.Marshal(numberSlice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(numberSlice) // err is checked
_ = err
var mapNumberStr map[json.Number]string
_, _ = json.Marshal(mapNumberStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` as map key found"
_, err = json.Marshal(mapNumberStr) // err is checked
_ = err
var mapStrNumber map[string]json.Number
_, _ = json.Marshal(mapStrNumber) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(mapStrNumber) // err is checked
_ = err
var ei interface{}
_, _ = json.Marshal(ei) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` found"
_, err = json.Marshal(ei) // err is checked
_ = err
var eiptr *interface{}
_, _ = json.Marshal(eiptr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `*interface{}` found"
_, err = json.Marshal(eiptr) // err is checked
_ = err
var stringer fmt.Stringer
_, _ = json.Marshal(stringer) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `fmt.Stringer` found"
_, err = json.Marshal(stringer) // err is checked
_ = err
var structWithEmptyInterface struct {
EmptyInterface interface{}
}
_, _ = json.Marshal(structWithEmptyInterface) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` found"
_, err = json.Marshal(structWithEmptyInterface) // err is checked
_ = err
var mt marshalText
_, _ = json.Marshal(mt) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `[a-z-]+.marshalText` found"
_, err = json.Marshal(mt) // err is checked
_ = err
var mapMarshalTextString map[marshalText]string
_, _ = json.Marshal(mapMarshalTextString) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `[a-z-]+.marshalText` as map key found"
_, err = json.Marshal(mapMarshalTextString) // err is checked
_ = err
}
// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that are invalid and not supported by json.Marshal, that is they will always return an error, if these types used
// with json.Marshal.
func JSONMarshalInvalidTypes() {
var err error
var c64 complex64
json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, _ = json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var c128 complex128
_, _ = json.Marshal(c128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(c128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var sliceC64 []complex64
_, _ = json.Marshal(sliceC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(sliceC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var sliceC128 []complex128
_, _ = json.Marshal(sliceC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(sliceC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var arrayC64 []complex64
_, _ = json.Marshal(arrayC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(arrayC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var arrayC128 []complex128
_, _ = json.Marshal(arrayC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(arrayC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var structPtrC64 struct {
C64 *complex64
}
_, _ = json.Marshal(structPtrC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(structPtrC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var structPtrC128 struct {
C128 *complex128
}
_, _ = json.Marshal(structPtrC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(structPtrC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var mapBoolStr map[bool]string
_, _ = json.Marshal(mapBoolStr) // ERROR "`encoding/json.Marshal` for unsupported type `bool` as map key found"
_, err = json.Marshal(mapBoolStr) // ERROR "`encoding/json.Marshal` for unsupported type `bool` as map key found"
_ = err
var mapF32Str map[float32]string
_, _ = json.Marshal(mapF32Str) // ERROR "`encoding/json.Marshal` for unsupported type `float32` as map key found"
_, err = json.Marshal(mapF32Str) // ERROR "`encoding/json.Marshal` for unsupported type `float32` as map key found"
_ = err
var mapF64Str map[float64]string
_, _ = json.Marshal(mapF64Str) // ERROR "`encoding/json.Marshal` for unsupported type `float64` as map key found"
_, err = json.Marshal(mapF64Str) // ERROR "`encoding/json.Marshal` for unsupported type `float64` as map key found"
_ = err
var mapC64Str map[complex64]string
_, _ = json.Marshal(mapC64Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` as map key found"
_, err = json.Marshal(mapC64Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` as map key found"
_ = err
var mapC128Str map[complex128]string
_, _ = json.Marshal(mapC128Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` as map key found"
_, err = json.Marshal(mapC128Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` as map key found"
_ = err
mapStructStr := map[structKey]string{structKey{1}: "str"}
_, _ = json.Marshal(mapStructStr) // ERROR "`encoding/json.Marshal` for unsupported type `[a-z-]+.structKey` as map key found"
_, err = json.Marshal(mapStructStr) // ERROR "`encoding/json.Marshal` for unsupported type `[a-z-]+.structKey` as map key found"
_ = err
f := func() {}
_, _ = json.Marshal(f) // ERROR "`encoding/json.Marshal` for unsupported type `func\\(\\)` found"
_, err = json.Marshal(f) // ERROR "`encoding/json.Marshal` for unsupported type `func\\(\\)` found"
_ = err
var ch chan struct{} = make(chan struct{})
_, _ = json.Marshal(ch) // ERROR "`encoding/json.Marshal` for unsupported type `chan struct{}` found"
_, err = json.Marshal(ch) // ERROR "`encoding/json.Marshal` for unsupported type `chan struct{}` found"
_ = err
var unsafePtr unsafe.Pointer
_, _ = json.Marshal(unsafePtr) // ERROR "`encoding/json.Marshal` for unsupported type `unsafe.Pointer` found"
_, err = json.Marshal(unsafePtr) // ERROR "`encoding/json.Marshal` for unsupported type `unsafe.Pointer` found"
_ = err
}
// NotJSONMarshal contains other go ast node types, that are not considered by errchkjson
func NotJSONMarshal() {
s := fmt.Sprintln("I am not considered by errchkjson")
_ = s
f := func() bool { return false }
_ = f()
}
// JSONMarshalStructWithoutExportedFields contains a struct without exported fields.
func JSONMarshalStructWithoutExportedFields() {
var err error
var withoutExportedFields struct {
privateField bool
ExportedButOmittedField bool `json:"-"`
}
_, err = json.Marshal(withoutExportedFields) // want "Error argument passed to `encoding/json.Marshal` does not contain any exported field"
_ = err
}
// JSONMarshalStructWithoutExportedFields contains a struct without exported fields.
func JSONMarshalStructWithNestedStructWithoutExportedFields() {
var err error
var withNestedStructWithoutExportedFields struct {
ExportedStruct struct {
privatField bool
}
}
_, err = json.Marshal(withNestedStructWithoutExportedFields)
_ = err
}

View File

@ -0,0 +1,616 @@
// args: -Eerrchkjson
// config_path: testdata/configs/errchkjson_check_error_free_encoding.yml
package testdata
import (
"encoding"
"encoding/json"
"fmt"
"io/ioutil"
"unsafe"
)
type marshalText struct{}
func (mt marshalText) MarshalText() ([]byte, error) {
return []byte(`mt`), nil
}
var _ encoding.TextMarshaler = marshalText(struct{}{})
// JSONMarshalSafeTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that are safe, that is, they will never return an error, if these types are marshaled to JSON.
func JSONMarshalSafeTypes() {
var err error
_, _ = json.Marshal(nil) // nil is safe
json.Marshal(nil) // nil is safe
_, err = json.Marshal(nil) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
_, _ = json.MarshalIndent(nil, "", " ") // nil is safe
json.MarshalIndent(nil, "", " ") // nil is safe
_, err = json.MarshalIndent(nil, "", " ") // ERROR "Error return value of `encoding/json.MarshalIndent` is checked but passed argument is safe"
_ = err
enc := json.NewEncoder(ioutil.Discard)
_ = enc.Encode(nil) // nil is safe
enc.Encode(nil) // nil is safe
err = enc.Encode(nil) // ERROR "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is checked but passed argument is safe"
_ = err
var b bool
_, _ = json.Marshal(b) // bool is safe
_, err = json.Marshal(b) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var i int
_, _ = json.Marshal(i) // int is safe
_, err = json.Marshal(i) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var i8 int8
_, _ = json.Marshal(i8) // int8 is safe
_, err = json.Marshal(i8) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var i16 int16
_, _ = json.Marshal(i16) // int16 is safe
_, err = json.Marshal(i16) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var i32 int32
_, _ = json.Marshal(i32) // int32 / rune is safe
_, err = json.Marshal(i32) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var i64 int64
_, _ = json.Marshal(i64) // int64 is safe
_, err = json.Marshal(i64) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ui uint
_, _ = json.Marshal(ui) // uint is safe
_, err = json.Marshal(ui) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ui8 uint8
_, _ = json.Marshal(ui8) // uint8 / byte is safe
_, err = json.Marshal(ui8) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ui16 uint16
_, _ = json.Marshal(ui16) // uint16 is safe
_, err = json.Marshal(ui16) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ui32 uint32
_, _ = json.Marshal(ui32) // uint32 / rune is safe
_, err = json.Marshal(ui32) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ui64 uint64
_, _ = json.Marshal(ui64) // uint64 is safe
_, err = json.Marshal(ui64) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var uiptr uintptr
_, _ = json.Marshal(uiptr) // uintptr is safe
_, err = json.Marshal(uiptr) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var str string
_, _ = json.Marshal(str) // string is safe
_, err = json.Marshal(str) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var strSlice []string
_, _ = json.Marshal(strSlice) // []string is safe
_, err = json.Marshal(strSlice) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var intSlice []int
_, _ = json.Marshal(intSlice) // []int is safe
_, err = json.Marshal(intSlice) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var boolSlice []bool
_, _ = json.Marshal(boolSlice) // []bool is safe
_, err = json.Marshal(boolSlice) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var strArray [10]string
_, _ = json.Marshal(strArray) // [10]string is safe
_, err = json.Marshal(strArray) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var intArray [10]int
_, _ = json.Marshal(intArray) // [10]int is safe
_, err = json.Marshal(intArray) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var boolArray [10]bool
_, _ = json.Marshal(boolArray) // [10]bool is safe
_, err = json.Marshal(boolArray) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var basicStruct struct {
Bool bool
Int int
Int8 int8
Int16 int16
Int32 int32 // also rune
Int64 int64
Uint uint
Uint8 uint8 // also byte
Uint16 uint16
Uint32 uint32
Uint64 uint64
Uintptr uintptr
String string
}
_, _ = json.Marshal(basicStruct) // struct containing only safe basic types is safe
_, err = json.Marshal(basicStruct) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var ptrStruct struct {
Bool *bool
Int *int
Int8 *int8
Int16 *int16
Int32 *int32
Int64 *int64
Uint *uint
Uint8 *uint8
Uint16 *uint16
Uint32 *uint32
Uint64 *uint64
Uintptr *uintptr
String *string
}
_, _ = json.Marshal(ptrStruct) // struct containing pointer to only safe basic types is safe
_, err = json.Marshal(ptrStruct) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapStrStr map[string]string
_, _ = json.Marshal(mapStrStr) // map[string]string is safe
_, err = json.Marshal(mapStrStr) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapStrInt map[string]int
_, _ = json.Marshal(mapStrInt) // map[string]int is safe
_, err = json.Marshal(mapStrInt) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapStrBool map[string]bool
_, _ = json.Marshal(mapStrBool) // map[string]bool is safe
_, err = json.Marshal(mapStrBool) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapIntStr map[int]string
_, _ = json.Marshal(mapIntStr) // map[int]string is safe
_, err = json.Marshal(mapIntStr) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapIntInt map[int]int
_, _ = json.Marshal(mapIntInt) // map[int]int is safe
_, err = json.Marshal(mapIntInt) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
var mapIntBool map[int]bool
_, _ = json.Marshal(mapIntBool) // map[int]bool is safe
_, err = json.Marshal(mapIntBool) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
type innerStruct struct {
Bool bool
Int int
String string
StrSlice []string
IntSlice []int
BoolSlice []bool
StrArray [10]string
IntArray [10]int
BoolArray [10]bool
MapStrStr map[string]string
MapStrInt map[string]int
MapStrBool map[string]bool
MapIntStr map[int]string
MapIntInt map[int]int
MapIntBool map[int]bool
}
var outerStruct struct {
Bool bool
Int int
String string
StrSlice []string
IntSlice []int
BoolSlice []bool
StrArray [10]string
IntArray [10]int
BoolArray [10]bool
MapStrStr map[string]string
MapStrInt map[string]int
MapStrBool map[string]bool
MapIntStr map[int]string
MapIntInt map[int]int
MapIntBool map[int]bool
InnerStruct innerStruct
}
_, _ = json.Marshal(outerStruct) // struct with only safe types
_, err = json.Marshal(outerStruct) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
}
type (
structKey struct{ id int }
ExportedUnsafeAndInvalidStruct struct { // unsafe unexported but omitted
F64 float64
F64Ptr *float64
F64Slice []float64
F64Array [10]float64
MapStrF64 map[string]float64
MapEIStr map[interface{}]string
Number json.Number
NumberPtr *json.Number
NumberSlice []json.Number
MapNumberStr map[json.Number]string
Ei interface{}
Stringer fmt.Stringer
Mt marshalText
MapMarshalTextString map[marshalText]string
C128 complex128
C128Ptr *complex128
C128Slice []complex128
C128Array [10]complex128
MapBoolStr map[bool]string
MapF64Str map[float64]string
F func()
Ch chan struct{}
UnsafePtr unsafe.Pointer
MapStructStr map[structKey]string
}
)
// JSONMarshalSaveStructWithUnexportedFields contains a struct with unexported, unsafe fields.
func JSONMarshalSaveStructWithUnexportedFields() {
var err error
var unexportedInStruct struct {
Bool bool // safe exported
f64 float64 // unsafe unexported
f64Ptr *float64 // unsafe unexported
f64Slice []float64 // unsafe unexported
f64Array [10]float64 // unsafe unexported
mapStrF64 map[string]float64 // unsafe unexported
mapEIStr map[interface{}]string // unsafe unexported
number json.Number // unsafe unexported
numberPtr *json.Number // unsafe unexported
numberSlice []json.Number // unsafe unexported
mapNumberStr map[json.Number]string // unsafe unexported
ei interface{} // unsafe unexported
stringer fmt.Stringer // unsafe unexported
mt marshalText // unsafe unexported
mapMarshalTextString map[marshalText]string // unsafe unexported
unexportedStruct ExportedUnsafeAndInvalidStruct // unsafe unexported
unexportedStructPtr *ExportedUnsafeAndInvalidStruct // unsafe unexported
c128 complex128 // invalid unexported
c128Slice []complex128 // invalid unexported
c128Array [10]complex128 // invalid unexported
mapBoolStr map[bool]string // invalid unexported
mapF64Str map[float64]string // invalid unexported
f func() // invalid unexported
ch chan struct{} // invalid unexported
unsafePtr unsafe.Pointer // invalid unexported
mapStructStr map[structKey]string // invalid unexported
}
_ = unexportedInStruct.f64
_ = unexportedInStruct.f64Ptr
_ = unexportedInStruct.f64Slice
_ = unexportedInStruct.f64Array
_ = unexportedInStruct.mapStrF64
_ = unexportedInStruct.mapEIStr
_ = unexportedInStruct.number
_ = unexportedInStruct.numberPtr
_ = unexportedInStruct.numberSlice
_ = unexportedInStruct.mapNumberStr
_ = unexportedInStruct.ei
_ = unexportedInStruct.stringer
_ = unexportedInStruct.mt
_ = unexportedInStruct.mapMarshalTextString
_ = unexportedInStruct.unexportedStruct
_ = unexportedInStruct.unexportedStructPtr
_ = unexportedInStruct.c128
_ = unexportedInStruct.c128Slice
_ = unexportedInStruct.c128Array
_ = unexportedInStruct.mapBoolStr
_ = unexportedInStruct.mapF64Str
_ = unexportedInStruct.f
_ = unexportedInStruct.ch
_ = unexportedInStruct.unsafePtr
_ = unexportedInStruct.mapStructStr[structKey{1}]
_, _ = json.Marshal(unexportedInStruct) // struct containing unsafe but unexported fields is safe
_, err = json.Marshal(unexportedInStruct) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
}
// JSONMarshalSaveStructWithOmittedFields contains a struct with omitted, unsafe fields.
func JSONMarshalSaveStructWithOmittedFields() {
var err error
var omitInStruct struct {
Bool bool // safe exported
F64 float64 `json:"-"` // unsafe exported but omitted
F64Ptr *float64 `json:"-"` // unsafe exported but omitted
F64Slice []float64 `json:"-"` // unsafe exported but omitted
F64Array [10]float64 `json:"-"` // unsafe exported but omitted
MapStrF64 map[string]float64 `json:"-"` // unsafe exported but omitted
MapEIStr map[interface{}]string `json:"-"` // unsafe exported but omitted
Number json.Number `json:"-"` // unsafe exported but omitted
NumberPtr *json.Number `json:"-"` // unsafe exported but omitted
NumberSlice []json.Number `json:"-"` // unsafe exported but omitted
MapNumberStr map[json.Number]string `json:"-"` // unsafe exported but omitted
Ei interface{} `json:"-"` // unsafe exported but omitted
Stringer fmt.Stringer `json:"-"` // unsafe exported but omitted
Mt marshalText `json:"-"` // unsafe exported but omitted
MapMarshalTextString map[marshalText]string `json:"-"` // unsafe exported but omitted
ExportedStruct ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
ExportedStructPtr *ExportedUnsafeAndInvalidStruct `json:"-"` // unsafe exported but omitted
C128 complex128 `json:"-"` // invalid exported but omitted
C128Slice []complex128 `json:"-"` // invalid exported but omitted
C128Array [10]complex128 `json:"-"` // invalid exported but omitted
MapBoolStr map[bool]string `json:"-"` // invalid exported but omitted
MapF64Str map[float64]string `json:"-"` // invalid exported but omitted
F func() `json:"-"` // invalid exported but omitted
Ch chan struct{} `json:"-"` // invalid exported but omitted
UnsafePtr unsafe.Pointer `json:"-"` // invalid exported but omitted
MapStructStr map[structKey]string `json:"-"` // invalid exported but omitted
}
_ = omitInStruct.MapStructStr[structKey{1}]
_, _ = json.Marshal(omitInStruct) // struct containing unsafe but omitted, exported fields is safe
_, err = json.Marshal(omitInStruct) // ERROR "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
_ = err
}
// JSONMarshalUnsafeTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that can potentially lead to json.Marshal returning an error.
func JSONMarshalUnsafeTypes() {
var err error
var f32 float32
json.Marshal(f32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, _ = json.Marshal(f32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32) // err is checked
_ = err
var f64 float64
_, _ = json.Marshal(f64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64) // err is checked
_ = err
var f32Slice []float32
_, _ = json.Marshal(f32Slice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32Slice) // err is checked
_ = err
var f64Slice []float64
_, _ = json.Marshal(f64Slice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64Slice) // err is checked
_ = err
var f32Array [10]float32
_, _ = json.Marshal(f32Array) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(f32Array) // err is checked
_ = err
var f64Array [10]float64
_, _ = json.Marshal(f64Array) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(f64Array) // err is checked
_ = err
var structPtrF32 struct {
F32 *float32
}
_, _ = json.Marshal(structPtrF32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(structPtrF32) // err is checked
_ = err
var structPtrF64 struct {
F64 *float64
}
_, _ = json.Marshal(structPtrF64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(structPtrF64) // err is checked
_ = err
var mapStrF32 map[string]float32
_, _ = json.Marshal(mapStrF32) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
_, err = json.Marshal(mapStrF32) // err is checked
_ = err
var mapStrF64 map[string]float64
_, _ = json.Marshal(mapStrF64) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
_, err = json.Marshal(mapStrF64) // err is checked
_ = err
var mapEIStr map[interface{}]string
_, _ = json.Marshal(mapEIStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` as map key found"
_, err = json.Marshal(mapEIStr) // err is checked
_ = err
var mapStringerStr map[fmt.Stringer]string
_, _ = json.Marshal(mapStringerStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `fmt.Stringer` as map key found"
_, err = json.Marshal(mapStringerStr) // err is checked
_ = err
var number json.Number
_, _ = json.Marshal(number) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(number) // err is checked
_ = err
var numberSlice []json.Number
_, _ = json.Marshal(numberSlice) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(numberSlice) // err is checked
_ = err
var mapNumberStr map[json.Number]string
_, _ = json.Marshal(mapNumberStr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` as map key found"
_, err = json.Marshal(mapNumberStr) // err is checked
_ = err
var mapStrNumber map[string]json.Number
_, _ = json.Marshal(mapStrNumber) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `encoding/json.Number` found"
_, err = json.Marshal(mapStrNumber) // err is checked
_ = err
var ei interface{}
_, _ = json.Marshal(ei) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` found"
_, err = json.Marshal(ei) // err is checked
_ = err
var eiptr *interface{}
_, _ = json.Marshal(eiptr) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `*interface{}` found"
_, err = json.Marshal(eiptr) // err is checked
_ = err
var stringer fmt.Stringer
_, _ = json.Marshal(stringer) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `fmt.Stringer` found"
_, err = json.Marshal(stringer) // err is checked
_ = err
var structWithEmptyInterface struct {
EmptyInterface interface{}
}
_, _ = json.Marshal(structWithEmptyInterface) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `interface{}` found"
_, err = json.Marshal(structWithEmptyInterface) // err is checked
_ = err
var mt marshalText
_, _ = json.Marshal(mt) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `[a-z-]+.marshalText` found"
_, err = json.Marshal(mt) // err is checked
_ = err
var mapMarshalTextString map[marshalText]string
_, _ = json.Marshal(mapMarshalTextString) // ERROR "Error return value of `encoding/json.Marshal` is not checked: unsafe type `[a-z-]+.marshalText` as map key found"
_, err = json.Marshal(mapMarshalTextString) // err is checked
_ = err
}
// JSONMarshalInvalidTypes contains a multitude of test cases to marshal different combinations of types to JSON,
// that are invalid and not supported by json.Marshal, that is they will always return an error, if these types used
// with json.Marshal.
func JSONMarshalInvalidTypes() {
var err error
var c64 complex64
json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, _ = json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(c64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var c128 complex128
_, _ = json.Marshal(c128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(c128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var sliceC64 []complex64
_, _ = json.Marshal(sliceC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(sliceC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var sliceC128 []complex128
_, _ = json.Marshal(sliceC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(sliceC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var arrayC64 []complex64
_, _ = json.Marshal(arrayC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(arrayC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var arrayC128 []complex128
_, _ = json.Marshal(arrayC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(arrayC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var structPtrC64 struct {
C64 *complex64
}
_, _ = json.Marshal(structPtrC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_, err = json.Marshal(structPtrC64) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` found"
_ = err
var structPtrC128 struct {
C128 *complex128
}
_, _ = json.Marshal(structPtrC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_, err = json.Marshal(structPtrC128) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` found"
_ = err
var mapBoolStr map[bool]string
_, _ = json.Marshal(mapBoolStr) // ERROR "`encoding/json.Marshal` for unsupported type `bool` as map key found"
_, err = json.Marshal(mapBoolStr) // ERROR "`encoding/json.Marshal` for unsupported type `bool` as map key found"
_ = err
var mapF32Str map[float32]string
_, _ = json.Marshal(mapF32Str) // ERROR "`encoding/json.Marshal` for unsupported type `float32` as map key found"
_, err = json.Marshal(mapF32Str) // ERROR "`encoding/json.Marshal` for unsupported type `float32` as map key found"
_ = err
var mapF64Str map[float64]string
_, _ = json.Marshal(mapF64Str) // ERROR "`encoding/json.Marshal` for unsupported type `float64` as map key found"
_, err = json.Marshal(mapF64Str) // ERROR "`encoding/json.Marshal` for unsupported type `float64` as map key found"
_ = err
var mapC64Str map[complex64]string
_, _ = json.Marshal(mapC64Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` as map key found"
_, err = json.Marshal(mapC64Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex64` as map key found"
_ = err
var mapC128Str map[complex128]string
_, _ = json.Marshal(mapC128Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` as map key found"
_, err = json.Marshal(mapC128Str) // ERROR "`encoding/json.Marshal` for unsupported type `complex128` as map key found"
_ = err
mapStructStr := map[structKey]string{structKey{1}: "str"}
_, _ = json.Marshal(mapStructStr) // ERROR "`encoding/json.Marshal` for unsupported type `[a-z-]+.structKey` as map key found"
_, err = json.Marshal(mapStructStr) // ERROR "`encoding/json.Marshal` for unsupported type `[a-z-]+.structKey` as map key found"
_ = err
f := func() {}
_, _ = json.Marshal(f) // ERROR "`encoding/json.Marshal` for unsupported type `func\\(\\)` found"
_, err = json.Marshal(f) // ERROR "`encoding/json.Marshal` for unsupported type `func\\(\\)` found"
_ = err
var ch chan struct{} = make(chan struct{})
_, _ = json.Marshal(ch) // ERROR "`encoding/json.Marshal` for unsupported type `chan struct{}` found"
_, err = json.Marshal(ch) // ERROR "`encoding/json.Marshal` for unsupported type `chan struct{}` found"
_ = err
var unsafePtr unsafe.Pointer
_, _ = json.Marshal(unsafePtr) // ERROR "`encoding/json.Marshal` for unsupported type `unsafe.Pointer` found"
_, err = json.Marshal(unsafePtr) // ERROR "`encoding/json.Marshal` for unsupported type `unsafe.Pointer` found"
_ = err
}
// NotJSONMarshal contains other go ast node types, that are not considered by errchkjson
func NotJSONMarshal() {
s := fmt.Sprintln("I am not considered by errchkjson")
_ = s
f := func() bool { return false }
_ = f()
}

28
test/testdata/errchkjson_no_exported.go vendored Normal file
View File

@ -0,0 +1,28 @@
// args: -Eerrchkjson
// config_path: testdata/configs/errchkjson_no_exported.yml
package testdata
import (
"encoding/json"
)
// JSONMarshalStructWithoutExportedFields contains a struct without exported fields.
func JSONMarshalStructWithoutExportedFields() {
var withoutExportedFields struct {
privateField bool
ExportedButOmittedField bool `json:"-"`
}
_, err := json.Marshal(withoutExportedFields) // ERROR "Error argument passed to `encoding/json.Marshal` does not contain any exported field"
_ = err
}
// JSONMarshalStructWithNestedStructWithoutExportedFields contains a struct without exported fields.
func JSONMarshalStructWithNestedStructWithoutExportedFields() {
var withNestedStructWithoutExportedFields struct {
ExportedStruct struct {
privatField bool
}
}
_, err := json.Marshal(withNestedStructWithoutExportedFields)
_ = err
}