Skip to content

Commit

Permalink
Merge branch 'ignore_labeled_continue_in_select' of github.com:tony20…
Browse files Browse the repository at this point in the history
…01/go-critic into ignore_labeled_continue_in_select

* 'ignore_labeled_continue_in_select' of github.com:tony2001/go-critic:
  checkers: move out embedded rules from checkers.go (go-critic#1186)
  cmd/gocritic: add -cpuprofile and -memprofile flags (go-critic#1185)
  checker/whyNoLint: compile regex when it is needed (go-critic#1182)
  checkers: add enable/disable flags to ruleguard checker (go-critic#1181)
  checkers: add io.WriteString patterns to preferFprint (go-critic#1180)
  checkers: fix equalFold rules autofix templates (go-critic#1178)
  checkers: rename undefinedFormatting to dynamicFmtString (go-critic#1174)
  checkers: add dynamicFmtString checker (go-critic#1156)
  update ruleguard (go-critic#1173)
  checkers: add tests for go-critic#1166 (go-critic#1172)
  checkers): treat //noinspection as pragma in commentFormatting (go-critic#1166)
  checkers: add At() for httpNoBody checker (go-critic#1164)
  tools: move tools into own module (go-critic#1162)
  • Loading branch information
tony2001 committed Jan 4, 2022
2 parents 947b00e + 1595cb2 commit 8dbc237
Show file tree
Hide file tree
Showing 23 changed files with 998 additions and 680 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -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:
Expand Down
7 changes: 4 additions & 3 deletions checkers/boolExprSimplify_checker.go
Expand Up @@ -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() {
Expand Down
96 changes: 0 additions & 96 deletions checkers/checkers.go
Expand Up @@ -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{
Expand All @@ -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,
})
}
2 changes: 1 addition & 1 deletion checkers/checkers_test.go
Expand Up @@ -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
}
}
Expand Down
1 change: 1 addition & 0 deletions checkers/commentFormatting_checker.go
Expand Up @@ -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)
Expand Down
103 changes: 103 additions & 0 deletions 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,
})
}
49 changes: 46 additions & 3 deletions checkers/ruleguard_checker.go
Expand Up @@ -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() {
Expand Down Expand Up @@ -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: "<all>",
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."
Expand Down Expand Up @@ -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 != "<all>" {
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 == "<all>" || 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 == ""
},
}

Expand Down Expand Up @@ -236,3 +275,7 @@ func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.En
}
}
}

func debugPrint(s string) {
fmt.Println("debug:", s)
}

0 comments on commit 8dbc237

Please sign in to comment.