github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa6000/sa6000.go (about) 1 package sa6000 2 3 import ( 4 "fmt" 5 6 "github.com/amarpal/go-tools/analysis/callcheck" 7 "github.com/amarpal/go-tools/analysis/lint" 8 "github.com/amarpal/go-tools/go/ir" 9 "github.com/amarpal/go-tools/go/ir/irutil" 10 "github.com/amarpal/go-tools/internal/passes/buildir" 11 12 "golang.org/x/tools/go/analysis" 13 ) 14 15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 16 Analyzer: &analysis.Analyzer{ 17 Name: "SA6000", 18 Requires: []*analysis.Analyzer{buildir.Analyzer}, 19 Run: callcheck.Analyzer(rules), 20 }, 21 Doc: &lint.Documentation{ 22 Title: `Using \'regexp.Match\' or related in a loop, should use \'regexp.Compile\'`, 23 Since: "2017.1", 24 Severity: lint.SeverityWarning, 25 MergeIf: lint.MergeIfAny, 26 }, 27 }) 28 29 var Analyzer = SCAnalyzer.Analyzer 30 31 var rules = map[string]callcheck.Check{ 32 "regexp.Match": check("regexp.Match"), 33 "regexp.MatchReader": check("regexp.MatchReader"), 34 "regexp.MatchString": check("regexp.MatchString"), 35 } 36 37 func check(name string) callcheck.Check { 38 return func(call *callcheck.Call) { 39 if callcheck.ExtractConst(call.Args[0].Value) == nil { 40 return 41 } 42 if !isInLoop(call.Instr.Block()) { 43 return 44 } 45 call.Invalid(fmt.Sprintf("calling %s in a loop has poor performance, consider using regexp.Compile", name)) 46 } 47 } 48 49 func isInLoop(b *ir.BasicBlock) bool { 50 sets := irutil.FindLoops(b.Parent()) 51 for _, set := range sets { 52 if set.Has(b) { 53 return true 54 } 55 } 56 return false 57 }