github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/simple/s1000/s1000.go (about) 1 package s1000 2 3 import ( 4 "go/ast" 5 6 "github.com/amarpal/go-tools/analysis/code" 7 "github.com/amarpal/go-tools/analysis/facts/generated" 8 "github.com/amarpal/go-tools/analysis/lint" 9 "github.com/amarpal/go-tools/analysis/report" 10 "github.com/amarpal/go-tools/pattern" 11 12 "golang.org/x/tools/go/analysis" 13 "golang.org/x/tools/go/analysis/passes/inspect" 14 ) 15 16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 17 Analyzer: &analysis.Analyzer{ 18 Name: "S1000", 19 Run: run, 20 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 21 }, 22 Doc: &lint.Documentation{ 23 Title: `Use plain channel send or receive instead of single-case select`, 24 Text: `Select statements with a single case can be replaced with a simple 25 send or receive.`, 26 Before: ` 27 select { 28 case x := <-ch: 29 fmt.Println(x) 30 }`, 31 After: ` 32 x := <-ch 33 fmt.Println(x) 34 `, 35 Since: "2017.1", 36 MergeIf: lint.MergeIfAny, 37 }, 38 }) 39 40 var Analyzer = SCAnalyzer.Analyzer 41 42 var ( 43 checkSingleCaseSelectQ1 = pattern.MustParse(` 44 (ForStmt 45 nil nil nil 46 select@(SelectStmt 47 (CommClause 48 (Or 49 (UnaryExpr "<-" _) 50 (AssignStmt _ _ (UnaryExpr "<-" _))) 51 _)))`) 52 checkSingleCaseSelectQ2 = pattern.MustParse(`(SelectStmt (CommClause _ _))`) 53 ) 54 55 func run(pass *analysis.Pass) (interface{}, error) { 56 seen := map[ast.Node]struct{}{} 57 fn := func(node ast.Node) { 58 if m, ok := code.Match(pass, checkSingleCaseSelectQ1, node); ok { 59 seen[m.State["select"].(ast.Node)] = struct{}{} 60 report.Report(pass, node, "should use for range instead of for { select {} }", report.FilterGenerated()) 61 } else if _, ok := code.Match(pass, checkSingleCaseSelectQ2, node); ok { 62 if _, ok := seen[node]; !ok { 63 report.Report(pass, node, "should use a simple channel send/receive instead of select with a single case", 64 report.ShortRange(), 65 report.FilterGenerated()) 66 } 67 } 68 } 69 code.Preorder(pass, fn, (*ast.ForStmt)(nil), (*ast.SelectStmt)(nil)) 70 return nil, nil 71 }