@@ -59,11 +59,11 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
59
59
60
60
switch fn .FullName () {
61
61
case "encoding/json.Marshal" , "encoding/json.MarshalIndent" :
62
- e .handleJSONMarshal (pass , ce , fn .FullName (), true )
62
+ e .handleJSONMarshal (pass , ce , fn .FullName (), blankIdentifier )
63
63
case "(*encoding/json.Encoder).Encode" :
64
- e .handleJSONMarshal (pass , ce , fn .FullName (), true )
64
+ e .handleJSONMarshal (pass , ce , fn .FullName (), blankIdentifier )
65
65
default :
66
- return true
66
+ e . inspectArgs ( pass , ce . Args )
67
67
}
68
68
return false
69
69
}
@@ -85,9 +85,9 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
85
85
86
86
switch fn .FullName () {
87
87
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 ]))
89
89
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 ]))
91
91
default :
92
92
return true
93
93
}
@@ -98,20 +98,28 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
98
98
return nil , nil
99
99
}
100
100
101
- func blankIdentifier (n ast.Expr ) bool {
101
+ func evaluateMarshalErrorTarget (n ast.Expr ) marshalErrorTarget {
102
102
if errIdent , ok := n .(* ast.Ident ); ok {
103
103
if errIdent .Name == "_" {
104
- return true
104
+ return blankIdentifier
105
105
}
106
106
}
107
- return false
107
+ return variableAssignment
108
108
}
109
109
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 ) {
111
119
t := pass .TypesInfo .TypeOf (ce .Args [0 ])
112
120
if t == nil {
113
121
// Not sure, if this is at all possible
114
- if blankIdentifier {
122
+ if errorTarget == blankIdentifier {
115
123
pass .Reportf (ce .Pos (), "Type of argument to `%s` could not be evaluated and error return value is not checked" , fnName )
116
124
}
117
125
return
@@ -131,15 +139,15 @@ func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fn
131
139
pass .Reportf (ce .Pos (), "Error argument passed to `%s` does not contain any exported field" , fnName )
132
140
}
133
141
// Only care about unsafe types if they are assigned to the blank identifier.
134
- if blankIdentifier {
142
+ if errorTarget == blankIdentifier {
135
143
pass .Reportf (ce .Pos (), "Error return value of `%s` is not checked: %v" , fnName , err )
136
144
}
137
145
}
138
- if err == nil && ! blankIdentifier && ! e .omitSafe {
146
+ if err == nil && errorTarget == variableAssignment && ! e .omitSafe {
139
147
pass .Reportf (ce .Pos (), "Error return value of `%s` is checked but passed argument is safe" , fnName )
140
148
}
141
149
// 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 {
143
151
pass .Reportf (ce .Pos (), "Error return value of `%s` is not checked" , fnName )
144
152
}
145
153
}
@@ -269,6 +277,36 @@ func jsonSafeMapKey(t types.Type) error {
269
277
}
270
278
}
271
279
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
+
272
310
// Construct *types.Interface for interface encoding.TextMarshaler
273
311
// type TextMarshaler interface {
274
312
// MarshalText() (text []byte, err error)
0 commit comments