53 lines
1.6 KiB
Go
53 lines
1.6 KiB
Go
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")
|
|
}
|
|
},
|
|
}
|