sa1026.go (2537B)
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/json.MarshalIndent": checkJSON, 35 "encoding/xml.Marshal": checkXML, 36 "encoding/xml.MarshalIndent": checkXML, 37 "(*encoding/json.Encoder).Encode": checkJSON, 38 "(*encoding/xml.Encoder).Encode": checkXML, 39 } 40 41 func checkJSON(call *callcheck.Call) { 42 arg := call.Args[0] 43 T := arg.Value.Value.Type() 44 if err := fakejson.Marshal(T); err != nil { 45 typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg)) 46 if err.Path == "x" { 47 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ)) 48 } else { 49 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path)) 50 } 51 } 52 } 53 54 func checkXML(call *callcheck.Call) { 55 arg := call.Args[0] 56 T := arg.Value.Value.Type() 57 if err := fakexml.Marshal(T); err != nil { 58 switch err := err.(type) { 59 case *fakexml.UnsupportedTypeError: 60 typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg)) 61 if err.Path == "x" { 62 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ)) 63 } else { 64 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path)) 65 } 66 case *fakexml.CyclicTypeError: 67 typ := types.TypeString(err.Type, types.RelativeTo(call.Parent.Pkg.Pkg)) 68 if err.Path == "x" { 69 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s", typ)) 70 } else { 71 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s, via %s", typ, err.Path)) 72 } 73 case *fakexml.TagPathError: 74 // Vet does a better job at reporting this error, because it can flag the actual struct tags, not just the call to Marshal 75 default: 76 // These errors get reported by SA5008 instead, which can flag the actual fields, independently of calls to xml.Marshal 77 } 78 } 79 }