sa5004.go raw
1 package sa5004
2
3 import (
4 "go/ast"
5
6 "honnef.co/go/tools/analysis/code"
7 "honnef.co/go/tools/analysis/edit"
8 "honnef.co/go/tools/analysis/lint"
9 "honnef.co/go/tools/analysis/report"
10
11 "golang.org/x/tools/go/analysis"
12 "golang.org/x/tools/go/analysis/passes/inspect"
13 )
14
15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
16 Analyzer: &analysis.Analyzer{
17 Name: "SA5004",
18 Run: run,
19 Requires: []*analysis.Analyzer{inspect.Analyzer},
20 },
21 Doc: &lint.RawDocumentation{
22 Title: `\"for { select { ...\" with an empty default branch spins`,
23 Since: "2017.1",
24 Severity: lint.SeverityWarning,
25 MergeIf: lint.MergeIfAny,
26 },
27 })
28
29 var Analyzer = SCAnalyzer.Analyzer
30
31 func run(pass *analysis.Pass) (interface{}, error) {
32 fn := func(node ast.Node) {
33 loop := node.(*ast.ForStmt)
34 if len(loop.Body.List) != 1 || loop.Cond != nil || loop.Init != nil {
35 return
36 }
37 sel, ok := loop.Body.List[0].(*ast.SelectStmt)
38 if !ok {
39 return
40 }
41 for _, c := range sel.Body.List {
42 // FIXME this leaves behind an empty line, and possibly
43 // comments in the default branch. We can't easily fix
44 // either.
45 if comm, ok := c.(*ast.CommClause); ok && comm.Comm == nil && len(comm.Body) == 0 {
46 report.Report(pass, comm, "should not have an empty default case in a for+select loop; the loop will spin",
47 report.Fixes(edit.Fix("remove empty default branch", edit.Delete(comm))))
48 // there can only be one default case
49 break
50 }
51 }
52 }
53 code.Preorder(pass, fn, (*ast.ForStmt)(nil))
54 return nil, nil
55 }
56