Skip to content

Commit 775551b

Browse files
authored
Merge pull request #16 from breml/issue_15
Handle case when error is passed as arg
2 parents 7e195c2 + a3b3dbf commit 775551b

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

errchkjson.go

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
5959

6060
switch fn.FullName() {
6161
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
62-
e.handleJSONMarshal(pass, ce, fn.FullName(), true)
62+
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier)
6363
case "(*encoding/json.Encoder).Encode":
64-
e.handleJSONMarshal(pass, ce, fn.FullName(), true)
64+
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier)
6565
default:
66-
return true
66+
e.inspectArgs(pass, ce.Args)
6767
}
6868
return false
6969
}
@@ -85,9 +85,9 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
8585

8686
switch fn.FullName() {
8787
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
88-
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier(as.Lhs[1]))
88+
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[1]))
8989
case "(*encoding/json.Encoder).Encode":
90-
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier(as.Lhs[0]))
90+
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[0]))
9191
default:
9292
return true
9393
}
@@ -98,20 +98,28 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
9898
return nil, nil
9999
}
100100

101-
func blankIdentifier(n ast.Expr) bool {
101+
func evaluateMarshalErrorTarget(n ast.Expr) marshalErrorTarget {
102102
if errIdent, ok := n.(*ast.Ident); ok {
103103
if errIdent.Name == "_" {
104-
return true
104+
return blankIdentifier
105105
}
106106
}
107-
return false
107+
return variableAssignment
108108
}
109109

110-
func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fnName string, blankIdentifier bool) {
110+
type marshalErrorTarget int
111+
112+
const (
113+
blankIdentifier = iota // the returned error from the JSON marshal function is assigned to the blank identifier "_".
114+
variableAssignment // the returned error from the JSON marshal function is assigned to a variable.
115+
functionArgument // the returned error from the JSON marshal function is passed to an other function as argument.
116+
)
117+
118+
func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fnName string, errorTarget marshalErrorTarget) {
111119
t := pass.TypesInfo.TypeOf(ce.Args[0])
112120
if t == nil {
113121
// Not sure, if this is at all possible
114-
if blankIdentifier {
122+
if errorTarget == blankIdentifier {
115123
pass.Reportf(ce.Pos(), "Type of argument to `%s` could not be evaluated and error return value is not checked", fnName)
116124
}
117125
return
@@ -131,15 +139,15 @@ func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fn
131139
pass.Reportf(ce.Pos(), "Error argument passed to `%s` does not contain any exported field", fnName)
132140
}
133141
// Only care about unsafe types if they are assigned to the blank identifier.
134-
if blankIdentifier {
142+
if errorTarget == blankIdentifier {
135143
pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked: %v", fnName, err)
136144
}
137145
}
138-
if err == nil && !blankIdentifier && !e.omitSafe {
146+
if err == nil && errorTarget == variableAssignment && !e.omitSafe {
139147
pass.Reportf(ce.Pos(), "Error return value of `%s` is checked but passed argument is safe", fnName)
140148
}
141149
// Report an error, if err for json.Marshal is not checked and safe types are omitted
142-
if err == nil && blankIdentifier && e.omitSafe {
150+
if err == nil && errorTarget == blankIdentifier && e.omitSafe {
143151
pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked", fnName)
144152
}
145153
}
@@ -269,6 +277,36 @@ func jsonSafeMapKey(t types.Type) error {
269277
}
270278
}
271279

280+
func (e *errchkjson) inspectArgs(pass *analysis.Pass, args []ast.Expr) {
281+
for _, a := range args {
282+
ast.Inspect(a, func(n ast.Node) bool {
283+
if n == nil {
284+
return true
285+
}
286+
287+
ce, ok := n.(*ast.CallExpr)
288+
if !ok {
289+
return false
290+
}
291+
292+
fn, _ := typeutil.Callee(pass.TypesInfo, ce).(*types.Func)
293+
if fn == nil {
294+
return true
295+
}
296+
297+
switch fn.FullName() {
298+
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
299+
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument)
300+
case "(*encoding/json.Encoder).Encode":
301+
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument)
302+
default:
303+
e.inspectArgs(pass, ce.Args)
304+
}
305+
return false
306+
})
307+
}
308+
}
309+
272310
// Construct *types.Interface for interface encoding.TextMarshaler
273311
// type TextMarshaler interface {
274312
// MarshalText() (text []byte, err error)

testdata/src/nosafe/a.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func JSONMarshalSafeTypesWithNoSafe() {
3333
json.Marshal(nil) // want "Error return value of `encoding/json.Marshal` is not checked"
3434
_, err = json.Marshal(nil) // nil is safe, but omit-safe is set
3535
_ = err
36+
fmt.Print(json.Marshal(nil)) // nil is safe, error is passed as argument
3637

3738
_, _ = json.MarshalIndent(nil, "", " ") // want "Error return value of `encoding/json.MarshalIndent` is not checked"
3839
json.MarshalIndent(nil, "", " ") // want "Error return value of `encoding/json.MarshalIndent` is not checked"
@@ -409,6 +410,7 @@ func JSONMarshalUnsafeTypes() {
409410
_, _ = json.Marshal(f32) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
410411
_, err = json.Marshal(f32) // err is checked
411412
_ = err
413+
fmt.Print(json.Marshal(f32)) // err is passed and therefore considered as checked
412414

413415
var f64 float64
414416
_, _ = json.Marshal(f64) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
@@ -543,6 +545,7 @@ func JSONMarshalInvalidTypes() {
543545
_, _ = json.Marshal(c64) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
544546
_, err = json.Marshal(c64) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
545547
_ = err
548+
fmt.Print(json.Marshal(c64)) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
546549

547550
var c128 complex128
548551
_, _ = json.Marshal(c128) // want "`encoding/json.Marshal` for unsupported type `complex128` found"

testdata/src/standard/a.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func JSONMarshalSafeTypes() {
3333
json.Marshal(nil) // nil is safe
3434
_, err = json.Marshal(nil) // want "Error return value of `encoding/json.Marshal` is checked but passed argument is safe"
3535
_ = err
36+
fmt.Print(json.Marshal(nil)) // nil is safe, error is passed as argument
3637

3738
_, _ = json.MarshalIndent(nil, "", " ") // nil is safe
3839
json.MarshalIndent(nil, "", " ") // nil is safe
@@ -409,6 +410,7 @@ func JSONMarshalUnsafeTypes() {
409410
_, _ = json.Marshal(f32) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float32` found"
410411
_, err = json.Marshal(f32) // err is checked
411412
_ = err
413+
fmt.Print(json.Marshal(f32)) // err is passed and therefore considered as checked
412414

413415
var f64 float64
414416
_, _ = json.Marshal(f64) // want "Error return value of `encoding/json.Marshal` is not checked: unsafe type `float64` found"
@@ -543,6 +545,7 @@ func JSONMarshalInvalidTypes() {
543545
_, _ = json.Marshal(c64) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
544546
_, err = json.Marshal(c64) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
545547
_ = err
548+
fmt.Print(json.Marshal(c64)) // want "`encoding/json.Marshal` for unsupported type `complex64` found"
546549

547550
var c128 complex128
548551
_, _ = json.Marshal(c128) // want "`encoding/json.Marshal` for unsupported type `complex128` found"

0 commit comments

Comments
 (0)