src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sa6002.go (1672B)


      1 package sa6002
      2 
      3 import (
      4 	"go/types"
      5 
      6 	"honnef.co/go/tools/analysis/callcheck"
      7 	"honnef.co/go/tools/analysis/lint"
      8 	"honnef.co/go/tools/go/types/typeutil"
      9 	"honnef.co/go/tools/internal/passes/buildir"
     10 	"honnef.co/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.RawDocumentation{
     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 }