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  }