github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1026/sa1026.go (about) 1 package sa1026 2 3 import ( 4 "fmt" 5 "go/types" 6 7 "github.com/amarpal/go-tools/analysis/callcheck" 8 "github.com/amarpal/go-tools/analysis/lint" 9 "github.com/amarpal/go-tools/internal/passes/buildir" 10 "github.com/amarpal/go-tools/staticcheck/fakejson" 11 "github.com/amarpal/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.Documentation{ 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 }