1package checkers 2 3import ( 4 "go/ast" 5 "go/constant" 6 "regexp" 7 "strings" 8 9 "github.com/go-critic/go-critic/checkers/internal/astwalk" 10 "github.com/go-critic/go-critic/framework/linter" 11) 12 13func init() { 14 var info linter.CheckerInfo 15 info.Name = "regexpPattern" 16 info.Tags = []string{"diagnostic", "experimental"} 17 info.Summary = "Detects suspicious regexp patterns" 18 info.Before = "regexp.MustCompile(`google.com|yandex.ru`)" 19 info.After = "regexp.MustCompile(`google\\.com|yandex\\.ru`)" 20 21 collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { 22 domains := []string{ 23 "com", 24 "org", 25 "info", 26 "net", 27 "ru", 28 "de", 29 } 30 31 allDomains := strings.Join(domains, "|") 32 domainRE := regexp.MustCompile(`[^\\]\.(` + allDomains + `)\b`) 33 return astwalk.WalkerForExpr(®expPatternChecker{ 34 ctx: ctx, 35 domainRE: domainRE, 36 }), nil 37 }) 38} 39 40type regexpPatternChecker struct { 41 astwalk.WalkHandler 42 ctx *linter.CheckerContext 43 44 domainRE *regexp.Regexp 45} 46 47func (c *regexpPatternChecker) VisitExpr(x ast.Expr) { 48 call, ok := x.(*ast.CallExpr) 49 if !ok { 50 return 51 } 52 53 switch qualifiedName(call.Fun) { 54 case "regexp.Compile", "regexp.CompilePOSIX", "regexp.MustCompile", "regexp.MustCompilePosix": 55 cv := c.ctx.TypesInfo.Types[call.Args[0]].Value 56 if cv == nil || cv.Kind() != constant.String { 57 return 58 } 59 s := constant.StringVal(cv) 60 if m := c.domainRE.FindStringSubmatch(s); m != nil { 61 c.warnDomain(call.Args[0], m[1]) 62 } 63 } 64} 65 66func (c *regexpPatternChecker) warnDomain(cause ast.Expr, domain string) { 67 c.ctx.Warn(cause, "'.%s' should probably be '\\.%s'", domain, domain) 68} 69