Files
odidere/vendor/honnef.co/go/tools/staticcheck/sa6002/sa6002.go

53 lines
1.6 KiB
Go
Raw Normal View History

2026-06-06 01:17:20 +00:00
package sa6002
import (
"go/types"
"honnef.co/go/tools/analysis/callcheck"
"honnef.co/go/tools/analysis/lint"
"honnef.co/go/tools/go/types/typeutil"
"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: "SA6002",
Requires: []*analysis.Analyzer{buildir.Analyzer},
Run: callcheck.Analyzer(rules),
},
Doc: &lint.RawDocumentation{
Title: `Storing non-pointer values in \'sync.Pool\' allocates memory`,
Text: `A \'sync.Pool\' is used to avoid unnecessary allocations and reduce the
amount of work the garbage collector has to do.
When passing a value that is not a pointer to a function that accepts
an interface, the value needs to be placed on the heap, which means an
additional allocation. Slices are a common thing to put in sync.Pools,
and they're structs with 3 fields (length, capacity, and a pointer to
an array). In order to avoid the extra allocation, one should store a
pointer to the slice instead.
See the comments on https://go-review.googlesource.com/c/go/+/24371
that discuss this problem.`,
Since: "2017.1",
Severity: lint.SeverityWarning,
MergeIf: lint.MergeIfAny,
},
})
var Analyzer = SCAnalyzer.Analyzer
var rules = map[string]callcheck.Check{
"(*sync.Pool).Put": func(call *callcheck.Call) {
arg := call.Args[knowledge.Arg("(*sync.Pool).Put.x")]
typ := arg.Value.Value.Type()
_, isSlice := typ.Underlying().(*types.Slice)
if !typeutil.IsPointerLike(typ) || isSlice {
arg.Invalid("argument should be pointer-like to avoid allocations")
}
},
}