sa1026.go raw
1 package sa1026
2
3 import (
4 "fmt"
5 "go/types"
6
7 "honnef.co/go/tools/analysis/callcheck"
8 "honnef.co/go/tools/analysis/lint"
9 "honnef.co/go/tools/internal/passes/buildir"
10 "honnef.co/go/tools/staticcheck/fakejson"
11 "honnef.co/go/tools/staticcheck/fakexml"
12
13 "golang.org/x/tools/go/analysis"
14 )
15
16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
17 Analyzer: &analysis.Analyzer{
18 Name: "SA1026",
19 Requires: []*analysis.Analyzer{buildir.Analyzer},
20 Run: callcheck.Analyzer(rules),
21 },
22 Doc: &lint.RawDocumentation{
23 Title: `Cannot marshal channels or functions`,
24 Since: "2019.2",
25 Severity: lint.SeverityError,
26 MergeIf: lint.MergeIfAny,
27 },
28 })
29
30 var Analyzer = SCAnalyzer.Analyzer
31
32 var rules = map[string]callcheck.Check{
33 "encoding/json.Marshal": checkJSON,
34 "encoding/xml.Marshal": checkXML,
35 "(*encoding/json.Encoder).Encode": checkJSON,
36 "(*encoding/xml.Encoder).Encode": checkXML,
37 }
38
39 func checkJSON(call *callcheck.Call) {
40 arg := call.Args[0]
41 T := arg.Value.Value.Type()
42 if err := fakejson.Marshal(T); err != nil {
43 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
44 if err.Path == "x" {
45 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
46 } else {
47 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
48 }
49 }
50 }
51
52 func checkXML(call *callcheck.Call) {
53 arg := call.Args[0]
54 T := arg.Value.Value.Type()
55 if err := fakexml.Marshal(T); err != nil {
56 switch err := err.(type) {
57 case *fakexml.UnsupportedTypeError:
58 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
59 if err.Path == "x" {
60 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
61 } else {
62 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
63 }
64 case *fakexml.CyclicTypeError:
65 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
66 if err.Path == "x" {
67 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s", typ))
68 } else {
69 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s, via %s", typ, err.Path))
70 }
71 case *fakexml.TagPathError:
72 // Vet does a better job at reporting this error, because it can flag the actual struct tags, not just the call to Marshal
73 default:
74 // These errors get reported by SA5008 instead, which can flag the actual fields, independently of calls to xml.Marshal
75 }
76 }
77 }
78