From 058d7c223d150698f13cb5f3228275de6368b347 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 15 Feb 2022 21:07:28 +0300 Subject: [PATCH 01/10] add filter by tags for ruleguard --- checkers/ruleguard_checker.go | 43 +++++++++++++++++++++++++++++++---- go.mod | 4 ++-- go.sum | 7 ++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 41d8754ae..968134695 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -135,38 +135,71 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( enabledGroups := make(map[string]bool) disabledGroups := make(map[string]bool) + enabledTags := make(map[string]bool) + disabledTags := make(map[string]bool) for _, g := range strings.Split(info.Params.String("disable"), ",") { g = strings.TrimSpace(g) + if t := strings.Split(g, "#"); len(t) == 2 { + disabledTags[t[1]] = true + continue + } + disabledGroups[g] = true } flagEnable := info.Params.String("enable") if flagEnable != "" { for _, g := range strings.Split(flagEnable, ",") { g = strings.TrimSpace(g) + if t := strings.Split(g, "#"); len(t) == 2 { + enabledTags[t[1]] = true + continue + } + enabledGroups[g] = true } } ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" + inDisabledByTags := func(g *ruleguard.GoRuleGroup) bool { + for _, t := range g.DocTags { + if disabledTags[t] { + return true + } + } + return false + } + inEnabledByTags := func(g *ruleguard.GoRuleGroup) bool { + for _, t := range g.DocTags { + if enabledTags[t] { + return true + } + } + return false + } + loadContext := &ruleguard.LoadContext{ Fset: fset, DebugImports: ruleguardDebug, DebugPrint: debugPrint, - GroupFilter: func(g string) bool { + GroupFilter: func(g *ruleguard.GoRuleGroup) bool { whyDisabled := "" - enabled := flagEnable == "" || enabledGroups[g] + enabled := len(enabledGroups) == 0 || enabledGroups[g.Name] switch { case !enabled: whyDisabled = "not enabled by -enabled flag" - case disabledGroups[g]: + case disabledGroups[g.Name]: whyDisabled = "disabled by -disable flag" + case len(enabledTags) != 0 && !inEnabledByTags(g): + whyDisabled = "not enabled by tags in -enable flag" + case inDisabledByTags(g): + whyDisabled = "disabled by tags in -disable flag" } if ruleguardDebug { if whyDisabled != "" { - debugPrint(fmt.Sprintf("(-) %s is %s", g, whyDisabled)) + debugPrint(fmt.Sprintf("(-) %s is %s", g.Name, whyDisabled)) } else { - debugPrint(fmt.Sprintf("(+) %s is enabled", g)) + debugPrint(fmt.Sprintf("(+) %s is enabled", g.Name)) } } return whyDisabled == "" diff --git a/go.mod b/go.mod index 2b081e413..5fd4b5f02 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/go-toolsmith/typep v1.0.2 github.com/google/go-cmp v0.5.6 github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e - github.com/quasilyte/go-ruleguard v0.3.15 - github.com/quasilyte/go-ruleguard/dsl v0.3.12 + github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a + github.com/quasilyte/go-ruleguard/dsl v0.3.16 github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da diff --git a/go.sum b/go.sum index 29eb5fa87..00517dcff 100644 --- a/go.sum +++ b/go.sum @@ -23,16 +23,23 @@ github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQ github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= github.com/quasilyte/go-ruleguard v0.3.15 h1:iWYzp1z72IlXTioET0+XI6SjQdPfMGfuAiZiKznOt7g= github.com/quasilyte/go-ruleguard v0.3.15/go.mod h1:NhuWhnlVEM1gT1A4VJHYfy9MuYSxxwHgxWoPsn9llB4= +github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a h1:sWFavxtIctGrVs5SYZ5Ml1CvrDAs8Kf5kx2PI3C41dA= +github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4= github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.12-0.20220101150716-969a394a9451/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.12 h1:g63WHzWZUyb9gqGReJUqhWfWpU038+R+IGzZD0BiT9o= github.com/quasilyte/go-ruleguard/dsl v0.3.12/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.16 h1:yJtIpd4oyNS+/c/gKqxNwoGO9+lPOsy1A4BzKjJRcrI= +github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 h1:P4QPNn+TK49zJjXKERt/vyPbv/mCHB/zQ4flDYOMN+M= github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= +github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= From 9714e2d8c1984675519524bd5e6de1ca78f2a7d9 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 15 Feb 2022 21:40:14 +0300 Subject: [PATCH 02/10] fixes --- checkers/analyzer/run.go | 3 ++- checkers/embedded_rules.go | 7 ++++--- framework/lintmain/internal/check/check.go | 5 +++-- go.sum | 10 ++-------- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/checkers/analyzer/run.go b/checkers/analyzer/run.go index e8d226286..c65ab120f 100644 --- a/checkers/analyzer/run.go +++ b/checkers/analyzer/run.go @@ -7,9 +7,10 @@ import ( "strings" "sync" + "golang.org/x/tools/go/analysis" + _ "github.com/go-critic/go-critic/checkers" // Register go-critic checkers "github.com/go-critic/go-critic/framework/linter" - "golang.org/x/tools/go/analysis" ) type gocritic struct { diff --git a/checkers/embedded_rules.go b/checkers/embedded_rules.go index e37fdf14a..ada03083c 100644 --- a/checkers/embedded_rules.go +++ b/checkers/embedded_rules.go @@ -7,9 +7,10 @@ import ( "go/token" "os" + "github.com/quasilyte/go-ruleguard/ruleguard" + "github.com/go-critic/go-critic/checkers/rulesdata" "github.com/go-critic/go-critic/framework/linter" - "github.com/quasilyte/go-ruleguard/ruleguard" ) //go:generate go run ./rules/precompile.go -rules ./rules/rules.go -o ./rulesdata/rulesdata.go @@ -65,8 +66,8 @@ func init() { collection.AddChecker(info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { parseContext := &ruleguard.LoadContext{ Fset: fset, - GroupFilter: func(name string) bool { - return name == g.Name + GroupFilter: func(gr *ruleguard.GoRuleGroup) bool { + return gr.Name == g.Name }, DebugImports: ruleguardDebug, DebugPrint: func(s string) { diff --git a/framework/lintmain/internal/check/check.go b/framework/lintmain/internal/check/check.go index 62678e7b6..0eff39acf 100644 --- a/framework/lintmain/internal/check/check.go +++ b/framework/lintmain/internal/check/check.go @@ -19,11 +19,12 @@ import ( "strings" "sync" - "github.com/go-critic/go-critic/framework/linter" - "github.com/go-critic/go-critic/framework/lintmain/internal/hotload" "github.com/go-toolsmith/pkgload" "github.com/logrusorgru/aurora" "golang.org/x/tools/go/packages" + + "github.com/go-critic/go-critic/framework/linter" + "github.com/go-critic/go-critic/framework/lintmain/internal/hotload" ) // Main implements sub-command entry point. diff --git a/go.sum b/go.sum index 00517dcff..7d100472b 100644 --- a/go.sum +++ b/go.sum @@ -21,24 +21,18 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.15 h1:iWYzp1z72IlXTioET0+XI6SjQdPfMGfuAiZiKznOt7g= -github.com/quasilyte/go-ruleguard v0.3.15/go.mod h1:NhuWhnlVEM1gT1A4VJHYfy9MuYSxxwHgxWoPsn9llB4= github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a h1:sWFavxtIctGrVs5SYZ5Ml1CvrDAs8Kf5kx2PI3C41dA= github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4= github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.12-0.20220101150716-969a394a9451/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.12 h1:g63WHzWZUyb9gqGReJUqhWfWpU038+R+IGzZD0BiT9o= -github.com/quasilyte/go-ruleguard/dsl v0.3.12/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.16 h1:yJtIpd4oyNS+/c/gKqxNwoGO9+lPOsy1A4BzKjJRcrI= github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= -github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 h1:P4QPNn+TK49zJjXKERt/vyPbv/mCHB/zQ4flDYOMN+M= -github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= +github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 h1:PDWGei+Rf2bBiuZIbZmM20J2ftEy9IeUCHA8HbQqed8= github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 39dabf07fcdc7f126374715666b08589452d1614 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 15 Feb 2022 21:55:42 +0300 Subject: [PATCH 03/10] update precompiled --- checkers/rulesdata/rulesdata.go | 2640 +++++++++++++------------------ 1 file changed, 1076 insertions(+), 1564 deletions(-) diff --git a/checkers/rulesdata/rulesdata.go b/checkers/rulesdata/rulesdata.go index b759c4abb..e145ba4fe 100644 --- a/checkers/rulesdata/rulesdata.go +++ b/checkers/rulesdata/rulesdata.go @@ -9,24 +9,21 @@ var PrecompiledRules = &ir.File{ CustomDecls: []string{}, BundleImports: []ir.BundleImport{}, RuleGroups: []ir.RuleGroup{ - ir.RuleGroup{ + { Line: 11, Name: "redundantSprint", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects redundant fmt.Sprint calls", - DocBefore: "fmt.Sprint(x)", - DocAfter: "x.String()", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects redundant fmt.Sprint calls", + DocBefore: "fmt.Sprint(x)", + DocAfter: "x.String()", Rules: []ir.Rule{ - ir.Rule{ + { Line: 12, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 12, Value: "fmt.Sprint($x)"}, - ir.PatternString{Line: 12, Value: "fmt.Sprintf(\"%s\", $x)"}, - ir.PatternString{Line: 12, Value: "fmt.Sprintf(\"%v\", $x)"}, + {Line: 12, Value: "fmt.Sprint($x)"}, + {Line: 12, Value: "fmt.Sprintf(\"%s\", $x)"}, + {Line: 12, Value: "fmt.Sprintf(\"%v\", $x)"}, }, ReportTemplate: "use $x.String() instead", SuggestTemplate: "$x.String()", @@ -35,17 +32,15 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"x\"].Type.Implements(`fmt.Stringer`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 13, Op: ir.FilterStringOp, Src: "`fmt.Stringer`", Value: "fmt.Stringer"}, - }, + Args: []ir.FilterExpr{{Line: 13, Op: ir.FilterStringOp, Src: "`fmt.Stringer`", Value: "fmt.Stringer"}}, }, }, - ir.Rule{ + { Line: 17, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 17, Value: "fmt.Sprint($x)"}, - ir.PatternString{Line: 17, Value: "fmt.Sprintf(\"%s\", $x)"}, - ir.PatternString{Line: 17, Value: "fmt.Sprintf(\"%v\", $x)"}, + {Line: 17, Value: "fmt.Sprint($x)"}, + {Line: 17, Value: "fmt.Sprintf(\"%s\", $x)"}, + {Line: 17, Value: "fmt.Sprintf(\"%v\", $x)"}, }, ReportTemplate: "use $x.Error() instead", SuggestTemplate: "$x.Error()", @@ -54,17 +49,15 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"x\"].Type.Implements(`error`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 18, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}, - }, + Args: []ir.FilterExpr{{Line: 18, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, }, }, - ir.Rule{ + { Line: 22, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 22, Value: "fmt.Sprint($x)"}, - ir.PatternString{Line: 22, Value: "fmt.Sprintf(\"%s\", $x)"}, - ir.PatternString{Line: 22, Value: "fmt.Sprintf(\"%v\", $x)"}, + {Line: 22, Value: "fmt.Sprint($x)"}, + {Line: 22, Value: "fmt.Sprintf(\"%s\", $x)"}, + {Line: 22, Value: "fmt.Sprintf(\"%v\", $x)"}, }, ReportTemplate: "$x is already string", SuggestTemplate: "$x", @@ -73,78 +66,69 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`string`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 23, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 23, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, - ir.RuleGroup{ + { Line: 32, Name: "deferUnlambda", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects deferred function literals that can be simplified", - DocBefore: "defer func() { f() }()", - DocAfter: "defer f()", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects deferred function literals that can be simplified", + DocBefore: "defer func() { f() }()", + DocAfter: "defer f()", Rules: []ir.Rule{ - ir.Rule{ - Line: 33, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 33, Value: "defer func() { $f($*args) }()"}, - }, + { + Line: 33, + SyntaxPatterns: []ir.PatternString{{Line: 33, Value: "defer func() { $f($*args) }()"}}, ReportTemplate: "can rewrite as `defer $f($args)`", WhereExpr: ir.FilterExpr{ Line: 34, Op: ir.FilterAndOp, Src: "m[\"f\"].Node.Is(`Ident`) && m[\"f\"].Text != \"panic\" && m[\"f\"].Text != \"recover\" && m[\"args\"].Const", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 34, Op: ir.FilterAndOp, Src: "m[\"f\"].Node.Is(`Ident`) && m[\"f\"].Text != \"panic\" && m[\"f\"].Text != \"recover\"", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 34, Op: ir.FilterAndOp, Src: "m[\"f\"].Node.Is(`Ident`) && m[\"f\"].Text != \"panic\"", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 34, Op: ir.FilterVarNodeIsOp, Src: "m[\"f\"].Node.Is(`Ident`)", Value: "f", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 34, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}, - }, + Args: []ir.FilterExpr{{Line: 34, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, }, - ir.FilterExpr{ + { Line: 34, Op: ir.FilterNeqOp, Src: "m[\"f\"].Text != \"panic\"", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 34, Op: ir.FilterVarTextOp, Src: "m[\"f\"].Text", Value: "f"}, - ir.FilterExpr{Line: 34, Op: ir.FilterStringOp, Src: "\"panic\"", Value: "panic"}, + {Line: 34, Op: ir.FilterVarTextOp, Src: "m[\"f\"].Text", Value: "f"}, + {Line: 34, Op: ir.FilterStringOp, Src: "\"panic\"", Value: "panic"}, }, }, }, }, - ir.FilterExpr{ + { Line: 34, Op: ir.FilterNeqOp, Src: "m[\"f\"].Text != \"recover\"", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 34, Op: ir.FilterVarTextOp, Src: "m[\"f\"].Text", Value: "f"}, - ir.FilterExpr{Line: 34, Op: ir.FilterStringOp, Src: "\"recover\"", Value: "recover"}, + {Line: 34, Op: ir.FilterVarTextOp, Src: "m[\"f\"].Text", Value: "f"}, + {Line: 34, Op: ir.FilterStringOp, Src: "\"recover\"", Value: "recover"}, }, }, }, }, - ir.FilterExpr{ + { Line: 34, Op: ir.FilterVarConstOp, Src: "m[\"args\"].Const", @@ -153,32 +137,28 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.Rule{ - Line: 37, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 37, Value: "defer func() { $pkg.$f($*args) }()"}, - }, + { + Line: 37, + SyntaxPatterns: []ir.PatternString{{Line: 37, Value: "defer func() { $pkg.$f($*args) }()"}}, ReportTemplate: "can rewrite as `defer $pkg.$f($args)`", WhereExpr: ir.FilterExpr{ Line: 38, Op: ir.FilterAndOp, Src: "m[\"f\"].Node.Is(`Ident`) && m[\"args\"].Const && m[\"pkg\"].Object.Is(`PkgName`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 38, Op: ir.FilterAndOp, Src: "m[\"f\"].Node.Is(`Ident`) && m[\"args\"].Const", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 38, Op: ir.FilterVarNodeIsOp, Src: "m[\"f\"].Node.Is(`Ident`)", Value: "f", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 38, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}, - }, + Args: []ir.FilterExpr{{Line: 38, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, }, - ir.FilterExpr{ + { Line: 38, Op: ir.FilterVarConstOp, Src: "m[\"args\"].Const", @@ -186,37 +166,30 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.FilterExpr{ + { Line: 38, Op: ir.FilterVarObjectIsOp, Src: "m[\"pkg\"].Object.Is(`PkgName`)", Value: "pkg", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 38, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}, - }, + Args: []ir.FilterExpr{{Line: 38, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, }, }, }, }, }, }, - ir.RuleGroup{ + { Line: 46, Name: "ioutilDeprecated", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects deprecated io/ioutil package usages", - DocBefore: "ioutil.ReadAll(r)", - DocAfter: "io.ReadAll(r)", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects deprecated io/ioutil package usages", + DocBefore: "ioutil.ReadAll(r)", + DocAfter: "io.ReadAll(r)", Rules: []ir.Rule{ - ir.Rule{ - Line: 47, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 47, Value: "ioutil.ReadAll($_)"}, - }, + { + Line: 47, + SyntaxPatterns: []ir.PatternString{{Line: 47, Value: "ioutil.ReadAll($_)"}}, ReportTemplate: "ioutil.ReadAll is deprecated, use io.ReadAll instead", WhereExpr: ir.FilterExpr{ Line: 48, @@ -225,11 +198,9 @@ var PrecompiledRules = &ir.File{ Value: "1.16", }, }, - ir.Rule{ - Line: 51, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 51, Value: "ioutil.ReadFile($_)"}, - }, + { + Line: 51, + SyntaxPatterns: []ir.PatternString{{Line: 51, Value: "ioutil.ReadFile($_)"}}, ReportTemplate: "ioutil.ReadFile is deprecated, use os.ReadFile instead", WhereExpr: ir.FilterExpr{ Line: 52, @@ -238,11 +209,9 @@ var PrecompiledRules = &ir.File{ Value: "1.16", }, }, - ir.Rule{ - Line: 55, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 55, Value: "ioutil.WriteFile($_, $_, $_)"}, - }, + { + Line: 55, + SyntaxPatterns: []ir.PatternString{{Line: 55, Value: "ioutil.WriteFile($_, $_, $_)"}}, ReportTemplate: "ioutil.WriteFile is deprecated, use os.WriteFile instead", WhereExpr: ir.FilterExpr{ Line: 56, @@ -251,11 +220,9 @@ var PrecompiledRules = &ir.File{ Value: "1.16", }, }, - ir.Rule{ - Line: 59, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 59, Value: "ioutil.ReadDir($_)"}, - }, + { + Line: 59, + SyntaxPatterns: []ir.PatternString{{Line: 59, Value: "ioutil.ReadDir($_)"}}, ReportTemplate: "ioutil.ReadDir is deprecated, use os.ReadDir instead", WhereExpr: ir.FilterExpr{ Line: 60, @@ -264,11 +231,9 @@ var PrecompiledRules = &ir.File{ Value: "1.16", }, }, - ir.Rule{ - Line: 63, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 63, Value: "ioutil.NopCloser($_)"}, - }, + { + Line: 63, + SyntaxPatterns: []ir.PatternString{{Line: 63, Value: "ioutil.NopCloser($_)"}}, ReportTemplate: "ioutil.NopCloser is deprecated, use io.NopCloser instead", WhereExpr: ir.FilterExpr{ Line: 64, @@ -277,11 +242,9 @@ var PrecompiledRules = &ir.File{ Value: "1.16", }, }, - ir.Rule{ - Line: 67, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 67, Value: "ioutil.Discard"}, - }, + { + Line: 67, + SyntaxPatterns: []ir.PatternString{{Line: 67, Value: "ioutil.Discard"}}, ReportTemplate: "ioutil.Discard is deprecated, use io.Discard instead", WhereExpr: ir.FilterExpr{ Line: 68, @@ -292,139 +255,119 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.RuleGroup{ + { Line: 76, Name: "badLock", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects suspicious mutex lock/unlock operations", - DocBefore: "mu.Lock(); mu.Unlock()", - DocAfter: "mu.Lock(); defer mu.Unlock()", + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects suspicious mutex lock/unlock operations", + DocBefore: "mu.Lock(); mu.Unlock()", + DocAfter: "mu.Lock(); defer mu.Unlock()", Rules: []ir.Rule{ - ir.Rule{ - Line: 80, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 80, Value: "$mu1.Lock(); $mu2.Unlock()"}, - }, + { + Line: 80, + SyntaxPatterns: []ir.PatternString{{Line: 80, Value: "$mu1.Lock(); $mu2.Unlock()"}}, ReportTemplate: "defer is missing, mutex is unlocked immediately", WhereExpr: ir.FilterExpr{ Line: 81, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 81, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 81, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 81, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 81, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, - ir.Rule{ - Line: 85, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 85, Value: "$mu1.RLock(); $mu2.RUnlock()"}, - }, + { + Line: 85, + SyntaxPatterns: []ir.PatternString{{Line: 85, Value: "$mu1.RLock(); $mu2.RUnlock()"}}, ReportTemplate: "defer is missing, mutex is unlocked immediately", WhereExpr: ir.FilterExpr{ Line: 86, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 86, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 86, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 86, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 86, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, - ir.Rule{ - Line: 91, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 91, Value: "$mu1.Lock(); defer $mu2.RUnlock()"}, - }, + { + Line: 91, + SyntaxPatterns: []ir.PatternString{{Line: 91, Value: "$mu1.Lock(); defer $mu2.RUnlock()"}}, ReportTemplate: "suspicious unlock, maybe Unlock was intended?", WhereExpr: ir.FilterExpr{ Line: 92, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 92, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 92, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 92, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 92, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, - ir.Rule{ - Line: 96, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 96, Value: "$mu1.RLock(); defer $mu2.Unlock()"}, - }, + { + Line: 96, + SyntaxPatterns: []ir.PatternString{{Line: 96, Value: "$mu1.RLock(); defer $mu2.Unlock()"}}, ReportTemplate: "suspicious unlock, maybe RUnlock was intended?", WhereExpr: ir.FilterExpr{ Line: 97, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 97, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 97, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 97, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 97, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, - ir.Rule{ - Line: 102, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 102, Value: "$mu1.Lock(); defer $mu2.Lock()"}, - }, + { + Line: 102, + SyntaxPatterns: []ir.PatternString{{Line: 102, Value: "$mu1.Lock(); defer $mu2.Lock()"}}, ReportTemplate: "maybe defer $mu1.Unlock() was intended?", WhereExpr: ir.FilterExpr{ Line: 103, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 103, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 103, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 103, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 103, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, - ir.Rule{ - Line: 107, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 107, Value: "$mu1.RLock(); defer $mu2.RLock()"}, - }, + { + Line: 107, + SyntaxPatterns: []ir.PatternString{{Line: 107, Value: "$mu1.RLock(); defer $mu2.RLock()"}}, ReportTemplate: "maybe defer $mu1.RUnlock() was intended?", WhereExpr: ir.FilterExpr{ Line: 108, Op: ir.FilterEqOp, Src: "m[\"mu1\"].Text == m[\"mu2\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 108, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, - ir.FilterExpr{Line: 108, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, + {Line: 108, Op: ir.FilterVarTextOp, Src: "m[\"mu1\"].Text", Value: "mu1"}, + {Line: 108, Op: ir.FilterVarTextOp, Src: "m[\"mu2\"].Text", Value: "mu2"}, }, }, LocationVar: "mu2", }, }, }, - ir.RuleGroup{ + { Line: 117, Name: "httpNoBody", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative", - DocBefore: "http.NewRequest(\"GET\", url, nil)", - DocAfter: "http.NewRequest(\"GET\", url, http.NoBody)", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects nil usages in http.NewRequest calls, suggesting http.NoBody as an alternative", + DocBefore: "http.NewRequest(\"GET\", url, nil)", + DocAfter: "http.NewRequest(\"GET\", url, http.NoBody)", Rules: []ir.Rule{ - ir.Rule{ - Line: 118, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 118, Value: "http.NewRequest($method, $url, $nil)"}, - }, + { + Line: 118, + SyntaxPatterns: []ir.PatternString{{Line: 118, Value: "http.NewRequest($method, $url, $nil)"}}, ReportTemplate: "http.NoBody should be preferred to the nil request body", SuggestTemplate: "http.NewRequest($method, $url, http.NoBody)", WhereExpr: ir.FilterExpr{ @@ -432,17 +375,15 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterEqOp, Src: "m[\"nil\"].Text == \"nil\"", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 119, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, - ir.FilterExpr{Line: 119, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, + {Line: 119, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, + {Line: 119, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, LocationVar: "nil", }, - ir.Rule{ - Line: 124, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 124, Value: "http.NewRequestWithContext($ctx, $method, $url, $nil)"}, - }, + { + Line: 124, + SyntaxPatterns: []ir.PatternString{{Line: 124, Value: "http.NewRequestWithContext($ctx, $method, $url, $nil)"}}, ReportTemplate: "http.NoBody should be preferred to the nil request body", SuggestTemplate: "http.NewRequestWithContext($ctx, $method, $url, http.NoBody)", WhereExpr: ir.FilterExpr{ @@ -450,264 +391,200 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterEqOp, Src: "m[\"nil\"].Text == \"nil\"", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 125, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, - ir.FilterExpr{Line: 125, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, + {Line: 125, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, + {Line: 125, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, LocationVar: "nil", }, }, }, - ir.RuleGroup{ + { Line: 136, Name: "preferDecodeRune", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - }, - DocSummary: "Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation", - DocBefore: "r := []rune(s)[0]", - DocAfter: "r, _ := utf8.DecodeRuneInString(s)", - DocNote: "See Go issue for details: https://github.com/golang/go/issues/45260", - Rules: []ir.Rule{ - ir.Rule{ - Line: 137, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 137, Value: "[]rune($s)[0]"}, - }, - ReportTemplate: "consider replacing $$ with utf8.DecodeRuneInString($s)", - WhereExpr: ir.FilterExpr{ - Line: 138, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"s\"].Type.Is(`string`)", - Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 138, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, - }, - }, - }, + DocTags: []string{"performance", "experimental"}, + DocSummary: "Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation", + DocBefore: "r := []rune(s)[0]", + DocAfter: "r, _ := utf8.DecodeRuneInString(s)", + DocNote: "See Go issue for details: https://github.com/golang/go/issues/45260", + Rules: []ir.Rule{{ + Line: 137, + SyntaxPatterns: []ir.PatternString{{Line: 137, Value: "[]rune($s)[0]"}}, + ReportTemplate: "consider replacing $$ with utf8.DecodeRuneInString($s)", + WhereExpr: ir.FilterExpr{ + Line: 138, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"s\"].Type.Is(`string`)", + Value: "s", + Args: []ir.FilterExpr{{Line: 138, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + }, + }}, }, - ir.RuleGroup{ + { Line: 146, Name: "sloppyLen", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects usage of `len` when result is obvious or doesn't make sense", - DocBefore: "len(arr) <= 0", - DocAfter: "len(arr) == 0", + DocTags: []string{"style"}, + DocSummary: "Detects usage of `len` when result is obvious or doesn't make sense", + DocBefore: "len(arr) <= 0", + DocAfter: "len(arr) == 0", Rules: []ir.Rule{ - ir.Rule{ - Line: 147, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 147, Value: "len($_) >= 0"}, - }, + { + Line: 147, + SyntaxPatterns: []ir.PatternString{{Line: 147, Value: "len($_) >= 0"}}, ReportTemplate: "$$ is always true", }, - ir.Rule{ - Line: 148, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 148, Value: "len($_) < 0"}, - }, + { + Line: 148, + SyntaxPatterns: []ir.PatternString{{Line: 148, Value: "len($_) < 0"}}, ReportTemplate: "$$ is always false", }, - ir.Rule{ - Line: 149, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 149, Value: "len($x) <= 0"}, - }, + { + Line: 149, + SyntaxPatterns: []ir.PatternString{{Line: 149, Value: "len($x) <= 0"}}, ReportTemplate: "$$ can be len($x) == 0", }, }, }, - ir.RuleGroup{ + { Line: 156, Name: "valSwap", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects value swapping code that are not using parallel assignment", - DocBefore: "*tmp = *x; *x = *y; *y = *tmp", - DocAfter: "*x, *y = *y, *x", - Rules: []ir.Rule{ - ir.Rule{ - Line: 157, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 157, Value: "$tmp := $y; $y = $x; $x = $tmp"}, - }, - ReportTemplate: "can re-write as `$y, $x = $x, $y`", - }, - }, + DocTags: []string{"style"}, + DocSummary: "Detects value swapping code that are not using parallel assignment", + DocBefore: "*tmp = *x; *x = *y; *y = *tmp", + DocAfter: "*x, *y = *y, *x", + Rules: []ir.Rule{{ + Line: 157, + SyntaxPatterns: []ir.PatternString{{Line: 157, Value: "$tmp := $y; $y = $x; $x = $tmp"}}, + ReportTemplate: "can re-write as `$y, $x = $x, $y`", + }}, }, - ir.RuleGroup{ + { Line: 165, Name: "switchTrue", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects switch-over-bool statements that use explicit `true` tag value", - DocBefore: "switch true {...}", - DocAfter: "switch {...}", + DocTags: []string{"style"}, + DocSummary: "Detects switch-over-bool statements that use explicit `true` tag value", + DocBefore: "switch true {...}", + DocAfter: "switch {...}", Rules: []ir.Rule{ - ir.Rule{ - Line: 166, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 166, Value: "switch true { $*_ }"}, - }, + { + Line: 166, + SyntaxPatterns: []ir.PatternString{{Line: 166, Value: "switch true { $*_ }"}}, ReportTemplate: "replace 'switch true {}' with 'switch {}'", }, - ir.Rule{ - Line: 168, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 168, Value: "switch $x; true { $*_ }"}, - }, + { + Line: 168, + SyntaxPatterns: []ir.PatternString{{Line: 168, Value: "switch $x; true { $*_ }"}}, ReportTemplate: "replace 'switch $x; true {}' with 'switch $x; {}'", }, }, }, - ir.RuleGroup{ + { Line: 176, Name: "flagDeref", MatcherName: "m", - DocTags: []string{ - "diagnostic", - }, - DocSummary: "Detects immediate dereferencing of `flag` package pointers", - DocBefore: "b := *flag.Bool(\"b\", false, \"b docs\")", - DocAfter: "var b bool; flag.BoolVar(&b, \"b\", false, \"b docs\")", + DocTags: []string{"diagnostic"}, + DocSummary: "Detects immediate dereferencing of `flag` package pointers", + DocBefore: "b := *flag.Bool(\"b\", false, \"b docs\")", + DocAfter: "var b bool; flag.BoolVar(&b, \"b\", false, \"b docs\")", Rules: []ir.Rule{ - ir.Rule{ - Line: 177, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 177, Value: "*flag.Bool($*_)"}, - }, + { + Line: 177, + SyntaxPatterns: []ir.PatternString{{Line: 177, Value: "*flag.Bool($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.BoolVar", }, - ir.Rule{ - Line: 178, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 178, Value: "*flag.Duration($*_)"}, - }, + { + Line: 178, + SyntaxPatterns: []ir.PatternString{{Line: 178, Value: "*flag.Duration($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.DurationVar", }, - ir.Rule{ - Line: 179, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 179, Value: "*flag.Float64($*_)"}, - }, + { + Line: 179, + SyntaxPatterns: []ir.PatternString{{Line: 179, Value: "*flag.Float64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Float64Var", }, - ir.Rule{ - Line: 180, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 180, Value: "*flag.Int($*_)"}, - }, + { + Line: 180, + SyntaxPatterns: []ir.PatternString{{Line: 180, Value: "*flag.Int($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.IntVar", }, - ir.Rule{ - Line: 181, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 181, Value: "*flag.Int64($*_)"}, - }, + { + Line: 181, + SyntaxPatterns: []ir.PatternString{{Line: 181, Value: "*flag.Int64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Int64Var", }, - ir.Rule{ - Line: 182, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 182, Value: "*flag.String($*_)"}, - }, + { + Line: 182, + SyntaxPatterns: []ir.PatternString{{Line: 182, Value: "*flag.String($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.StringVar", }, - ir.Rule{ - Line: 183, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 183, Value: "*flag.Uint($*_)"}, - }, + { + Line: 183, + SyntaxPatterns: []ir.PatternString{{Line: 183, Value: "*flag.Uint($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.UintVar", }, - ir.Rule{ - Line: 184, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 184, Value: "*flag.Uint64($*_)"}, - }, + { + Line: 184, + SyntaxPatterns: []ir.PatternString{{Line: 184, Value: "*flag.Uint64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Uint64Var", }, }, }, - ir.RuleGroup{ + { Line: 191, Name: "emptyStringTest", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects empty string checks that can be written more idiomatically", - DocBefore: "len(s) == 0", - DocAfter: "s == \"\"", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects empty string checks that can be written more idiomatically", + DocBefore: "len(s) == 0", + DocAfter: "s == \"\"", Rules: []ir.Rule{ - ir.Rule{ - Line: 192, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 192, Value: "len($s) != 0"}, - }, + { + Line: 192, + SyntaxPatterns: []ir.PatternString{{Line: 192, Value: "len($s) != 0"}}, ReportTemplate: "replace `$$` with `$s != \"\"`", WhereExpr: ir.FilterExpr{ Line: 193, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 193, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 193, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, - ir.Rule{ - Line: 196, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 196, Value: "len($s) == 0"}, - }, + { + Line: 196, + SyntaxPatterns: []ir.PatternString{{Line: 196, Value: "len($s) == 0"}}, ReportTemplate: "replace `$$` with `$s == \"\"`", WhereExpr: ir.FilterExpr{ Line: 197, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 197, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 197, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, - ir.RuleGroup{ + { Line: 205, Name: "stringXbytes", MatcherName: "m", - DocTags: []string{ - "performance", - }, - DocSummary: "Detects redundant conversions between string and []byte", - DocBefore: "copy(b, []byte(s))", - DocAfter: "copy(b, s)", + DocTags: []string{"performance"}, + DocSummary: "Detects redundant conversions between string and []byte", + DocBefore: "copy(b, []byte(s))", + DocAfter: "copy(b, s)", Rules: []ir.Rule{ - ir.Rule{ - Line: 206, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 206, Value: "copy($_, []byte($s))"}, - }, + { + Line: 206, + SyntaxPatterns: []ir.PatternString{{Line: 206, Value: "copy($_, []byte($s))"}}, ReportTemplate: "can simplify `[]byte($s)` to `$s`", }, - ir.Rule{ - Line: 208, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 208, Value: "string($b) == \"\""}, - }, + { + Line: 208, + SyntaxPatterns: []ir.PatternString{{Line: 208, Value: "string($b) == \"\""}}, ReportTemplate: "suggestion: len($b) == 0", SuggestTemplate: "len($b) == 0", WhereExpr: ir.FilterExpr{ @@ -715,16 +592,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 208, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 208, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, - ir.Rule{ - Line: 209, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 209, Value: "string($b) != \"\""}, - }, + { + Line: 209, + SyntaxPatterns: []ir.PatternString{{Line: 209, Value: "string($b) != \"\""}}, ReportTemplate: "suggestion: len($b) != 0", SuggestTemplate: "len($b) != 0", WhereExpr: ir.FilterExpr{ @@ -732,16 +605,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 209, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 209, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, - ir.Rule{ - Line: 211, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 211, Value: "len(string($b))"}, - }, + { + Line: 211, + SyntaxPatterns: []ir.PatternString{{Line: 211, Value: "len(string($b))"}}, ReportTemplate: "suggestion: len($b)", SuggestTemplate: "len($b)", WhereExpr: ir.FilterExpr{ @@ -749,16 +618,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 211, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 211, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, - ir.Rule{ - Line: 213, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 213, Value: "string($x) == string($y)"}, - }, + { + Line: 213, + SyntaxPatterns: []ir.PatternString{{Line: 213, Value: "string($x) == string($y)"}}, ReportTemplate: "suggestion: bytes.Equal($x, $y)", SuggestTemplate: "bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ @@ -766,32 +631,26 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 214, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, - ir.FilterExpr{ + { Line: 214, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, }, }, - ir.Rule{ - Line: 217, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 217, Value: "string($x) != string($y)"}, - }, + { + Line: 217, + SyntaxPatterns: []ir.PatternString{{Line: 217, Value: "string($x) != string($y)"}}, ReportTemplate: "suggestion: !bytes.Equal($x, $y)", SuggestTemplate: "!bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ @@ -799,32 +658,26 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 218, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, - ir.FilterExpr{ + { Line: 218, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, - }, + Args: []ir.FilterExpr{{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, }, }, - ir.Rule{ - Line: 221, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 221, Value: "$re.Match([]byte($s))"}, - }, + { + Line: 221, + SyntaxPatterns: []ir.PatternString{{Line: 221, Value: "$re.Match([]byte($s))"}}, ReportTemplate: "suggestion: $re.MatchString($s)", SuggestTemplate: "$re.MatchString($s)", WhereExpr: ir.FilterExpr{ @@ -832,32 +685,26 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 222, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 222, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, - }, + Args: []ir.FilterExpr{{Line: 222, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, - ir.FilterExpr{ + { Line: 222, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 222, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 222, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, - ir.Rule{ - Line: 225, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 225, Value: "$re.FindIndex([]byte($s))"}, - }, + { + Line: 225, + SyntaxPatterns: []ir.PatternString{{Line: 225, Value: "$re.FindIndex([]byte($s))"}}, ReportTemplate: "suggestion: $re.FindStringIndex($s)", SuggestTemplate: "$re.FindStringIndex($s)", WhereExpr: ir.FilterExpr{ @@ -865,32 +712,26 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 226, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 226, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, - }, + Args: []ir.FilterExpr{{Line: 226, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, - ir.FilterExpr{ + { Line: 226, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 226, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 226, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, - ir.Rule{ - Line: 229, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 229, Value: "$re.FindAllIndex([]byte($s), $n)"}, - }, + { + Line: 229, + SyntaxPatterns: []ir.PatternString{{Line: 229, Value: "$re.FindAllIndex([]byte($s), $n)"}}, ReportTemplate: "suggestion: $re.FindAllStringIndex($s, $n)", SuggestTemplate: "$re.FindAllStringIndex($s, $n)", WhereExpr: ir.FilterExpr{ @@ -898,190 +739,146 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 230, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 230, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, - }, + Args: []ir.FilterExpr{{Line: 230, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, - ir.FilterExpr{ + { Line: 230, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 230, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, + Args: []ir.FilterExpr{{Line: 230, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, }, }, - ir.RuleGroup{ + { Line: 239, Name: "indexAlloc", MatcherName: "m", - DocTags: []string{ - "performance", - }, - DocSummary: "Detects strings.Index calls that may cause unwanted allocs", - DocBefore: "strings.Index(string(x), y)", - DocAfter: "bytes.Index(x, []byte(y))", - DocNote: "See Go issue for details: https://github.com/golang/go/issues/25864", - Rules: []ir.Rule{ - ir.Rule{ - Line: 240, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 240, Value: "strings.Index(string($x), $y)"}, - }, - ReportTemplate: "consider replacing $$ with bytes.Index($x, []byte($y))", - WhereExpr: ir.FilterExpr{ - Line: 241, - Op: ir.FilterAndOp, - Src: "m[\"x\"].Pure && m[\"y\"].Pure", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, - }, - }, - }, - }, + DocTags: []string{"performance"}, + DocSummary: "Detects strings.Index calls that may cause unwanted allocs", + DocBefore: "strings.Index(string(x), y)", + DocAfter: "bytes.Index(x, []byte(y))", + DocNote: "See Go issue for details: https://github.com/golang/go/issues/25864", + Rules: []ir.Rule{{ + Line: 240, + SyntaxPatterns: []ir.PatternString{{Line: 240, Value: "strings.Index(string($x), $y)"}}, + ReportTemplate: "consider replacing $$ with bytes.Index($x, []byte($y))", + WhereExpr: ir.FilterExpr{ + Line: 241, + Op: ir.FilterAndOp, + Src: "m[\"x\"].Pure && m[\"y\"].Pure", + Args: []ir.FilterExpr{ + {Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 249, Name: "wrapperFunc", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects function calls that can be replaced with convenience wrappers", - DocBefore: "wg.Add(-1)", - DocAfter: "wg.Done()", + DocTags: []string{"style"}, + DocSummary: "Detects function calls that can be replaced with convenience wrappers", + DocBefore: "wg.Add(-1)", + DocAfter: "wg.Done()", Rules: []ir.Rule{ - ir.Rule{ - Line: 250, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 250, Value: "$wg.Add(-1)"}, - }, + { + Line: 250, + SyntaxPatterns: []ir.PatternString{{Line: 250, Value: "$wg.Add(-1)"}}, ReportTemplate: "use WaitGroup.Done method in `$$`", WhereExpr: ir.FilterExpr{ Line: 251, Op: ir.FilterVarTypeIsOp, Src: "m[\"wg\"].Type.Is(`sync.WaitGroup`)", Value: "wg", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 251, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}, - }, + Args: []ir.FilterExpr{{Line: 251, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}}, }, }, - ir.Rule{ - Line: 254, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 254, Value: "$buf.Truncate(0)"}, - }, + { + Line: 254, + SyntaxPatterns: []ir.PatternString{{Line: 254, Value: "$buf.Truncate(0)"}}, ReportTemplate: "use Buffer.Reset method in `$$`", WhereExpr: ir.FilterExpr{ Line: 255, Op: ir.FilterVarTypeIsOp, Src: "m[\"buf\"].Type.Is(`bytes.Buffer`)", Value: "buf", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 255, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}, - }, + Args: []ir.FilterExpr{{Line: 255, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}}, }, }, - ir.Rule{ - Line: 258, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 258, Value: "http.HandlerFunc(http.NotFound)"}, - }, + { + Line: 258, + SyntaxPatterns: []ir.PatternString{{Line: 258, Value: "http.HandlerFunc(http.NotFound)"}}, ReportTemplate: "use http.NotFoundHandler method in `$$`", }, - ir.Rule{ - Line: 260, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 260, Value: "strings.SplitN($_, $_, -1)"}, - }, + { + Line: 260, + SyntaxPatterns: []ir.PatternString{{Line: 260, Value: "strings.SplitN($_, $_, -1)"}}, ReportTemplate: "use strings.Split method in `$$`", }, - ir.Rule{ - Line: 261, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 261, Value: "strings.Replace($_, $_, $_, -1)"}, - }, + { + Line: 261, + SyntaxPatterns: []ir.PatternString{{Line: 261, Value: "strings.Replace($_, $_, $_, -1)"}}, ReportTemplate: "use strings.ReplaceAll method in `$$`", }, - ir.Rule{ - Line: 262, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 262, Value: "strings.Map(unicode.ToTitle, $_)"}, - }, + { + Line: 262, + SyntaxPatterns: []ir.PatternString{{Line: 262, Value: "strings.Map(unicode.ToTitle, $_)"}}, ReportTemplate: "use strings.ToTitle method in `$$`", }, - ir.Rule{ - Line: 264, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 264, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}, - }, + { + Line: 264, + SyntaxPatterns: []ir.PatternString{{Line: 264, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}}, ReportTemplate: "use bytes.Split method in `$$`", }, - ir.Rule{ - Line: 265, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 265, Value: "bytes.Replace($_, $_, $_, -1)"}, - }, + { + Line: 265, + SyntaxPatterns: []ir.PatternString{{Line: 265, Value: "bytes.Replace($_, $_, $_, -1)"}}, ReportTemplate: "use bytes.ReplaceAll method in `$$`", }, - ir.Rule{ - Line: 266, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 266, Value: "bytes.Map(unicode.ToUpper, $_)"}, - }, + { + Line: 266, + SyntaxPatterns: []ir.PatternString{{Line: 266, Value: "bytes.Map(unicode.ToUpper, $_)"}}, ReportTemplate: "use bytes.ToUpper method in `$$`", }, - ir.Rule{ - Line: 267, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 267, Value: "bytes.Map(unicode.ToLower, $_)"}, - }, + { + Line: 267, + SyntaxPatterns: []ir.PatternString{{Line: 267, Value: "bytes.Map(unicode.ToLower, $_)"}}, ReportTemplate: "use bytes.ToLower method in `$$`", }, - ir.Rule{ - Line: 268, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 268, Value: "bytes.Map(unicode.ToTitle, $_)"}, - }, + { + Line: 268, + SyntaxPatterns: []ir.PatternString{{Line: 268, Value: "bytes.Map(unicode.ToTitle, $_)"}}, ReportTemplate: "use bytes.ToTitle method in `$$`", }, - ir.Rule{ - Line: 270, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 270, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}, - }, + { + Line: 270, + SyntaxPatterns: []ir.PatternString{{Line: 270, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}}, ReportTemplate: "use draw.Draw method in `$$`", }, }, }, - ir.RuleGroup{ + { Line: 278, Name: "regexpMust", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`", - DocBefore: "re, _ := regexp.Compile(\"const pattern\")", - DocAfter: "re := regexp.MustCompile(\"const pattern\")", + DocTags: []string{"style"}, + DocSummary: "Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`", + DocBefore: "re, _ := regexp.Compile(\"const pattern\")", + DocAfter: "re := regexp.MustCompile(\"const pattern\")", Rules: []ir.Rule{ - ir.Rule{ - Line: 279, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 279, Value: "regexp.Compile($pat)"}, - }, + { + Line: 279, + SyntaxPatterns: []ir.PatternString{{Line: 279, Value: "regexp.Compile($pat)"}}, ReportTemplate: "for const patterns like $pat, use regexp.MustCompile", WhereExpr: ir.FilterExpr{ Line: 280, @@ -1090,11 +887,9 @@ var PrecompiledRules = &ir.File{ Value: "pat", }, }, - ir.Rule{ - Line: 283, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 283, Value: "regexp.CompilePOSIX($pat)"}, - }, + { + Line: 283, + SyntaxPatterns: []ir.PatternString{{Line: 283, Value: "regexp.CompilePOSIX($pat)"}}, ReportTemplate: "for const patterns like $pat, use regexp.MustCompilePOSIX", WhereExpr: ir.FilterExpr{ Line: 284, @@ -1105,35 +900,31 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.RuleGroup{ + { Line: 292, Name: "badCall", MatcherName: "m", - DocTags: []string{ - "diagnostic", - }, - DocSummary: "Detects suspicious function calls", - DocBefore: "strings.Replace(s, from, to, 0)", - DocAfter: "strings.Replace(s, from, to, -1)", + DocTags: []string{"diagnostic"}, + DocSummary: "Detects suspicious function calls", + DocBefore: "strings.Replace(s, from, to, 0)", + DocAfter: "strings.Replace(s, from, to, -1)", Rules: []ir.Rule{ - ir.Rule{ - Line: 293, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 293, Value: "strings.Replace($_, $_, $_, $zero)"}, - }, + { + Line: 293, + SyntaxPatterns: []ir.PatternString{{Line: 293, Value: "strings.Replace($_, $_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ Line: 294, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 294, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, - ir.FilterExpr{ + { Line: 294, Op: ir.FilterIntOp, Src: "0", @@ -1143,24 +934,22 @@ var PrecompiledRules = &ir.File{ }, LocationVar: "zero", }, - ir.Rule{ - Line: 296, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 296, Value: "bytes.Replace($_, $_, $_, $zero)"}, - }, + { + Line: 296, + SyntaxPatterns: []ir.PatternString{{Line: 296, Value: "bytes.Replace($_, $_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ Line: 297, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 297, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, - ir.FilterExpr{ + { Line: 297, Op: ir.FilterIntOp, Src: "0", @@ -1170,24 +959,22 @@ var PrecompiledRules = &ir.File{ }, LocationVar: "zero", }, - ir.Rule{ - Line: 300, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 300, Value: "strings.SplitN($_, $_, $zero)"}, - }, + { + Line: 300, + SyntaxPatterns: []ir.PatternString{{Line: 300, Value: "strings.SplitN($_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ Line: 301, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 301, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, - ir.FilterExpr{ + { Line: 301, Op: ir.FilterIntOp, Src: "0", @@ -1197,24 +984,22 @@ var PrecompiledRules = &ir.File{ }, LocationVar: "zero", }, - ir.Rule{ - Line: 303, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 303, Value: "bytes.SplitN($_, $_, $zero)"}, - }, + { + Line: 303, + SyntaxPatterns: []ir.PatternString{{Line: 303, Value: "bytes.SplitN($_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ Line: 304, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 304, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, - ir.FilterExpr{ + { Line: 304, Op: ir.FilterIntOp, Src: "0", @@ -1224,200 +1009,158 @@ var PrecompiledRules = &ir.File{ }, LocationVar: "zero", }, - ir.Rule{ - Line: 307, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 307, Value: "append($_)"}, - }, + { + Line: 307, + SyntaxPatterns: []ir.PatternString{{Line: 307, Value: "append($_)"}}, ReportTemplate: "no-op append call, probably missing arguments", }, - ir.Rule{ - Line: 309, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 309, Value: "filepath.Join($_)"}, - }, + { + Line: 309, + SyntaxPatterns: []ir.PatternString{{Line: 309, Value: "filepath.Join($_)"}}, ReportTemplate: "suspicious Join on 1 argument", }, }, }, - ir.RuleGroup{ + { Line: 316, Name: "assignOp", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects assignments that can be simplified by using assignment operators", - DocBefore: "x = x * 2", - DocAfter: "x *= 2", + DocTags: []string{"style"}, + DocSummary: "Detects assignments that can be simplified by using assignment operators", + DocBefore: "x = x * 2", + DocAfter: "x *= 2", Rules: []ir.Rule{ - ir.Rule{ - Line: 317, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 317, Value: "$x = $x + 1"}, - }, + { + Line: 317, + SyntaxPatterns: []ir.PatternString{{Line: 317, Value: "$x = $x + 1"}}, ReportTemplate: "replace `$$` with `$x++`", WhereExpr: ir.FilterExpr{Line: 317, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 318, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 318, Value: "$x = $x - 1"}, - }, + { + Line: 318, + SyntaxPatterns: []ir.PatternString{{Line: 318, Value: "$x = $x - 1"}}, ReportTemplate: "replace `$$` with `$x--`", WhereExpr: ir.FilterExpr{Line: 318, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 320, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 320, Value: "$x = $x + $y"}, - }, + { + Line: 320, + SyntaxPatterns: []ir.PatternString{{Line: 320, Value: "$x = $x + $y"}}, ReportTemplate: "replace `$$` with `$x += $y`", WhereExpr: ir.FilterExpr{Line: 320, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 321, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 321, Value: "$x = $x - $y"}, - }, + { + Line: 321, + SyntaxPatterns: []ir.PatternString{{Line: 321, Value: "$x = $x - $y"}}, ReportTemplate: "replace `$$` with `$x -= $y`", WhereExpr: ir.FilterExpr{Line: 321, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 323, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 323, Value: "$x = $x * $y"}, - }, + { + Line: 323, + SyntaxPatterns: []ir.PatternString{{Line: 323, Value: "$x = $x * $y"}}, ReportTemplate: "replace `$$` with `$x *= $y`", WhereExpr: ir.FilterExpr{Line: 323, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 324, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 324, Value: "$x = $x / $y"}, - }, + { + Line: 324, + SyntaxPatterns: []ir.PatternString{{Line: 324, Value: "$x = $x / $y"}}, ReportTemplate: "replace `$$` with `$x /= $y`", WhereExpr: ir.FilterExpr{Line: 324, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 325, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 325, Value: "$x = $x % $y"}, - }, + { + Line: 325, + SyntaxPatterns: []ir.PatternString{{Line: 325, Value: "$x = $x % $y"}}, ReportTemplate: "replace `$$` with `$x %= $y`", WhereExpr: ir.FilterExpr{Line: 325, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 326, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 326, Value: "$x = $x & $y"}, - }, + { + Line: 326, + SyntaxPatterns: []ir.PatternString{{Line: 326, Value: "$x = $x & $y"}}, ReportTemplate: "replace `$$` with `$x &= $y`", WhereExpr: ir.FilterExpr{Line: 326, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 327, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 327, Value: "$x = $x | $y"}, - }, + { + Line: 327, + SyntaxPatterns: []ir.PatternString{{Line: 327, Value: "$x = $x | $y"}}, ReportTemplate: "replace `$$` with `$x |= $y`", WhereExpr: ir.FilterExpr{Line: 327, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 328, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 328, Value: "$x = $x ^ $y"}, - }, + { + Line: 328, + SyntaxPatterns: []ir.PatternString{{Line: 328, Value: "$x = $x ^ $y"}}, ReportTemplate: "replace `$$` with `$x ^= $y`", WhereExpr: ir.FilterExpr{Line: 328, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 329, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 329, Value: "$x = $x << $y"}, - }, + { + Line: 329, + SyntaxPatterns: []ir.PatternString{{Line: 329, Value: "$x = $x << $y"}}, ReportTemplate: "replace `$$` with `$x <<= $y`", WhereExpr: ir.FilterExpr{Line: 329, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 330, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 330, Value: "$x = $x >> $y"}, - }, + { + Line: 330, + SyntaxPatterns: []ir.PatternString{{Line: 330, Value: "$x = $x >> $y"}}, ReportTemplate: "replace `$$` with `$x >>= $y`", WhereExpr: ir.FilterExpr{Line: 330, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ - Line: 331, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 331, Value: "$x = $x &^ $y"}, - }, + { + Line: 331, + SyntaxPatterns: []ir.PatternString{{Line: 331, Value: "$x = $x &^ $y"}}, ReportTemplate: "replace `$$` with `$x &^= $y`", WhereExpr: ir.FilterExpr{Line: 331, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, - ir.RuleGroup{ + { Line: 338, Name: "preferWriteByte", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - "opinionated", - }, - DocSummary: "Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead", - DocBefore: "w.WriteRune('\\n')", - DocAfter: "w.WriteByte('\\n')", - Rules: []ir.Rule{ - ir.Rule{ - Line: 342, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 342, Value: "$w.WriteRune($c)"}, - }, - ReportTemplate: "consider writing single byte rune $c with $w.WriteByte($c)", - WhereExpr: ir.FilterExpr{ - Line: 343, - Op: ir.FilterAndOp, - Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\") && (m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 343, - Op: ir.FilterVarTypeImplementsOp, - Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\")", - Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 343, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}, + DocTags: []string{"performance", "experimental", "opinionated"}, + DocSummary: "Detects WriteRune calls with rune literal argument that is single byte and reports to use WriteByte instead", + DocBefore: "w.WriteRune('\\n')", + DocAfter: "w.WriteByte('\\n')", + Rules: []ir.Rule{{ + Line: 342, + SyntaxPatterns: []ir.PatternString{{Line: 342, Value: "$w.WriteRune($c)"}}, + ReportTemplate: "consider writing single byte rune $c with $w.WriteByte($c)", + WhereExpr: ir.FilterExpr{ + Line: 343, + Op: ir.FilterAndOp, + Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\") && (m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", + Args: []ir.FilterExpr{ + { + Line: 343, + Op: ir.FilterVarTypeImplementsOp, + Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\")", + Value: "w", + Args: []ir.FilterExpr{{Line: 343, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}}, + }, + { + Line: 343, + Op: ir.FilterAndOp, + Src: "(m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", + Args: []ir.FilterExpr{ + { + Line: 343, + Op: ir.FilterVarConstOp, + Src: "m[\"c\"].Const", + Value: "c", }, - }, - ir.FilterExpr{ - Line: 343, - Op: ir.FilterAndOp, - Src: "(m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 343, - Op: ir.FilterVarConstOp, - Src: "m[\"c\"].Const", - Value: "c", - }, - ir.FilterExpr{ - Line: 343, - Op: ir.FilterLtOp, - Src: "m[\"c\"].Value.Int() < runeSelf", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 343, - Op: ir.FilterVarValueIntOp, - Src: "m[\"c\"].Value.Int()", - Value: "c", - }, - ir.FilterExpr{ - Line: 343, - Op: ir.FilterIntOp, - Src: "runeSelf", - Value: int64(128), - }, + { + Line: 343, + Op: ir.FilterLtOp, + Src: "m[\"c\"].Value.Int() < runeSelf", + Args: []ir.FilterExpr{ + { + Line: 343, + Op: ir.FilterVarValueIntOp, + Src: "m[\"c\"].Value.Int()", + Value: "c", + }, + { + Line: 343, + Op: ir.FilterIntOp, + Src: "runeSelf", + Value: int64(128), }, }, }, @@ -1425,25 +1168,20 @@ var PrecompiledRules = &ir.File{ }, }, }, - }, + }}, }, - ir.RuleGroup{ + { Line: 351, Name: "preferFprint", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - }, - DocSummary: "Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln)", - DocBefore: "w.Write([]byte(fmt.Sprintf(\"%x\", 10)))", - DocAfter: "fmt.Fprintf(w, \"%x\", 10)", + DocTags: []string{"performance", "experimental"}, + DocSummary: "Detects fmt.Sprint(f/ln) calls which can be replaced with fmt.Fprint(f/ln)", + DocBefore: "w.Write([]byte(fmt.Sprintf(\"%x\", 10)))", + DocAfter: "fmt.Fprintf(w, \"%x\", 10)", Rules: []ir.Rule{ - ir.Rule{ - Line: 352, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 352, Value: "$w.Write([]byte(fmt.Sprint($*args)))"}, - }, + { + Line: 352, + SyntaxPatterns: []ir.PatternString{{Line: 352, Value: "$w.Write([]byte(fmt.Sprint($*args)))"}}, ReportTemplate: "fmt.Fprint($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprint($w, $args)", WhereExpr: ir.FilterExpr{ @@ -1451,16 +1189,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 353, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, - }, + Args: []ir.FilterExpr{{Line: 353, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, - ir.Rule{ - Line: 357, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 357, Value: "$w.Write([]byte(fmt.Sprintf($*args)))"}, - }, + { + Line: 357, + SyntaxPatterns: []ir.PatternString{{Line: 357, Value: "$w.Write([]byte(fmt.Sprintf($*args)))"}}, ReportTemplate: "fmt.Fprintf($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprintf($w, $args)", WhereExpr: ir.FilterExpr{ @@ -1468,16 +1202,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 358, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, - }, + Args: []ir.FilterExpr{{Line: 358, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, - ir.Rule{ - Line: 362, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 362, Value: "$w.Write([]byte(fmt.Sprintln($*args)))"}, - }, + { + Line: 362, + SyntaxPatterns: []ir.PatternString{{Line: 362, Value: "$w.Write([]byte(fmt.Sprintln($*args)))"}}, ReportTemplate: "fmt.Fprintln($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprintln($w, $args)", WhereExpr: ir.FilterExpr{ @@ -1485,189 +1215,156 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 363, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, - }, + Args: []ir.FilterExpr{{Line: 363, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, - ir.Rule{ - Line: 367, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 367, Value: "io.WriteString($w, fmt.Sprint($*args))"}, - }, + { + Line: 367, + SyntaxPatterns: []ir.PatternString{{Line: 367, Value: "io.WriteString($w, fmt.Sprint($*args))"}}, ReportTemplate: "suggestion: fmt.Fprint($w, $args)", SuggestTemplate: "fmt.Fprint($w, $args)", }, - ir.Rule{ - Line: 368, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 368, Value: "io.WriteString($w, fmt.Sprintf($*args))"}, - }, + { + Line: 368, + SyntaxPatterns: []ir.PatternString{{Line: 368, Value: "io.WriteString($w, fmt.Sprintf($*args))"}}, ReportTemplate: "suggestion: fmt.Fprintf($w, $args)", SuggestTemplate: "fmt.Fprintf($w, $args)", }, - ir.Rule{ - Line: 369, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 369, Value: "io.WriteString($w, fmt.Sprintln($*args))"}, - }, + { + Line: 369, + SyntaxPatterns: []ir.PatternString{{Line: 369, Value: "io.WriteString($w, fmt.Sprintln($*args))"}}, ReportTemplate: "suggestion: fmt.Fprintln($w, $args)", SuggestTemplate: "fmt.Fprintln($w, $args)", }, }, }, - ir.RuleGroup{ + { Line: 376, Name: "dupArg", MatcherName: "m", - DocTags: []string{ - "diagnostic", - }, - DocSummary: "Detects suspicious duplicated arguments", - DocBefore: "copy(dst, dst)", - DocAfter: "copy(dst, src)", + DocTags: []string{"diagnostic"}, + DocSummary: "Detects suspicious duplicated arguments", + DocBefore: "copy(dst, dst)", + DocAfter: "copy(dst, src)", Rules: []ir.Rule{ - ir.Rule{ + { Line: 377, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 377, Value: "$x.Equal($x)"}, - ir.PatternString{Line: 377, Value: "$x.Equals($x)"}, - ir.PatternString{Line: 377, Value: "$x.Compare($x)"}, - ir.PatternString{Line: 377, Value: "$x.Cmp($x)"}, + {Line: 377, Value: "$x.Equal($x)"}, + {Line: 377, Value: "$x.Equals($x)"}, + {Line: 377, Value: "$x.Compare($x)"}, + {Line: 377, Value: "$x.Cmp($x)"}, }, ReportTemplate: "suspicious method call with the same argument and receiver", WhereExpr: ir.FilterExpr{Line: 378, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, - ir.Rule{ + { Line: 381, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 381, Value: "copy($x, $x)"}, - ir.PatternString{Line: 382, Value: "math.Max($x, $x)"}, - ir.PatternString{Line: 383, Value: "math.Min($x, $x)"}, - ir.PatternString{Line: 384, Value: "reflect.Copy($x, $x)"}, - ir.PatternString{Line: 385, Value: "reflect.DeepEqual($x, $x)"}, - ir.PatternString{Line: 386, Value: "strings.Contains($x, $x)"}, - ir.PatternString{Line: 387, Value: "strings.Compare($x, $x)"}, - ir.PatternString{Line: 388, Value: "strings.EqualFold($x, $x)"}, - ir.PatternString{Line: 389, Value: "strings.HasPrefix($x, $x)"}, - ir.PatternString{Line: 390, Value: "strings.HasSuffix($x, $x)"}, - ir.PatternString{Line: 391, Value: "strings.Index($x, $x)"}, - ir.PatternString{Line: 392, Value: "strings.LastIndex($x, $x)"}, - ir.PatternString{Line: 393, Value: "strings.Split($x, $x)"}, - ir.PatternString{Line: 394, Value: "strings.SplitAfter($x, $x)"}, - ir.PatternString{Line: 395, Value: "strings.SplitAfterN($x, $x, $_)"}, - ir.PatternString{Line: 396, Value: "strings.SplitN($x, $x, $_)"}, - ir.PatternString{Line: 397, Value: "strings.Replace($_, $x, $x, $_)"}, - ir.PatternString{Line: 398, Value: "strings.ReplaceAll($_, $x, $x)"}, - ir.PatternString{Line: 399, Value: "bytes.Contains($x, $x)"}, - ir.PatternString{Line: 400, Value: "bytes.Compare($x, $x)"}, - ir.PatternString{Line: 401, Value: "bytes.Equal($x, $x)"}, - ir.PatternString{Line: 402, Value: "bytes.EqualFold($x, $x)"}, - ir.PatternString{Line: 403, Value: "bytes.HasPrefix($x, $x)"}, - ir.PatternString{Line: 404, Value: "bytes.HasSuffix($x, $x)"}, - ir.PatternString{Line: 405, Value: "bytes.Index($x, $x)"}, - ir.PatternString{Line: 406, Value: "bytes.LastIndex($x, $x)"}, - ir.PatternString{Line: 407, Value: "bytes.Split($x, $x)"}, - ir.PatternString{Line: 408, Value: "bytes.SplitAfter($x, $x)"}, - ir.PatternString{Line: 409, Value: "bytes.SplitAfterN($x, $x, $_)"}, - ir.PatternString{Line: 410, Value: "bytes.SplitN($x, $x, $_)"}, - ir.PatternString{Line: 411, Value: "bytes.Replace($_, $x, $x, $_)"}, - ir.PatternString{Line: 412, Value: "bytes.ReplaceAll($_, $x, $x)"}, - ir.PatternString{Line: 413, Value: "types.Identical($x, $x)"}, - ir.PatternString{Line: 414, Value: "types.IdenticalIgnoreTags($x, $x)"}, - ir.PatternString{Line: 415, Value: "draw.Draw($x, $_, $x, $_, $_)"}, + {Line: 381, Value: "copy($x, $x)"}, + {Line: 382, Value: "math.Max($x, $x)"}, + {Line: 383, Value: "math.Min($x, $x)"}, + {Line: 384, Value: "reflect.Copy($x, $x)"}, + {Line: 385, Value: "reflect.DeepEqual($x, $x)"}, + {Line: 386, Value: "strings.Contains($x, $x)"}, + {Line: 387, Value: "strings.Compare($x, $x)"}, + {Line: 388, Value: "strings.EqualFold($x, $x)"}, + {Line: 389, Value: "strings.HasPrefix($x, $x)"}, + {Line: 390, Value: "strings.HasSuffix($x, $x)"}, + {Line: 391, Value: "strings.Index($x, $x)"}, + {Line: 392, Value: "strings.LastIndex($x, $x)"}, + {Line: 393, Value: "strings.Split($x, $x)"}, + {Line: 394, Value: "strings.SplitAfter($x, $x)"}, + {Line: 395, Value: "strings.SplitAfterN($x, $x, $_)"}, + {Line: 396, Value: "strings.SplitN($x, $x, $_)"}, + {Line: 397, Value: "strings.Replace($_, $x, $x, $_)"}, + {Line: 398, Value: "strings.ReplaceAll($_, $x, $x)"}, + {Line: 399, Value: "bytes.Contains($x, $x)"}, + {Line: 400, Value: "bytes.Compare($x, $x)"}, + {Line: 401, Value: "bytes.Equal($x, $x)"}, + {Line: 402, Value: "bytes.EqualFold($x, $x)"}, + {Line: 403, Value: "bytes.HasPrefix($x, $x)"}, + {Line: 404, Value: "bytes.HasSuffix($x, $x)"}, + {Line: 405, Value: "bytes.Index($x, $x)"}, + {Line: 406, Value: "bytes.LastIndex($x, $x)"}, + {Line: 407, Value: "bytes.Split($x, $x)"}, + {Line: 408, Value: "bytes.SplitAfter($x, $x)"}, + {Line: 409, Value: "bytes.SplitAfterN($x, $x, $_)"}, + {Line: 410, Value: "bytes.SplitN($x, $x, $_)"}, + {Line: 411, Value: "bytes.Replace($_, $x, $x, $_)"}, + {Line: 412, Value: "bytes.ReplaceAll($_, $x, $x)"}, + {Line: 413, Value: "types.Identical($x, $x)"}, + {Line: 414, Value: "types.IdenticalIgnoreTags($x, $x)"}, + {Line: 415, Value: "draw.Draw($x, $_, $x, $_, $_)"}, }, ReportTemplate: "suspicious duplicated args in $$", WhereExpr: ir.FilterExpr{Line: 416, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, - ir.RuleGroup{ + { Line: 424, Name: "returnAfterHttpError", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects suspicious http.Error call without following return", - DocBefore: "if err != nil { http.Error(...); }", - DocAfter: "if err != nil { http.Error(...); return; }", - Rules: []ir.Rule{ - ir.Rule{ - Line: 425, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 425, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}, - }, - ReportTemplate: "Possibly return is missed after the http.Error call", - LocationVar: "w", - }, - }, + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects suspicious http.Error call without following return", + DocBefore: "if err != nil { http.Error(...); }", + DocAfter: "if err != nil { http.Error(...); return; }", + Rules: []ir.Rule{{ + Line: 425, + SyntaxPatterns: []ir.PatternString{{Line: 425, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}}, + ReportTemplate: "Possibly return is missed after the http.Error call", + LocationVar: "w", + }}, }, - ir.RuleGroup{ + { Line: 434, Name: "preferFilepathJoin", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects concatenation with os.PathSeparator which can be replaced with filepath.Join", - DocBefore: "x + string(os.PathSeparator) + y", - DocAfter: "filepath.Join(x, y)", - Rules: []ir.Rule{ - ir.Rule{ - Line: 435, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 435, Value: "$x + string(os.PathSeparator) + $y"}, - }, - ReportTemplate: "filepath.Join($x, $y) should be preferred to the $$", - SuggestTemplate: "filepath.Join($x, $y)", - WhereExpr: ir.FilterExpr{ - Line: 436, - Op: ir.FilterAndOp, - Src: "m[\"x\"].Type.Is(`string`) && m[\"y\"].Type.Is(`string`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 436, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"x\"].Type.Is(`string`)", - Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, - }, - ir.FilterExpr{ - Line: 436, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"y\"].Type.Is(`string`)", - Value: "y", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, - }, - }, - }, - }, - }, + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects concatenation with os.PathSeparator which can be replaced with filepath.Join", + DocBefore: "x + string(os.PathSeparator) + y", + DocAfter: "filepath.Join(x, y)", + Rules: []ir.Rule{{ + Line: 435, + SyntaxPatterns: []ir.PatternString{{Line: 435, Value: "$x + string(os.PathSeparator) + $y"}}, + ReportTemplate: "filepath.Join($x, $y) should be preferred to the $$", + SuggestTemplate: "filepath.Join($x, $y)", + WhereExpr: ir.FilterExpr{ + Line: 436, + Op: ir.FilterAndOp, + Src: "m[\"x\"].Type.Is(`string`) && m[\"y\"].Type.Is(`string`)", + Args: []ir.FilterExpr{ + { + Line: 436, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"x\"].Type.Is(`string`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + }, + { + Line: 436, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"y\"].Type.Is(`string`)", + Value: "y", + Args: []ir.FilterExpr{{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 445, Name: "preferStringWriter", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - }, - DocSummary: "Detects w.Write or io.WriteString calls which can be replaced with w.WriteString", - DocBefore: "w.Write([]byte(\"foo\"))", - DocAfter: "w.WriteString(\"foo\")", + DocTags: []string{"performance", "experimental"}, + DocSummary: "Detects w.Write or io.WriteString calls which can be replaced with w.WriteString", + DocBefore: "w.Write([]byte(\"foo\"))", + DocAfter: "w.WriteString(\"foo\")", Rules: []ir.Rule{ - ir.Rule{ - Line: 446, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 446, Value: "$w.Write([]byte($s))"}, - }, + { + Line: 446, + SyntaxPatterns: []ir.PatternString{{Line: 446, Value: "$w.Write([]byte($s))"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ @@ -1675,16 +1372,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 447, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, - }, + Args: []ir.FilterExpr{{Line: 447, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, - ir.Rule{ - Line: 451, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 451, Value: "io.WriteString($w, $s)"}, - }, + { + Line: 451, + SyntaxPatterns: []ir.PatternString{{Line: 451, Value: "io.WriteString($w, $s)"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ @@ -1692,158 +1385,125 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 452, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, - }, + Args: []ir.FilterExpr{{Line: 452, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, }, }, - ir.RuleGroup{ + { Line: 461, Name: "sliceClear", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - }, - DocSummary: "Detects slice clear loops, suggests an idiom that is recognized by the Go compiler", - DocBefore: "for i := 0; i < len(buf); i++ { buf[i] = 0 }", - DocAfter: "for i := range buf { buf[i] = 0 }", - Rules: []ir.Rule{ - ir.Rule{ - Line: 462, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 462, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}, - }, - ReportTemplate: "rewrite as for-range so compiler can recognize this pattern", - WhereExpr: ir.FilterExpr{ - Line: 463, - Op: ir.FilterEqOp, - Src: "m[\"zero\"].Value.Int() == 0", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 463, - Op: ir.FilterVarValueIntOp, - Src: "m[\"zero\"].Value.Int()", - Value: "zero", - }, - ir.FilterExpr{ - Line: 463, - Op: ir.FilterIntOp, - Src: "0", - Value: int64(0), - }, - }, - }, - }, - }, + DocTags: []string{"performance", "experimental"}, + DocSummary: "Detects slice clear loops, suggests an idiom that is recognized by the Go compiler", + DocBefore: "for i := 0; i < len(buf); i++ { buf[i] = 0 }", + DocAfter: "for i := range buf { buf[i] = 0 }", + Rules: []ir.Rule{{ + Line: 462, + SyntaxPatterns: []ir.PatternString{{Line: 462, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}}, + ReportTemplate: "rewrite as for-range so compiler can recognize this pattern", + WhereExpr: ir.FilterExpr{ + Line: 463, + Op: ir.FilterEqOp, + Src: "m[\"zero\"].Value.Int() == 0", + Args: []ir.FilterExpr{ + { + Line: 463, + Op: ir.FilterVarValueIntOp, + Src: "m[\"zero\"].Value.Int()", + Value: "zero", + }, + { + Line: 463, + Op: ir.FilterIntOp, + Src: "0", + Value: int64(0), + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 471, Name: "syncMapLoadAndDelete", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects sync.Map load+delete operations that can be replaced with LoadAndDelete", - DocBefore: "v, ok := m.Load(k); if ok { m.Delete($k); f(v); }", - DocAfter: "v, deleted := m.LoadAndDelete(k); if deleted { f(v) }", - Rules: []ir.Rule{ - ir.Rule{ - Line: 472, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 472, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}, - }, - ReportTemplate: "use $m.LoadAndDelete to perform load+delete operations atomically", - WhereExpr: ir.FilterExpr{ - Line: 473, - Op: ir.FilterAndOp, - Src: "m.GoVersion().GreaterEqThan(\"1.15\") &&\n\tm[\"m\"].Type.Is(`*sync.Map`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 473, - Op: ir.FilterGoVersionGreaterEqThanOp, - Src: "m.GoVersion().GreaterEqThan(\"1.15\")", - Value: "1.15", - }, - ir.FilterExpr{ - Line: 474, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"m\"].Type.Is(`*sync.Map`)", - Value: "m", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 474, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}, - }, - }, - }, - }, - }, - }, + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects sync.Map load+delete operations that can be replaced with LoadAndDelete", + DocBefore: "v, ok := m.Load(k); if ok { m.Delete($k); f(v); }", + DocAfter: "v, deleted := m.LoadAndDelete(k); if deleted { f(v) }", + Rules: []ir.Rule{{ + Line: 472, + SyntaxPatterns: []ir.PatternString{{Line: 472, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}}, + ReportTemplate: "use $m.LoadAndDelete to perform load+delete operations atomically", + WhereExpr: ir.FilterExpr{ + Line: 473, + Op: ir.FilterAndOp, + Src: "m.GoVersion().GreaterEqThan(\"1.15\") &&\n\tm[\"m\"].Type.Is(`*sync.Map`)", + Args: []ir.FilterExpr{ + { + Line: 473, + Op: ir.FilterGoVersionGreaterEqThanOp, + Src: "m.GoVersion().GreaterEqThan(\"1.15\")", + Value: "1.15", + }, + { + Line: 474, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"m\"].Type.Is(`*sync.Map`)", + Value: "m", + Args: []ir.FilterExpr{{Line: 474, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}}, + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 482, Name: "sprintfQuotedString", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects \"%s\" formatting directives that can be replaced with %q", - DocBefore: "fmt.Sprintf(`\"%s\"`, s)", - DocAfter: "fmt.Sprintf(`%q`, s)", - Rules: []ir.Rule{ - ir.Rule{ - Line: 483, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 483, Value: "fmt.Sprintf($s, $*_)"}, - }, - ReportTemplate: "use %q instead of \"%s\" for quoted strings", - WhereExpr: ir.FilterExpr{ - Line: 484, - Op: ir.FilterOrOp, - Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\") ||\n\tm[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 484, - Op: ir.FilterVarTextMatchesOp, - Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\")", - Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 484, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}, - }, - }, - ir.FilterExpr{ - Line: 485, - Op: ir.FilterVarTextMatchesOp, - Src: "m[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", - Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 485, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}, - }, - }, - }, - }, - }, - }, + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects \"%s\" formatting directives that can be replaced with %q", + DocBefore: "fmt.Sprintf(`\"%s\"`, s)", + DocAfter: "fmt.Sprintf(`%q`, s)", + Rules: []ir.Rule{{ + Line: 483, + SyntaxPatterns: []ir.PatternString{{Line: 483, Value: "fmt.Sprintf($s, $*_)"}}, + ReportTemplate: "use %q instead of \"%s\" for quoted strings", + WhereExpr: ir.FilterExpr{ + Line: 484, + Op: ir.FilterOrOp, + Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\") ||\n\tm[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", + Args: []ir.FilterExpr{ + { + Line: 484, + Op: ir.FilterVarTextMatchesOp, + Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\")", + Value: "s", + Args: []ir.FilterExpr{{Line: 484, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}}, + }, + { + Line: 485, + Op: ir.FilterVarTextMatchesOp, + Src: "m[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", + Value: "s", + Args: []ir.FilterExpr{{Line: 485, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}}, + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 493, Name: "offBy1", MatcherName: "m", - DocTags: []string{ - "diagnostic", - }, - DocSummary: "Detects various off-by-one kind of errors", - DocBefore: "xs[len(xs)]", - DocAfter: "xs[len(xs)-1]", + DocTags: []string{"diagnostic"}, + DocSummary: "Detects various off-by-one kind of errors", + DocBefore: "xs[len(xs)]", + DocAfter: "xs[len(xs)-1]", Rules: []ir.Rule{ - ir.Rule{ - Line: 494, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 494, Value: "$x[len($x)]"}, - }, + { + Line: 494, + SyntaxPatterns: []ir.PatternString{{Line: 494, Value: "$x[len($x)]"}}, ReportTemplate: "index expr always panics; maybe you wanted $x[len($x)-1]?", SuggestTemplate: "$x[len($x)-1]", WhereExpr: ir.FilterExpr{ @@ -1851,26 +1511,24 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"x\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 495, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{ + {Line: 495, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + { Line: 495, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]$_`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 495, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, - }, + Args: []ir.FilterExpr{{Line: 495, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, }, }, }, }, - ir.Rule{ + { Line: 502, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 503, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, - ir.PatternString{Line: 504, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, - ir.PatternString{Line: 505, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, - ir.PatternString{Line: 506, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 503, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 504, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 505, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 506, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[$i+1:]", WhereExpr: ir.FilterExpr{ @@ -1878,19 +1536,19 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - ir.FilterExpr{Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, - ir.Rule{ + { Line: 511, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 512, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, - ir.PatternString{Line: 513, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, - ir.PatternString{Line: 514, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, - ir.PatternString{Line: 515, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 512, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 513, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 514, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 515, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[:$i+1]", WhereExpr: ir.FilterExpr{ @@ -1898,229 +1556,185 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - ir.FilterExpr{Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, - ir.Rule{ + { Line: 520, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 521, Value: "$s[strings.Index($s, $_):]"}, - ir.PatternString{Line: 522, Value: "$s[:strings.Index($s, $_)]"}, - ir.PatternString{Line: 523, Value: "$s[bytes.Index($s, $_):]"}, - ir.PatternString{Line: 524, Value: "$s[:bytes.Index($s, $_)]"}, + {Line: 521, Value: "$s[strings.Index($s, $_):]"}, + {Line: 522, Value: "$s[:strings.Index($s, $_)]"}, + {Line: 523, Value: "$s[bytes.Index($s, $_):]"}, + {Line: 524, Value: "$s[:bytes.Index($s, $_)]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do Index()+1", }, }, }, - ir.RuleGroup{ + { Line: 532, Name: "unslice", MatcherName: "m", - DocTags: []string{ - "style", - }, - DocSummary: "Detects slice expressions that can be simplified to sliced expression itself", - DocBefore: "copy(b[:], values...)", - DocAfter: "copy(b, values...)", - Rules: []ir.Rule{ - ir.Rule{ - Line: 533, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 533, Value: "$s[:]"}, - }, - ReportTemplate: "could simplify $$ to $s", - SuggestTemplate: "$s", - WhereExpr: ir.FilterExpr{ - Line: 534, - Op: ir.FilterOrOp, - Src: "m[\"s\"].Type.Is(`string`) || m[\"s\"].Type.Is(`[]$_`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 534, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"s\"].Type.Is(`string`)", - Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 534, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, - }, - }, - ir.FilterExpr{ - Line: 534, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"s\"].Type.Is(`[]$_`)", - Value: "s", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 534, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, - }, - }, - }, - }, - }, - }, + DocTags: []string{"style"}, + DocSummary: "Detects slice expressions that can be simplified to sliced expression itself", + DocBefore: "copy(b[:], values...)", + DocAfter: "copy(b, values...)", + Rules: []ir.Rule{{ + Line: 533, + SyntaxPatterns: []ir.PatternString{{Line: 533, Value: "$s[:]"}}, + ReportTemplate: "could simplify $$ to $s", + SuggestTemplate: "$s", + WhereExpr: ir.FilterExpr{ + Line: 534, + Op: ir.FilterOrOp, + Src: "m[\"s\"].Type.Is(`string`) || m[\"s\"].Type.Is(`[]$_`)", + Args: []ir.FilterExpr{ + { + Line: 534, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"s\"].Type.Is(`string`)", + Value: "s", + Args: []ir.FilterExpr{{Line: 534, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + }, + { + Line: 534, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"s\"].Type.Is(`[]$_`)", + Value: "s", + Args: []ir.FilterExpr{{Line: 534, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 543, Name: "yodaStyleExpr", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects Yoda style expressions and suggests to replace them", - DocBefore: "return nil != ptr", - DocAfter: "return ptr != nil", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects Yoda style expressions and suggests to replace them", + DocBefore: "return nil != ptr", + DocAfter: "return ptr != nil", Rules: []ir.Rule{ - ir.Rule{ - Line: 544, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 544, Value: "$constval != $x"}, - }, + { + Line: 544, + SyntaxPatterns: []ir.PatternString{{Line: 544, Value: "$constval != $x"}}, ReportTemplate: "consider to change order in expression to $x != $constval", WhereExpr: ir.FilterExpr{ Line: 544, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 544, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, + Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, - ir.FilterExpr{ + { Line: 544, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 544, - Op: ir.FilterVarNodeIsOp, - Src: "m[\"x\"].Node.Is(`BasicLit`)", - Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, - }, - }, + Args: []ir.FilterExpr{{ + Line: 544, + Op: ir.FilterVarNodeIsOp, + Src: "m[\"x\"].Node.Is(`BasicLit`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + }}, }, }, }, }, - ir.Rule{ - Line: 546, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 546, Value: "$constval == $x"}, - }, + { + Line: 546, + SyntaxPatterns: []ir.PatternString{{Line: 546, Value: "$constval == $x"}}, ReportTemplate: "consider to change order in expression to $x == $constval", WhereExpr: ir.FilterExpr{ Line: 546, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 546, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, + Args: []ir.FilterExpr{{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, - ir.FilterExpr{ + { Line: 546, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 546, - Op: ir.FilterVarNodeIsOp, - Src: "m[\"x\"].Node.Is(`BasicLit`)", - Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, - }, - }, + Args: []ir.FilterExpr{{ + Line: 546, + Op: ir.FilterVarNodeIsOp, + Src: "m[\"x\"].Node.Is(`BasicLit`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + }}, }, }, }, }, - ir.Rule{ - Line: 549, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 549, Value: "nil != $x"}, - }, + { + Line: 549, + SyntaxPatterns: []ir.PatternString{{Line: 549, Value: "nil != $x"}}, ReportTemplate: "consider to change order in expression to $x != nil", WhereExpr: ir.FilterExpr{ Line: 549, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 549, - Op: ir.FilterVarNodeIsOp, - Src: "m[\"x\"].Node.Is(`BasicLit`)", - Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, - }, - }, - }, - }, - ir.Rule{ - Line: 551, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 551, Value: "nil == $x"}, - }, + Args: []ir.FilterExpr{{ + Line: 549, + Op: ir.FilterVarNodeIsOp, + Src: "m[\"x\"].Node.Is(`BasicLit`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + }}, + }, + }, + { + Line: 551, + SyntaxPatterns: []ir.PatternString{{Line: 551, Value: "nil == $x"}}, ReportTemplate: "consider to change order in expression to $x == nil", WhereExpr: ir.FilterExpr{ Line: 551, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 551, - Op: ir.FilterVarNodeIsOp, - Src: "m[\"x\"].Node.Is(`BasicLit`)", - Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 551, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, - }, - }, - }, + Args: []ir.FilterExpr{{ + Line: 551, + Op: ir.FilterVarNodeIsOp, + Src: "m[\"x\"].Node.Is(`BasicLit`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 551, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + }}, }, }, }, }, - ir.RuleGroup{ + { Line: 559, Name: "equalFold", MatcherName: "m", - DocTags: []string{ - "performance", - "experimental", - }, - DocSummary: "Detects unoptimal strings/bytes case-insensitive comparison", - DocBefore: "strings.ToLower(x) == strings.ToLower(y)", - DocAfter: "strings.EqualFold(x, y)", + DocTags: []string{"performance", "experimental"}, + DocSummary: "Detects unoptimal strings/bytes case-insensitive comparison", + DocBefore: "strings.ToLower(x) == strings.ToLower(y)", + DocAfter: "strings.EqualFold(x, y)", Rules: []ir.Rule{ - ir.Rule{ + { Line: 568, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 569, Value: "strings.ToLower($x) == $y"}, - ir.PatternString{Line: 570, Value: "strings.ToLower($x) == strings.ToLower($y)"}, - ir.PatternString{Line: 571, Value: "$x == strings.ToLower($y)"}, - ir.PatternString{Line: 572, Value: "strings.ToUpper($x) == $y"}, - ir.PatternString{Line: 573, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, - ir.PatternString{Line: 574, Value: "$x == strings.ToUpper($y)"}, + {Line: 569, Value: "strings.ToLower($x) == $y"}, + {Line: 570, Value: "strings.ToLower($x) == strings.ToLower($y)"}, + {Line: 571, Value: "$x == strings.ToLower($y)"}, + {Line: 572, Value: "strings.ToUpper($x) == $y"}, + {Line: 573, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, + {Line: 574, Value: "$x == strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with strings.EqualFold($x, $y)", SuggestTemplate: "strings.EqualFold($x, $y)", @@ -2129,36 +1743,36 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 575, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, - ir.FilterExpr{ + { Line: 575, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, - ir.Rule{ + { Line: 580, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 581, Value: "strings.ToLower($x) != $y"}, - ir.PatternString{Line: 582, Value: "strings.ToLower($x) != strings.ToLower($y)"}, - ir.PatternString{Line: 583, Value: "$x != strings.ToLower($y)"}, - ir.PatternString{Line: 584, Value: "strings.ToUpper($x) != $y"}, - ir.PatternString{Line: 585, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, - ir.PatternString{Line: 586, Value: "$x != strings.ToUpper($y)"}, + {Line: 581, Value: "strings.ToLower($x) != $y"}, + {Line: 582, Value: "strings.ToLower($x) != strings.ToLower($y)"}, + {Line: 583, Value: "$x != strings.ToLower($y)"}, + {Line: 584, Value: "strings.ToUpper($x) != $y"}, + {Line: 585, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, + {Line: 586, Value: "$x != strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with !strings.EqualFold($x, $y)", SuggestTemplate: "!strings.EqualFold($x, $y)", @@ -2167,36 +1781,36 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 587, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, - ir.FilterExpr{ + { Line: 587, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, - ir.Rule{ + { Line: 592, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 593, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, - ir.PatternString{Line: 594, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, - ir.PatternString{Line: 595, Value: "bytes.Equal($x, bytes.ToLower($y))"}, - ir.PatternString{Line: 596, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, - ir.PatternString{Line: 597, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, - ir.PatternString{Line: 598, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, + {Line: 593, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, + {Line: 594, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, + {Line: 595, Value: "bytes.Equal($x, bytes.ToLower($y))"}, + {Line: 596, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, + {Line: 597, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, + {Line: 598, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, }, ReportTemplate: "consider replacing with bytes.EqualFold($x, $y)", SuggestTemplate: "bytes.EqualFold($x, $y)", @@ -2205,22 +1819,22 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 599, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, - ir.FilterExpr{ + { Line: 599, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, @@ -2228,167 +1842,143 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.RuleGroup{ + { Line: 608, Name: "argOrder", MatcherName: "m", - DocTags: []string{ - "diagnostic", - }, - DocSummary: "Detects suspicious arguments order", - DocBefore: "strings.HasPrefix(\"#\", userpass)", - DocAfter: "strings.HasPrefix(userpass, \"#\")", - Rules: []ir.Rule{ - ir.Rule{ - Line: 609, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 610, Value: "strings.HasPrefix($lit, $s)"}, - ir.PatternString{Line: 611, Value: "bytes.HasPrefix($lit, $s)"}, - ir.PatternString{Line: 612, Value: "strings.HasSuffix($lit, $s)"}, - ir.PatternString{Line: 613, Value: "bytes.HasSuffix($lit, $s)"}, - ir.PatternString{Line: 614, Value: "strings.Contains($lit, $s)"}, - ir.PatternString{Line: 615, Value: "bytes.Contains($lit, $s)"}, - ir.PatternString{Line: 616, Value: "strings.TrimPrefix($lit, $s)"}, - ir.PatternString{Line: 617, Value: "bytes.TrimPrefix($lit, $s)"}, - ir.PatternString{Line: 618, Value: "strings.TrimSuffix($lit, $s)"}, - ir.PatternString{Line: 619, Value: "bytes.TrimSuffix($lit, $s)"}, - ir.PatternString{Line: 620, Value: "strings.Split($lit, $s)"}, - ir.PatternString{Line: 621, Value: "bytes.Split($lit, $s)"}, - }, - ReportTemplate: "$lit and $s arguments order looks reversed", - WhereExpr: ir.FilterExpr{ - Line: 622, - Op: ir.FilterAndOp, - Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice) &&\n\t!m[\"lit\"].Node.Is(`Ident`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 622, - Op: ir.FilterAndOp, - Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 622, + DocTags: []string{"diagnostic"}, + DocSummary: "Detects suspicious arguments order", + DocBefore: "strings.HasPrefix(\"#\", userpass)", + DocAfter: "strings.HasPrefix(userpass, \"#\")", + Rules: []ir.Rule{{ + Line: 609, + SyntaxPatterns: []ir.PatternString{ + {Line: 610, Value: "strings.HasPrefix($lit, $s)"}, + {Line: 611, Value: "bytes.HasPrefix($lit, $s)"}, + {Line: 612, Value: "strings.HasSuffix($lit, $s)"}, + {Line: 613, Value: "bytes.HasSuffix($lit, $s)"}, + {Line: 614, Value: "strings.Contains($lit, $s)"}, + {Line: 615, Value: "bytes.Contains($lit, $s)"}, + {Line: 616, Value: "strings.TrimPrefix($lit, $s)"}, + {Line: 617, Value: "bytes.TrimPrefix($lit, $s)"}, + {Line: 618, Value: "strings.TrimSuffix($lit, $s)"}, + {Line: 619, Value: "bytes.TrimSuffix($lit, $s)"}, + {Line: 620, Value: "strings.Split($lit, $s)"}, + {Line: 621, Value: "bytes.Split($lit, $s)"}, + }, + ReportTemplate: "$lit and $s arguments order looks reversed", + WhereExpr: ir.FilterExpr{ + Line: 622, + Op: ir.FilterAndOp, + Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice) &&\n\t!m[\"lit\"].Node.Is(`Ident`)", + Args: []ir.FilterExpr{ + { + Line: 622, + Op: ir.FilterAndOp, + Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice)", + Args: []ir.FilterExpr{ + { + Line: 622, + Op: ir.FilterOrOp, + Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice)", + Args: []ir.FilterExpr{ + { + Line: 622, + Op: ir.FilterVarConstOp, + Src: "m[\"lit\"].Const", + Value: "lit", + }, + { + Line: 622, + Op: ir.FilterVarConstSliceOp, + Src: "m[\"lit\"].ConstSlice", + Value: "lit", + }, + }, + }, + { + Line: 623, + Op: ir.FilterNotOp, + Src: "!(m[\"s\"].Const || m[\"s\"].ConstSlice)", + Args: []ir.FilterExpr{{ + Line: 623, Op: ir.FilterOrOp, - Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice)", + Src: "(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 622, + { + Line: 623, Op: ir.FilterVarConstOp, - Src: "m[\"lit\"].Const", - Value: "lit", + Src: "m[\"s\"].Const", + Value: "s", }, - ir.FilterExpr{ - Line: 622, + { + Line: 623, Op: ir.FilterVarConstSliceOp, - Src: "m[\"lit\"].ConstSlice", - Value: "lit", - }, - }, - }, - ir.FilterExpr{ - Line: 623, - Op: ir.FilterNotOp, - Src: "!(m[\"s\"].Const || m[\"s\"].ConstSlice)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 623, - Op: ir.FilterOrOp, - Src: "(m[\"s\"].Const || m[\"s\"].ConstSlice)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 623, - Op: ir.FilterVarConstOp, - Src: "m[\"s\"].Const", - Value: "s", - }, - ir.FilterExpr{ - Line: 623, - Op: ir.FilterVarConstSliceOp, - Src: "m[\"s\"].ConstSlice", - Value: "s", - }, - }, + Src: "m[\"s\"].ConstSlice", + Value: "s", }, }, - }, - }, - }, - ir.FilterExpr{ - Line: 624, - Op: ir.FilterNotOp, - Src: "!m[\"lit\"].Node.Is(`Ident`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 624, - Op: ir.FilterVarNodeIsOp, - Src: "m[\"lit\"].Node.Is(`Ident`)", - Value: "lit", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 624, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}, - }, - }, + }}, }, }, }, + { + Line: 624, + Op: ir.FilterNotOp, + Src: "!m[\"lit\"].Node.Is(`Ident`)", + Args: []ir.FilterExpr{{ + Line: 624, + Op: ir.FilterVarNodeIsOp, + Src: "m[\"lit\"].Node.Is(`Ident`)", + Value: "lit", + Args: []ir.FilterExpr{{Line: 624, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, + }}, + }, }, }, - }, + }}, }, - ir.RuleGroup{ + { Line: 632, Name: "stringConcatSimplify", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects string concat operations that can be simplified", - DocBefore: "strings.Join([]string{x, y}, \"_\")", - DocAfter: "x + \"_\" + y", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects string concat operations that can be simplified", + DocBefore: "strings.Join([]string{x, y}, \"_\")", + DocAfter: "x + \"_\" + y", Rules: []ir.Rule{ - ir.Rule{ - Line: 633, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 633, Value: "strings.Join([]string{$x, $y}, \"\")"}, - }, + { + Line: 633, + SyntaxPatterns: []ir.PatternString{{Line: 633, Value: "strings.Join([]string{$x, $y}, \"\")"}}, ReportTemplate: "suggestion: $x + $y", SuggestTemplate: "$x + $y", }, - ir.Rule{ - Line: 634, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 634, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}, - }, + { + Line: 634, + SyntaxPatterns: []ir.PatternString{{Line: 634, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}}, ReportTemplate: "suggestion: $x + $y + $z", SuggestTemplate: "$x + $y + $z", }, - ir.Rule{ - Line: 635, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 635, Value: "strings.Join([]string{$x, $y}, $glue)"}, - }, + { + Line: 635, + SyntaxPatterns: []ir.PatternString{{Line: 635, Value: "strings.Join([]string{$x, $y}, $glue)"}}, ReportTemplate: "suggestion: $x + $glue + $y", SuggestTemplate: "$x + $glue + $y", }, }, }, - ir.RuleGroup{ + { Line: 642, Name: "timeExprSimplify", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects manual conversion to milli- or microseconds", - DocBefore: "t.Unix() / 1000", - DocAfter: "t.UnixMilli()", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects manual conversion to milli- or microseconds", + DocBefore: "t.Unix() / 1000", + DocAfter: "t.UnixMilli()", Rules: []ir.Rule{ - ir.Rule{ - Line: 647, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 647, Value: "$t.Unix() / 1000"}, - }, + { + Line: 647, + SyntaxPatterns: []ir.PatternString{{Line: 647, Value: "$t.Unix() / 1000"}}, ReportTemplate: "use $t.UnixMilli() instead of $$", SuggestTemplate: "$t.UnixMilli()", WhereExpr: ir.FilterExpr{ @@ -2396,45 +1986,39 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 648, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, - ir.FilterExpr{ + { Line: 648, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 648, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, - }, + Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, - ir.FilterExpr{ + { Line: 648, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, - }, + Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, }, }, }, - ir.Rule{ - Line: 652, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 652, Value: "$t.UnixNano() * 1000"}, - }, + { + Line: 652, + SyntaxPatterns: []ir.PatternString{{Line: 652, Value: "$t.UnixNano() * 1000"}}, ReportTemplate: "use $t.UnixMicro() instead of $$", SuggestTemplate: "$t.UnixMicro()", WhereExpr: ir.FilterExpr{ @@ -2442,34 +2026,30 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 653, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, - ir.FilterExpr{ + { Line: 653, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ - ir.FilterExpr{ + { Line: 653, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, - }, + Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, - ir.FilterExpr{ + { Line: 653, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, - }, + Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2478,101 +2058,77 @@ var PrecompiledRules = &ir.File{ }, }, }, - ir.RuleGroup{ + { Line: 662, Name: "exposedSyncMutex", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects exposed methods from sync.Mutex and sync.RWMutex", - DocBefore: "type Foo struct{ ...; sync.Mutex; ... }", - DocAfter: "type Foo struct{ ...; mu sync.Mutex; ... }", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects exposed methods from sync.Mutex and sync.RWMutex", + DocBefore: "type Foo struct{ ...; sync.Mutex; ... }", + DocAfter: "type Foo struct{ ...; mu sync.Mutex; ... }", Rules: []ir.Rule{ - ir.Rule{ - Line: 667, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 667, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}, - }, + { + Line: 667, + SyntaxPatterns: []ir.PatternString{{Line: 667, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed sync.Mutex", WhereExpr: ir.FilterExpr{ Line: 668, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, - }, + Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, - ir.Rule{ - Line: 671, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 671, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}, - }, + { + Line: 671, + SyntaxPatterns: []ir.PatternString{{Line: 671, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed *sync.Mutex", WhereExpr: ir.FilterExpr{ Line: 672, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, - }, + Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, - ir.Rule{ - Line: 675, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 675, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}, - }, + { + Line: 675, + SyntaxPatterns: []ir.PatternString{{Line: 675, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed sync.RWMutex", WhereExpr: ir.FilterExpr{ Line: 676, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, - }, + Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, - ir.Rule{ - Line: 679, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 679, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}, - }, + { + Line: 679, + SyntaxPatterns: []ir.PatternString{{Line: 679, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed *sync.RWMutex", WhereExpr: ir.FilterExpr{ Line: 680, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, - }, + Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, }, }, - ir.RuleGroup{ + { Line: 688, Name: "badSorting", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects bad usage of sort package", - DocBefore: "xs = sort.StringSlice(xs)", - DocAfter: "sort.Strings(xs)", + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects bad usage of sort package", + DocBefore: "xs = sort.StringSlice(xs)", + DocAfter: "sort.Strings(xs)", Rules: []ir.Rule{ - ir.Rule{ - Line: 689, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 689, Value: "$x = sort.IntSlice($x)"}, - }, + { + Line: 689, + SyntaxPatterns: []ir.PatternString{{Line: 689, Value: "$x = sort.IntSlice($x)"}}, ReportTemplate: "suspicious sort.IntSlice usage, maybe sort.Ints was intended?", SuggestTemplate: "sort.Ints($x)", WhereExpr: ir.FilterExpr{ @@ -2580,16 +2136,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]int`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 690, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}, - }, + Args: []ir.FilterExpr{{Line: 690, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}}, }, }, - ir.Rule{ - Line: 694, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 694, Value: "$x = sort.Float64Slice($x)"}, - }, + { + Line: 694, + SyntaxPatterns: []ir.PatternString{{Line: 694, Value: "$x = sort.Float64Slice($x)"}}, ReportTemplate: "suspicious sort.Float64s usage, maybe sort.Float64s was intended?", SuggestTemplate: "sort.Float64s($x)", WhereExpr: ir.FilterExpr{ @@ -2597,16 +2149,12 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]float64`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 695, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}, - }, + Args: []ir.FilterExpr{{Line: 695, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}}, }, }, - ir.Rule{ - Line: 699, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 699, Value: "$x = sort.StringSlice($x)"}, - }, + { + Line: 699, + SyntaxPatterns: []ir.PatternString{{Line: 699, Value: "$x = sort.StringSlice($x)"}}, ReportTemplate: "suspicious sort.StringSlice usage, maybe sort.Strings was intended?", SuggestTemplate: "sort.Strings($x)", WhereExpr: ir.FilterExpr{ @@ -2614,171 +2162,135 @@ var PrecompiledRules = &ir.File{ Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]string`)", Value: "x", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 700, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}, - }, + Args: []ir.FilterExpr{{Line: 700, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}}, }, }, }, }, - ir.RuleGroup{ + { Line: 709, Name: "externalErrorReassign", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects suspicious reassigment of error from another package", - DocBefore: "io.EOF = nil", - DocAfter: "/* don't do it */", - Rules: []ir.Rule{ - ir.Rule{ - Line: 710, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 710, Value: "$pkg.$err = $x"}, - }, - ReportTemplate: "suspicious reassigment of error from another package", - WhereExpr: ir.FilterExpr{ - Line: 711, - Op: ir.FilterAndOp, - Src: "m[\"err\"].Type.Is(`error`) && m[\"pkg\"].Object.Is(`PkgName`)", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 711, - Op: ir.FilterVarTypeIsOp, - Src: "m[\"err\"].Type.Is(`error`)", - Value: "err", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 711, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}, - }, - }, - ir.FilterExpr{ - Line: 711, - Op: ir.FilterVarObjectIsOp, - Src: "m[\"pkg\"].Object.Is(`PkgName`)", - Value: "pkg", - Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 711, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}, - }, - }, - }, - }, - }, - }, + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects suspicious reassigment of error from another package", + DocBefore: "io.EOF = nil", + DocAfter: "/* don't do it */", + Rules: []ir.Rule{{ + Line: 710, + SyntaxPatterns: []ir.PatternString{{Line: 710, Value: "$pkg.$err = $x"}}, + ReportTemplate: "suspicious reassigment of error from another package", + WhereExpr: ir.FilterExpr{ + Line: 711, + Op: ir.FilterAndOp, + Src: "m[\"err\"].Type.Is(`error`) && m[\"pkg\"].Object.Is(`PkgName`)", + Args: []ir.FilterExpr{ + { + Line: 711, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"err\"].Type.Is(`error`)", + Value: "err", + Args: []ir.FilterExpr{{Line: 711, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, + }, + { + Line: 711, + Op: ir.FilterVarObjectIsOp, + Src: "m[\"pkg\"].Object.Is(`PkgName`)", + Value: "pkg", + Args: []ir.FilterExpr{{Line: 711, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, + }, + }, + }, + }}, }, - ir.RuleGroup{ + { Line: 719, Name: "emptyDecl", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects suspicious empty declarations blocks", - DocBefore: "var()", - DocAfter: "/* nothing */", + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects suspicious empty declarations blocks", + DocBefore: "var()", + DocAfter: "/* nothing */", Rules: []ir.Rule{ - ir.Rule{ - Line: 720, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 720, Value: "var()"}, - }, + { + Line: 720, + SyntaxPatterns: []ir.PatternString{{Line: 720, Value: "var()"}}, ReportTemplate: "empty var() block", }, - ir.Rule{ - Line: 721, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 721, Value: "const()"}, - }, + { + Line: 721, + SyntaxPatterns: []ir.PatternString{{Line: 721, Value: "const()"}}, ReportTemplate: "empty const() block", }, - ir.Rule{ - Line: 722, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 722, Value: "type()"}, - }, + { + Line: 722, + SyntaxPatterns: []ir.PatternString{{Line: 722, Value: "type()"}}, ReportTemplate: "empty type() block", }, }, }, - ir.RuleGroup{ + { Line: 729, Name: "dynamicFmtString", MatcherName: "m", - DocTags: []string{ - "diagnostic", - "experimental", - }, - DocSummary: "Detects suspicious formatting strings usage", - DocBefore: "fmt.Errorf(msg)", - DocAfter: "fmt.Errorf(\"%s\", msg)", + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects suspicious formatting strings usage", + DocBefore: "fmt.Errorf(msg)", + DocAfter: "fmt.Errorf(\"%s\", msg)", Rules: []ir.Rule{ - ir.Rule{ - Line: 730, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 730, Value: "fmt.Errorf($f)"}, - }, + { + Line: 730, + SyntaxPatterns: []ir.PatternString{{Line: 730, Value: "fmt.Errorf($f)"}}, ReportTemplate: "use errors.New($f) or fmt.Errorf(\"%s\", $f) instead", SuggestTemplate: "errors.New($f)", WhereExpr: ir.FilterExpr{ Line: 731, Op: ir.FilterNotOp, Src: "!m[\"f\"].Const", - Args: []ir.FilterExpr{ - ir.FilterExpr{ - Line: 731, - Op: ir.FilterVarConstOp, - Src: "m[\"f\"].Const", - Value: "f", - }, - }, + Args: []ir.FilterExpr{{ + Line: 731, + Op: ir.FilterVarConstOp, + Src: "m[\"f\"].Const", + Value: "f", + }}, }, }, - ir.Rule{ - Line: 735, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 735, Value: "fmt.Errorf($f($*args))"}, - }, + { + Line: 735, + SyntaxPatterns: []ir.PatternString{{Line: 735, Value: "fmt.Errorf($f($*args))"}}, ReportTemplate: "use errors.New($f($*args)) or fmt.Errorf(\"%s\", $f($*args)) instead", SuggestTemplate: "errors.New($f($*args))", }, }, }, - ir.RuleGroup{ + { Line: 744, Name: "stringsCompare", MatcherName: "m", - DocTags: []string{ - "style", - "experimental", - }, - DocSummary: "Detects strings.Compare usage", - DocBefore: "strings.Compare(x, y)", - DocAfter: "x < y", + DocTags: []string{"style", "experimental"}, + DocSummary: "Detects strings.Compare usage", + DocBefore: "strings.Compare(x, y)", + DocAfter: "x < y", Rules: []ir.Rule{ - ir.Rule{ - Line: 745, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 745, Value: "strings.Compare($s1, $s2) == 0"}, - }, + { + Line: 745, + SyntaxPatterns: []ir.PatternString{{Line: 745, Value: "strings.Compare($s1, $s2) == 0"}}, ReportTemplate: "suggestion: $s1 == $s2", SuggestTemplate: "$s1 == $s2", }, - ir.Rule{ + { Line: 748, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 748, Value: "strings.Compare($s1, $s2) == -1"}, - ir.PatternString{Line: 749, Value: "strings.Compare($s1, $s2) < 0"}, + {Line: 748, Value: "strings.Compare($s1, $s2) == -1"}, + {Line: 749, Value: "strings.Compare($s1, $s2) < 0"}, }, ReportTemplate: "suggestion: $s1 < $s2", SuggestTemplate: "$s1 < $s2", }, - ir.Rule{ + { Line: 752, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 752, Value: "strings.Compare($s1, $s2) == 1"}, - ir.PatternString{Line: 753, Value: "strings.Compare($s1, $s2) > 0"}, + {Line: 752, Value: "strings.Compare($s1, $s2) == 1"}, + {Line: 753, Value: "strings.Compare($s1, $s2) > 0"}, }, ReportTemplate: "suggestion: $s1 > $s2", SuggestTemplate: "$s1 > $s2", From ae90e61c61479d5bdfcf0b6e02842e5bd6b9aef1 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 27 Mar 2022 23:41:45 +0300 Subject: [PATCH 04/10] fix --- checkers/ruleguard_checker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index a6db91ae0..7352977f3 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -184,7 +184,7 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( DebugPrint: debugPrint, GroupFilter: func(g *ruleguard.GoRuleGroup) bool { whyDisabled := "" - enabled := len(enabledGroups) == 0 || enabledGroups[g.Name] + enabled := flagEnable == "" || enabledGroups[g.Name] switch { case !enabled: whyDisabled = "not enabled by -enabled flag" @@ -192,7 +192,7 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( whyDisabled = "disabled by -disable flag" case len(enabledTags) != 0 && !inEnabledByTags(g): whyDisabled = "not enabled by tags in -enable flag" - case inDisabledByTags(g): + case len(disabledTags) != 0 && inDisabledByTags(g): whyDisabled = "disabled by tags in -disable flag" } if ruleguardDebug { From 5dd6baf3d6d082891161fab68d79cd43e1c44cba Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 09:02:40 +0300 Subject: [PATCH 05/10] merge two last commits for rerun tests --- checkers/ruleguard_checker.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 7352977f3..1444f3bb7 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -161,17 +161,9 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( } ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" - inDisabledByTags := func(g *ruleguard.GoRuleGroup) bool { + inTags := func(g *ruleguard.GoRuleGroup, tags map[string]bool) bool { for _, t := range g.DocTags { - if disabledTags[t] { - return true - } - } - return false - } - inEnabledByTags := func(g *ruleguard.GoRuleGroup) bool { - for _, t := range g.DocTags { - if enabledTags[t] { + if tags[t] { return true } } @@ -190,9 +182,9 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( whyDisabled = "not enabled by -enabled flag" case disabledGroups[g.Name]: whyDisabled = "disabled by -disable flag" - case len(enabledTags) != 0 && !inEnabledByTags(g): + case len(enabledTags) != 0 && !inTags(g, enabledTags): whyDisabled = "not enabled by tags in -enable flag" - case len(disabledTags) != 0 && inDisabledByTags(g): + case len(disabledTags) != 0 && inTags(g, disabledTags): whyDisabled = "disabled by tags in -disable flag" } if ruleguardDebug { From 41fd4b8dcf7727a4f02cdc5901dafcc4bd02cf05 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 20:36:04 +0300 Subject: [PATCH 06/10] add test --- checkers/ruleguard_checker.go | 8 ++++---- checkers/testdata/_integration/ruleguard/f1.go | 9 +++++++++ checkers/testdata/_integration/ruleguard/linttest.params | 2 +- checkers/testdata/_integration/ruleguard/rules.go | 7 +++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 1444f3bb7..5ce22bc25 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -140,8 +140,8 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( for _, g := range strings.Split(info.Params.String("disable"), ",") { g = strings.TrimSpace(g) - if t := strings.Split(g, "#"); len(t) == 2 { - disabledTags[t[1]] = true + if strings.HasPrefix(g, "#") { + disabledTags[strings.TrimPrefix(g, "#")] = true continue } @@ -151,8 +151,8 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( if flagEnable != "" { for _, g := range strings.Split(flagEnable, ",") { g = strings.TrimSpace(g) - if t := strings.Split(g, "#"); len(t) == 2 { - enabledTags[t[1]] = true + if strings.HasPrefix(g, "#") { + enabledTags[strings.TrimPrefix(g, "#")] = true continue } diff --git a/checkers/testdata/_integration/ruleguard/f1.go b/checkers/testdata/_integration/ruleguard/f1.go index 7773e577a..c09c736fb 100644 --- a/checkers/testdata/_integration/ruleguard/f1.go +++ b/checkers/testdata/_integration/ruleguard/f1.go @@ -8,3 +8,12 @@ func _() { var s1, s2 string var _ = fmt.Sprintf("%s%s", s1, s2) } + +func _() { + var s1, s2 string + if s1 == s2 { + if s1 != "" { + println(s1, s2) + } + } +} diff --git a/checkers/testdata/_integration/ruleguard/linttest.params b/checkers/testdata/_integration/ruleguard/linttest.params index e8c6192c5..dc1692ec9 100644 --- a/checkers/testdata/_integration/ruleguard/linttest.params +++ b/checkers/testdata/_integration/ruleguard/linttest.params @@ -1 +1 @@ -check -@ruleguard.rules ./rules.go -enable ruleguard ./... | linttest.golden +check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.disable=#test ./... | linttest.golden diff --git a/checkers/testdata/_integration/ruleguard/rules.go b/checkers/testdata/_integration/ruleguard/rules.go index a35da1ac4..b4004182f 100644 --- a/checkers/testdata/_integration/ruleguard/rules.go +++ b/checkers/testdata/_integration/ruleguard/rules.go @@ -1,3 +1,4 @@ +//go:build ignore // +build ignore package gorules @@ -15,3 +16,9 @@ func sprintfConcat(m dsl.Matcher) { Where(m["a"].Type.Is(`string`) && m["b"].Type.Is(`string`)). Suggest(`$a+$b`) } + +//doc:tags test +func stackedIf(m dsl.Matcher) { + m.Match(`if $*_ { if $*_ { $*_ } }`). + Report(`may be simplified to one if`) +} From c862379224721ccd75a3e686aae0190b884ea75e Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 20:55:34 +0300 Subject: [PATCH 07/10] add test --- checkers/ruleguard_checker.go | 2 +- checkers/testdata/_integration/ruleguard/f1.go | 7 +++++++ checkers/testdata/_integration/ruleguard/linttest.golden | 3 ++- checkers/testdata/_integration/ruleguard/linttest.params | 1 + checkers/testdata/_integration/ruleguard/rules.go | 7 +++++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 5ce22bc25..54b4ac9ea 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -176,7 +176,7 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( DebugPrint: debugPrint, GroupFilter: func(g *ruleguard.GoRuleGroup) bool { whyDisabled := "" - enabled := flagEnable == "" || enabledGroups[g.Name] + enabled := len(enabledGroups) == 0 || enabledGroups[g.Name] switch { case !enabled: whyDisabled = "not enabled by -enabled flag" diff --git a/checkers/testdata/_integration/ruleguard/f1.go b/checkers/testdata/_integration/ruleguard/f1.go index c09c736fb..21a0cdae8 100644 --- a/checkers/testdata/_integration/ruleguard/f1.go +++ b/checkers/testdata/_integration/ruleguard/f1.go @@ -17,3 +17,10 @@ func _() { } } } + +func _() { + k := func() string { + return "test" + } + _ = fmt.Errorf(k()) +} diff --git a/checkers/testdata/_integration/ruleguard/linttest.golden b/checkers/testdata/_integration/ruleguard/linttest.golden index 360f7d5a2..7d97651a6 100644 --- a/checkers/testdata/_integration/ruleguard/linttest.golden +++ b/checkers/testdata/_integration/ruleguard/linttest.golden @@ -1,3 +1,4 @@ exit status 1 ./f1.go:5:1: ruleguard: error as an underlying type is probably a mistake -./f1.go:9:10: ruleguard: suggestion: s1+s2 \ No newline at end of file +./f1.go:9:10: ruleguard: suggestion: s1+s2 +./f1.go:25:6: ruleguard: use errors.New(k()) or fmt.Errorf("%s", k()) instead diff --git a/checkers/testdata/_integration/ruleguard/linttest.params b/checkers/testdata/_integration/ruleguard/linttest.params index dc1692ec9..1372ec669 100644 --- a/checkers/testdata/_integration/ruleguard/linttest.params +++ b/checkers/testdata/_integration/ruleguard/linttest.params @@ -1 +1,2 @@ check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.disable=#test ./... | linttest.golden +check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.enable=#style -@ruleguard.disable=#test ./... | linttest.golden2 diff --git a/checkers/testdata/_integration/ruleguard/rules.go b/checkers/testdata/_integration/ruleguard/rules.go index b4004182f..14f1c91cd 100644 --- a/checkers/testdata/_integration/ruleguard/rules.go +++ b/checkers/testdata/_integration/ruleguard/rules.go @@ -22,3 +22,10 @@ func stackedIf(m dsl.Matcher) { m.Match(`if $*_ { if $*_ { $*_ } }`). Report(`may be simplified to one if`) } + +//doc:tags style +func dynamicFmtString(m dsl.Matcher) { + m.Match(`fmt.Errorf($f($*args))`). + Suggest("errors.New($f($args))"). + Report(`use errors.New($f($args)) or fmt.Errorf("%s", $f($args)) instead`) +} From 332858ddd5b3358746c6792ec95ac4405fac20dc Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 20:59:11 +0300 Subject: [PATCH 08/10] add forgotten file --- checkers/testdata/_integration/ruleguard/linttest.golden2 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 checkers/testdata/_integration/ruleguard/linttest.golden2 diff --git a/checkers/testdata/_integration/ruleguard/linttest.golden2 b/checkers/testdata/_integration/ruleguard/linttest.golden2 new file mode 100644 index 000000000..a67559d8f --- /dev/null +++ b/checkers/testdata/_integration/ruleguard/linttest.golden2 @@ -0,0 +1,2 @@ +exit status 1 +./f1.go:25:6: ruleguard: use errors.New(k()) or fmt.Errorf("%s", k()) instead From eb657ee8f3d251b99f681d16788b7f7948a28b0a Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 21:59:41 +0300 Subject: [PATCH 09/10] add test case --- checkers/testdata/_integration/ruleguard/linttest.golden3 | 3 +++ checkers/testdata/_integration/ruleguard/linttest.params | 1 + 2 files changed, 4 insertions(+) create mode 100644 checkers/testdata/_integration/ruleguard/linttest.golden3 diff --git a/checkers/testdata/_integration/ruleguard/linttest.golden3 b/checkers/testdata/_integration/ruleguard/linttest.golden3 new file mode 100644 index 000000000..f28cd4cec --- /dev/null +++ b/checkers/testdata/_integration/ruleguard/linttest.golden3 @@ -0,0 +1,3 @@ +exit status 1 +./f1.go:14:2: ruleguard: may be simplified to one if +./f1.go:25:6: ruleguard: use errors.New(k()) or fmt.Errorf("%s", k()) instead diff --git a/checkers/testdata/_integration/ruleguard/linttest.params b/checkers/testdata/_integration/ruleguard/linttest.params index 1372ec669..ef5e14652 100644 --- a/checkers/testdata/_integration/ruleguard/linttest.params +++ b/checkers/testdata/_integration/ruleguard/linttest.params @@ -1,2 +1,3 @@ check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.disable=#test ./... | linttest.golden check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.enable=#style -@ruleguard.disable=#test ./... | linttest.golden2 +check -@ruleguard.rules ./rules.go -enable ruleguard -@ruleguard.enable=#style,#test ./... | linttest.golden3 From 40ee868841744def3990c769d2a994abcf1bfc28 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Mar 2022 22:35:33 +0300 Subject: [PATCH 10/10] copied filter logic from internal checks --- checkers/ruleguard_checker.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 54b4ac9ea..8ec2e4373 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -161,32 +161,42 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( } ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" - inTags := func(g *ruleguard.GoRuleGroup, tags map[string]bool) bool { + inEnabledTags := func(g *ruleguard.GoRuleGroup) bool { for _, t := range g.DocTags { - if tags[t] { + if enabledTags[t] { return true } } return false } + inDisabledTags := func(g *ruleguard.GoRuleGroup) string { + for _, t := range g.DocTags { + if disabledTags[t] { + return t + } + } + return "" + } loadContext := &ruleguard.LoadContext{ Fset: fset, DebugImports: ruleguardDebug, DebugPrint: debugPrint, GroupFilter: func(g *ruleguard.GoRuleGroup) bool { + enabled := flagEnable == "" || enabledGroups[g.Name] || inEnabledTags(g) whyDisabled := "" - enabled := len(enabledGroups) == 0 || enabledGroups[g.Name] + switch { case !enabled: - whyDisabled = "not enabled by -enabled flag" + whyDisabled = "not enabled by name or tag (-enable flag)" case disabledGroups[g.Name]: - whyDisabled = "disabled by -disable flag" - case len(enabledTags) != 0 && !inTags(g, enabledTags): - whyDisabled = "not enabled by tags in -enable flag" - case len(disabledTags) != 0 && inTags(g, disabledTags): - whyDisabled = "disabled by tags in -disable flag" + whyDisabled = "disabled by name (-disable flag)" + default: + if tag := inDisabledTags(g); tag != "" { + whyDisabled = fmt.Sprintf("disabled by %s tag (-disable flag)", tag) + } } + if ruleguardDebug { if whyDisabled != "" { debugPrint(fmt.Sprintf("(-) %s is %s", g.Name, whyDisabled))