sa2000.go (1310B)
1 package sa2000 2 3 import ( 4 "fmt" 5 "go/ast" 6 7 "honnef.co/go/tools/analysis/code" 8 "honnef.co/go/tools/analysis/lint" 9 "honnef.co/go/tools/analysis/report" 10 "honnef.co/go/tools/pattern" 11 12 "golang.org/x/tools/go/analysis" 13 ) 14 15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 16 Analyzer: &analysis.Analyzer{ 17 Name: "SA2000", 18 Run: run, 19 Requires: code.RequiredAnalyzers, 20 }, 21 Doc: &lint.RawDocumentation{ 22 Title: `\'(*sync.WaitGroup).Add\' called inside the goroutine, leading to a race condition`, 23 Text: `\'(*sync.WaitGroup).Add\' must be called before starting the goroutine 24 it is meant to wait for. Calling \'Add\' inside the goroutine creates a race 25 condition between the call to \'Add\' and the call to \'Wait\'.`, 26 Since: "2017.1", 27 Severity: lint.SeverityWarning, 28 MergeIf: lint.MergeIfAny, 29 }, 30 }) 31 32 var Analyzer = SCAnalyzer.Analyzer 33 34 var checkWaitgroupAddQ = pattern.MustParse(` 35 (GoStmt 36 (CallExpr 37 (FuncLit 38 _ 39 call@(CallExpr (Symbol "(*sync.WaitGroup).Add") _):_) _))`) 40 41 func run(pass *analysis.Pass) (any, error) { 42 for _, m := range code.Matches(pass, checkWaitgroupAddQ) { 43 call := m.State["call"].(ast.Node) 44 report.Report(pass, call, fmt.Sprintf("should call %s before starting the goroutine to avoid a race", report.Render(pass, call))) 45 } 46 return nil, nil 47 }