src

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

sa1017.go (1873B)


      1 package sa1017
      2 
      3 import (
      4 	"go/constant"
      5 
      6 	"honnef.co/go/tools/analysis/callcheck"
      7 	"honnef.co/go/tools/analysis/lint"
      8 	"honnef.co/go/tools/go/ir"
      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:     "SA1017",
     18 		Requires: []*analysis.Analyzer{buildir.Analyzer},
     19 		Run:      callcheck.Analyzer(rules),
     20 	},
     21 	Doc: &lint.RawDocumentation{
     22 		Title: `Channels used with \'os/signal.Notify\' should be buffered`,
     23 		Text: `The \'os/signal\' package uses non-blocking channel sends when delivering
     24 signals. If the receiving end of the channel isn't ready and the
     25 channel is either unbuffered or full, the signal will be dropped. To
     26 avoid missing signals, the channel should be buffered and of the
     27 appropriate size. For a channel used for notification of just one
     28 signal value, a buffer of size 1 is sufficient.`,
     29 		Since:    "2017.1",
     30 		Severity: lint.SeverityWarning,
     31 		MergeIf:  lint.MergeIfAny,
     32 	},
     33 })
     34 
     35 var Analyzer = SCAnalyzer.Analyzer
     36 
     37 var rules = map[string]callcheck.Check{
     38 	"os/signal.Notify": func(call *callcheck.Call) {
     39 		arg := call.Args[knowledge.Arg("os/signal.Notify.c")]
     40 		if isUnbufferedChannel(arg.Value) {
     41 			arg.Invalid("the channel used with signal.Notify should be buffered")
     42 		}
     43 	},
     44 }
     45 
     46 func isUnbufferedChannel(v callcheck.Value) bool {
     47 	// TODO(dh): this check of course misses many cases of unbuffered
     48 	// channels, such as any in phi or sigma nodes. We'll eventually
     49 	// replace this function.
     50 	val := v.Value
     51 	if ct, ok := val.(*ir.ChangeType); ok {
     52 		val = ct.X
     53 	}
     54 	mk, ok := val.(*ir.MakeChan)
     55 	if !ok {
     56 		return false
     57 	}
     58 	if k, ok := mk.Size.(*ir.Const); ok && k.Value.Kind() == constant.Int {
     59 		if v, ok := constant.Int64Val(k.Value); ok && v == 0 {
     60 			return true
     61 		}
     62 	}
     63 	return false
     64 }