diff --git a/Makefile b/Makefile index 4d08c9238..ea27ed5e2 100644 --- a/Makefile +++ b/Makefile @@ -38,13 +38,13 @@ ci-tests: ci-linter: @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.30.0 @$(GOPATH_DIR)/bin/golangci-lint run -v - go install github.com/quasilyte/go-consistent + cd tools && go install github.com/quasilyte/go-consistent @$(GOPATH_DIR)/bin/go-consistent ./... go build -o gocritic ./cmd/gocritic ./gocritic check -enableAll ./... cover: - go install github.com/mattn/goveralls + cd tools && go install github.com/mattn/goveralls goveralls -package github.com/go-critic/go-critic/checkers -coverprofile=coverage.out -service travis-ci -repotoken ${COVERALLS_TOKEN} gocritic: diff --git a/checkers/boolExprSimplify_checker.go b/checkers/boolExprSimplify_checker.go index 325fb56a3..8e931cc4b 100644 --- a/checkers/boolExprSimplify_checker.go +++ b/checkers/boolExprSimplify_checker.go @@ -6,15 +6,16 @@ import ( "go/token" "strconv" - "github.com/go-critic/go-critic/checkers/internal/astwalk" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astequal" "github.com/go-toolsmith/astp" "github.com/go-toolsmith/typep" "golang.org/x/tools/go/ast/astutil" + + "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/checkers/internal/lintutil" + "github.com/go-critic/go-critic/framework/linter" ) func init() { diff --git a/checkers/checkers.go b/checkers/checkers.go index 7ce829d36..0c2ebc00c 100644 --- a/checkers/checkers.go +++ b/checkers/checkers.go @@ -2,15 +2,9 @@ package checkers import ( - "fmt" - "go/ast" - "go/build" - "go/token" "os" - "github.com/go-critic/go-critic/checkers/rulesdata" "github.com/go-critic/go-critic/framework/linter" - "github.com/quasilyte/go-ruleguard/ruleguard" ) var collection = &linter.CheckerCollection{ @@ -23,93 +17,3 @@ var debug = func() func() bool { return v } }() - -//go:generate go run ./rules/precompile.go -rules ./rules/rules.go -o ./rulesdata/rulesdata.go - -func init() { - filename := "rules/rules.go" - - fset := token.NewFileSet() - var groups []ruleguard.GoRuleGroup - - var buildContext *build.Context - - ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" - - // First we create an Engine to parse all rules. - // We need it to get the structured info about our rules - // that will be used to generate checkers. - // We introduce an extra scope in hope that rootEngine - // will be garbage-collected after we don't need it. - // LoadedGroups() returns a slice copy and that's all what we need. - { - rootEngine := ruleguard.NewEngine() - rootEngine.InferBuildContext() - buildContext = rootEngine.BuildContext - - loadContext := &ruleguard.LoadContext{ - Fset: fset, - DebugImports: ruleguardDebug, - DebugPrint: func(s string) { - fmt.Println("debug:", s) - }, - } - if err := rootEngine.LoadFromIR(loadContext, filename, rulesdata.PrecompiledRules); err != nil { - panic(fmt.Sprintf("load embedded ruleguard rules: %v", err)) - } - groups = rootEngine.LoadedGroups() - } - - // For every rules group we create a new checker and a separate engine. - // That dedicated ruleguard engine will contain rules only from one group. - for i := range groups { - g := groups[i] - info := &linter.CheckerInfo{ - Name: g.Name, - Summary: g.DocSummary, - Before: g.DocBefore, - After: g.DocAfter, - Note: g.DocNote, - Tags: g.DocTags, - - EmbeddedRuleguard: true, - } - collection.AddChecker(info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { - parseContext := &ruleguard.LoadContext{ - Fset: fset, - GroupFilter: func(name string) bool { - return name == g.Name - }, - DebugImports: ruleguardDebug, - DebugPrint: func(s string) { - fmt.Println("debug:", s) - }, - } - engine := ruleguard.NewEngine() - engine.BuildContext = buildContext - err := engine.LoadFromIR(parseContext, filename, rulesdata.PrecompiledRules) - if err != nil { - return nil, err - } - c := &embeddedRuleguardChecker{ - ctx: ctx, - engine: engine, - } - return c, nil - }) - } -} - -type embeddedRuleguardChecker struct { - ctx *linter.CheckerContext - engine *ruleguard.Engine -} - -func (c *embeddedRuleguardChecker) WalkFile(f *ast.File) { - runRuleguardEngine(c.ctx, f, c.engine, &ruleguard.RunContext{ - Pkg: c.ctx.Pkg, - Types: c.ctx.TypesInfo, - Sizes: c.ctx.SizesInfo, - Fset: c.ctx.FileSet, - }) -} diff --git a/checkers/checkers_test.go b/checkers/checkers_test.go index a37a0237b..fa2ebb8d1 100644 --- a/checkers/checkers_test.go +++ b/checkers/checkers_test.go @@ -199,7 +199,7 @@ func TestExternal(t *testing.T) { continue } if diff := cmp.Diff(want, have); diff != "" { - t.Errorf("%s output mismatches:\n%s", proj.Name(), diff) + t.Errorf("%s output mismatches (+have -want):\n%s", proj.Name(), diff) continue } } diff --git a/checkers/commentFormatting_checker.go b/checkers/commentFormatting_checker.go index 513eb246d..74eff3b09 100644 --- a/checkers/commentFormatting_checker.go +++ b/checkers/commentFormatting_checker.go @@ -27,6 +27,7 @@ func init() { `^//line /.*:\d+`, // e.g.: line /path/to/file:123 `^//export \w+$`, // e.g.: export Foo `^//[/+#-]+.*$`, // e.g.: vertical breaker ///////////// + `^//noinspection `, // e.g.: noinspection ALL, some GoLand and friends versions } pat := "(?m)" + strings.Join(parts, "|") pragmaRE := regexp.MustCompile(pat) diff --git a/checkers/embedded_rules.go b/checkers/embedded_rules.go new file mode 100644 index 000000000..e37fdf14a --- /dev/null +++ b/checkers/embedded_rules.go @@ -0,0 +1,103 @@ +package checkers + +import ( + "fmt" + "go/ast" + "go/build" + "go/token" + "os" + + "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 + +func init() { + filename := "rules/rules.go" + + fset := token.NewFileSet() + var groups []ruleguard.GoRuleGroup + + var buildContext *build.Context + + ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" + + // First we create an Engine to parse all rules. + // We need it to get the structured info about our rules + // that will be used to generate checkers. + // We introduce an extra scope in hope that rootEngine + // will be garbage-collected after we don't need it. + // LoadedGroups() returns a slice copy and that's all what we need. + { + rootEngine := ruleguard.NewEngine() + rootEngine.InferBuildContext() + buildContext = rootEngine.BuildContext + + loadContext := &ruleguard.LoadContext{ + Fset: fset, + DebugImports: ruleguardDebug, + DebugPrint: func(s string) { + fmt.Println("debug:", s) + }, + } + if err := rootEngine.LoadFromIR(loadContext, filename, rulesdata.PrecompiledRules); err != nil { + panic(fmt.Sprintf("load embedded ruleguard rules: %v", err)) + } + groups = rootEngine.LoadedGroups() + } + + // For every rules group we create a new checker and a separate engine. + // That dedicated ruleguard engine will contain rules only from one group. + for i := range groups { + g := groups[i] + info := &linter.CheckerInfo{ + Name: g.Name, + Summary: g.DocSummary, + Before: g.DocBefore, + After: g.DocAfter, + Note: g.DocNote, + Tags: g.DocTags, + + EmbeddedRuleguard: true, + } + collection.AddChecker(info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + parseContext := &ruleguard.LoadContext{ + Fset: fset, + GroupFilter: func(name string) bool { + return name == g.Name + }, + DebugImports: ruleguardDebug, + DebugPrint: func(s string) { + fmt.Println("debug:", s) + }, + } + engine := ruleguard.NewEngine() + engine.BuildContext = buildContext + err := engine.LoadFromIR(parseContext, filename, rulesdata.PrecompiledRules) + if err != nil { + return nil, err + } + c := &embeddedRuleguardChecker{ + ctx: ctx, + engine: engine, + } + return c, nil + }) + } +} + +type embeddedRuleguardChecker struct { + ctx *linter.CheckerContext + engine *ruleguard.Engine +} + +func (c *embeddedRuleguardChecker) WalkFile(f *ast.File) { + runRuleguardEngine(c.ctx, f, c.engine, &ruleguard.RunContext{ + Pkg: c.ctx.Pkg, + Types: c.ctx.TypesInfo, + Sizes: c.ctx.SizesInfo, + Fset: c.ctx.FileSet, + }) +} diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index d65669fdd..e164dede8 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -12,8 +12,9 @@ import ( "sort" "strings" - "github.com/go-critic/go-critic/framework/linter" "github.com/quasilyte/go-ruleguard/ruleguard" + + "github.com/go-critic/go-critic/framework/linter" ) func init() { @@ -41,6 +42,14 @@ If flag is set, the value must be a comma-separated list of error conditions. * 'import': rule refers to a package that cannot be loaded. * 'dsl': gorule file does not comply with the ruleguard DSL.`, }, + "enable": { + Value: "", + Usage: "comma-separated list of enabled groups or skip empty to enable everything", + }, + "disable": { + Value: "", + Usage: "comma-separated list of disabled groups or skip empty to enable everything", + }, } info.Summary = "Runs user-defined rules using ruleguard linter" info.Details = "Reads a rules file and turns them into go-critic checkers." @@ -124,13 +133,43 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) ( fset := token.NewFileSet() filePatterns := strings.Split(rulesFlag, ",") + enabledGroups := make(map[string]bool) + disabledGroups := make(map[string]bool) + + for _, g := range strings.Split(info.Params.String("disable"), ",") { + g = strings.TrimSpace(g) + disabledGroups[g] = true + } + flagEnable := info.Params.String("enable") + if flagEnable != "" { + for _, g := range strings.Split(flagEnable, ",") { + g = strings.TrimSpace(g) + enabledGroups[g] = true + } + } ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != "" loadContext := &ruleguard.LoadContext{ Fset: fset, DebugImports: ruleguardDebug, - DebugPrint: func(s string) { - fmt.Println("debug:", s) + DebugPrint: debugPrint, + GroupFilter: func(g string) bool { + whyDisabled := "" + enabled := flagEnable == "" || enabledGroups[g] + switch { + case !enabled: + whyDisabled = "not enabled by -enabled flag" + case disabledGroups[g]: + whyDisabled = "disabled by -disable flag" + } + if ruleguardDebug { + if whyDisabled != "" { + debugPrint(fmt.Sprintf("(-) %s is %s", g, whyDisabled)) + } else { + debugPrint(fmt.Sprintf("(+) %s is enabled", g)) + } + } + return whyDisabled == "" }, } @@ -236,3 +275,7 @@ func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.En } } } + +func debugPrint(s string) { + fmt.Println("debug:", s) +} diff --git a/checkers/rules/rules.go b/checkers/rules/rules.go index 841ff42e7..a612c90b6 100644 --- a/checkers/rules/rules.go +++ b/checkers/rules/rules.go @@ -118,12 +118,14 @@ func httpNoBody(m dsl.Matcher) { m.Match("http.NewRequest($method, $url, $nil)"). Where(m["nil"].Text == "nil"). Suggest("http.NewRequest($method, $url, http.NoBody)"). - Report("http.NoBody should be preferred to the nil request body") + Report("http.NoBody should be preferred to the nil request body"). + At(m["nil"]) m.Match("http.NewRequestWithContext($ctx, $method, $url, $nil)"). Where(m["nil"].Text == "nil"). Suggest("http.NewRequestWithContext($ctx, $method, $url, http.NoBody)"). - Report("http.NoBody should be preferred to the nil request body") + Report("http.NoBody should be preferred to the nil request body"). + At(m["nil"]) } //doc:summary Detects expressions like []rune(s)[0] that may cause unwanted rune slice allocation @@ -361,6 +363,10 @@ func preferFprint(m dsl.Matcher) { Where(m["w"].Type.Implements("io.Writer")). Suggest("fmt.Fprintln($w, $args)"). Report(`fmt.Fprintln($w, $args) should be preferred to the $$`) + + m.Match(`io.WriteString($w, fmt.Sprint($*args))`).Suggest(`fmt.Fprint($w, $args)`) + m.Match(`io.WriteString($w, fmt.Sprintf($*args))`).Suggest(`fmt.Fprintf($w, $args)`) + m.Match(`io.WriteString($w, fmt.Sprintln($*args))`).Suggest(`fmt.Fprintln($w, $args)`) } //doc:summary Detects suspicious duplicated arguments @@ -567,7 +573,7 @@ func equalFold(m dsl.Matcher) { `strings.ToUpper($x) == strings.ToUpper($y)`, `$x == strings.ToUpper($y)`). Where(m["x"].Pure && m["y"].Pure && m["x"].Text != m["y"].Text). - Suggest(`strings.EqualFold($x, $y)]`). + Suggest(`strings.EqualFold($x, $y)`). Report(`consider replacing with strings.EqualFold($x, $y)`) // string != patterns @@ -579,7 +585,7 @@ func equalFold(m dsl.Matcher) { `strings.ToUpper($x) != strings.ToUpper($y)`, `$x != strings.ToUpper($y)`). Where(m["x"].Pure && m["y"].Pure && m["x"].Text != m["y"].Text). - Suggest(`!strings.EqualFold($x, $y)]`). + Suggest(`!strings.EqualFold($x, $y)`). Report(`consider replacing with !strings.EqualFold($x, $y)`) // bytes.Equal patterns @@ -591,7 +597,7 @@ func equalFold(m dsl.Matcher) { `bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))`, `bytes.Equal($x, bytes.ToUpper($y))`). Where(m["x"].Pure && m["y"].Pure && m["x"].Text != m["y"].Text). - Suggest(`bytes.EqualFold($x, $y)]`). + Suggest(`bytes.EqualFold($x, $y)`). Report(`consider replacing with bytes.EqualFold($x, $y)`) } @@ -634,15 +640,17 @@ func stringConcatSimplify(m dsl.Matcher) { //doc:before t.Unix() / 1000 //doc:after t.UnixMilli() func timeExprSimplify(m dsl.Matcher) { + isTime := func(v dsl.Var) bool { + return v.Type.Is(`time.Time`) || v.Type.Is(`*time.Time`) + } + m.Match(`$t.Unix() / 1000`). - Where(m.GoVersion().GreaterEqThan("1.17") && - (m["t"].Type.Is(`time.Time`) || m["t"].Type.Is(`*time.Time`))). + Where(m.GoVersion().GreaterEqThan("1.17") && isTime(m["t"])). Suggest("$t.UnixMilli()"). Report(`use $t.UnixMilli() instead of $$`) m.Match(`$t.UnixNano() * 1000`). - Where(m.GoVersion().GreaterEqThan("1.17") && - (m["t"].Type.Is(`time.Time`) || m["t"].Type.Is(`*time.Time`))). + Where(m.GoVersion().GreaterEqThan("1.17") && isTime(m["t"])). Suggest("$t.UnixMicro()"). Report(`use $t.UnixMicro() instead of $$`) } @@ -652,20 +660,24 @@ func timeExprSimplify(m dsl.Matcher) { //doc:before type Foo struct{ ...; sync.Mutex; ... } //doc:after type Foo struct{ ...; mu sync.Mutex; ... } func exposedSyncMutex(m dsl.Matcher) { + isExported := func(v dsl.Var) bool { + return v.Text.Matches(`^\p{Lu}`) + } + m.Match(`type $x struct { $*_; sync.Mutex; $*_ }`). - Where(m["x"].Text.Matches(`^\p{Lu}`)). + Where(isExported(m["x"])). Report("don't embed sync.Mutex") m.Match(`type $x struct { $*_; *sync.Mutex; $*_ }`). - Where(m["x"].Text.Matches(`^\p{Lu}`)). + Where(isExported(m["x"])). Report("don't embed *sync.Mutex") m.Match(`type $x struct { $*_; sync.RWMutex; $*_ }`). - Where(m["x"].Text.Matches(`^\p{Lu}`)). + Where(isExported(m["x"])). Report("don't embed sync.RWMutex") m.Match(`type $x struct { $*_; *sync.RWMutex; $*_ }`). - Where(m["x"].Text.Matches(`^\p{Lu}`)). + Where(isExported(m["x"])). Report("don't embed *sync.RWMutex") } @@ -709,3 +721,18 @@ func emptyDecl(m dsl.Matcher) { m.Match(`const()`).Report(`empty const() block`) m.Match(`type()`).Report(`empty type() block`) } + +//doc:summary Detects suspicious formatting strings usage +//doc:tags diagnostic experimental +//doc:before fmt.Errorf(msg) +//doc:after fmt.Errorf("%s", msg) +func dynamicFmtString(m dsl.Matcher) { + m.Match(`fmt.Errorf($f)`). + Where(!m["f"].Const). + Suggest("errors.New($f)"). + Report(`use errors.New($f) or fmt.Errorf("%s", $f) instead`) + + m.Match(`fmt.Errorf($f($*args))`). + Suggest("errors.New($f($*args))"). + Report(`use errors.New($f($*args)) or fmt.Errorf("%s", $f($*args)) instead`) +} diff --git a/checkers/rulesdata/rulesdata.go b/checkers/rulesdata/rulesdata.go index 95b3e715d..8a952b7c2 100644 --- a/checkers/rulesdata/rulesdata.go +++ b/checkers/rulesdata/rulesdata.go @@ -436,28 +436,30 @@ var PrecompiledRules = &ir.File{ ir.FilterExpr{Line: 119, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, + LocationVar: "nil", }, ir.Rule{ - Line: 123, + Line: 124, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 123, Value: "http.NewRequestWithContext($ctx, $method, $url, $nil)"}, + 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{ - Line: 124, + Line: 125, Op: ir.FilterEqOp, Src: "m[\"nil\"].Text == \"nil\"", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 124, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, - ir.FilterExpr{Line: 124, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, + ir.FilterExpr{Line: 125, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, + ir.FilterExpr{Line: 125, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, + LocationVar: "nil", }, }, }, ir.RuleGroup{ - Line: 134, + Line: 136, Name: "preferDecodeRune", MatcherName: "m", DocTags: []string{ @@ -470,25 +472,25 @@ var PrecompiledRules = &ir.File{ DocNote: "See Go issue for details: https://github.com/golang/go/issues/45260", Rules: []ir.Rule{ ir.Rule{ - Line: 135, + Line: 137, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 135, Value: "[]rune($s)[0]"}, + ir.PatternString{Line: 137, Value: "[]rune($s)[0]"}, }, ReportTemplate: "consider replacing $$ with utf8.DecodeRuneInString($s)", WhereExpr: ir.FilterExpr{ - Line: 136, + Line: 138, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 136, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 138, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, }, }, ir.RuleGroup{ - Line: 144, + Line: 146, Name: "sloppyLen", MatcherName: "m", DocTags: []string{ @@ -499,30 +501,30 @@ var PrecompiledRules = &ir.File{ DocAfter: "len(arr) == 0", Rules: []ir.Rule{ ir.Rule{ - Line: 145, + Line: 147, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 145, Value: "len($_) >= 0"}, + ir.PatternString{Line: 147, Value: "len($_) >= 0"}, }, ReportTemplate: "$$ is always true", }, ir.Rule{ - Line: 146, + Line: 148, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 146, Value: "len($_) < 0"}, + ir.PatternString{Line: 148, Value: "len($_) < 0"}, }, ReportTemplate: "$$ is always false", }, ir.Rule{ - Line: 147, + Line: 149, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 147, Value: "len($x) <= 0"}, + ir.PatternString{Line: 149, Value: "len($x) <= 0"}, }, ReportTemplate: "$$ can be len($x) == 0", }, }, }, ir.RuleGroup{ - Line: 154, + Line: 156, Name: "valSwap", MatcherName: "m", DocTags: []string{ @@ -533,16 +535,16 @@ var PrecompiledRules = &ir.File{ DocAfter: "*x, *y = *y, *x", Rules: []ir.Rule{ ir.Rule{ - Line: 155, + Line: 157, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 155, Value: "$tmp := $y; $y = $x; $x = $tmp"}, + ir.PatternString{Line: 157, Value: "$tmp := $y; $y = $x; $x = $tmp"}, }, ReportTemplate: "can re-write as `$y, $x = $x, $y`", }, }, }, ir.RuleGroup{ - Line: 163, + Line: 165, Name: "switchTrue", MatcherName: "m", DocTags: []string{ @@ -553,23 +555,23 @@ var PrecompiledRules = &ir.File{ DocAfter: "switch {...}", Rules: []ir.Rule{ ir.Rule{ - Line: 164, + Line: 166, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 164, Value: "switch true { $*_ }"}, + ir.PatternString{Line: 166, Value: "switch true { $*_ }"}, }, ReportTemplate: "replace 'switch true {}' with 'switch {}'", }, ir.Rule{ - Line: 166, + Line: 168, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 166, Value: "switch $x; true { $*_ }"}, + ir.PatternString{Line: 168, Value: "switch $x; true { $*_ }"}, }, ReportTemplate: "replace 'switch $x; true {}' with 'switch $x; {}'", }, }, }, ir.RuleGroup{ - Line: 174, + Line: 176, Name: "flagDeref", MatcherName: "m", DocTags: []string{ @@ -580,65 +582,65 @@ var PrecompiledRules = &ir.File{ DocAfter: "var b bool; flag.BoolVar(&b, \"b\", false, \"b docs\")", Rules: []ir.Rule{ ir.Rule{ - Line: 175, + Line: 177, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 175, Value: "*flag.Bool($*_)"}, + ir.PatternString{Line: 177, Value: "*flag.Bool($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.BoolVar", }, ir.Rule{ - Line: 176, + Line: 178, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 176, Value: "*flag.Duration($*_)"}, + ir.PatternString{Line: 178, Value: "*flag.Duration($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.DurationVar", }, ir.Rule{ - Line: 177, + Line: 179, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 177, Value: "*flag.Float64($*_)"}, + ir.PatternString{Line: 179, Value: "*flag.Float64($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Float64Var", }, ir.Rule{ - Line: 178, + Line: 180, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 178, Value: "*flag.Int($*_)"}, + ir.PatternString{Line: 180, Value: "*flag.Int($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.IntVar", }, ir.Rule{ - Line: 179, + Line: 181, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 179, Value: "*flag.Int64($*_)"}, + ir.PatternString{Line: 181, Value: "*flag.Int64($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Int64Var", }, ir.Rule{ - Line: 180, + Line: 182, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 180, Value: "*flag.String($*_)"}, + ir.PatternString{Line: 182, Value: "*flag.String($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.StringVar", }, ir.Rule{ - Line: 181, + Line: 183, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 181, Value: "*flag.Uint($*_)"}, + ir.PatternString{Line: 183, Value: "*flag.Uint($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.UintVar", }, ir.Rule{ - Line: 182, + Line: 184, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 182, Value: "*flag.Uint64($*_)"}, + ir.PatternString{Line: 184, Value: "*flag.Uint64($*_)"}, }, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Uint64Var", }, }, }, ir.RuleGroup{ - Line: 189, + Line: 191, Name: "emptyStringTest", MatcherName: "m", DocTags: []string{ @@ -650,41 +652,41 @@ var PrecompiledRules = &ir.File{ DocAfter: "s == \"\"", Rules: []ir.Rule{ ir.Rule{ - Line: 190, + Line: 192, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 190, Value: "len($s) != 0"}, + ir.PatternString{Line: 192, Value: "len($s) != 0"}, }, ReportTemplate: "replace `$$` with `$s != \"\"`", WhereExpr: ir.FilterExpr{ - Line: 191, + Line: 193, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 191, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 193, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, ir.Rule{ - Line: 194, + Line: 196, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 194, Value: "len($s) == 0"}, + ir.PatternString{Line: 196, Value: "len($s) == 0"}, }, ReportTemplate: "replace `$$` with `$s == \"\"`", WhereExpr: ir.FilterExpr{ - Line: 195, + Line: 197, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 195, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 197, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, }, }, ir.RuleGroup{ - Line: 203, + Line: 205, Name: "stringXbytes", MatcherName: "m", DocTags: []string{ @@ -695,223 +697,223 @@ var PrecompiledRules = &ir.File{ DocAfter: "copy(b, s)", Rules: []ir.Rule{ ir.Rule{ - Line: 204, + Line: 206, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 204, Value: "copy($_, []byte($s))"}, + ir.PatternString{Line: 206, Value: "copy($_, []byte($s))"}, }, ReportTemplate: "can simplify `[]byte($s)` to `$s`", }, ir.Rule{ - Line: 206, + Line: 208, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 206, Value: "string($b) == \"\""}, + ir.PatternString{Line: 208, Value: "string($b) == \"\""}, }, ReportTemplate: "suggestion: len($b) == 0", SuggestTemplate: "len($b) == 0", WhereExpr: ir.FilterExpr{ - Line: 206, + Line: 208, Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 206, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 208, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, }, ir.Rule{ - Line: 207, + Line: 209, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 207, Value: "string($b) != \"\""}, + ir.PatternString{Line: 209, Value: "string($b) != \"\""}, }, ReportTemplate: "suggestion: len($b) != 0", SuggestTemplate: "len($b) != 0", WhereExpr: ir.FilterExpr{ - Line: 207, + Line: 209, Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 207, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 209, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, }, ir.Rule{ - Line: 209, + Line: 211, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 209, Value: "len(string($b))"}, + ir.PatternString{Line: 211, Value: "len(string($b))"}, }, ReportTemplate: "suggestion: len($b)", SuggestTemplate: "len($b)", WhereExpr: ir.FilterExpr{ - Line: 209, + Line: 211, 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"}, + ir.FilterExpr{Line: 211, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, }, ir.Rule{ - Line: 211, + Line: 213, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 211, Value: "string($x) == string($y)"}, + ir.PatternString{Line: 213, Value: "string($x) == string($y)"}, }, ReportTemplate: "suggestion: bytes.Equal($x, $y)", SuggestTemplate: "bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 212, + Line: 214, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 212, + Line: 214, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 212, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, ir.FilterExpr{ - Line: 212, + Line: 214, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 212, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, }, }, }, ir.Rule{ - Line: 215, + Line: 217, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 215, Value: "string($x) != string($y)"}, + ir.PatternString{Line: 217, Value: "string($x) != string($y)"}, }, ReportTemplate: "suggestion: !bytes.Equal($x, $y)", SuggestTemplate: "!bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 216, + Line: 218, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 216, + Line: 218, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 216, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, ir.FilterExpr{ - Line: 216, + Line: 218, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 216, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, + ir.FilterExpr{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}, }, }, }, }, }, ir.Rule{ - Line: 219, + Line: 221, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 219, Value: "$re.Match([]byte($s))"}, + ir.PatternString{Line: 221, Value: "$re.Match([]byte($s))"}, }, ReportTemplate: "suggestion: $re.MatchString($s)", SuggestTemplate: "$re.MatchString($s)", WhereExpr: ir.FilterExpr{ - Line: 220, + Line: 222, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 220, + Line: 222, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 220, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, + ir.FilterExpr{Line: 222, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, }, }, ir.FilterExpr{ - Line: 220, + Line: 222, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 220, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 222, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, }, }, ir.Rule{ - Line: 223, + Line: 225, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 223, Value: "$re.FindIndex([]byte($s))"}, + ir.PatternString{Line: 225, Value: "$re.FindIndex([]byte($s))"}, }, ReportTemplate: "suggestion: $re.FindStringIndex($s)", SuggestTemplate: "$re.FindStringIndex($s)", WhereExpr: ir.FilterExpr{ - Line: 224, + Line: 226, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 224, + Line: 226, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 224, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, + ir.FilterExpr{Line: 226, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, }, }, ir.FilterExpr{ - Line: 224, + Line: 226, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 224, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 226, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, }, }, ir.Rule{ - Line: 227, + Line: 229, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 227, Value: "$re.FindAllIndex([]byte($s), $n)"}, + ir.PatternString{Line: 229, Value: "$re.FindAllIndex([]byte($s), $n)"}, }, ReportTemplate: "suggestion: $re.FindAllStringIndex($s, $n)", SuggestTemplate: "$re.FindAllStringIndex($s, $n)", WhereExpr: ir.FilterExpr{ - Line: 228, + Line: 230, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 228, + Line: 230, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 228, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, + ir.FilterExpr{Line: 230, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}, }, }, ir.FilterExpr{ - Line: 228, + Line: 230, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 228, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 230, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, @@ -920,7 +922,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 237, + Line: 239, Name: "indexAlloc", MatcherName: "m", DocTags: []string{ @@ -932,25 +934,25 @@ var PrecompiledRules = &ir.File{ DocNote: "See Go issue for details: https://github.com/golang/go/issues/25864", Rules: []ir.Rule{ ir.Rule{ - Line: 238, + Line: 240, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 238, Value: "strings.Index(string($x), $y)"}, + ir.PatternString{Line: 240, Value: "strings.Index(string($x), $y)"}, }, ReportTemplate: "consider replacing $$ with bytes.Index($x, []byte($y))", WhereExpr: ir.FilterExpr{ - Line: 239, + Line: 241, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 239, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 239, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + 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"}, }, }, }, }, }, ir.RuleGroup{ - Line: 247, + Line: 249, Name: "wrapperFunc", MatcherName: "m", DocTags: []string{ @@ -961,111 +963,111 @@ var PrecompiledRules = &ir.File{ DocAfter: "wg.Done()", Rules: []ir.Rule{ ir.Rule{ - Line: 248, + Line: 250, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 248, Value: "$wg.Add(-1)"}, + ir.PatternString{Line: 250, Value: "$wg.Add(-1)"}, }, ReportTemplate: "use WaitGroup.Done method in `$$`", WhereExpr: ir.FilterExpr{ - Line: 249, + Line: 251, Op: ir.FilterVarTypeIsOp, Src: "m[\"wg\"].Type.Is(`sync.WaitGroup`)", Value: "wg", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 249, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}, + ir.FilterExpr{Line: 251, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}, }, }, }, ir.Rule{ - Line: 252, + Line: 254, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 252, Value: "$buf.Truncate(0)"}, + ir.PatternString{Line: 254, Value: "$buf.Truncate(0)"}, }, ReportTemplate: "use Buffer.Reset method in `$$`", WhereExpr: ir.FilterExpr{ - Line: 253, + Line: 255, Op: ir.FilterVarTypeIsOp, Src: "m[\"buf\"].Type.Is(`bytes.Buffer`)", Value: "buf", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 253, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}, + ir.FilterExpr{Line: 255, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}, }, }, }, ir.Rule{ - Line: 256, + Line: 258, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 256, Value: "http.HandlerFunc(http.NotFound)"}, + ir.PatternString{Line: 258, Value: "http.HandlerFunc(http.NotFound)"}, }, ReportTemplate: "use http.NotFoundHandler method in `$$`", }, ir.Rule{ - Line: 258, + Line: 260, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 258, Value: "strings.SplitN($_, $_, -1)"}, + ir.PatternString{Line: 260, Value: "strings.SplitN($_, $_, -1)"}, }, ReportTemplate: "use strings.Split method in `$$`", }, ir.Rule{ - Line: 259, + Line: 261, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 259, Value: "strings.Replace($_, $_, $_, -1)"}, + ir.PatternString{Line: 261, Value: "strings.Replace($_, $_, $_, -1)"}, }, ReportTemplate: "use strings.ReplaceAll method in `$$`", }, ir.Rule{ - Line: 260, + Line: 262, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 260, Value: "strings.Map(unicode.ToTitle, $_)"}, + ir.PatternString{Line: 262, Value: "strings.Map(unicode.ToTitle, $_)"}, }, ReportTemplate: "use strings.ToTitle method in `$$`", }, ir.Rule{ - Line: 262, + Line: 264, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 262, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}, + ir.PatternString{Line: 264, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}, }, ReportTemplate: "use bytes.Split method in `$$`", }, ir.Rule{ - Line: 263, + Line: 265, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 263, Value: "bytes.Replace($_, $_, $_, -1)"}, + ir.PatternString{Line: 265, Value: "bytes.Replace($_, $_, $_, -1)"}, }, ReportTemplate: "use bytes.ReplaceAll method in `$$`", }, ir.Rule{ - Line: 264, + Line: 266, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 264, Value: "bytes.Map(unicode.ToUpper, $_)"}, + ir.PatternString{Line: 266, Value: "bytes.Map(unicode.ToUpper, $_)"}, }, ReportTemplate: "use bytes.ToUpper method in `$$`", }, ir.Rule{ - Line: 265, + Line: 267, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 265, Value: "bytes.Map(unicode.ToLower, $_)"}, + ir.PatternString{Line: 267, Value: "bytes.Map(unicode.ToLower, $_)"}, }, ReportTemplate: "use bytes.ToLower method in `$$`", }, ir.Rule{ - Line: 266, + Line: 268, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 266, Value: "bytes.Map(unicode.ToTitle, $_)"}, + ir.PatternString{Line: 268, Value: "bytes.Map(unicode.ToTitle, $_)"}, }, ReportTemplate: "use bytes.ToTitle method in `$$`", }, ir.Rule{ - Line: 268, + Line: 270, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 268, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}, + ir.PatternString{Line: 270, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}, }, ReportTemplate: "use draw.Draw method in `$$`", }, }, }, ir.RuleGroup{ - Line: 276, + Line: 278, Name: "regexpMust", MatcherName: "m", DocTags: []string{ @@ -1076,26 +1078,26 @@ var PrecompiledRules = &ir.File{ DocAfter: "re := regexp.MustCompile(\"const pattern\")", Rules: []ir.Rule{ ir.Rule{ - Line: 277, + Line: 279, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 277, Value: "regexp.Compile($pat)"}, + ir.PatternString{Line: 279, Value: "regexp.Compile($pat)"}, }, ReportTemplate: "for const patterns like $pat, use regexp.MustCompile", WhereExpr: ir.FilterExpr{ - Line: 278, + Line: 280, Op: ir.FilterVarConstOp, Src: "m[\"pat\"].Const", Value: "pat", }, }, ir.Rule{ - Line: 281, + Line: 283, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 281, Value: "regexp.CompilePOSIX($pat)"}, + ir.PatternString{Line: 283, Value: "regexp.CompilePOSIX($pat)"}, }, ReportTemplate: "for const patterns like $pat, use regexp.MustCompilePOSIX", WhereExpr: ir.FilterExpr{ - Line: 282, + Line: 284, Op: ir.FilterVarConstOp, Src: "m[\"pat\"].Const", Value: "pat", @@ -1104,7 +1106,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 290, + Line: 292, Name: "badCall", MatcherName: "m", DocTags: []string{ @@ -1115,24 +1117,24 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.Replace(s, from, to, -1)", Rules: []ir.Rule{ ir.Rule{ - Line: 291, + Line: 293, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 291, Value: "strings.Replace($_, $_, $_, $zero)"}, + ir.PatternString{Line: 293, Value: "strings.Replace($_, $_, $_, $zero)"}, }, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 292, + Line: 294, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 292, + Line: 294, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, ir.FilterExpr{ - Line: 292, + Line: 294, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1142,24 +1144,24 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, ir.Rule{ - Line: 294, + Line: 296, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 294, Value: "bytes.Replace($_, $_, $_, $zero)"}, + ir.PatternString{Line: 296, Value: "bytes.Replace($_, $_, $_, $zero)"}, }, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 295, + Line: 297, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 295, + Line: 297, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, ir.FilterExpr{ - Line: 295, + Line: 297, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1169,24 +1171,24 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, ir.Rule{ - Line: 298, + Line: 300, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 298, Value: "strings.SplitN($_, $_, $zero)"}, + ir.PatternString{Line: 300, Value: "strings.SplitN($_, $_, $zero)"}, }, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 299, + Line: 301, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 299, + Line: 301, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, ir.FilterExpr{ - Line: 299, + Line: 301, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1196,24 +1198,24 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, ir.Rule{ - Line: 301, + Line: 303, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 301, Value: "bytes.SplitN($_, $_, $zero)"}, + ir.PatternString{Line: 303, Value: "bytes.SplitN($_, $_, $zero)"}, }, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 302, + Line: 304, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 302, + Line: 304, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, ir.FilterExpr{ - Line: 302, + Line: 304, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1223,23 +1225,23 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, ir.Rule{ - Line: 305, + Line: 307, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 305, Value: "append($_)"}, + ir.PatternString{Line: 307, Value: "append($_)"}, }, ReportTemplate: "no-op append call, probably missing arguments", }, ir.Rule{ - Line: 307, + Line: 309, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 307, Value: "filepath.Join($_)"}, + ir.PatternString{Line: 309, Value: "filepath.Join($_)"}, }, ReportTemplate: "suspicious Join on 1 argument", }, }, }, ir.RuleGroup{ - Line: 314, + Line: 316, Name: "assignOp", MatcherName: "m", DocTags: []string{ @@ -1250,113 +1252,113 @@ var PrecompiledRules = &ir.File{ DocAfter: "x *= 2", Rules: []ir.Rule{ ir.Rule{ - Line: 315, + Line: 317, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 315, Value: "$x = $x + 1"}, + ir.PatternString{Line: 317, Value: "$x = $x + 1"}, }, ReportTemplate: "replace `$$` with `$x++`", - WhereExpr: ir.FilterExpr{Line: 315, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 317, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 316, + Line: 318, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 316, Value: "$x = $x - 1"}, + ir.PatternString{Line: 318, Value: "$x = $x - 1"}, }, ReportTemplate: "replace `$$` with `$x--`", - WhereExpr: ir.FilterExpr{Line: 316, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 318, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 318, + Line: 320, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 318, Value: "$x = $x + $y"}, + ir.PatternString{Line: 320, Value: "$x = $x + $y"}, }, ReportTemplate: "replace `$$` with `$x += $y`", - WhereExpr: ir.FilterExpr{Line: 318, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 320, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 319, + Line: 321, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 319, Value: "$x = $x - $y"}, + ir.PatternString{Line: 321, Value: "$x = $x - $y"}, }, ReportTemplate: "replace `$$` with `$x -= $y`", - WhereExpr: ir.FilterExpr{Line: 319, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 321, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 321, + Line: 323, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 321, Value: "$x = $x * $y"}, + ir.PatternString{Line: 323, Value: "$x = $x * $y"}, }, ReportTemplate: "replace `$$` with `$x *= $y`", - WhereExpr: ir.FilterExpr{Line: 321, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 323, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 322, + Line: 324, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 322, Value: "$x = $x / $y"}, + ir.PatternString{Line: 324, Value: "$x = $x / $y"}, }, ReportTemplate: "replace `$$` with `$x /= $y`", - WhereExpr: ir.FilterExpr{Line: 322, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 324, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 323, + Line: 325, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 323, Value: "$x = $x % $y"}, + ir.PatternString{Line: 325, Value: "$x = $x % $y"}, }, ReportTemplate: "replace `$$` with `$x %= $y`", - WhereExpr: ir.FilterExpr{Line: 323, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 325, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 324, + Line: 326, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 324, Value: "$x = $x & $y"}, + ir.PatternString{Line: 326, Value: "$x = $x & $y"}, }, ReportTemplate: "replace `$$` with `$x &= $y`", - WhereExpr: ir.FilterExpr{Line: 324, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 326, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 325, + Line: 327, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 325, Value: "$x = $x | $y"}, + ir.PatternString{Line: 327, Value: "$x = $x | $y"}, }, ReportTemplate: "replace `$$` with `$x |= $y`", - WhereExpr: ir.FilterExpr{Line: 325, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 327, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 326, + Line: 328, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 326, Value: "$x = $x ^ $y"}, + ir.PatternString{Line: 328, Value: "$x = $x ^ $y"}, }, ReportTemplate: "replace `$$` with `$x ^= $y`", - WhereExpr: ir.FilterExpr{Line: 326, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 328, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 327, + Line: 329, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 327, Value: "$x = $x << $y"}, + ir.PatternString{Line: 329, Value: "$x = $x << $y"}, }, ReportTemplate: "replace `$$` with `$x <<= $y`", - WhereExpr: ir.FilterExpr{Line: 327, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 329, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 328, + Line: 330, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 328, Value: "$x = $x >> $y"}, + ir.PatternString{Line: 330, Value: "$x = $x >> $y"}, }, ReportTemplate: "replace `$$` with `$x >>= $y`", - WhereExpr: ir.FilterExpr{Line: 328, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 330, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, ir.Rule{ - Line: 329, + Line: 331, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 329, Value: "$x = $x &^ $y"}, + ir.PatternString{Line: 331, Value: "$x = $x &^ $y"}, }, ReportTemplate: "replace `$$` with `$x &^= $y`", - WhereExpr: ir.FilterExpr{Line: 329, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 331, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, ir.RuleGroup{ - Line: 336, + Line: 338, Name: "preferWriteByte", MatcherName: "m", DocTags: []string{ @@ -1369,49 +1371,49 @@ var PrecompiledRules = &ir.File{ DocAfter: "w.WriteByte('\\n')", Rules: []ir.Rule{ ir.Rule{ - Line: 340, + Line: 342, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 340, Value: "$w.WriteRune($c)"}, + ir.PatternString{Line: 342, Value: "$w.WriteRune($c)"}, }, ReportTemplate: "consider writing single byte rune $c with $w.WriteByte($c)", WhereExpr: ir.FilterExpr{ - Line: 341, + 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: 341, + Line: 343, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 341, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}, + ir.FilterExpr{Line: 343, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}, }, }, ir.FilterExpr{ - Line: 341, + Line: 343, Op: ir.FilterAndOp, Src: "(m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 341, + Line: 343, Op: ir.FilterVarConstOp, Src: "m[\"c\"].Const", Value: "c", }, ir.FilterExpr{ - Line: 341, + Line: 343, Op: ir.FilterLtOp, Src: "m[\"c\"].Value.Int() < runeSelf", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 341, + Line: 343, Op: ir.FilterVarValueIntOp, Src: "m[\"c\"].Value.Int()", Value: "c", }, ir.FilterExpr{ - Line: 341, + Line: 343, Op: ir.FilterIntOp, Src: "runeSelf", Value: int64(128), @@ -1426,7 +1428,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 349, + Line: 351, Name: "preferFprint", MatcherName: "m", DocTags: []string{ @@ -1438,60 +1440,84 @@ var PrecompiledRules = &ir.File{ DocAfter: "fmt.Fprintf(w, \"%x\", 10)", Rules: []ir.Rule{ ir.Rule{ - Line: 350, + Line: 352, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 350, Value: "$w.Write([]byte(fmt.Sprint($*args)))"}, + 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{ - Line: 351, + Line: 353, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 351, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, + ir.FilterExpr{Line: 353, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, }, }, }, ir.Rule{ - Line: 355, + Line: 357, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 355, Value: "$w.Write([]byte(fmt.Sprintf($*args)))"}, + 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{ - Line: 356, + Line: 358, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 356, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, + ir.FilterExpr{Line: 358, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, }, }, }, ir.Rule{ - Line: 360, + Line: 362, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 360, Value: "$w.Write([]byte(fmt.Sprintln($*args)))"}, + 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{ - Line: 361, + Line: 363, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 361, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}, + 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))"}, + }, + 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))"}, + }, + 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))"}, + }, + ReportTemplate: "suggestion: fmt.Fprintln($w, $args)", + SuggestTemplate: "fmt.Fprintln($w, $args)", + }, }, }, ir.RuleGroup{ - Line: 370, + Line: 376, Name: "dupArg", MatcherName: "m", DocTags: []string{ @@ -1502,62 +1528,62 @@ var PrecompiledRules = &ir.File{ DocAfter: "copy(dst, src)", Rules: []ir.Rule{ ir.Rule{ - Line: 371, + Line: 377, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 371, Value: "$x.Equal($x)"}, - ir.PatternString{Line: 371, Value: "$x.Equals($x)"}, - ir.PatternString{Line: 371, Value: "$x.Compare($x)"}, - ir.PatternString{Line: 371, Value: "$x.Cmp($x)"}, + 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)"}, }, ReportTemplate: "suspicious method call with the same argument and receiver", - WhereExpr: ir.FilterExpr{Line: 372, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - }, - ir.Rule{ - Line: 375, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 375, Value: "copy($x, $x)"}, - ir.PatternString{Line: 376, Value: "math.Max($x, $x)"}, - ir.PatternString{Line: 377, Value: "math.Min($x, $x)"}, - ir.PatternString{Line: 378, Value: "reflect.Copy($x, $x)"}, - ir.PatternString{Line: 379, Value: "reflect.DeepEqual($x, $x)"}, - ir.PatternString{Line: 380, Value: "strings.Contains($x, $x)"}, - ir.PatternString{Line: 381, Value: "strings.Compare($x, $x)"}, - ir.PatternString{Line: 382, Value: "strings.EqualFold($x, $x)"}, - ir.PatternString{Line: 383, Value: "strings.HasPrefix($x, $x)"}, - ir.PatternString{Line: 384, Value: "strings.HasSuffix($x, $x)"}, - ir.PatternString{Line: 385, Value: "strings.Index($x, $x)"}, - ir.PatternString{Line: 386, Value: "strings.LastIndex($x, $x)"}, - ir.PatternString{Line: 387, Value: "strings.Split($x, $x)"}, - ir.PatternString{Line: 388, Value: "strings.SplitAfter($x, $x)"}, - ir.PatternString{Line: 389, Value: "strings.SplitAfterN($x, $x, $_)"}, - ir.PatternString{Line: 390, Value: "strings.SplitN($x, $x, $_)"}, - ir.PatternString{Line: 391, Value: "strings.Replace($_, $x, $x, $_)"}, - ir.PatternString{Line: 392, Value: "strings.ReplaceAll($_, $x, $x)"}, - ir.PatternString{Line: 393, Value: "bytes.Contains($x, $x)"}, - ir.PatternString{Line: 394, Value: "bytes.Compare($x, $x)"}, - ir.PatternString{Line: 395, Value: "bytes.Equal($x, $x)"}, - ir.PatternString{Line: 396, Value: "bytes.EqualFold($x, $x)"}, - ir.PatternString{Line: 397, Value: "bytes.HasPrefix($x, $x)"}, - ir.PatternString{Line: 398, Value: "bytes.HasSuffix($x, $x)"}, - ir.PatternString{Line: 399, Value: "bytes.Index($x, $x)"}, - ir.PatternString{Line: 400, Value: "bytes.LastIndex($x, $x)"}, - ir.PatternString{Line: 401, Value: "bytes.Split($x, $x)"}, - ir.PatternString{Line: 402, Value: "bytes.SplitAfter($x, $x)"}, - ir.PatternString{Line: 403, Value: "bytes.SplitAfterN($x, $x, $_)"}, - ir.PatternString{Line: 404, Value: "bytes.SplitN($x, $x, $_)"}, - ir.PatternString{Line: 405, Value: "bytes.Replace($_, $x, $x, $_)"}, - ir.PatternString{Line: 406, Value: "bytes.ReplaceAll($_, $x, $x)"}, - ir.PatternString{Line: 407, Value: "types.Identical($x, $x)"}, - ir.PatternString{Line: 408, Value: "types.IdenticalIgnoreTags($x, $x)"}, - ir.PatternString{Line: 409, Value: "draw.Draw($x, $_, $x, $_, $_)"}, + 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, $_, $_)"}, }, ReportTemplate: "suspicious duplicated args in $$", - WhereExpr: ir.FilterExpr{Line: 410, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 416, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, ir.RuleGroup{ - Line: 418, + Line: 424, Name: "returnAfterHttpError", MatcherName: "m", DocTags: []string{ @@ -1569,9 +1595,9 @@ var PrecompiledRules = &ir.File{ DocAfter: "if err != nil { http.Error(...); return; }", Rules: []ir.Rule{ ir.Rule{ - Line: 419, + Line: 425, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 419, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}, + ir.PatternString{Line: 425, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}, }, ReportTemplate: "Possibly return is missed after the http.Error call", LocationVar: "w", @@ -1579,7 +1605,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 428, + Line: 434, Name: "preferFilepathJoin", MatcherName: "m", DocTags: []string{ @@ -1591,33 +1617,33 @@ var PrecompiledRules = &ir.File{ DocAfter: "filepath.Join(x, y)", Rules: []ir.Rule{ ir.Rule{ - Line: 429, + Line: 435, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 429, Value: "$x + string(os.PathSeparator) + $y"}, + 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: 430, + Line: 436, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`string`) && m[\"y\"].Type.Is(`string`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 430, + Line: 436, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`string`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 430, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, ir.FilterExpr{ - Line: 430, + Line: 436, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`string`)", Value: "y", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 430, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, }, @@ -1626,7 +1652,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 439, + Line: 445, Name: "preferStringWriter", MatcherName: "m", DocTags: []string{ @@ -1638,43 +1664,43 @@ var PrecompiledRules = &ir.File{ DocAfter: "w.WriteString(\"foo\")", Rules: []ir.Rule{ ir.Rule{ - Line: 440, + Line: 446, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 440, Value: "$w.Write([]byte($s))"}, + 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{ - Line: 441, + Line: 447, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 441, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, + ir.FilterExpr{Line: 447, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, }, }, }, ir.Rule{ - Line: 445, + Line: 451, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 445, Value: "io.WriteString($w, $s)"}, + 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{ - Line: 446, + Line: 452, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 446, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, + ir.FilterExpr{Line: 452, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}, }, }, }, }, }, ir.RuleGroup{ - Line: 455, + Line: 461, Name: "sliceClear", MatcherName: "m", DocTags: []string{ @@ -1686,24 +1712,24 @@ var PrecompiledRules = &ir.File{ DocAfter: "for i := range buf { buf[i] = 0 }", Rules: []ir.Rule{ ir.Rule{ - Line: 456, + Line: 462, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 456, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}, + 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: 457, + Line: 463, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 457, + Line: 463, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, ir.FilterExpr{ - Line: 457, + Line: 463, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1714,7 +1740,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 465, + Line: 471, Name: "syncMapLoadAndDelete", MatcherName: "m", DocTags: []string{ @@ -1726,29 +1752,29 @@ var PrecompiledRules = &ir.File{ DocAfter: "v, deleted := m.LoadAndDelete(k); if deleted { f(v) }", Rules: []ir.Rule{ ir.Rule{ - Line: 466, + Line: 472, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 466, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}, + 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: 467, + Line: 473, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\") &&\n\tm[\"m\"].Type.Is(`*sync.Map`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 467, + Line: 473, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\")", Value: "1.15", }, ir.FilterExpr{ - Line: 468, + Line: 474, Op: ir.FilterVarTypeIsOp, Src: "m[\"m\"].Type.Is(`*sync.Map`)", Value: "m", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 468, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}, + ir.FilterExpr{Line: 474, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}, }, }, }, @@ -1757,7 +1783,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 476, + Line: 482, Name: "sprintfQuotedString", MatcherName: "m", DocTags: []string{ @@ -1769,32 +1795,32 @@ var PrecompiledRules = &ir.File{ DocAfter: "fmt.Sprintf(`%q`, s)", Rules: []ir.Rule{ ir.Rule{ - Line: 477, + Line: 483, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 477, Value: "fmt.Sprintf($s, $*_)"}, + ir.PatternString{Line: 483, Value: "fmt.Sprintf($s, $*_)"}, }, ReportTemplate: "use %q instead of \"%s\" for quoted strings", WhereExpr: ir.FilterExpr{ - Line: 478, + Line: 484, Op: ir.FilterOrOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\") ||\n\tm[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 478, + Line: 484, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\")", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 478, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}, + ir.FilterExpr{Line: 484, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}, }, }, ir.FilterExpr{ - Line: 479, + Line: 485, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 479, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}, + ir.FilterExpr{Line: 485, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}, }, }, }, @@ -1803,7 +1829,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 487, + Line: 493, Name: "offBy1", MatcherName: "m", DocTags: []string{ @@ -1814,84 +1840,84 @@ var PrecompiledRules = &ir.File{ DocAfter: "xs[len(xs)-1]", Rules: []ir.Rule{ ir.Rule{ - Line: 488, + Line: 494, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 488, Value: "$x[len($x)]"}, + 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{ - Line: 489, + Line: 495, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"x\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 489, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + ir.FilterExpr{Line: 495, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, ir.FilterExpr{ - Line: 489, + Line: 495, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]$_`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 489, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, + ir.FilterExpr{Line: 495, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, }, }, }, }, }, ir.Rule{ - Line: 496, + Line: 502, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 497, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, - ir.PatternString{Line: 498, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, - ir.PatternString{Line: 499, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, - ir.PatternString{Line: 500, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, + 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:]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[$i+1:]", WhereExpr: ir.FilterExpr{ - Line: 501, + Line: 507, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 501, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - ir.FilterExpr{Line: 501, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + 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"}, }, }, LocationVar: "slicing", }, ir.Rule{ - Line: 505, + Line: 511, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 506, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, - ir.PatternString{Line: 507, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, - ir.PatternString{Line: 508, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, - ir.PatternString{Line: 509, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, + 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]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[:$i+1]", WhereExpr: ir.FilterExpr{ - Line: 510, + Line: 516, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 510, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - ir.FilterExpr{Line: 510, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + 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"}, }, }, LocationVar: "slicing", }, ir.Rule{ - Line: 514, + Line: 520, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 515, Value: "$s[strings.Index($s, $_):]"}, - ir.PatternString{Line: 516, Value: "$s[:strings.Index($s, $_)]"}, - ir.PatternString{Line: 517, Value: "$s[bytes.Index($s, $_):]"}, - ir.PatternString{Line: 518, Value: "$s[:bytes.Index($s, $_)]"}, + 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, $_)]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do Index()+1", }, }, }, ir.RuleGroup{ - Line: 526, + Line: 532, Name: "unslice", MatcherName: "m", DocTags: []string{ @@ -1902,33 +1928,33 @@ var PrecompiledRules = &ir.File{ DocAfter: "copy(b, values...)", Rules: []ir.Rule{ ir.Rule{ - Line: 527, + Line: 533, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 527, Value: "$s[:]"}, + ir.PatternString{Line: 533, Value: "$s[:]"}, }, ReportTemplate: "could simplify $$ to $s", SuggestTemplate: "$s", WhereExpr: ir.FilterExpr{ - Line: 528, + Line: 534, Op: ir.FilterOrOp, Src: "m[\"s\"].Type.Is(`string`) || m[\"s\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 528, + Line: 534, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 528, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, + ir.FilterExpr{Line: 534, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}, }, }, ir.FilterExpr{ - Line: 528, + Line: 534, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`[]$_`)", Value: "s", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 528, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, + ir.FilterExpr{Line: 534, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}, }, }, }, @@ -1937,7 +1963,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 537, + Line: 543, Name: "yodaStyleExpr", MatcherName: "m", DocTags: []string{ @@ -1949,37 +1975,37 @@ var PrecompiledRules = &ir.File{ DocAfter: "return ptr != nil", Rules: []ir.Rule{ ir.Rule{ - Line: 538, + Line: 544, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 538, Value: "$constval != $x"}, + ir.PatternString{Line: 544, Value: "$constval != $x"}, }, ReportTemplate: "consider to change order in expression to $x != $constval", WhereExpr: ir.FilterExpr{ - Line: 538, + Line: 544, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 538, + Line: 544, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 538, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, ir.FilterExpr{ - Line: 538, + Line: 544, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 538, + Line: 544, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 538, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, }, @@ -1988,37 +2014,37 @@ var PrecompiledRules = &ir.File{ }, }, ir.Rule{ - Line: 540, + Line: 546, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 540, Value: "$constval == $x"}, + ir.PatternString{Line: 546, Value: "$constval == $x"}, }, ReportTemplate: "consider to change order in expression to $x == $constval", WhereExpr: ir.FilterExpr{ - Line: 540, + Line: 546, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 540, + Line: 546, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 540, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, ir.FilterExpr{ - Line: 540, + Line: 546, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 540, + Line: 546, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 540, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, }, @@ -2027,46 +2053,46 @@ var PrecompiledRules = &ir.File{ }, }, ir.Rule{ - Line: 543, + Line: 549, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 543, Value: "nil != $x"}, + ir.PatternString{Line: 549, Value: "nil != $x"}, }, ReportTemplate: "consider to change order in expression to $x != nil", WhereExpr: ir.FilterExpr{ - Line: 543, + Line: 549, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 543, + Line: 549, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 543, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, }, }, }, ir.Rule{ - Line: 545, + Line: 551, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 545, Value: "nil == $x"}, + ir.PatternString{Line: 551, Value: "nil == $x"}, }, ReportTemplate: "consider to change order in expression to $x == nil", WhereExpr: ir.FilterExpr{ - Line: 545, + Line: 551, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 545, + Line: 551, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 545, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, + ir.FilterExpr{Line: 551, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}, }, }, }, @@ -2075,7 +2101,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 553, + Line: 559, Name: "equalFold", MatcherName: "m", DocTags: []string{ @@ -2087,114 +2113,114 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.EqualFold(x, y)", Rules: []ir.Rule{ ir.Rule{ - Line: 562, + Line: 568, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 563, Value: "strings.ToLower($x) == $y"}, - ir.PatternString{Line: 564, Value: "strings.ToLower($x) == strings.ToLower($y)"}, - ir.PatternString{Line: 565, Value: "$x == strings.ToLower($y)"}, - ir.PatternString{Line: 566, Value: "strings.ToUpper($x) == $y"}, - ir.PatternString{Line: 567, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, - ir.PatternString{Line: 568, Value: "$x == strings.ToUpper($y)"}, + 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)"}, }, ReportTemplate: "consider replacing with strings.EqualFold($x, $y)", - SuggestTemplate: "strings.EqualFold($x, $y)]", + SuggestTemplate: "strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 569, + Line: 575, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 569, + Line: 575, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 569, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 569, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + 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"}, }, }, ir.FilterExpr{ - Line: 569, + Line: 575, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 569, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 569, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + 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"}, }, }, }, }, }, ir.Rule{ - Line: 574, + Line: 580, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 575, Value: "strings.ToLower($x) != $y"}, - ir.PatternString{Line: 576, Value: "strings.ToLower($x) != strings.ToLower($y)"}, - ir.PatternString{Line: 577, Value: "$x != strings.ToLower($y)"}, - ir.PatternString{Line: 578, Value: "strings.ToUpper($x) != $y"}, - ir.PatternString{Line: 579, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, - ir.PatternString{Line: 580, Value: "$x != strings.ToUpper($y)"}, + 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)"}, }, ReportTemplate: "consider replacing with !strings.EqualFold($x, $y)", - SuggestTemplate: "!strings.EqualFold($x, $y)]", + SuggestTemplate: "!strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 581, + Line: 587, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 581, + Line: 587, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 581, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 581, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + 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"}, }, }, ir.FilterExpr{ - Line: 581, + Line: 587, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 581, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 581, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + 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"}, }, }, }, }, }, ir.Rule{ - Line: 586, + Line: 592, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 587, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, - ir.PatternString{Line: 588, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, - ir.PatternString{Line: 589, Value: "bytes.Equal($x, bytes.ToLower($y))"}, - ir.PatternString{Line: 590, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, - ir.PatternString{Line: 591, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, - ir.PatternString{Line: 592, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, + 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))"}, }, ReportTemplate: "consider replacing with bytes.EqualFold($x, $y)", - SuggestTemplate: "bytes.EqualFold($x, $y)]", + SuggestTemplate: "bytes.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 593, + Line: 599, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 593, + Line: 599, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 593, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - ir.FilterExpr{Line: 593, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + 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"}, }, }, ir.FilterExpr{ - Line: 593, + Line: 599, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 593, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - ir.FilterExpr{Line: 593, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + 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"}, }, }, }, @@ -2203,7 +2229,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 602, + Line: 608, Name: "argOrder", MatcherName: "m", DocTags: []string{ @@ -2214,45 +2240,45 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.HasPrefix(userpass, \"#\")", Rules: []ir.Rule{ ir.Rule{ - Line: 603, - SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 604, Value: "strings.HasPrefix($lit, $s)"}, - ir.PatternString{Line: 605, Value: "bytes.HasPrefix($lit, $s)"}, - ir.PatternString{Line: 606, Value: "strings.HasSuffix($lit, $s)"}, - ir.PatternString{Line: 607, Value: "bytes.HasSuffix($lit, $s)"}, - ir.PatternString{Line: 608, Value: "strings.Contains($lit, $s)"}, - ir.PatternString{Line: 609, Value: "bytes.Contains($lit, $s)"}, - ir.PatternString{Line: 610, Value: "strings.TrimPrefix($lit, $s)"}, - ir.PatternString{Line: 611, Value: "bytes.TrimPrefix($lit, $s)"}, - ir.PatternString{Line: 612, Value: "strings.TrimSuffix($lit, $s)"}, - ir.PatternString{Line: 613, Value: "bytes.TrimSuffix($lit, $s)"}, - ir.PatternString{Line: 614, Value: "strings.Split($lit, $s)"}, - ir.PatternString{Line: 615, Value: "bytes.Split($lit, $s)"}, + 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: 616, + 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: 616, + 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: 616, + Line: 622, Op: ir.FilterOrOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 616, + Line: 622, Op: ir.FilterVarConstOp, Src: "m[\"lit\"].Const", Value: "lit", }, ir.FilterExpr{ - Line: 616, + Line: 622, Op: ir.FilterVarConstSliceOp, Src: "m[\"lit\"].ConstSlice", Value: "lit", @@ -2260,23 +2286,23 @@ var PrecompiledRules = &ir.File{ }, }, ir.FilterExpr{ - Line: 617, + Line: 623, Op: ir.FilterNotOp, Src: "!(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 617, + Line: 623, Op: ir.FilterOrOp, Src: "(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 617, + Line: 623, Op: ir.FilterVarConstOp, Src: "m[\"s\"].Const", Value: "s", }, ir.FilterExpr{ - Line: 617, + Line: 623, Op: ir.FilterVarConstSliceOp, Src: "m[\"s\"].ConstSlice", Value: "s", @@ -2288,17 +2314,17 @@ var PrecompiledRules = &ir.File{ }, }, ir.FilterExpr{ - Line: 618, + Line: 624, Op: ir.FilterNotOp, Src: "!m[\"lit\"].Node.Is(`Ident`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 618, + Line: 624, Op: ir.FilterVarNodeIsOp, Src: "m[\"lit\"].Node.Is(`Ident`)", Value: "lit", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 618, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}, + ir.FilterExpr{Line: 624, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}, }, }, }, @@ -2309,7 +2335,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 626, + Line: 632, Name: "stringConcatSimplify", MatcherName: "m", DocTags: []string{ @@ -2321,25 +2347,25 @@ var PrecompiledRules = &ir.File{ DocAfter: "x + \"_\" + y", Rules: []ir.Rule{ ir.Rule{ - Line: 627, + Line: 633, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 627, Value: "strings.Join([]string{$x, $y}, \"\")"}, + ir.PatternString{Line: 633, Value: "strings.Join([]string{$x, $y}, \"\")"}, }, ReportTemplate: "suggestion: $x + $y", SuggestTemplate: "$x + $y", }, ir.Rule{ - Line: 628, + Line: 634, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 628, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}, + ir.PatternString{Line: 634, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}, }, ReportTemplate: "suggestion: $x + $y + $z", SuggestTemplate: "$x + $y + $z", }, ir.Rule{ - Line: 629, + Line: 635, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 629, Value: "strings.Join([]string{$x, $y}, $glue)"}, + ir.PatternString{Line: 635, Value: "strings.Join([]string{$x, $y}, $glue)"}, }, ReportTemplate: "suggestion: $x + $glue + $y", SuggestTemplate: "$x + $glue + $y", @@ -2347,7 +2373,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 636, + Line: 642, Name: "timeExprSimplify", MatcherName: "m", DocTags: []string{ @@ -2359,44 +2385,44 @@ var PrecompiledRules = &ir.File{ DocAfter: "t.UnixMilli()", Rules: []ir.Rule{ ir.Rule{ - Line: 637, + Line: 647, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 637, Value: "$t.Unix() / 1000"}, + ir.PatternString{Line: 647, Value: "$t.Unix() / 1000"}, }, ReportTemplate: "use $t.UnixMilli() instead of $$", SuggestTemplate: "$t.UnixMilli()", WhereExpr: ir.FilterExpr{ - Line: 638, + Line: 648, Op: ir.FilterAndOp, - Src: "m.GoVersion().GreaterEqThan(\"1.17\") &&\n\t(m[\"t\"].Type.Is(`time.Time`) || m[\"t\"].Type.Is(`*time.Time`))", + Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 638, + Line: 648, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, ir.FilterExpr{ - Line: 639, + Line: 648, Op: ir.FilterOrOp, - Src: "(m[\"t\"].Type.Is(`time.Time`) || m[\"t\"].Type.Is(`*time.Time`))", + Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 639, + Line: 648, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 639, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, + ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, }, }, ir.FilterExpr{ - Line: 639, + Line: 648, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 639, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, + ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, }, }, }, @@ -2405,44 +2431,44 @@ var PrecompiledRules = &ir.File{ }, }, ir.Rule{ - Line: 643, + Line: 652, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 643, Value: "$t.UnixNano() * 1000"}, + ir.PatternString{Line: 652, Value: "$t.UnixNano() * 1000"}, }, ReportTemplate: "use $t.UnixMicro() instead of $$", SuggestTemplate: "$t.UnixMicro()", WhereExpr: ir.FilterExpr{ - Line: 644, + Line: 653, Op: ir.FilterAndOp, - Src: "m.GoVersion().GreaterEqThan(\"1.17\") &&\n\t(m[\"t\"].Type.Is(`time.Time`) || m[\"t\"].Type.Is(`*time.Time`))", + Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 644, + Line: 653, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, ir.FilterExpr{ - Line: 645, + Line: 653, Op: ir.FilterOrOp, - Src: "(m[\"t\"].Type.Is(`time.Time`) || m[\"t\"].Type.Is(`*time.Time`))", + Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 645, + Line: 653, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 645, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, + ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}, }, }, ir.FilterExpr{ - Line: 645, + Line: 653, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 645, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, + ir.FilterExpr{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}, }, }, }, @@ -2453,7 +2479,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 654, + Line: 662, Name: "exposedSyncMutex", MatcherName: "m", DocTags: []string{ @@ -2465,47 +2491,47 @@ var PrecompiledRules = &ir.File{ DocAfter: "type Foo struct{ ...; mu sync.Mutex; ... }", Rules: []ir.Rule{ ir.Rule{ - Line: 655, + Line: 667, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 655, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}, + ir.PatternString{Line: 667, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}, }, ReportTemplate: "don't embed sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 656, + Line: 668, Op: ir.FilterVarTextMatchesOp, - Src: "m[\"x\"].Text.Matches(`^\\p{Lu}`)", + Src: "isExported(m[\"x\"])", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 656, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, + ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, }, }, }, ir.Rule{ - Line: 659, + Line: 671, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 659, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}, + ir.PatternString{Line: 671, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}, }, ReportTemplate: "don't embed *sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 660, + Line: 672, Op: ir.FilterVarTextMatchesOp, - Src: "m[\"x\"].Text.Matches(`^\\p{Lu}`)", + Src: "isExported(m[\"x\"])", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 660, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, + ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, }, }, }, ir.Rule{ - Line: 663, + Line: 675, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 663, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}, + ir.PatternString{Line: 675, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}, }, ReportTemplate: "don't embed sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 664, + Line: 676, Op: ir.FilterVarTextMatchesOp, - Src: "m[\"x\"].Text.Matches(`^\\p{Lu}`)", + Src: "isExported(m[\"x\"])", Value: "x", Args: []ir.FilterExpr{ ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, @@ -2513,25 +2539,25 @@ var PrecompiledRules = &ir.File{ }, }, ir.Rule{ - Line: 667, + Line: 679, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 667, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}, + ir.PatternString{Line: 679, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}, }, ReportTemplate: "don't embed *sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 668, + Line: 680, Op: ir.FilterVarTextMatchesOp, - Src: "m[\"x\"].Text.Matches(`^\\p{Lu}`)", + Src: "isExported(m[\"x\"])", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 668, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, + ir.FilterExpr{Line: 664, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}, }, }, }, }, }, ir.RuleGroup{ - Line: 676, + Line: 688, Name: "badSorting", MatcherName: "m", DocTags: []string{ @@ -2543,60 +2569,60 @@ var PrecompiledRules = &ir.File{ DocAfter: "sort.Strings(xs)", Rules: []ir.Rule{ ir.Rule{ - Line: 677, + Line: 689, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 677, Value: "$x = sort.IntSlice($x)"}, + 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{ - Line: 678, + Line: 690, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]int`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 678, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}, + ir.FilterExpr{Line: 690, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}, }, }, }, ir.Rule{ - Line: 682, + Line: 694, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 682, Value: "$x = sort.Float64Slice($x)"}, + 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{ - Line: 683, + Line: 695, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]float64`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 683, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}, + ir.FilterExpr{Line: 695, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}, }, }, }, ir.Rule{ - Line: 687, + Line: 699, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 687, Value: "$x = sort.StringSlice($x)"}, + 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{ - Line: 688, + Line: 700, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]string`)", Value: "x", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 688, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}, + ir.FilterExpr{Line: 700, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}, }, }, }, }, }, ir.RuleGroup{ - Line: 697, + Line: 709, Name: "externalErrorReassign", MatcherName: "m", DocTags: []string{ @@ -2608,32 +2634,32 @@ var PrecompiledRules = &ir.File{ DocAfter: "/* don't do it */", Rules: []ir.Rule{ ir.Rule{ - Line: 698, + Line: 710, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 698, Value: "$pkg.$err = $x"}, + ir.PatternString{Line: 710, Value: "$pkg.$err = $x"}, }, ReportTemplate: "suspicious reassigment of error from another package", WhereExpr: ir.FilterExpr{ - Line: 699, + Line: 711, Op: ir.FilterAndOp, Src: "m[\"err\"].Type.Is(`error`) && m[\"pkg\"].Object.Is(`PkgName`)", Args: []ir.FilterExpr{ ir.FilterExpr{ - Line: 699, + Line: 711, Op: ir.FilterVarTypeIsOp, Src: "m[\"err\"].Type.Is(`error`)", Value: "err", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 699, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}, + ir.FilterExpr{Line: 711, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}, }, }, ir.FilterExpr{ - Line: 699, + Line: 711, Op: ir.FilterVarObjectIsOp, Src: "m[\"pkg\"].Object.Is(`PkgName`)", Value: "pkg", Args: []ir.FilterExpr{ - ir.FilterExpr{Line: 699, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}, + ir.FilterExpr{Line: 711, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}, }, }, }, @@ -2642,7 +2668,7 @@ var PrecompiledRules = &ir.File{ }, }, ir.RuleGroup{ - Line: 707, + Line: 719, Name: "emptyDecl", MatcherName: "m", DocTags: []string{ @@ -2654,27 +2680,71 @@ var PrecompiledRules = &ir.File{ DocAfter: "/* nothing */", Rules: []ir.Rule{ ir.Rule{ - Line: 708, + Line: 720, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 708, Value: "var()"}, + ir.PatternString{Line: 720, Value: "var()"}, }, ReportTemplate: "empty var() block", }, ir.Rule{ - Line: 709, + Line: 721, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 709, Value: "const()"}, + ir.PatternString{Line: 721, Value: "const()"}, }, ReportTemplate: "empty const() block", }, ir.Rule{ - Line: 710, + Line: 722, SyntaxPatterns: []ir.PatternString{ - ir.PatternString{Line: 710, Value: "type()"}, + 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)", + Rules: []ir.Rule{ + ir.Rule{ + Line: 730, + SyntaxPatterns: []ir.PatternString{ + 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", + }, + }, + }, + }, + ir.Rule{ + Line: 735, + SyntaxPatterns: []ir.PatternString{ + 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))", + }, + }, + }, }, } + diff --git a/checkers/testdata/commentFormatting/negative_tests.go b/checkers/testdata/commentFormatting/negative_tests.go index 1afbc9ce2..00d27b1c2 100644 --- a/checkers/testdata/commentFormatting/negative_tests.go +++ b/checkers/testdata/commentFormatting/negative_tests.go @@ -3,6 +3,9 @@ package checker_test //nolint reason +//noinspection this is ignored +//noinspection ALL + /* multi-line comments are ignored diff --git a/checkers/testdata/commentFormatting/positive_tests.go b/checkers/testdata/commentFormatting/positive_tests.go index e2b3b6abf..ba7d72b4c 100644 --- a/checkers/testdata/commentFormatting/positive_tests.go +++ b/checkers/testdata/commentFormatting/positive_tests.go @@ -6,6 +6,12 @@ package checker_test /*! put a space between `//` and comment text */ //nolinto +/*! put a space between `//` and comment text */ +//no inspection + +/*! put a space between `//` and comment text */ +//no inspection something + func f1() { /*! put a space between `//` and comment text */ //block with diff --git a/checkers/testdata/dynamicFmtString/negative_tests.go b/checkers/testdata/dynamicFmtString/negative_tests.go new file mode 100644 index 000000000..7ffdfced0 --- /dev/null +++ b/checkers/testdata/dynamicFmtString/negative_tests.go @@ -0,0 +1,15 @@ +package checker_test + +import ( + "fmt" +) + +var foo = "bar" + +func fmtFormatting() { + fmt.Errorf("%s", foo) + fmt.Errorf("123") + fmt.Errorf("%s", fooError()) +} + +func fooError() string { return "foo" } diff --git a/checkers/testdata/dynamicFmtString/positive_tests.go b/checkers/testdata/dynamicFmtString/positive_tests.go new file mode 100644 index 000000000..5e80c5375 --- /dev/null +++ b/checkers/testdata/dynamicFmtString/positive_tests.go @@ -0,0 +1,19 @@ +package checker_test + +import ( + "fmt" +) + +func fmtUndefinedFormatting() { + foo := "foo happend" + fooFunc := func(k string) (string, string) { return "", "123" } + var barFunc = func() string { return "123" } + /*! use errors.New(foo) or fmt.Errorf("%s", foo) instead */ + fmt.Errorf(foo) + + /*! use errors.New(fooFunc("123")) or fmt.Errorf("%s", fooFunc("123")) instead */ + fmt.Errorf(fooFunc("123")) + + /*! use errors.New(barFunc()) or fmt.Errorf("%s", barFunc()) instead */ + fmt.Errorf(barFunc()) +} diff --git a/checkers/testdata/preferFprint/positive_tests.go b/checkers/testdata/preferFprint/positive_tests.go index 7151c7ae3..7c52b5045 100644 --- a/checkers/testdata/preferFprint/positive_tests.go +++ b/checkers/testdata/preferFprint/positive_tests.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "os" ) func _(w io.Writer) { @@ -21,4 +22,18 @@ func _(w io.Writer) { buf.Write([]byte(fmt.Sprint(1, 2, 3, 4))) /*! fmt.Fprintln(buf, 1, 2, 3, 4) should be preferred to the buf.Write([]byte(fmt.Sprintln(1, 2, 3, 4))) */ buf.Write([]byte(fmt.Sprintln(1, 2, 3, 4))) + + var i int + + /*! suggestion: fmt.Fprint(buf, i) */ + io.WriteString(buf, fmt.Sprint(i)) + + /*! suggestion: fmt.Fprintf(buf, "<%4d>", i) */ + io.WriteString(buf, fmt.Sprintf("<%4d>", i)) + + /*! suggestion: fmt.Fprintln(buf, i, i) */ + io.WriteString(buf, fmt.Sprintln(i, i)) + + /*! suggestion: fmt.Fprint(os.Stdout, i, i) */ + io.WriteString(os.Stdout, fmt.Sprint(i, i)) } diff --git a/checkers/whyNoLint_checker.go b/checkers/whyNoLint_checker.go index 260039f2b..6829433ea 100644 --- a/checkers/whyNoLint_checker.go +++ b/checkers/whyNoLint_checker.go @@ -17,12 +17,11 @@ func init() { Before: `//nolint`, After: `//nolint // reason`, } - re := regexp.MustCompile(`^// *nolint(?::[^ ]+)? *(.*)$`) collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { return astwalk.WalkerForComment(&whyNoLintChecker{ ctx: ctx, - re: re, + re: regexp.MustCompile(`^// *nolint(?::[^ ]+)? *(.*)$`), }), nil }) } diff --git a/framework/lintmain/internal/check/check.go b/framework/lintmain/internal/check/check.go index a38799040..62678e7b6 100644 --- a/framework/lintmain/internal/check/check.go +++ b/framework/lintmain/internal/check/check.go @@ -1,6 +1,7 @@ package check import ( + "bytes" "errors" "flag" "fmt" @@ -13,6 +14,7 @@ import ( "path/filepath" "regexp" "runtime" + "runtime/pprof" "sort" "strings" "sync" @@ -37,10 +39,12 @@ func Main() { {"bind checker params", p.bindCheckerParams}, {"bind default enabled list", p.bindDefaultEnabledList}, {"parse args", p.parseArgs}, + {"start profiling", p.startProfiling}, {"assign checker params", p.assignCheckerParams}, {"load program", p.loadProgram}, {"init checkers", p.initCheckers}, {"run checkers", p.runCheckers}, + {"finish profiling", p.finishProfiling}, {"exit if found issues", p.exit}, } @@ -79,6 +83,11 @@ type program struct { gopath string goroot string + cpuProfile string + memProfile string + + cpuProfileData bytes.Buffer + goVersion string exitCode int checkTests bool @@ -363,6 +372,11 @@ func (p *program) parseArgs() error { flag.StringVar(&p.goVersion, "go", "", `select the Go version to target. Leave as string for the latest`) + flag.StringVar(&p.memProfile, "memprofile", "", + `write memory profile to the specified file`) + flag.StringVar(&p.cpuProfile, "cpuprofile", "", + `write CPU profile to the specified file`) + flag.Parse() p.packages = flag.Args() @@ -389,6 +403,46 @@ func addTrailingSlash(s string) string { return s + string(os.PathSeparator) } +func (p *program) startProfiling() error { + if p.memProfile != "" { + runtime.MemProfileRate = 2048 + } + + if p.cpuProfile == "" { + return nil + } + + if err := pprof.StartCPUProfile(&p.cpuProfileData); err != nil { + return fmt.Errorf("could not start CPU profile: %v", err) + } + + return nil +} + +func (p *program) finishProfiling() error { + if p.cpuProfile != "" { + pprof.StopCPUProfile() + err := os.WriteFile(p.cpuProfile, p.cpuProfileData.Bytes(), 0o666) + if err != nil { + return fmt.Errorf("write CPU profile: %v", err) + } + } + + if p.memProfile != "" { + f, err := os.Create(p.memProfile) + if err != nil { + return fmt.Errorf("create mem profile: %v", err) + } + defer f.Close() + runtime.GC() // get up-to-date statistics + if err := pprof.WriteHeapProfile(f); err != nil { + return fmt.Errorf("write mem profile: %v", err) + } + } + + return nil +} + // assignCheckerParams initializes checker parameter values using // values that are coming from the command-line arguments. func (p *program) assignCheckerParams() error { diff --git a/framework/lintmain/internal/hotload/hotload.go b/framework/lintmain/internal/hotload/hotload.go index 324d7e78f..5e5567a32 100644 --- a/framework/lintmain/internal/hotload/hotload.go +++ b/framework/lintmain/internal/hotload/hotload.go @@ -7,7 +7,7 @@ import ( "github.com/go-critic/go-critic/framework/linter" ) -// CheckersFromDylib loads checkers provided by a dynamic lybrary found under path. +// CheckersFromDylib loads checkers provided by a dynamic library found under path. // // The returned info slice must be re-assigned to the original info slice, // since there will be new entries there. diff --git a/framework/linttest/linttest.go b/framework/linttest/linttest.go index bb837ed2c..9545ba448 100644 --- a/framework/linttest/linttest.go +++ b/framework/linttest/linttest.go @@ -240,7 +240,7 @@ func loadPackages(cfg *packages.Config, patterns []string) ([]*packages.Package, if u.Test != nil { // Prefer tests to the base package, if present. result = append(result, u.Test) - } else { + } else if u.Base != nil { result = append(result, u.Base) } }) diff --git a/go.mod b/go.mod index c7da8f0ec..4370a0137 100644 --- a/go.mod +++ b/go.mod @@ -8,16 +8,14 @@ require ( github.com/go-toolsmith/astequal v1.0.1 github.com/go-toolsmith/astfmt v1.0.0 github.com/go-toolsmith/astp v1.0.0 - github.com/go-toolsmith/pkgload v1.0.0 + github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 github.com/go-toolsmith/strparse v1.0.0 github.com/go-toolsmith/typep v1.0.2 - github.com/google/go-cmp v0.5.2 + github.com/google/go-cmp v0.5.6 github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e - github.com/mattn/goveralls v0.0.2 - github.com/pborman/uuid v1.2.0 // indirect - github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c - github.com/quasilyte/go-ruleguard v0.3.13 + github.com/quasilyte/go-ruleguard v0.3.14 github.com/quasilyte/go-ruleguard/dsl v0.3.10 github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 - golang.org/x/tools v0.1.8-0.20211102225717-714668c9f9a3 + 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 a9e0798cf..71ee98ca1 100644 --- a/go.sum +++ b/go.sum @@ -7,39 +7,33 @@ github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLpo github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k= github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21 h1:wP6mXeB2V/d1P1K7bZ5vDUO3YqEzcvOREOxZPEu3gVI= -github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg= github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101211029-f9bca7b6a3d9 h1:izv+hZZg5x9r2fSf1b0mwl8Ysu+O8ZpiwU67cxmsYFk= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101211029-f9bca7b6a3d9/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk= github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/mattn/goveralls v0.0.2 h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c h1:JoUA0uz9U0FVFq5p4LjEq4C0VgQ0El320s3Ms0V4eww= -github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.13 h1:O1G41cq1jUr3cJmqp7vOUT0SokqjzmS9aESWJuIDRaY= -github.com/quasilyte/go-ruleguard v0.3.13/go.mod h1:Ul8wwdqR6kBVOCt2dipDBkE+T6vAV/iixkrKuRTN1oQ= +github.com/quasilyte/go-ruleguard v0.3.14 h1:gJBLtjuQr3yAkWQ/9rFspwACmCV95yFfC4959jYGJm4= +github.com/quasilyte/go-ruleguard v0.3.14/go.mod h1:gP9bl2y/36TTgBhQ/FkixCBAcDIsen29DSlJ2N9rMrk= github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.10 h1:4tVlVVcBT+nNWoF+t/zrAMO13sHAqYotX1K12Gc8f8A= github.com/quasilyte/go-ruleguard/dsl v0.3.10/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-20210428214800-545e0d2e0bf7/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/gogrep v0.0.0-20211226113550-e12a97c7d96d h1:HUyLC9v8wzT8PBFdZjGehLLNSPzQMXDsbREsMHxwma8= +github.com/quasilyte/gogrep v0.0.0-20211226113550-e12a97c7d96d/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/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -68,6 +62,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -80,6 +76,10 @@ golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.8-0.20211102225717-714668c9f9a3 h1:dDxElkpRI634Opa6XdqYX2K1+CHLHHf2TFqPEHyy2XE= golang.org/x/tools v0.1.8-0.20211102225717-714668c9f9a3/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da h1:Tno72dYE94v/7SyyIj9iBsc7OOjFu2PyNcl7yxxeZD8= +golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/tools/go.mod b/tools/go.mod new file mode 100644 index 000000000..901a8a490 --- /dev/null +++ b/tools/go.mod @@ -0,0 +1,8 @@ +module github.com/go-critic/go-critic/tools + +go 1.16 + +require ( + github.com/mattn/goveralls v0.0.11 + github.com/quasilyte/go-consistent v0.0.0-20200404105227-766526bf1e96 +) diff --git a/tools/go.sum b/tools/go.sum new file mode 100644 index 000000000..50ce4868d --- /dev/null +++ b/tools/go.sum @@ -0,0 +1,52 @@ +github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21 h1:wP6mXeB2V/d1P1K7bZ5vDUO3YqEzcvOREOxZPEu3gVI= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/mattn/goveralls v0.0.11 h1:eJXea6R6IFlL1QMKNMzDvvHv/hwGrnvyig4N+0+XiMM= +github.com/mattn/goveralls v0.0.11/go.mod h1:gU8SyhNswsJKchEV93xRQxX6X3Ei4PJdQk/6ZHvrvRk= +github.com/quasilyte/go-consistent v0.0.0-20200404105227-766526bf1e96 h1:6VBkISnfYpPtRvpE9wsVoxX+i0cDQFBPQPYzw259xWY= +github.com/quasilyte/go-consistent v0.0.0-20200404105227-766526bf1e96/go.mod h1:h5ob45vcE3sydtmo0lUDUmG3Y0HXudxMId1w+5G99VI= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/tools.go b/tools/tools.go similarity index 100% rename from tools.go rename to tools/tools.go