github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa6002/sa6002.go (about) 1 package sa6002 2 3 import ( 4 "go/types" 5 6 "github.com/amarpal/go-tools/analysis/callcheck" 7 "github.com/amarpal/go-tools/analysis/lint" 8 "github.com/amarpal/go-tools/go/types/typeutil" 9 "github.com/amarpal/go-tools/internal/passes/buildir" 10 "github.com/amarpal/go-tools/knowledge" 11 12 "golang.org/x/tools/go/analysis" 13 ) 14 15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 16 Analyzer: &analysis.Analyzer{ 17 Name: "SA6002", 18 Requires: []*analysis.Analyzer{buildir.Analyzer}, 19 Run: callcheck.Analyzer(rules), 20 }, 21 Doc: &lint.Documentation{ 22 Title: `Storing non-pointer values in \'sync.Pool\' allocates memory`, 23 Text: `A \'sync.Pool\' is used to avoid unnecessary allocations and reduce the 24 amount of work the garbage collector has to do. 25 26 When passing a value that is not a pointer to a function that accepts 27 an interface, the value needs to be placed on the heap, which means an 28 additional allocation. Slices are a common thing to put in sync.Pools, 29 and they're structs with 3 fields (length, capacity, and a pointer to 30 an array). In order to avoid the extra allocation, one should store a 31 pointer to the slice instead. 32 33 See the comments on https://go-review.googlesource.com/c/go/+/24371 34 that discuss this problem.`, 35 Since: "2017.1", 36 Severity: lint.SeverityWarning, 37 MergeIf: lint.MergeIfAny, 38 }, 39 }) 40 41 var Analyzer = SCAnalyzer.Analyzer 42 43 var rules = map[string]callcheck.Check{ 44 "(*sync.Pool).Put": func(call *callcheck.Call) { 45 arg := call.Args[knowledge.Arg("(*sync.Pool).Put.x")] 46 typ := arg.Value.Value.Type() 47 _, isSlice := typ.Underlying().(*types.Slice) 48 if !typeutil.IsPointerLike(typ) || isSlice { 49 arg.Invalid("argument should be pointer-like to avoid allocations") 50 } 51 }, 52 }