github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1014/sa1014.go (about) 1 package sa1014 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 11 "golang.org/x/tools/go/analysis" 12 ) 13 14 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 15 Analyzer: &analysis.Analyzer{ 16 Name: "SA1014", 17 Requires: []*analysis.Analyzer{buildir.Analyzer}, 18 Run: callcheck.Analyzer(checkUnmarshalPointerRules), 19 }, 20 Doc: &lint.Documentation{ 21 Title: `Non-pointer value passed to \'Unmarshal\' or \'Decode\'`, 22 Since: "2017.1", 23 Severity: lint.SeverityError, 24 MergeIf: lint.MergeIfAny, 25 }, 26 }) 27 28 var Analyzer = SCAnalyzer.Analyzer 29 30 var checkUnmarshalPointerRules = map[string]callcheck.Check{ 31 "encoding/xml.Unmarshal": unmarshalPointer("xml.Unmarshal", 1), 32 "(*encoding/xml.Decoder).Decode": unmarshalPointer("Decode", 0), 33 "(*encoding/xml.Decoder).DecodeElement": unmarshalPointer("DecodeElement", 0), 34 "encoding/json.Unmarshal": unmarshalPointer("json.Unmarshal", 1), 35 "(*encoding/json.Decoder).Decode": unmarshalPointer("Decode", 0), 36 } 37 38 func unmarshalPointer(name string, arg int) callcheck.Check { 39 return func(call *callcheck.Call) { 40 if !Pointer(call.Args[arg].Value) { 41 call.Args[arg].Invalid(fmt.Sprintf("%s expects to unmarshal into a pointer, but the provided value is not a pointer", name)) 42 } 43 } 44 } 45 46 func Pointer(v callcheck.Value) bool { 47 switch v.Value.Type().Underlying().(type) { 48 case *types.Pointer, *types.Interface: 49 return true 50 } 51 return false 52 }