src

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

s1000.go (1902B)


      1 package s1000
      2 
      3 import (
      4 	"go/ast"
      5 
      6 	"honnef.co/go/tools/analysis/code"
      7 	"honnef.co/go/tools/analysis/facts/generated"
      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 	"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.RawDocumentation{
     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) (any, 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 }