github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1021/sa1021.go (about)

     1  package sa1021
     2  
     3  import (
     4  	"github.com/amarpal/go-tools/analysis/callcheck"
     5  	"github.com/amarpal/go-tools/analysis/lint"
     6  	"github.com/amarpal/go-tools/go/ir"
     7  	"github.com/amarpal/go-tools/go/types/typeutil"
     8  	"github.com/amarpal/go-tools/internal/passes/buildir"
     9  	"github.com/amarpal/go-tools/knowledge"
    10  
    11  	"golang.org/x/tools/go/analysis"
    12  )
    13  
    14  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
    15  	Analyzer: &analysis.Analyzer{
    16  		Name:     "SA1021",
    17  		Requires: []*analysis.Analyzer{buildir.Analyzer},
    18  		Run:      callcheck.Analyzer(rules),
    19  	},
    20  	Doc: &lint.Documentation{
    21  		Title: `Using \'bytes.Equal\' to compare two \'net.IP\'`,
    22  		Text: `A \'net.IP\' stores an IPv4 or IPv6 address as a slice of bytes. The
    23  length of the slice for an IPv4 address, however, can be either 4 or
    24  16 bytes long, using different ways of representing IPv4 addresses. In
    25  order to correctly compare two \'net.IP\'s, the \'net.IP.Equal\' method should
    26  be used, as it takes both representations into account.`,
    27  		Since:    "2017.1",
    28  		Severity: lint.SeverityWarning,
    29  		MergeIf:  lint.MergeIfAny,
    30  	},
    31  })
    32  
    33  var Analyzer = SCAnalyzer.Analyzer
    34  
    35  var rules = map[string]callcheck.Check{
    36  	"bytes.Equal": func(call *callcheck.Call) {
    37  		if isConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.a")].Value, "net.IP") &&
    38  			isConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.b")].Value, "net.IP") {
    39  			call.Invalid("use net.IP.Equal to compare net.IPs, not bytes.Equal")
    40  		}
    41  	},
    42  }
    43  
    44  // ConvertedFrom reports whether value v was converted from type typ.
    45  func isConvertedFrom(v callcheck.Value, typ string) bool {
    46  	change, ok := v.Value.(*ir.ChangeType)
    47  	return ok && typeutil.IsType(change.X.Type(), typ)
    48  }