Add staticcheck tool

This commit is contained in:
dwrz
2026-06-06 01:17:20 +00:00
parent 6fb63c8c90
commit ad58cd78ff
315 changed files with 56337 additions and 4 deletions

View File

@@ -0,0 +1,92 @@
package sa1003
import (
"fmt"
"go/types"
"go/version"
"honnef.co/go/tools/analysis/callcheck"
"honnef.co/go/tools/analysis/code"
"honnef.co/go/tools/analysis/lint"
"honnef.co/go/tools/internal/passes/buildir"
"honnef.co/go/tools/knowledge"
"golang.org/x/tools/go/analysis"
)
var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
Analyzer: &analysis.Analyzer{
Name: "SA1003",
Requires: []*analysis.Analyzer{buildir.Analyzer},
Run: callcheck.Analyzer(checkEncodingBinaryRules),
},
Doc: &lint.RawDocumentation{
Title: `Unsupported argument to functions in \'encoding/binary\'`,
Text: `The \'encoding/binary\' package can only serialize types with known sizes.
This precludes the use of the \'int\' and \'uint\' types, as their sizes
differ on different architectures. Furthermore, it doesn't support
serializing maps, channels, strings, or functions.
Before Go 1.8, \'bool\' wasn't supported, either.`,
Since: "2017.1",
Severity: lint.SeverityError,
MergeIf: lint.MergeIfAny,
},
})
var Analyzer = SCAnalyzer.Analyzer
var checkEncodingBinaryRules = map[string]callcheck.Check{
"encoding/binary.Write": func(call *callcheck.Call) {
arg := call.Args[knowledge.Arg("encoding/binary.Write.data")]
if !CanBinaryMarshal(call.Pass, call.Parent, arg.Value) {
arg.Invalid(fmt.Sprintf("value of type %s cannot be used with binary.Write", arg.Value.Value.Type()))
}
},
}
func CanBinaryMarshal(pass *analysis.Pass, node code.Positioner, v callcheck.Value) bool {
typ := v.Value.Type().Underlying()
if ttyp, ok := typ.(*types.Pointer); ok {
typ = ttyp.Elem().Underlying()
}
if ttyp, ok := types.Unalias(typ).(interface {
Elem() types.Type
}); ok {
if _, ok := ttyp.(*types.Pointer); !ok {
typ = ttyp.Elem()
}
}
return validEncodingBinaryType(pass, node, typ)
}
func validEncodingBinaryType(pass *analysis.Pass, node code.Positioner, typ types.Type) bool {
typ = typ.Underlying()
switch typ := typ.(type) {
case *types.Basic:
switch typ.Kind() {
case types.Uint8, types.Uint16, types.Uint32, types.Uint64,
types.Int8, types.Int16, types.Int32, types.Int64,
types.Float32, types.Float64, types.Complex64, types.Complex128, types.Invalid:
return true
case types.Bool:
return version.Compare(code.StdlibVersion(pass, node), "go1.8") >= 0
}
return false
case *types.Struct:
n := typ.NumFields()
for i := range n {
if !validEncodingBinaryType(pass, node, typ.Field(i).Type()) {
return false
}
}
return true
case *types.Array:
return validEncodingBinaryType(pass, node, typ.Elem())
case *types.Interface:
// we can't determine if it's a valid type or not
return true
}
return false
}