sa1014.go raw

   1  package sa1014
   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  
  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.RawDocumentation{
  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  }
  53