From 94678bc9c9d848d8e73cfcc7b22a6b6c2b62aaf4 Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Mon, 15 Jun 2020 14:32:09 +0300 Subject: [PATCH] all: integrate lintpack as internal framework (#937) Instead of using a lintpack as a dependency, clone most of its code that we need. This is an intermediate step to make transition to go/analysis easier. Now we don't need to keep lintpack dependency in sync and can make framework/linter compatible with go/analysis later. Doing a v0.5.0 release is suggested. Updates #854 Signed-off-by: Iskander Sharipov --- .gitignore | 2 +- CONTRIBUTING.md | 2 +- Makefile | 2 +- README.md | 22 +- checkers/appendAssign_checker.go | 8 +- checkers/appendCombine_checker.go | 8 +- checkers/argOrder_checker.go | 8 +- checkers/assignOp_checker.go | 8 +- checkers/badCall_checker.go | 8 +- checkers/badCond_checker.go | 10 +- checkers/badRegexp_checker.go | 8 +- checkers/boolExprSimplify_checker.go | 10 +- checkers/builtinShadow_checker.go | 8 +- checkers/captLocal_checker.go | 10 +- checkers/caseOrder_checker.go | 8 +- checkers/checkers.go | 4 +- checkers/checkers_test.go | 20 +- checkers/codegenComment_checker.go | 8 +- checkers/commentFormatting_checker.go | 8 +- checkers/commentedOutCode_checker.go | 8 +- checkers/commentedOutImport_checker.go | 8 +- checkers/defaultCaseOrder_checker.go | 8 +- checkers/deferUnlambda_checker.go | 8 +- checkers/deprecatedComment_checker.go | 8 +- checkers/docStub_checker.go | 8 +- checkers/dupArg_checker.go | 8 +- checkers/dupBranchBody_checker.go | 8 +- checkers/dupCase_checker.go | 10 +- checkers/dupImports_checker.go | 8 +- checkers/dupSubExpr_checker.go | 8 +- checkers/elseif_checker.go | 10 +- checkers/emptyFallthrough_checker.go | 8 +- checkers/emptyStringTest_checker.go | 8 +- checkers/equalFold_checker.go | 8 +- checkers/evalOrder_checker.go | 10 +- checkers/exitAfterDefer_checker.go | 8 +- checkers/filepathJoin_checker.go | 8 +- checkers/flagDeref_checker.go | 8 +- checkers/flagName_checker.go | 8 +- checkers/hexLiteral_checker.go | 8 +- checkers/hugeParam_checker.go | 10 +- checkers/ifElseChain_checker.go | 8 +- checkers/importShadow_checker.go | 8 +- checkers/indexAlloc_checker.go | 8 +- checkers/initClause_checker.go | 8 +- checkers/internal/astwalk/walker.go | 22 +- checkers/mapKey_checker.go | 10 +- checkers/methodExprCall_checker.go | 8 +- checkers/nestingReduce_checker.go | 10 +- checkers/newDeref_checker.go | 10 +- checkers/nilValReturn_checker.go | 8 +- checkers/octalLiteral_checker.go | 8 +- checkers/offBy1_checker.go | 8 +- checkers/paramTypeCombine_checker.go | 8 +- checkers/ptrToRefParam_checker.go | 8 +- checkers/rangeExprCopy_checker.go | 10 +- checkers/rangeValCopy_checker.go | 10 +- checkers/regexpMust_checker.go | 8 +- checkers/regexpPattern_checker.go | 8 +- checkers/regexpSimplify_checker.go | 8 +- checkers/ruleguard_checker.go | 12 +- checkers/singleCaseSwitch_checker.go | 8 +- checkers/sloppyLen_checker.go | 8 +- checkers/sloppyReassign_checker.go | 8 +- checkers/sloppyTypeAssert_checker.go | 8 +- checkers/sortSlice_checker.go | 10 +- checkers/sqlQuery_checker.go | 8 +- checkers/stringXbytes_checker.go | 8 +- checkers/switchTrue_checker.go | 8 +- .../testdata/importShadow/negative_tests.go | 4 +- .../testdata/importShadow/positive_tests.go | 16 +- checkers/truncateCmp_checker.go | 10 +- checkers/typeAssertChain_checker.go | 10 +- checkers/typeSwitchVar_checker.go | 10 +- checkers/typeUnparen_checker.go | 10 +- checkers/underef_checker.go | 10 +- checkers/unlabelStmt_checker.go | 10 +- checkers/unlambda_checker.go | 8 +- checkers/unnamedResult_checker.go | 10 +- checkers/unnecessaryBlock_checker.go | 8 +- checkers/unnecessaryDefer_checker.go | 10 +- checkers/unslice_checker.go | 8 +- checkers/utils.go | 4 +- checkers/valSwap_checker.go | 8 +- checkers/weakCond_checker.go | 10 +- checkers/whyNoLint_checker.go | 8 +- checkers/wrapperFunc_checker.go | 8 +- checkers/yodaStyleExpr_checker.go | 8 +- cmd/gocritic/main.go | 13 + cmd/makedocs/main.go | 6 +- framework/cmdutil/cmdutil.go | 72 +++ framework/linter/checkers_db.go | 135 +++++ framework/linter/context.go | 35 ++ framework/linter/lintpack.go | 247 +++++++++ framework/lintmain/internal/check/check.go | 469 ++++++++++++++++++ .../lintmain/internal/check/check_test.go | 41 ++ .../lintmain/internal/hotload/hotload.go | 30 ++ framework/lintmain/internal/lintdoc/doc.go | 89 ++++ framework/lintmain/lintmain.go | 68 +++ framework/linttest/end2end.go | 46 ++ framework/linttest/integration.go | 122 +++++ framework/linttest/linttest.go | 190 +++++++ framework/linttest/testdata/sanity/tests.go | 213 ++++++++ go.mod | 3 + naming_conventions.json | 2 +- 105 files changed, 2159 insertions(+), 392 deletions(-) create mode 100644 cmd/gocritic/main.go create mode 100644 framework/cmdutil/cmdutil.go create mode 100644 framework/linter/checkers_db.go create mode 100644 framework/linter/context.go create mode 100644 framework/linter/lintpack.go create mode 100644 framework/lintmain/internal/check/check.go create mode 100644 framework/lintmain/internal/check/check_test.go create mode 100644 framework/lintmain/internal/hotload/hotload.go create mode 100644 framework/lintmain/internal/lintdoc/doc.go create mode 100644 framework/lintmain/lintmain.go create mode 100644 framework/linttest/end2end.go create mode 100644 framework/linttest/integration.go create mode 100644 framework/linttest/linttest.go create mode 100644 framework/linttest/testdata/sanity/tests.go diff --git a/.gitignore b/.gitignore index c20772dc1..83c77eab2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *.dll *.so *.dylib -gocritic +/gocritic pkg/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0488e02a1..d7162e2aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,7 @@ you'll find all answers there in a short time. 3. Define checker type and constructor function inside a new file under `checkers/${checkerName}_checker.go`. -4. Define a `lintpack.CheckerInfo` within an `init()` function in your new file. Specify the checker `Name`, `Summary`, `Before`, and `After` fields. It's a good idea to also specify appropriate `Tags` (e.g. `"diagnostic"`, `"style"`, `"performace"`, `"opinionated"`); new checkers should generally include the `"experimental"` tag. +4. Define a `linter.CheckerInfo` within an `init()` function in your new file. Specify the checker `Name`, `Summary`, `Before`, and `After` fields. It's a good idea to also specify appropriate `Tags` (e.g. `"diagnostic"`, `"style"`, `"performace"`, `"opinionated"`); new checkers should generally include the `"experimental"` tag. 5. Register the checker by calling `AddChecker` function in `init()`, passing in the `CheckerInfo`. diff --git a/Makefile b/Makefile index 11830c93c..f8ef76fa6 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ cover: goveralls -package github.com/go-critic/go-critic/checkers -coverprofile=coverage.out -service travis-ci -repotoken ${COVERALLS_TOKEN} gocritic: - lintpack build -o gocritic -linter.version='v0.4.3' -linter.name='gocritic' github.com/go-critic/go-critic/checkers + go build -o gocritic ./cmd/gocritic install: go install ./cmd/gocritic diff --git a/README.md b/README.md index 74b0114a5..41e2aee0e 100644 --- a/README.md +++ b/README.md @@ -34,28 +34,16 @@ The latest documentation is available at [go-critic.github.io](https://go-critic For most users, using `go-critic` under [golangci-lint](https://github.com/golangci/golangci-lint) is enough. -Instructions below describe how to install "bare" `go-critic`. +Precompiled `go-critic` binaries can be found at [releases](https://github.com/go-critic/go-critic/releases) page. -If you don't have [lintpack](https://github.com/go-lintpack/lintpack) installed, do: +Instructions below show how to build `go-critic` from sources. ```bash -go get -v github.com/go-lintpack/lintpack/... +GO111MODULE=on go get -v -u github.com/go-critic/go-critic/cmd/gocritic ``` -Get `go-critic` checkers: - -```bash -go get -v github.com/go-critic/go-critic/... -``` - -After that, you can create `gocritic` binary by running: - -```bash -cd $(go env GOPATH)/src/github.com/go-critic/go-critic && - make gocritic -``` - -> Windows note: `lintpack build` might emit a warning. See https://github.com/go-critic/go-critic/issues/760. +If the command above does not work, you can try cloning this repository +under your `GOPATH` and run `make gocritic`. ## Usage diff --git a/checkers/appendAssign_checker.go b/checkers/appendAssign_checker.go index 2a54f3b6c..d26921770 100644 --- a/checkers/appendAssign_checker.go +++ b/checkers/appendAssign_checker.go @@ -5,15 +5,15 @@ import ( "go/token" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" "github.com/go-toolsmith/astp" "golang.org/x/tools/go/ast/astutil" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "appendAssign" info.Tags = []string{"diagnostic"} info.Summary = "Detects suspicious append result assignments" @@ -24,14 +24,14 @@ p.negatives = append(p.negatives, y)` p.positives = append(p.positives, x) p.negatives = append(p.negatives, y)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&appendAssignChecker{ctx: ctx}) }) } type appendAssignChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *appendAssignChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/appendCombine_checker.go b/checkers/appendCombine_checker.go index bbede5a97..a761f2a8f 100644 --- a/checkers/appendCombine_checker.go +++ b/checkers/appendCombine_checker.go @@ -4,14 +4,14 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "appendCombine" info.Tags = []string{"performance"} info.Summary = "Detects `append` chains to the same slice that can be done in a single `append` call" @@ -20,14 +20,14 @@ xs = append(xs, 1) xs = append(xs, 2)` info.After = `xs = append(xs, 1, 2)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmtList(&appendCombineChecker{ctx: ctx}) }) } type appendCombineChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *appendCombineChecker) VisitStmtList(list []ast.Stmt) { diff --git a/checkers/argOrder_checker.go b/checkers/argOrder_checker.go index 74a4414e7..3b8bf9f52 100644 --- a/checkers/argOrder_checker.go +++ b/checkers/argOrder_checker.go @@ -4,8 +4,8 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astp" @@ -13,21 +13,21 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "argOrder" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious arguments order" info.Before = `strings.HasPrefix("#", userpass)` info.After = `strings.HasPrefix(userpass, "#")` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&argOrderChecker{ctx: ctx}) }) } type argOrderChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *argOrderChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/assignOp_checker.go b/checkers/assignOp_checker.go index a6f42d5a5..e3acd09ef 100644 --- a/checkers/assignOp_checker.go +++ b/checkers/assignOp_checker.go @@ -4,29 +4,29 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astequal" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "assignOp" info.Tags = []string{"style"} info.Summary = "Detects assignments that can be simplified by using assignment operators" info.Before = `x = x * 2` info.After = `x *= 2` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&assignOpChecker{ctx: ctx}) }) } type assignOpChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *assignOpChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/badCall_checker.go b/checkers/badCall_checker.go index 71a07c5fc..278e3b1e7 100644 --- a/checkers/badCall_checker.go +++ b/checkers/badCall_checker.go @@ -3,28 +3,28 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "badCall" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious function calls" info.Before = `strings.Replace(s, from, to, 0)` info.After = `strings.Replace(s, from, to, -1)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&badCallChecker{ctx: ctx}) }) } type badCallChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *badCallChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/badCond_checker.go b/checkers/badCond_checker.go index 5a9fcd1b8..8d664366d 100644 --- a/checkers/badCond_checker.go +++ b/checkers/badCond_checker.go @@ -5,9 +5,9 @@ import ( "go/constant" "go/token" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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" @@ -16,7 +16,7 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "badCond" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious condition expressions" @@ -29,14 +29,14 @@ for i := 0; i < n; i++ { xs[i] = 0 }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(&badCondChecker{ctx: ctx}) }) } type badCondChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *badCondChecker) VisitFuncDecl(decl *ast.FuncDecl) { diff --git a/checkers/badRegexp_checker.go b/checkers/badRegexp_checker.go index 1ec1f2fd7..1025454df 100644 --- a/checkers/badRegexp_checker.go +++ b/checkers/badRegexp_checker.go @@ -8,20 +8,20 @@ import ( "unicode" "unicode/utf8" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/quasilyte/regex/syntax" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "badRegexp" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious regexp patterns" info.Before = "regexp.MustCompile(`(?:^aa|bb|cc)foo[aba]`)" info.After = "regexp.MustCompile(`^(?:aa|bb|cc)foo[ab]`)" - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { opts := &syntax.ParserOptions{} c := &badRegexpChecker{ ctx: ctx, @@ -33,7 +33,7 @@ func init() { type badRegexpChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext parser *syntax.Parser cause ast.Expr diff --git a/checkers/boolExprSimplify_checker.go b/checkers/boolExprSimplify_checker.go index 5ef09d615..8c599031d 100644 --- a/checkers/boolExprSimplify_checker.go +++ b/checkers/boolExprSimplify_checker.go @@ -6,9 +6,9 @@ import ( "go/token" "strconv" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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" @@ -18,7 +18,7 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "boolExprSimplify" info.Tags = []string{"style", "experimental"} info.Summary = "Detects bool expressions that can be simplified" @@ -29,14 +29,14 @@ b := !(x) == !(y)` a := elapsed < expectElapsedMin b := (x) == (y)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&boolExprSimplifyChecker{ctx: ctx}) }) } type boolExprSimplifyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext hasFloats bool } diff --git a/checkers/builtinShadow_checker.go b/checkers/builtinShadow_checker.go index afa6eceb3..ff5e51746 100644 --- a/checkers/builtinShadow_checker.go +++ b/checkers/builtinShadow_checker.go @@ -3,26 +3,26 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "builtinShadow" info.Tags = []string{"style", "opinionated"} info.Summary = "Detects when predeclared identifiers shadowed in assignments" info.Before = `len := 10` info.After = `length := 10` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForLocalDef(&builtinShadowChecker{ctx: ctx}, ctx.TypesInfo) }) } type builtinShadowChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *builtinShadowChecker) VisitLocalDef(name astwalk.Name, _ ast.Expr) { diff --git a/checkers/captLocal_checker.go b/checkers/captLocal_checker.go index f521d96d3..76b6fb4fc 100644 --- a/checkers/captLocal_checker.go +++ b/checkers/captLocal_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "captLocal" info.Tags = []string{"style"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "paramsOnly": { Value: true, Usage: "whether to restrict checker to params only", @@ -21,7 +21,7 @@ func init() { info.Before = `func f(IN int, OUT *int) (ERR error) {}` info.After = `func f(in int, out *int) (err error) {}` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &captLocalChecker{ctx: ctx} c.paramsOnly = info.Params.Bool("paramsOnly") return astwalk.WalkerForLocalDef(c, ctx.TypesInfo) @@ -30,7 +30,7 @@ func init() { type captLocalChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext paramsOnly bool } diff --git a/checkers/caseOrder_checker.go b/checkers/caseOrder_checker.go index d5547ad3f..950367520 100644 --- a/checkers/caseOrder_checker.go +++ b/checkers/caseOrder_checker.go @@ -4,12 +4,12 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "caseOrder" info.Tags = []string{"diagnostic"} info.Summary = "Detects erroneous case order inside switch statements" @@ -28,14 +28,14 @@ case ast.Expr: fmt.Println("expr") }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&caseOrderChecker{ctx: ctx}) }) } type caseOrderChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *caseOrderChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/checkers.go b/checkers/checkers.go index 1916e9bd8..0c2ebc00c 100644 --- a/checkers/checkers.go +++ b/checkers/checkers.go @@ -4,10 +4,10 @@ package checkers import ( "os" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) -var collection = &lintpack.CheckerCollection{ +var collection = &linter.CheckerCollection{ URL: "https://github.com/go-critic/go-critic/checkers", } diff --git a/checkers/checkers_test.go b/checkers/checkers_test.go index e05c47796..83207a4e4 100644 --- a/checkers/checkers_test.go +++ b/checkers/checkers_test.go @@ -3,8 +3,8 @@ package checkers import ( "testing" - "github.com/go-lintpack/lintpack" - "github.com/go-lintpack/lintpack/linttest" + "github.com/go-critic/go-critic/framework/linter" + "github.com/go-critic/go-critic/framework/linttest" ) func TestCheckers(t *testing.T) { @@ -12,7 +12,7 @@ func TestCheckers(t *testing.T) { "captLocal": {"paramsOnly": false}, } - for _, info := range lintpack.GetCheckersInfo() { + for _, info := range linter.GetCheckersInfo() { params := allParams[info.Name] for key, p := range info.Params { v, ok := params[key] @@ -25,7 +25,13 @@ func TestCheckers(t *testing.T) { linttest.TestCheckers(t) } -func TestIntegration(t *testing.T) { linttest.TestIntegration(t) } +func TestIntegration(t *testing.T) { + cfg := linttest.IntegrationTest{ + Main: "github.com/go-critic/go-critic/cmd/gocritic", + Dir: "./testdata/_integration", + } + cfg.Run(t) +} func TestTags(t *testing.T) { // Verify that we're only using strict set of tags. @@ -33,7 +39,7 @@ func TestTags(t *testing.T) { // // Also check that exactly 1 category tag is used. - for _, info := range lintpack.GetCheckersInfo() { + for _, info := range linter.GetCheckersInfo() { categories := 0 for _, tag := range info.Tags { switch tag { @@ -55,7 +61,7 @@ func TestTags(t *testing.T) { } func TestDocs(t *testing.T) { - for _, info := range lintpack.GetCheckersInfo() { + for _, info := range linter.GetCheckersInfo() { if info.Summary == "" { t.Errorf("%q checker lacks summary", info.Name) } @@ -111,7 +117,7 @@ func TestStableList(t *testing.T) { m[name] = true } - for _, info := range lintpack.GetCheckersInfo() { + for _, info := range linter.GetCheckersInfo() { if info.HasTag("experimental") { continue } diff --git a/checkers/codegenComment_checker.go b/checkers/codegenComment_checker.go index 8fd72d39d..377895386 100644 --- a/checkers/codegenComment_checker.go +++ b/checkers/codegenComment_checker.go @@ -5,19 +5,19 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "codegenComment" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects malformed 'code generated' file comments" info.Before = `// This file was automatically generated by foogen` info.After = `// Code generated by foogen. DO NOT EDIT.` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { patterns := []string{ "this (?:file|code) (?:was|is) auto(?:matically)? generated", "this (?:file|code) (?:was|is) generated automatically", @@ -38,7 +38,7 @@ func init() { type codegenCommentChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext badCommentRE *regexp.Regexp } diff --git a/checkers/commentFormatting_checker.go b/checkers/commentFormatting_checker.go index 58bb54c22..cb69331be 100644 --- a/checkers/commentFormatting_checker.go +++ b/checkers/commentFormatting_checker.go @@ -7,19 +7,19 @@ import ( "unicode" "unicode/utf8" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "commentFormatting" info.Tags = []string{"style", "experimental"} info.Summary = "Detects comments with non-idiomatic formatting" info.Before = `//This is a comment` info.After = `// This is a comment` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { parts := []string{ `^//go:generate .*$`, // e.g.: go:generate value `^//\w+:.*$`, // e.g.: key: value @@ -38,7 +38,7 @@ func init() { type commentFormattingChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext pragmaRE *regexp.Regexp } diff --git a/checkers/commentedOutCode_checker.go b/checkers/commentedOutCode_checker.go index 2542dd330..8d9387045 100644 --- a/checkers/commentedOutCode_checker.go +++ b/checkers/commentedOutCode_checker.go @@ -7,13 +7,13 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/strparse" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "commentedOutCode" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects commented-out code inside function bodies" @@ -22,7 +22,7 @@ func init() { foo(1, 2)` info.After = `foo(1, 2)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForLocalComment(&commentedOutCodeChecker{ ctx: ctx, notQuiteFuncCall: regexp.MustCompile(`\w+\s+\([^)]*\)\s*$`), @@ -32,7 +32,7 @@ foo(1, 2)` type commentedOutCodeChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext fn *ast.FuncDecl notQuiteFuncCall *regexp.Regexp diff --git a/checkers/commentedOutImport_checker.go b/checkers/commentedOutImport_checker.go index 36abad2c1..096a90241 100644 --- a/checkers/commentedOutImport_checker.go +++ b/checkers/commentedOutImport_checker.go @@ -5,12 +5,12 @@ import ( "go/token" "regexp" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "commentedOutImport" info.Tags = []string{"style", "experimental"} info.Summary = "Detects commented-out imports" @@ -24,7 +24,7 @@ import ( "fmt" )` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { const pattern = `(?m)^(?://|/\*)?\s*"([a-zA-Z0-9_/]+)"\s*(?:\*/)?$` return &commentedOutImportChecker{ ctx: ctx, @@ -35,7 +35,7 @@ import ( type commentedOutImportChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext importStringRE *regexp.Regexp } diff --git a/checkers/defaultCaseOrder_checker.go b/checkers/defaultCaseOrder_checker.go index 794a6f6d2..755449e07 100644 --- a/checkers/defaultCaseOrder_checker.go +++ b/checkers/defaultCaseOrder_checker.go @@ -3,12 +3,12 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "defaultCaseOrder" info.Tags = []string{"style"} info.Summary = "Detects when default case in switch isn't on 1st or last position" @@ -31,14 +31,14 @@ default: // <- last case (could also be the first one) // ... }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&defaultCaseOrderChecker{ctx: ctx}) }) } type defaultCaseOrderChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *defaultCaseOrderChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/deferUnlambda_checker.go b/checkers/deferUnlambda_checker.go index bbeba9353..3cab7827c 100644 --- a/checkers/deferUnlambda_checker.go +++ b/checkers/deferUnlambda_checker.go @@ -4,27 +4,27 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "deferUnlambda" info.Tags = []string{"style", "experimental"} info.Summary = "Detects deferred function literals that can be simplified" info.Before = `defer func() { f() }()` info.After = `f()` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&deferUnlambdaChecker{ctx: ctx}) }) } type deferUnlambdaChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *deferUnlambdaChecker) VisitStmt(x ast.Stmt) { diff --git a/checkers/deprecatedComment_checker.go b/checkers/deprecatedComment_checker.go index 5f501ce20..aec237ca9 100644 --- a/checkers/deprecatedComment_checker.go +++ b/checkers/deprecatedComment_checker.go @@ -5,12 +5,12 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "deprecatedComment" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects malformed 'deprecated' doc-comments" @@ -21,7 +21,7 @@ func FuncOld() int` // Deprecated: use FuncNew instead func FuncOld() int` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &deprecatedCommentChecker{ctx: ctx} c.commonPatterns = []*regexp.Regexp{ @@ -61,7 +61,7 @@ func FuncOld() int` type deprecatedCommentChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext commonPatterns []*regexp.Regexp commonTypos []string diff --git a/checkers/docStub_checker.go b/checkers/docStub_checker.go index 7b679037a..2a3b393a0 100644 --- a/checkers/docStub_checker.go +++ b/checkers/docStub_checker.go @@ -6,12 +6,12 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "docStub" info.Tags = []string{"style", "experimental"} info.Summary = "Detects comments that silence go lint complaints about doc-comment" @@ -26,7 +26,7 @@ func Foo() {} // Foo is a demonstration-only function. func Foo() {}` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { re := `(?i)^\.\.\.$|^\.$|^xxx\.?$|^whatever\.?$` c := &docStubChecker{ ctx: ctx, @@ -38,7 +38,7 @@ func Foo() {}` type docStubChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext stubCommentRE *regexp.Regexp } diff --git a/checkers/dupArg_checker.go b/checkers/dupArg_checker.go index 0fddabb2a..24e921b09 100644 --- a/checkers/dupArg_checker.go +++ b/checkers/dupArg_checker.go @@ -4,21 +4,21 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "dupArg" info.Tags = []string{"diagnostic"} info.Summary = "Detects suspicious duplicated arguments" info.Before = `copy(dst, dst)` info.After = `copy(dst, src)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &dupArgChecker{ctx: ctx} // newMatcherFunc returns a function that matches a call if // args[xIndex] and args[yIndex] are equal. @@ -101,7 +101,7 @@ func init() { type dupArgChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext matchers map[string]func(*ast.CallExpr) bool } diff --git a/checkers/dupBranchBody_checker.go b/checkers/dupBranchBody_checker.go index 2a92b2e23..3399f0531 100644 --- a/checkers/dupBranchBody_checker.go +++ b/checkers/dupBranchBody_checker.go @@ -3,13 +3,13 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "dupBranchBody" info.Tags = []string{"diagnostic"} info.Summary = "Detects duplicated branch bodies inside conditional statements" @@ -26,14 +26,14 @@ if cond { println("cond=false") }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&dupBranchBodyChecker{ctx: ctx}) }) } type dupBranchBodyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *dupBranchBodyChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/dupCase_checker.go b/checkers/dupCase_checker.go index 59aa21bf8..89ec66bbf 100644 --- a/checkers/dupCase_checker.go +++ b/checkers/dupCase_checker.go @@ -3,13 +3,13 @@ package checkers import ( "go/ast" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "dupCase" info.Tags = []string{"diagnostic"} info.Summary = "Detects duplicated case clauses inside switch statements" @@ -22,14 +22,14 @@ switch x { case ys[0], ys[1], ys[2], ys[3], ys[4]: }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&dupCaseChecker{ctx: ctx}) }) } type dupCaseChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext astSet lintutil.AstSet } diff --git a/checkers/dupImports_checker.go b/checkers/dupImports_checker.go index d531413a1..27b796cdc 100644 --- a/checkers/dupImports_checker.go +++ b/checkers/dupImports_checker.go @@ -4,11 +4,11 @@ import ( "fmt" "go/ast" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "dupImport" info.Tags = []string{"style", "experimental"} info.Summary = "Detects multiple imports of the same package under different aliases" @@ -22,13 +22,13 @@ import( "fmt" )` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return &dupImportChecker{ctx: ctx} }) } type dupImportChecker struct { - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *dupImportChecker) WalkFile(f *ast.File) { diff --git a/checkers/dupSubExpr_checker.go b/checkers/dupSubExpr_checker.go index 0b87ebc44..4966cd2a5 100644 --- a/checkers/dupSubExpr_checker.go +++ b/checkers/dupSubExpr_checker.go @@ -5,14 +5,14 @@ import ( "go/token" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "dupSubExpr" info.Tags = []string{"diagnostic"} info.Summary = "Detects suspicious duplicated sub-expressions" @@ -25,7 +25,7 @@ sort.Slice(xs, func(i, j int) bool { return xs[i].v < xs[j].v })` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &dupSubExprChecker{ctx: ctx} ops := []struct { @@ -65,7 +65,7 @@ sort.Slice(xs, func(i, j int) bool { type dupSubExprChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext // opSet is a set of binary operations that do not make // sense with duplicated (same) RHS and LHS. diff --git a/checkers/elseif_checker.go b/checkers/elseif_checker.go index 99315e877..9e56d1c40 100644 --- a/checkers/elseif_checker.go +++ b/checkers/elseif_checker.go @@ -3,16 +3,16 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "elseif" info.Tags = []string{"style"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "skipBalanced": { Value: true, Usage: "whether to skip balanced if-else pairs", @@ -30,7 +30,7 @@ if cond1 { } else if x := cond2; x { }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &elseifChecker{ctx: ctx} c.skipBalanced = info.Params.Bool("skipBalanced") return astwalk.WalkerForStmt(c) @@ -39,7 +39,7 @@ if cond1 { type elseifChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext skipBalanced bool } diff --git a/checkers/emptyFallthrough_checker.go b/checkers/emptyFallthrough_checker.go index 2db2a8fd3..16bfa7e45 100644 --- a/checkers/emptyFallthrough_checker.go +++ b/checkers/emptyFallthrough_checker.go @@ -4,12 +4,12 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "emptyFallthrough" info.Tags = []string{"style", "experimental"} info.Summary = "Detects fallthrough that can be avoided by using multi case values" @@ -24,14 +24,14 @@ case reflect.Int, reflect.Int32: return Int }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&emptyFallthroughChecker{ctx: ctx}) }) } type emptyFallthroughChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *emptyFallthroughChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/emptyStringTest_checker.go b/checkers/emptyStringTest_checker.go index 65431caba..20d647ffa 100644 --- a/checkers/emptyStringTest_checker.go +++ b/checkers/emptyStringTest_checker.go @@ -4,15 +4,15 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "emptyStringTest" info.Tags = []string{"style", "experimental"} info.Summary = "Detects empty string checks that can be written more idiomatically" @@ -20,14 +20,14 @@ func init() { info.After = `s == ""` info.Note = "See https://dmitri.shuralyov.com/idiomatic-go#empty-string-check." - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&emptyStringTestChecker{ctx: ctx}) }) } type emptyStringTestChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *emptyStringTestChecker) VisitExpr(e ast.Expr) { diff --git a/checkers/equalFold_checker.go b/checkers/equalFold_checker.go index eae34a11a..b8dfdc02f 100644 --- a/checkers/equalFold_checker.go +++ b/checkers/equalFold_checker.go @@ -4,28 +4,28 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "equalFold" info.Tags = []string{"performance", "experimental"} info.Summary = "Detects unoptimal strings/bytes case-insensitive comparison" info.Before = `strings.ToLower(x) == strings.ToLower(y)` info.After = `strings.EqualFold(x, y)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&equalFoldChecker{ctx: ctx}) }) } type equalFoldChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *equalFoldChecker) VisitExpr(e ast.Expr) { diff --git a/checkers/evalOrder_checker.go b/checkers/evalOrder_checker.go index 2e520523b..0bec0e83a 100644 --- a/checkers/evalOrder_checker.go +++ b/checkers/evalOrder_checker.go @@ -5,16 +5,16 @@ import ( "go/token" "go/types" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astequal" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "evalOrder" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects unwanted dependencies on the evaluation order" @@ -24,14 +24,14 @@ err := f(&x) return x, err ` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&evalOrderChecker{ctx: ctx}) }) } type evalOrderChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *evalOrderChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/exitAfterDefer_checker.go b/checkers/exitAfterDefer_checker.go index 92cd1ef1c..524c8f2c9 100644 --- a/checkers/exitAfterDefer_checker.go +++ b/checkers/exitAfterDefer_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astfmt" "github.com/go-toolsmith/astp" "golang.org/x/tools/go/ast/astutil" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "exitAfterDefer" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects calls to exit/fatal inside functions that use defer" @@ -27,14 +27,14 @@ if bad { return }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(&exitAfterDeferChecker{ctx: ctx}) }) } type exitAfterDeferChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *exitAfterDeferChecker) VisitFuncDecl(fn *ast.FuncDecl) { diff --git a/checkers/filepathJoin_checker.go b/checkers/filepathJoin_checker.go index c0c12b533..b11dc2470 100644 --- a/checkers/filepathJoin_checker.go +++ b/checkers/filepathJoin_checker.go @@ -4,27 +4,27 @@ import ( "go/ast" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "filepathJoin" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects problems in filepath.Join() function calls" info.Before = `filepath.Join("dir/", filename)` info.After = `filepath.Join("dir", filename)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&filepathJoinChecker{ctx: ctx}) }) } type filepathJoinChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *filepathJoinChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/flagDeref_checker.go b/checkers/flagDeref_checker.go index dd9e515ec..393274c43 100644 --- a/checkers/flagDeref_checker.go +++ b/checkers/flagDeref_checker.go @@ -3,12 +3,12 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "flagDeref" info.Tags = []string{"diagnostic"} info.Summary = "Detects immediate dereferencing of `flag` package pointers" @@ -21,7 +21,7 @@ flag.BoolVar(&b, "b", false, "b docs")` Dereferencing returned pointers will lead to hard to find errors where flag values are not updated after flag.Parse().` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &flagDerefChecker{ ctx: ctx, flagPtrFuncs: map[string]bool{ @@ -41,7 +41,7 @@ where flag values are not updated after flag.Parse().` type flagDerefChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext flagPtrFuncs map[string]bool } diff --git a/checkers/flagName_checker.go b/checkers/flagName_checker.go index a32d96cd2..a3bb1c7cd 100644 --- a/checkers/flagName_checker.go +++ b/checkers/flagName_checker.go @@ -6,27 +6,27 @@ import ( "go/types" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "flagName" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects flag names with whitespace" info.Before = `b := flag.Bool(" foo ", false, "description")` info.After = `b := flag.Bool("foo", false, "description")` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&flagNameChecker{ctx: ctx}) }) } type flagNameChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *flagNameChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/hexLiteral_checker.go b/checkers/hexLiteral_checker.go index aed0201cc..f3f9c535c 100644 --- a/checkers/hexLiteral_checker.go +++ b/checkers/hexLiteral_checker.go @@ -5,13 +5,13 @@ import ( "go/token" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "hexLiteral" info.Tags = []string{"style", "experimental"} info.Summary = "Detects hex literals that have mixed case letter digits" @@ -25,14 +25,14 @@ y := 0xff // (B) y := 0xFF` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&hexLiteralChecker{ctx: ctx}) }) } type hexLiteralChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *hexLiteralChecker) warn0X(lit *ast.BasicLit) { diff --git a/checkers/hugeParam_checker.go b/checkers/hugeParam_checker.go index 7ea17df04..54be77638 100644 --- a/checkers/hugeParam_checker.go +++ b/checkers/hugeParam_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "hugeParam" info.Tags = []string{"performance"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "sizeThreshold": { Value: 80, Usage: "size in bytes that makes the warning trigger", @@ -21,7 +21,7 @@ func init() { info.Before = `func f(x [1024]int) {}` info.After = `func f(x *[1024]int) {}` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(&hugeParamChecker{ ctx: ctx, sizeThreshold: int64(info.Params.Int("sizeThreshold")), @@ -31,7 +31,7 @@ func init() { type hugeParamChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext sizeThreshold int64 } diff --git a/checkers/ifElseChain_checker.go b/checkers/ifElseChain_checker.go index 1c7d702c8..91e1cfb39 100644 --- a/checkers/ifElseChain_checker.go +++ b/checkers/ifElseChain_checker.go @@ -3,12 +3,12 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "ifElseChain" info.Tags = []string{"style"} info.Summary = "Detects repeated if-else statements and suggests to replace them with switch statement" @@ -34,14 +34,14 @@ Permits single else or else-if; repeated else-if or else + else-if will trigger suggestion to use switch statement. See [EffectiveGo#switch](https://golang.org/doc/effective_go.html#switch).` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&ifElseChainChecker{ctx: ctx}) }) } type ifElseChainChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext cause *ast.IfStmt visited map[*ast.IfStmt]bool diff --git a/checkers/importShadow_checker.go b/checkers/importShadow_checker.go index 80d7af69f..60c0ab21e 100644 --- a/checkers/importShadow_checker.go +++ b/checkers/importShadow_checker.go @@ -4,12 +4,12 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "importShadow" info.Tags = []string{"style", "opinionated"} info.Summary = "Detects when imported package names shadowed in the assignments" @@ -19,7 +19,7 @@ filepath := "foo.txt"` info.After = ` filename := "foo.txt"` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { ctx.Require.PkgObjects = true return astwalk.WalkerForLocalDef(&importShadowChecker{ctx: ctx}, ctx.TypesInfo) }) @@ -27,7 +27,7 @@ filename := "foo.txt"` type importShadowChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *importShadowChecker) VisitLocalDef(def astwalk.Name, _ ast.Expr) { diff --git a/checkers/indexAlloc_checker.go b/checkers/indexAlloc_checker.go index 1dcfeb409..733998873 100644 --- a/checkers/indexAlloc_checker.go +++ b/checkers/indexAlloc_checker.go @@ -3,14 +3,14 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "indexAlloc" info.Tags = []string{"performance"} info.Summary = "Detects strings.Index calls that may cause unwanted allocs" @@ -18,14 +18,14 @@ func init() { info.After = `bytes.Index(x, []byte(y))` info.Note = `See Go issue for details: https://github.com/golang/go/issues/25864` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&indexAllocChecker{ctx: ctx}) }) } type indexAllocChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *indexAllocChecker) VisitExpr(e ast.Expr) { diff --git a/checkers/initClause_checker.go b/checkers/initClause_checker.go index 0c4496285..91e8816d2 100644 --- a/checkers/initClause_checker.go +++ b/checkers/initClause_checker.go @@ -3,13 +3,13 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "initClause" info.Tags = []string{"style", "opinionated", "experimental"} info.Summary = "Detects non-assignment statements inside if/switch init clause" @@ -19,14 +19,14 @@ func init() { if cond { }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&initClauseChecker{ctx: ctx}) }) } type initClauseChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *initClauseChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/internal/astwalk/walker.go b/checkers/internal/astwalk/walker.go index fddae710a..cd5e1c979 100644 --- a/checkers/internal/astwalk/walker.go +++ b/checkers/internal/astwalk/walker.go @@ -3,55 +3,55 @@ package astwalk import ( "go/types" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) // WalkerForFuncDecl returns file walker implementation for FuncDeclVisitor. -func WalkerForFuncDecl(v FuncDeclVisitor) lintpack.FileWalker { +func WalkerForFuncDecl(v FuncDeclVisitor) linter.FileWalker { return &funcDeclWalker{visitor: v} } // WalkerForExpr returns file walker implementation for ExprVisitor. -func WalkerForExpr(v ExprVisitor) lintpack.FileWalker { +func WalkerForExpr(v ExprVisitor) linter.FileWalker { return &exprWalker{visitor: v} } // WalkerForLocalExpr returns file walker implementation for LocalExprVisitor. -func WalkerForLocalExpr(v LocalExprVisitor) lintpack.FileWalker { +func WalkerForLocalExpr(v LocalExprVisitor) linter.FileWalker { return &localExprWalker{visitor: v} } // WalkerForStmtList returns file walker implementation for StmtListVisitor. -func WalkerForStmtList(v StmtListVisitor) lintpack.FileWalker { +func WalkerForStmtList(v StmtListVisitor) linter.FileWalker { return &stmtListWalker{visitor: v} } // WalkerForStmt returns file walker implementation for StmtVisitor. -func WalkerForStmt(v StmtVisitor) lintpack.FileWalker { +func WalkerForStmt(v StmtVisitor) linter.FileWalker { return &stmtWalker{visitor: v} } // WalkerForTypeExpr returns file walker implementation for TypeExprVisitor. -func WalkerForTypeExpr(v TypeExprVisitor, info *types.Info) lintpack.FileWalker { +func WalkerForTypeExpr(v TypeExprVisitor, info *types.Info) linter.FileWalker { return &typeExprWalker{visitor: v, info: info} } // WalkerForLocalComment returns file walker implementation for LocalCommentVisitor. -func WalkerForLocalComment(v LocalCommentVisitor) lintpack.FileWalker { +func WalkerForLocalComment(v LocalCommentVisitor) linter.FileWalker { return &localCommentWalker{visitor: v} } // WalkerForComment returns file walker implementation for CommentVisitor. -func WalkerForComment(v CommentVisitor) lintpack.FileWalker { +func WalkerForComment(v CommentVisitor) linter.FileWalker { return &commentWalker{visitor: v} } // WalkerForDocComment returns file walker implementation for DocCommentVisitor. -func WalkerForDocComment(v DocCommentVisitor) lintpack.FileWalker { +func WalkerForDocComment(v DocCommentVisitor) linter.FileWalker { return &docCommentWalker{visitor: v} } // WalkerForLocalDef returns file walker implementation for LocalDefVisitor. -func WalkerForLocalDef(v LocalDefVisitor, info *types.Info) lintpack.FileWalker { +func WalkerForLocalDef(v LocalDefVisitor, info *types.Info) linter.FileWalker { return &localDefWalker{visitor: v, info: info} } diff --git a/checkers/mapKey_checker.go b/checkers/mapKey_checker.go index c1774102f..0b7100c72 100644 --- a/checkers/mapKey_checker.go +++ b/checkers/mapKey_checker.go @@ -5,16 +5,16 @@ import ( "go/types" "strings" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astp" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "mapKey" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious map literal keys" @@ -29,14 +29,14 @@ _ = map[string]int{ "bar": 2, }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&mapKeyChecker{ctx: ctx}) }) } type mapKeyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext astSet lintutil.AstSet } diff --git a/checkers/methodExprCall_checker.go b/checkers/methodExprCall_checker.go index 95d06efa5..efd631143 100644 --- a/checkers/methodExprCall_checker.go +++ b/checkers/methodExprCall_checker.go @@ -4,15 +4,15 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "methodExprCall" info.Tags = []string{"style", "experimental"} info.Summary = "Detects method expression call that can be replaced with a method call" @@ -21,14 +21,14 @@ foo.bar(f)` info.After = `f := foo{} f.bar()` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&methodExprCallChecker{ctx: ctx}) }) } type methodExprCallChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *methodExprCallChecker) VisitExpr(x ast.Expr) { diff --git a/checkers/nestingReduce_checker.go b/checkers/nestingReduce_checker.go index 234b09d50..de02c7eec 100644 --- a/checkers/nestingReduce_checker.go +++ b/checkers/nestingReduce_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "nestingReduce" info.Tags = []string{"style", "opinionated", "experimental"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "bodyWidth": { Value: 5, Usage: "min number of statements inside a branch to trigger a warning", @@ -32,7 +32,7 @@ for _, v := range a { body() }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &nestingReduceChecker{ctx: ctx} c.bodyWidth = info.Params.Int("bodyWidth") return astwalk.WalkerForStmt(c) @@ -41,7 +41,7 @@ for _, v := range a { type nestingReduceChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext bodyWidth int } diff --git a/checkers/newDeref_checker.go b/checkers/newDeref_checker.go index 2d8c2fac4..e03ec9514 100644 --- a/checkers/newDeref_checker.go +++ b/checkers/newDeref_checker.go @@ -3,29 +3,29 @@ package checkers import ( "go/ast" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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" "golang.org/x/tools/go/ast/astutil" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "newDeref" info.Tags = []string{"style", "experimental"} info.Summary = "Detects immediate dereferencing of `new` expressions" info.Before = `x := *new(bool)` info.After = `x := false` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&newDerefChecker{ctx: ctx}) }) } type newDerefChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *newDerefChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/nilValReturn_checker.go b/checkers/nilValReturn_checker.go index b1a7d6341..37f964f70 100644 --- a/checkers/nilValReturn_checker.go +++ b/checkers/nilValReturn_checker.go @@ -4,14 +4,14 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "nilValReturn" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects return statements those results evaluate to nil" @@ -29,14 +29,14 @@ if err != nil { return err }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&nilValReturnChecker{ctx: ctx}) }) } type nilValReturnChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *nilValReturnChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/octalLiteral_checker.go b/checkers/octalLiteral_checker.go index 7adc6ae9a..a1d968043 100644 --- a/checkers/octalLiteral_checker.go +++ b/checkers/octalLiteral_checker.go @@ -5,20 +5,20 @@ import ( "go/token" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "octalLiteral" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects octal literals passed to functions" info.Before = `foo(02)` info.After = `foo(2)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &octalLiteralChecker{ ctx: ctx, octFriendlyPkg: map[string]bool{ @@ -32,7 +32,7 @@ func init() { type octalLiteralChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext octFriendlyPkg map[string]bool } diff --git a/checkers/offBy1_checker.go b/checkers/offBy1_checker.go index 9bd695c36..1d8a45e32 100644 --- a/checkers/offBy1_checker.go +++ b/checkers/offBy1_checker.go @@ -4,8 +4,8 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astequal" @@ -13,21 +13,21 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "offBy1" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects various off-by-one kind of errors" info.Before = `xs[len(xs)]` info.After = `xs[len(xs)-1]` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&offBy1Checker{ctx: ctx}) }) } type offBy1Checker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *offBy1Checker) VisitExpr(e ast.Expr) { diff --git a/checkers/paramTypeCombine_checker.go b/checkers/paramTypeCombine_checker.go index 0e10f2a77..e13ea9006 100644 --- a/checkers/paramTypeCombine_checker.go +++ b/checkers/paramTypeCombine_checker.go @@ -3,27 +3,27 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "paramTypeCombine" info.Tags = []string{"style", "opinionated"} info.Summary = "Detects if function parameters could be combined by type and suggest the way to do it" info.Before = `func foo(a, b int, c, d int, e, f int, g int) {}` info.After = `func foo(a, b, c, d, e, f, g int) {}` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(¶mTypeCombineChecker{ctx: ctx}) }) } type paramTypeCombineChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *paramTypeCombineChecker) EnterFunc(*ast.FuncDecl) bool { diff --git a/checkers/ptrToRefParam_checker.go b/checkers/ptrToRefParam_checker.go index e67703d33..2716fe04b 100644 --- a/checkers/ptrToRefParam_checker.go +++ b/checkers/ptrToRefParam_checker.go @@ -4,26 +4,26 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "ptrToRefParam" info.Tags = []string{"style", "opinionated", "experimental"} info.Summary = "Detects input and output parameters that have a type of pointer to referential type" info.Before = `func f(m *map[string]int) (*chan *int)` info.After = `func f(m map[string]int) (chan *int)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(&ptrToRefParamChecker{ctx: ctx}) }) } type ptrToRefParamChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *ptrToRefParamChecker) VisitFuncDecl(fn *ast.FuncDecl) { diff --git a/checkers/rangeExprCopy_checker.go b/checkers/rangeExprCopy_checker.go index 564cd9d7f..90b5987ab 100644 --- a/checkers/rangeExprCopy_checker.go +++ b/checkers/rangeExprCopy_checker.go @@ -4,15 +4,15 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "rangeExprCopy" info.Tags = []string{"performance"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "sizeThreshold": { Value: 512, Usage: "size in bytes that makes the warning trigger", @@ -36,7 +36,7 @@ for _, x := range &xs { // No copy }` info.Note = "See Go issue for details: https://github.com/golang/go/issues/15812." - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &rangeExprCopyChecker{ctx: ctx} c.sizeThreshold = int64(info.Params.Int("sizeThreshold")) c.skipTestFuncs = info.Params.Bool("skipTestFuncs") @@ -46,7 +46,7 @@ for _, x := range &xs { // No copy type rangeExprCopyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext sizeThreshold int64 skipTestFuncs bool diff --git a/checkers/rangeValCopy_checker.go b/checkers/rangeValCopy_checker.go index 03040412a..57dcc3151 100644 --- a/checkers/rangeValCopy_checker.go +++ b/checkers/rangeValCopy_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "rangeValCopy" info.Tags = []string{"performance"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "sizeThreshold": { Value: 128, Usage: "size in bytes that makes the warning trigger", @@ -35,7 +35,7 @@ for i := range xs { // Loop body. }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &rangeValCopyChecker{ctx: ctx} c.sizeThreshold = int64(info.Params.Int("sizeThreshold")) c.skipTestFuncs = info.Params.Bool("skipTestFuncs") @@ -45,7 +45,7 @@ for i := range xs { type rangeValCopyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext sizeThreshold int64 skipTestFuncs bool diff --git a/checkers/regexpMust_checker.go b/checkers/regexpMust_checker.go index a8c106580..411932ee5 100644 --- a/checkers/regexpMust_checker.go +++ b/checkers/regexpMust_checker.go @@ -4,28 +4,28 @@ import ( "go/ast" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astp" "golang.org/x/tools/go/ast/astutil" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "regexpMust" info.Tags = []string{"style"} info.Summary = "Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`" info.Before = `re, _ := regexp.Compile("const pattern")` info.After = `re := regexp.MustCompile("const pattern")` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(®expMustChecker{ctx: ctx}) }) } type regexpMustChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *regexpMustChecker) VisitExpr(x ast.Expr) { diff --git a/checkers/regexpPattern_checker.go b/checkers/regexpPattern_checker.go index 476d7e3a8..018ab42d1 100644 --- a/checkers/regexpPattern_checker.go +++ b/checkers/regexpPattern_checker.go @@ -6,19 +6,19 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "regexpPattern" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious regexp patterns" info.Before = "regexp.MustCompile(`google.com|yandex.ru`)" info.After = "regexp.MustCompile(`google\\.com|yandex\\.ru`)" - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { domains := []string{ "com", "org", @@ -39,7 +39,7 @@ func init() { type regexpPatternChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext domainRE *regexp.Regexp } diff --git a/checkers/regexpSimplify_checker.go b/checkers/regexpSimplify_checker.go index 7bedd7100..10dcb327f 100644 --- a/checkers/regexpSimplify_checker.go +++ b/checkers/regexpSimplify_checker.go @@ -8,13 +8,13 @@ import ( "strings" "unicode/utf8" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/quasilyte/regex/syntax" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "regexpSimplify" info.Tags = []string{"style", "experimental", "opinionated"} info.Summary = "Detects regexp patterns that can be simplified" @@ -26,7 +26,7 @@ func init() { // `[[:digit:]] -> \d` // `[A-Za-z0-9_]` -> `\w` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { opts := &syntax.ParserOptions{ NoLiterals: true, } @@ -41,7 +41,7 @@ func init() { type regexpSimplifyChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext parser *syntax.Parser // out is a tmp buffer where we build a simplified regexp pattern. diff --git a/checkers/ruleguard_checker.go b/checkers/ruleguard_checker.go index 4968a81ed..5a9fc46d8 100644 --- a/checkers/ruleguard_checker.go +++ b/checkers/ruleguard_checker.go @@ -7,15 +7,15 @@ import ( "io/ioutil" "log" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" "github.com/quasilyte/go-ruleguard/ruleguard" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "ruleguard" info.Tags = []string{"style", "experimental"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "rules": { Value: "", Usage: "path to a gorules file", @@ -27,12 +27,12 @@ func init() { info.After = `N/A` info.Note = "See https://github.com/quasilyte/go-ruleguard." - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return newRuleguardChecker(&info, ctx) }) } -func newRuleguardChecker(info *lintpack.CheckerInfo, ctx *lintpack.CheckerContext) *ruleguardChecker { +func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) *ruleguardChecker { c := &ruleguardChecker{ctx: ctx} rulesFilename := info.Params.String("rules") if rulesFilename == "" { @@ -63,7 +63,7 @@ func newRuleguardChecker(info *lintpack.CheckerInfo, ctx *lintpack.CheckerContex } type ruleguardChecker struct { - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext rset *ruleguard.GoRuleSet } diff --git a/checkers/singleCaseSwitch_checker.go b/checkers/singleCaseSwitch_checker.go index 3ef952a58..e8dc5800c 100644 --- a/checkers/singleCaseSwitch_checker.go +++ b/checkers/singleCaseSwitch_checker.go @@ -3,12 +3,12 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "singleCaseSwitch" info.Tags = []string{"style"} info.Summary = "Detects switch statements that could be better written as if statement" @@ -22,14 +22,14 @@ if x, ok := x.(int); ok { body() }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&singleCaseSwitchChecker{ctx: ctx}) }) } type singleCaseSwitchChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *singleCaseSwitchChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/sloppyLen_checker.go b/checkers/sloppyLen_checker.go index e27cb31b2..e12545ffe 100644 --- a/checkers/sloppyLen_checker.go +++ b/checkers/sloppyLen_checker.go @@ -4,14 +4,14 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astfmt" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "sloppyLen" info.Tags = []string{"style"} info.Summary = "Detects usage of `len` when result is obvious or doesn't make sense" @@ -23,14 +23,14 @@ len(arr) < 0 // Doesn't make sense at all` len(arr) > 0 len(arr) == 0` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&sloppyLenChecker{ctx: ctx}) }) } type sloppyLenChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *sloppyLenChecker) VisitExpr(x ast.Expr) { diff --git a/checkers/sloppyReassign_checker.go b/checkers/sloppyReassign_checker.go index 9a3bca766..d099450d1 100644 --- a/checkers/sloppyReassign_checker.go +++ b/checkers/sloppyReassign_checker.go @@ -4,29 +4,29 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "sloppyReassign" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious/confusing re-assignments" info.Before = `if err = f(); err != nil { return err }` info.After = `if err := f(); err != nil { return err }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&sloppyReassignChecker{ctx: ctx}) }) } type sloppyReassignChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *sloppyReassignChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/sloppyTypeAssert_checker.go b/checkers/sloppyTypeAssert_checker.go index e451de0e1..4abfcbab4 100644 --- a/checkers/sloppyTypeAssert_checker.go +++ b/checkers/sloppyTypeAssert_checker.go @@ -4,13 +4,13 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "sloppyTypeAssert" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects redundant type assertions" @@ -25,14 +25,14 @@ function f(r io.Reader) interface{} { } ` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&sloppyTypeAssertChecker{ctx: ctx}) }) } type sloppyTypeAssertChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *sloppyTypeAssertChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/sortSlice_checker.go b/checkers/sortSlice_checker.go index 06bedfbb2..b80c17873 100644 --- a/checkers/sortSlice_checker.go +++ b/checkers/sortSlice_checker.go @@ -4,9 +4,9 @@ import ( "go/ast" "go/token" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astequal" "github.com/go-toolsmith/typep" @@ -14,21 +14,21 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "sortSlice" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects suspicious sort.Slice calls" info.Before = `sort.Slice(xs, func(i, j) bool { return keys[i] < keys[j] })` info.After = `sort.Slice(kv, func(i, j) bool { return kv[i].key < kv[j].key })` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&sortSliceChecker{ctx: ctx}) }) } type sortSliceChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *sortSliceChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/sqlQuery_checker.go b/checkers/sqlQuery_checker.go index 0c45203b6..697a82ccf 100644 --- a/checkers/sqlQuery_checker.go +++ b/checkers/sqlQuery_checker.go @@ -4,27 +4,27 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "sqlQuery" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects issue in Query() and Exec() calls" info.Before = `_, err := db.Query("UPDATE ...")` info.After = `_, err := db.Exec("UPDATE ...")` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&sqlQueryChecker{ctx: ctx}) }) } type sqlQueryChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *sqlQueryChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/stringXbytes_checker.go b/checkers/stringXbytes_checker.go index a0745a85d..5108b4787 100644 --- a/checkers/stringXbytes_checker.go +++ b/checkers/stringXbytes_checker.go @@ -3,27 +3,27 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/typep" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "stringXbytes" info.Tags = []string{"style", "experimental"} info.Summary = "Detects redundant conversions between string and []byte" info.Before = `copy(b, []byte(s))` info.After = `copy(b, s)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&stringXbytes{ctx: ctx}) }) } type stringXbytes struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *stringXbytes) VisitExpr(expr ast.Expr) { diff --git a/checkers/switchTrue_checker.go b/checkers/switchTrue_checker.go index e531ceeb5..5390360c5 100644 --- a/checkers/switchTrue_checker.go +++ b/checkers/switchTrue_checker.go @@ -3,12 +3,12 @@ package checkers import ( "go/ast" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "switchTrue" info.Tags = []string{"style"} info.Summary = "Detects switch-over-bool statements that use explicit `true` tag value" @@ -21,14 +21,14 @@ switch { case x > y: }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&switchTrueChecker{ctx: ctx}) }) } type switchTrueChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *switchTrueChecker) VisitStmt(stmt ast.Stmt) { diff --git a/checkers/testdata/importShadow/negative_tests.go b/checkers/testdata/importShadow/negative_tests.go index 674ecec15..b7dc82787 100644 --- a/checkers/testdata/importShadow/negative_tests.go +++ b/checkers/testdata/importShadow/negative_tests.go @@ -6,11 +6,11 @@ import ( _ "github.com/go-toolsmith/astfmt" // To reproduce #665 - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) func noWarnings() { - fmt.Printf("Hello PI=%v, Info=%v", math.Pi, lintpack.CheckerInfo{}) + fmt.Printf("Hello PI=%v, Info=%v", math.Pi, linter.CheckerInfo{}) } func noShadowByParams(x string, y int) (a string, b int) { return } diff --git a/checkers/testdata/importShadow/positive_tests.go b/checkers/testdata/importShadow/positive_tests.go index 6fa74fde8..94d9e6511 100644 --- a/checkers/testdata/importShadow/positive_tests.go +++ b/checkers/testdata/importShadow/positive_tests.go @@ -7,21 +7,21 @@ import ( mymath1 "math" mymath2 "math" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) var _ = mymath1.E var _ = mymath2.E func shadowImportedPackages() { - fmt.Printf("Hello PI=%v, Info=%v", math.Pi, lintpack.CheckerInfo{}) + fmt.Printf("Hello PI=%v, Info=%v", math.Pi, linter.CheckerInfo{}) /*! shadow of imported package 'math' */ math := "some math" - /*! shadow of imported from 'github.com/go-lintpack/lintpack' package 'lintpack' */ - lintpack := "some lint" + /*! shadow of imported from 'github.com/go-critic/go-critic/framework/linter' package 'linter' */ + linter := "some lint" - fmt.Printf("Hello math=%v, lint=%v", math, lint) + fmt.Printf("Hello math=%v, lint=%v", math, linter) } func genDeclShadow() { @@ -30,10 +30,10 @@ func genDeclShadow() { var ( /*! shadow of imported package 'fmt' */ fmt = 2 - /*! shadow of imported from 'github.com/go-lintpack/lintpack' package 'lintpack' */ - lintpack = 3 + /*! shadow of imported from 'github.com/go-critic/go-critic/framework/linter' package 'linter' */ + linter = 3 ) - _, _ = fmt, lintpack + _, _ = fmt, linter } /*! shadow of imported package 'math' */ diff --git a/checkers/truncateCmp_checker.go b/checkers/truncateCmp_checker.go index e6df669f0..a5b7bdd32 100644 --- a/checkers/truncateCmp_checker.go +++ b/checkers/truncateCmp_checker.go @@ -5,17 +5,17 @@ import ( "go/token" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "truncateCmp" info.Tags = []string{"diagnostic", "experimental"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "skipArchDependent": { Value: true, Usage: "whether to skip int/uint/uintptr types", @@ -31,7 +31,7 @@ func f(x int32, int16) bool { return x < int32(y) }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &truncateCmpChecker{ctx: ctx} c.skipArchDependent = info.Params.Bool("skipArchDependent") return astwalk.WalkerForExpr(c) @@ -40,7 +40,7 @@ func f(x int32, int16) bool { type truncateCmpChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext skipArchDependent bool } diff --git a/checkers/typeAssertChain_checker.go b/checkers/typeAssertChain_checker.go index 48f3c8d35..2940e57f9 100644 --- a/checkers/typeAssertChain_checker.go +++ b/checkers/typeAssertChain_checker.go @@ -4,16 +4,16 @@ import ( "go/ast" "go/token" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astequal" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "typeAssertChain" info.Tags = []string{"style", "experimental"} info.Summary = "Detects repeated type assertions and suggests to replace them with type switch statement" @@ -35,14 +35,14 @@ default: // Code C, uses x. }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&typeAssertChainChecker{ctx: ctx}) }) } type typeAssertChainChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext cause *ast.IfStmt visited map[*ast.IfStmt]bool diff --git a/checkers/typeSwitchVar_checker.go b/checkers/typeSwitchVar_checker.go index c1a36556f..2ade4a954 100644 --- a/checkers/typeSwitchVar_checker.go +++ b/checkers/typeSwitchVar_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astequal" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "typeSwitchVar" info.Tags = []string{"style"} info.Summary = "Detects type switches that can benefit from type guard clause with variable" @@ -34,14 +34,14 @@ default: return 0 }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&typeSwitchVarChecker{ctx: ctx}) }) } type typeSwitchVarChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext count int } diff --git a/checkers/typeUnparen_checker.go b/checkers/typeUnparen_checker.go index b6c62485b..620d2d797 100644 --- a/checkers/typeUnparen_checker.go +++ b/checkers/typeUnparen_checker.go @@ -3,30 +3,30 @@ package checkers import ( "go/ast" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astcopy" "github.com/go-toolsmith/astp" "golang.org/x/tools/go/ast/astutil" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "typeUnparen" info.Tags = []string{"style", "opinionated"} info.Summary = "Detects unneded parenthesis inside type expressions and suggests to remove them" info.Before = `type foo [](func([](func())))` info.After = `type foo []func([]func())` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForTypeExpr(&typeUnparenChecker{ctx: ctx}, ctx.TypesInfo) }) } type typeUnparenChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *typeUnparenChecker) VisitTypeExpr(x ast.Expr) { diff --git a/checkers/underef_checker.go b/checkers/underef_checker.go index 8b11885bb..561270c7c 100644 --- a/checkers/underef_checker.go +++ b/checkers/underef_checker.go @@ -4,17 +4,17 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "underef" info.Tags = []string{"style"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "skipRecvDeref": { Value: true, Usage: "whether to skip (*x).method() calls where x is a pointer receiver", @@ -28,7 +28,7 @@ v := (*a)[5] // only if a is array` k.field = 5 v := a[5]` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &underefChecker{ctx: ctx} c.skipRecvDeref = info.Params.Bool("skipRecvDeref") return astwalk.WalkerForExpr(c) @@ -37,7 +37,7 @@ v := a[5]` type underefChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext skipRecvDeref bool } diff --git a/checkers/unlabelStmt_checker.go b/checkers/unlabelStmt_checker.go index 94e0b4ac4..83c5b1484 100644 --- a/checkers/unlabelStmt_checker.go +++ b/checkers/unlabelStmt_checker.go @@ -4,13 +4,13 @@ import ( "go/ast" "go/token" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unlabelStmt" info.Tags = []string{"style", "experimental"} info.Summary = "Detects redundant statement labels" @@ -28,14 +28,14 @@ for x := range xs { } }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmt(&unlabelStmtChecker{ctx: ctx}) }) } type unlabelStmtChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *unlabelStmtChecker) EnterFunc(fn *ast.FuncDecl) bool { diff --git a/checkers/unlambda_checker.go b/checkers/unlambda_checker.go index 860cfbad7..946227c2f 100644 --- a/checkers/unlambda_checker.go +++ b/checkers/unlambda_checker.go @@ -4,28 +4,28 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unlambda" info.Tags = []string{"style"} info.Summary = "Detects function literals that can be simplified" info.Before = `func(x int) int { return fn(x) }` info.After = `fn` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&unlambdaChecker{ctx: ctx}) }) } type unlambdaChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *unlambdaChecker) VisitExpr(x ast.Expr) { diff --git a/checkers/unnamedResult_checker.go b/checkers/unnamedResult_checker.go index 54e5ce1cd..f053842ec 100644 --- a/checkers/unnamedResult_checker.go +++ b/checkers/unnamedResult_checker.go @@ -4,15 +4,15 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unnamedResult" info.Tags = []string{"style", "opinionated", "experimental"} - info.Params = lintpack.CheckerParams{ + info.Params = linter.CheckerParams{ "checkExported": { Value: false, Usage: "whether to check exported functions", @@ -22,7 +22,7 @@ func init() { info.Before = `func f() (float64, float64)` info.After = `func f() (x, y float64)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { c := &unnamedResultChecker{ctx: ctx} c.checkExported = info.Params.Bool("checkExported") return astwalk.WalkerForFuncDecl(c) @@ -31,7 +31,7 @@ func init() { type unnamedResultChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext checkExported bool } diff --git a/checkers/unnecessaryBlock_checker.go b/checkers/unnecessaryBlock_checker.go index b61f3cc06..acc9fadbf 100644 --- a/checkers/unnecessaryBlock_checker.go +++ b/checkers/unnecessaryBlock_checker.go @@ -4,12 +4,12 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unnecessaryBlock" info.Tags = []string{"style", "opinionated", "experimental"} info.Summary = "Detects unnecessary braced statement blocks" @@ -22,14 +22,14 @@ x := 1 x := 1 print(x)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmtList(&unnecessaryBlockChecker{ctx: ctx}) }) } type unnecessaryBlockChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *unnecessaryBlockChecker) VisitStmtList(statements []ast.Stmt) { diff --git a/checkers/unnecessaryDefer_checker.go b/checkers/unnecessaryDefer_checker.go index f4f0ae680..ce25a07ca 100644 --- a/checkers/unnecessaryDefer_checker.go +++ b/checkers/unnecessaryDefer_checker.go @@ -3,15 +3,15 @@ package checkers import ( "go/ast" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astfmt" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unnecessaryDefer" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects redundantly deferred calls" @@ -24,14 +24,14 @@ func() { os.Remove(filename) }` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForFuncDecl(&unnecessaryDeferChecker{ctx: ctx}) }) } type unnecessaryDeferChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext isFunc bool } diff --git a/checkers/unslice_checker.go b/checkers/unslice_checker.go index a2bfd5a91..73f67bc8e 100644 --- a/checkers/unslice_checker.go +++ b/checkers/unslice_checker.go @@ -4,13 +4,13 @@ import ( "go/ast" "go/types" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "unslice" info.Tags = []string{"style"} info.Summary = "Detects slice expressions that can be simplified to sliced expression itself" @@ -21,14 +21,14 @@ copy(b[:], values...) // b is []byte` f(s) copy(b, values...)` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&unsliceChecker{ctx: ctx}) }) } type unsliceChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *unsliceChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/utils.go b/checkers/utils.go index ba4777dbd..b71f24d74 100644 --- a/checkers/utils.go +++ b/checkers/utils.go @@ -5,7 +5,7 @@ import ( "go/types" "strings" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) // goStdlib contains `go list std` command output list. @@ -247,7 +247,7 @@ func isExampleTestFunc(fn *ast.FuncDecl) bool { } // isUnitTestFunc reports whether FuncDecl declares testing function. -func isUnitTestFunc(ctx *lintpack.CheckerContext, fn *ast.FuncDecl) bool { +func isUnitTestFunc(ctx *linter.CheckerContext, fn *ast.FuncDecl) bool { if !strings.HasPrefix(fn.Name.Name, "Test") { return false } diff --git a/checkers/valSwap_checker.go b/checkers/valSwap_checker.go index 3e16ac98c..8a8c9f743 100644 --- a/checkers/valSwap_checker.go +++ b/checkers/valSwap_checker.go @@ -4,14 +4,14 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "valSwap" info.Tags = []string{"style", "experimental"} info.Summary = "Detects value swapping code that are not using parallel assignment" @@ -21,14 +21,14 @@ tmp := *x *y = tmp` info.After = `*x, *y = *y, *x` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForStmtList(&valSwapChecker{ctx: ctx}) }) } type valSwapChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *valSwapChecker) VisitStmtList(list []ast.Stmt) { diff --git a/checkers/weakCond_checker.go b/checkers/weakCond_checker.go index 3a9dc7e68..1d6ee58ef 100644 --- a/checkers/weakCond_checker.go +++ b/checkers/weakCond_checker.go @@ -4,9 +4,9 @@ import ( "go/ast" "go/token" - "github.com/go-critic/go-critic/checkers/internal/lintutil" - "github.com/go-lintpack/lintpack" "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/astequal" "github.com/go-toolsmith/typep" @@ -14,21 +14,21 @@ import ( ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "weakCond" info.Tags = []string{"diagnostic", "experimental"} info.Summary = "Detects conditions that are unsafe due to not being exhaustive" info.Before = `xs != nil && xs[0] != nil` info.After = `len(xs) != 0 && xs[0] != nil` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForExpr(&weakCondChecker{ctx: ctx}) }) } type weakCondChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *weakCondChecker) VisitExpr(expr ast.Expr) { diff --git a/checkers/whyNoLint_checker.go b/checkers/whyNoLint_checker.go index 401a20f39..cc5c5172e 100644 --- a/checkers/whyNoLint_checker.go +++ b/checkers/whyNoLint_checker.go @@ -5,12 +5,12 @@ import ( "regexp" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" ) func init() { - info := lintpack.CheckerInfo{ + info := linter.CheckerInfo{ Name: "whyNoLint", Tags: []string{"style", "experimental"}, Summary: "Ensures that `//nolint` comments include an explanation", @@ -19,7 +19,7 @@ func init() { } re := regexp.MustCompile(`^// *nolint(?::[^ ]+)? *(.*)$`) - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForComment(&whyNoLintChecker{ ctx: ctx, re: re, @@ -30,7 +30,7 @@ func init() { type whyNoLintChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext re *regexp.Regexp } diff --git a/checkers/wrapperFunc_checker.go b/checkers/wrapperFunc_checker.go index f4245dc6e..05e633d3d 100644 --- a/checkers/wrapperFunc_checker.go +++ b/checkers/wrapperFunc_checker.go @@ -6,20 +6,20 @@ import ( "go/types" "strings" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "wrapperFunc" info.Tags = []string{"style", "experimental"} info.Summary = "Detects function calls that can be replaced with convenience wrappers" info.Before = `wg.Add(-1)` info.After = `wg.Done()` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { type arg struct { index int value string @@ -208,7 +208,7 @@ func init() { type wrapperFuncChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext findSuggestion func(*ast.CallExpr) string } diff --git a/checkers/yodaStyleExpr_checker.go b/checkers/yodaStyleExpr_checker.go index 8740f132d..b4672fcca 100644 --- a/checkers/yodaStyleExpr_checker.go +++ b/checkers/yodaStyleExpr_checker.go @@ -4,28 +4,28 @@ import ( "go/ast" "go/token" - "github.com/go-lintpack/lintpack" "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcopy" "github.com/go-toolsmith/astp" ) func init() { - var info lintpack.CheckerInfo + var info linter.CheckerInfo info.Name = "yodaStyleExpr" info.Tags = []string{"style", "experimental"} info.Summary = "Detects Yoda style expressions and suggests to replace them" info.Before = `return nil != ptr` info.After = `return ptr != nil` - collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { return astwalk.WalkerForLocalExpr(&yodaStyleExprChecker{ctx: ctx}) }) } type yodaStyleExprChecker struct { astwalk.WalkHandler - ctx *lintpack.CheckerContext + ctx *linter.CheckerContext } func (c *yodaStyleExprChecker) VisitLocalExpr(expr ast.Expr) { diff --git a/cmd/gocritic/main.go b/cmd/gocritic/main.go new file mode 100644 index 000000000..09eaf2ca3 --- /dev/null +++ b/cmd/gocritic/main.go @@ -0,0 +1,13 @@ +package main + +import ( + _ "github.com/go-critic/go-critic/checkers" // Register go-critic checkers + "github.com/go-critic/go-critic/framework/lintmain" +) + +func main() { + lintmain.Run(lintmain.Config{ + Name: "gocritic", + Version: "v0.5.0", + }) +} diff --git a/cmd/makedocs/main.go b/cmd/makedocs/main.go index ec8466857..018ab5916 100644 --- a/cmd/makedocs/main.go +++ b/cmd/makedocs/main.go @@ -7,7 +7,7 @@ import ( "text/template" _ "github.com/go-critic/go-critic/checkers" - "github.com/go-lintpack/lintpack" + "github.com/go-critic/go-critic/framework/linter" ) const ( @@ -23,9 +23,9 @@ func main() { buf := bytes.Buffer{} err := tmpl.ExecuteTemplate(&buf, "overview", struct { - Checkers []*lintpack.CheckerInfo + Checkers []*linter.CheckerInfo }{ - Checkers: lintpack.GetCheckersInfo(), + Checkers: linter.GetCheckersInfo(), }) if err != nil { log.Fatalf("render template: %v", err) diff --git a/framework/cmdutil/cmdutil.go b/framework/cmdutil/cmdutil.go new file mode 100644 index 000000000..624a8efc3 --- /dev/null +++ b/framework/cmdutil/cmdutil.go @@ -0,0 +1,72 @@ +package cmdutil + +import ( + "log" + "os" +) + +// SubCommand is an implementation of a linter sub-command. +type SubCommand struct { + // Main is command entry point. + Main func() + + // Name is sub-command name used to execute it. + Name string + + // Short describes command in one line of text. + Short string + + // Examples shows one or more sub-command execution examples. + Examples []string +} + +// DispatchCommand runs sub command out of specified cmdList based on +// the first command line argument. +func DispatchCommand(cmdList []*SubCommand) { + argv := os.Args + if len(argv) < 2 { + log.Printf("not enough arguments, expected sub-command name\n\n") + printSubCommands(cmdList) + os.Exit(1) + } + + subIdx := 1 // [0] is program name + sub := os.Args[subIdx] + // Erase sub-command argument (index=1) to make it invisible for + // sub commands themselves. + os.Args = append(os.Args[:subIdx], os.Args[subIdx+1:]...) + + // Choose and run sub-command main. + cmd := findSubCommand(cmdList, sub) + if cmd == nil { + log.Printf("unknown sub-command: %s\n\n", sub) + printSubCommands(cmdList) + os.Exit(1) + } + + // The called function may exit with non-zero status. + // No code should follow this call. + cmd.Main() +} + +// findSubCommand looks up SubCommand by its name. +// Returns nil if requested command not found. +func findSubCommand(cmdList []*SubCommand, name string) *SubCommand { + for _, cmd := range cmdList { + if cmd.Name == name { + return cmd + } + } + return nil +} + +// printSubCommands prints cmdList info to the logger (usually stderr). +func printSubCommands(cmdList []*SubCommand) { + log.Println("Supported sub-commands:") + for _, cmd := range cmdList { + log.Printf("\t%s - %s", cmd.Name, cmd.Short) + for _, ex := range cmd.Examples { + log.Printf("\t\t$ %s", ex) + } + } +} diff --git a/framework/linter/checkers_db.go b/framework/linter/checkers_db.go new file mode 100644 index 000000000..b4bebe443 --- /dev/null +++ b/framework/linter/checkers_db.go @@ -0,0 +1,135 @@ +package linter + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "github.com/go-toolsmith/astfmt" +) + +type checkerProto struct { + info *CheckerInfo + constructor func(*Context) *Checker +} + +// prototypes is a set of registered checkers that are not yet instantiated. +// Registration should be done with AddChecker function. +// Initialized checkers can be obtained with NewChecker function. +var prototypes = make(map[string]checkerProto) + +func getCheckersInfo() []*CheckerInfo { + infoList := make([]*CheckerInfo, 0, len(prototypes)) + for _, proto := range prototypes { + infoCopy := *proto.info + infoList = append(infoList, &infoCopy) + } + sort.Slice(infoList, func(i, j int) bool { + return infoList[i].Name < infoList[j].Name + }) + return infoList +} + +func addChecker(info *CheckerInfo, constructor func(*CheckerContext) FileWalker) { + if _, ok := prototypes[info.Name]; ok { + panic(fmt.Sprintf("checker with name %q already registered", info.Name)) + } + + // Validate param value type. + for pname, param := range info.Params { + switch param.Value.(type) { + case string, int, bool: + // OK. + default: + panic(fmt.Sprintf("unsupported %q param type value: %T", + pname, param.Value)) + } + } + + trimDocumentation := func(info *CheckerInfo) { + fields := []*string{ + &info.Summary, + &info.Details, + &info.Before, + &info.After, + &info.Note, + } + for _, f := range fields { + *f = strings.TrimSpace(*f) + } + } + + trimDocumentation(info) + + if err := validateCheckerInfo(info); err != nil { + panic(err) + } + + proto := checkerProto{ + info: info, + constructor: func(ctx *Context) *Checker { + var c Checker + c.Info = info + c.ctx = CheckerContext{ + Context: ctx, + printer: astfmt.NewPrinter(ctx.FileSet), + } + c.fileWalker = constructor(&c.ctx) + return &c + }, + } + + prototypes[info.Name] = proto +} + +func newChecker(ctx *Context, info *CheckerInfo) *Checker { + proto, ok := prototypes[info.Name] + if !ok { + panic(fmt.Sprintf("checker with name %q not registered", info.Name)) + } + return proto.constructor(ctx) +} + +func validateCheckerInfo(info *CheckerInfo) error { + steps := []func(*CheckerInfo) error{ + validateCheckerName, + validateCheckerDocumentation, + validateCheckerTags, + } + + for _, step := range steps { + if err := step(info); err != nil { + return fmt.Errorf("%q validation error: %v", info.Name, err) + } + } + return nil +} + +var validIdentRE = regexp.MustCompile(`^\w+$`) + +func validateCheckerName(info *CheckerInfo) error { + if !validIdentRE.MatchString(info.Name) { + return fmt.Errorf("checker name contains illegal chars") + } + return nil +} + +func validateCheckerDocumentation(info *CheckerInfo) error { + // TODO(Quasilyte): validate documentation. + return nil +} + +func validateCheckerTags(info *CheckerInfo) error { + tagSet := make(map[string]bool) + for _, tag := range info.Tags { + if tagSet[tag] { + return fmt.Errorf("duplicated tag %q", tag) + } + if !validIdentRE.MatchString(tag) { + return fmt.Errorf("checker tag %q contains illegal chars", tag) + } + tagSet[tag] = true + } + return nil +} diff --git a/framework/linter/context.go b/framework/linter/context.go new file mode 100644 index 000000000..6e108ab6a --- /dev/null +++ b/framework/linter/context.go @@ -0,0 +1,35 @@ +package linter + +import ( + "go/ast" + "go/types" + "strconv" +) + +func resolvePkgObjects(ctx *Context, f *ast.File) { + ctx.PkgObjects = make(map[*types.PkgName]string, len(f.Imports)) + + for _, spec := range f.Imports { + if spec.Name != nil { + obj := ctx.TypesInfo.ObjectOf(spec.Name) + ctx.PkgObjects[obj.(*types.PkgName)] = spec.Name.Name + } else { + obj := ctx.TypesInfo.Implicits[spec] + ctx.PkgObjects[obj.(*types.PkgName)] = obj.Name() + } + } +} + +func resolvePkgRenames(ctx *Context, f *ast.File) { + ctx.PkgRenames = make(map[string]string) + + for _, spec := range f.Imports { + if spec.Name != nil { + path, err := strconv.Unquote(spec.Path.Value) + if err != nil { + panic(err) + } + ctx.PkgRenames[path] = spec.Name.Name + } + } +} diff --git a/framework/linter/lintpack.go b/framework/linter/lintpack.go new file mode 100644 index 000000000..1f984d146 --- /dev/null +++ b/framework/linter/lintpack.go @@ -0,0 +1,247 @@ +package linter + +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/go-toolsmith/astfmt" +) + +// CheckerCollection provides additional information for a group of checkers. +type CheckerCollection struct { + // URL is a link for a main source of information on the collection. + URL string +} + +// AddChecker registers a new checker into a checkers pool. +// Constructor is used to create a new checker instance. +// Checker name (defined in CheckerInfo.Name) must be unique. +// +// CheckerInfo.Collection is automatically set to the coll (the receiver). +// +// If checker is never needed, for example if it is disabled, +// constructor will not be called. +func (coll *CheckerCollection) AddChecker(info *CheckerInfo, constructor func(*CheckerContext) FileWalker) { + if coll == nil { + panic("adding checker to a nil collection") + } + info.Collection = coll + addChecker(info, constructor) +} + +// CheckerParam describes a single checker customizable parameter. +type CheckerParam struct { + // Value holds parameter bound value. + // It might be overwritten by the integrating linter. + // + // Permitted types include: + // - int + // - bool + // - string + Value interface{} + + // Usage gives an overview about what parameter does. + Usage string +} + +// CheckerParams holds all checker-specific parameters. +// +// Provides convenient access to the loosely typed underlying map. +type CheckerParams map[string]*CheckerParam + +// Int lookups pname key in underlying map and type-asserts it to int. +func (params CheckerParams) Int(pname string) int { return params[pname].Value.(int) } + +// Bool lookups pname key in underlying map and type-asserts it to bool. +func (params CheckerParams) Bool(pname string) bool { return params[pname].Value.(bool) } + +// String lookups pname key in underlying map and type-asserts it to string. +func (params CheckerParams) String(pname string) string { return params[pname].Value.(string) } + +// CheckerInfo holds checker metadata and structured documentation. +type CheckerInfo struct { + // Name is a checker name. + Name string + + // Tags is a list of labels that can be used to enable or disable checker. + // Common tags are "experimental" and "performance". + Tags []string + + // Params declares checker-specific parameters. Optional. + Params CheckerParams + + // Summary is a short one sentence description. + // Should not end with a period. + Summary string + + // Details extends summary with additional info. Optional. + Details string + + // Before is a code snippet of code that will violate rule. + Before string + + // After is a code snippet of fixed code that complies to the rule. + After string + + // Note is an optional caution message or advice. + Note string + + // Collection establishes a checker-to-collection relationship. + Collection *CheckerCollection +} + +// GetCheckersInfo returns a checkers info list for all registered checkers. +// The slice is sorted by a checker name. +// +// Info objects can be used to instantiate checkers with NewChecker function. +func GetCheckersInfo() []*CheckerInfo { + return getCheckersInfo() +} + +// HasTag reports whether checker described by the info has specified tag. +func (info *CheckerInfo) HasTag(tag string) bool { + for i := range info.Tags { + if info.Tags[i] == tag { + return true + } + } + return false +} + +// Checker is an implementation of a check that is described by the associated info. +type Checker struct { + // Info is an info object that was used to instantiate this checker. + Info *CheckerInfo + + ctx CheckerContext + + fileWalker FileWalker +} + +// Check runs rule checker over file f. +func (c *Checker) Check(f *ast.File) []Warning { + c.ctx.warnings = c.ctx.warnings[:0] + c.fileWalker.WalkFile(f) + return c.ctx.warnings +} + +// Warning represents issue that is found by checker. +type Warning struct { + // Node is an AST node that caused warning to trigger. + // Can be used to obtain proper error location. + Node ast.Node + + // Text is warning message without source location info. + Text string +} + +// NewChecker returns initialized checker identified by an info. +// info must be non-nil. +// Panics if info describes a checker that was not properly registered. +func NewChecker(ctx *Context, info *CheckerInfo) *Checker { + return newChecker(ctx, info) +} + +// Context is a readonly state shared among every checker. +type Context struct { + // TypesInfo carries parsed packages types information. + TypesInfo *types.Info + + // SizesInfo carries alignment and type size information. + // Arch-dependent. + SizesInfo types.Sizes + + // FileSet is a file set that was used during the program loading. + FileSet *token.FileSet + + // Pkg describes package that is being checked. + Pkg *types.Package + + // Filename is a currently checked file name. + Filename string + + // Require records what optional resources are required + // by the checkers set that use this context. + // + // Every require fields makes associated context field + // to be properly initialized. + // For example, Context.require.PkgObjects => Context.PkgObjects. + Require struct { + PkgObjects bool + PkgRenames bool + } + + // PkgObjects stores all imported packages and their local names. + PkgObjects map[*types.PkgName]string + + // PkgRenames maps package path to its local renaming. + // Contains no entries for packages that were imported without + // explicit local names. + PkgRenames map[string]string +} + +// NewContext returns new shared context to be used by every checker. +// +// All data carried by the context is readonly for checkers, +// but can be modified by the integrating application. +func NewContext(fset *token.FileSet, sizes types.Sizes) *Context { + return &Context{ + FileSet: fset, + SizesInfo: sizes, + TypesInfo: &types.Info{}, + } +} + +// SetPackageInfo sets package-related metadata. +// +// Must be called for every package being checked. +func (c *Context) SetPackageInfo(info *types.Info, pkg *types.Package) { + if info != nil { + // We do this kind of assignment to avoid + // changing c.typesInfo field address after + // every re-assignment. + *c.TypesInfo = *info + } + c.Pkg = pkg +} + +// SetFileInfo sets file-related metadata. +// +// Must be called for every source code file being checked. +func (c *Context) SetFileInfo(name string, f *ast.File) { + c.Filename = name + if c.Require.PkgObjects { + resolvePkgObjects(c, f) + } + if c.Require.PkgRenames { + resolvePkgRenames(c, f) + } +} + +// CheckerContext is checker-local context copy. +// Fields that are not from Context itself are writeable. +type CheckerContext struct { + *Context + + // printer used to format warning text. + printer *astfmt.Printer + + warnings []Warning +} + +// Warn adds a Warning to checker output. +func (ctx *CheckerContext) Warn(node ast.Node, format string, args ...interface{}) { + ctx.warnings = append(ctx.warnings, Warning{ + Text: ctx.printer.Sprintf(format, args...), + Node: node, + }) +} + +// FileWalker is an interface every checker should implement. +// +// The WalkFile method is executed for every Go file inside the +// package that is being checked. +type FileWalker interface { + WalkFile(*ast.File) +} diff --git a/framework/lintmain/internal/check/check.go b/framework/lintmain/internal/check/check.go new file mode 100644 index 000000000..4ea38e925 --- /dev/null +++ b/framework/lintmain/internal/check/check.go @@ -0,0 +1,469 @@ +package check + +import ( + "errors" + "flag" + "fmt" + "go/ast" + "go/build" + "go/token" + "go/types" + "log" + "os" + "path/filepath" + "regexp" + "runtime" + "sort" + "strings" + "sync" + + "github.com/go-critic/go-critic/framework/linter" + "github.com/go-critic/go-critic/framework/lintmain/internal/hotload" + "github.com/go-toolsmith/pkgload" + "github.com/logrusorgru/aurora" + "golang.org/x/tools/go/packages" +) + +// Main implements sub-command entry point. +func Main() { + var p program + p.infoList = linter.GetCheckersInfo() + + steps := []struct { + name string + fn func() error + }{ + {"load plugin", p.loadPlugin}, + {"bind checker params", p.bindCheckerParams}, + {"bind default enabled list", p.bindDefaultEnabledList}, + {"parse args", p.parseArgs}, + {"assign checker params", p.assignCheckerParams}, + {"load program", p.loadProgram}, + {"init checkers", p.initCheckers}, + {"run checkers", p.runCheckers}, + {"exit if found issues", p.exit}, + } + + for _, step := range steps { + if err := step.fn(); err != nil { + log.Fatalf("%s: %v", step.name, err) + } + } +} + +type program struct { + ctx *linter.Context + + fset *token.FileSet + + loadedPackages []*packages.Package + + infoList []*linter.CheckerInfo + + checkers []*linter.Checker + + packages []string + + foundIssues bool + + checkerParams boundCheckerParams + + filters struct { + enableAll bool + enable []string + disable []string + defaultCheckers []string + } + + workDir string + gopath string + goroot string + + exitCode int + checkTests bool + checkGenerated bool + shorterErrLocation bool + coloredOutput bool + verbose bool +} + +func (p *program) exit() error { + if p.foundIssues { + os.Exit(p.exitCode) + } + return nil +} + +func (p *program) runCheckers() error { + for _, pkg := range p.loadedPackages { + if p.verbose { + log.Printf("\tdebug: checking %q package (%d files)", + pkg.String(), len(pkg.Syntax)) + } + p.checkPackage(pkg) + } + + return nil +} + +func (p *program) checkPackage(pkg *packages.Package) { + p.ctx.SetPackageInfo(pkg.TypesInfo, pkg.Types) + for _, f := range pkg.Syntax { + filename := p.getFilename(f) + if !p.checkTests && strings.HasSuffix(filename, "_test.go") { + continue + } + if !p.checkGenerated && p.isGenerated(f) { + continue + } + p.ctx.SetFileInfo(filename, f) + p.checkFile(f) + } +} + +func (p *program) checkFile(f *ast.File) { + warnings := make([][]linter.Warning, len(p.checkers)) + + var wg sync.WaitGroup + wg.Add(len(p.checkers)) + for i, c := range p.checkers { + // All checkers are expected to use *lint.Context + // as read-only structure, so no copying is required. + go func(i int, c *linter.Checker) { + defer func() { + wg.Done() + // Checker signals unexpected error with panic(error). + r := recover() + if r == nil { + return // There were no panic + } + if err, ok := r.(error); ok { + log.Printf("%s: error: %v\n", c.Info.Name, err) + panic(err) + } else { + // Some other kind of run-time panic. + // Undo the recover and resume panic. + panic(r) + } + }() + + for _, warn := range c.Check(f) { + warnings[i] = append(warnings[i], warn) + } + }(i, c) + } + wg.Wait() + + for i, c := range p.checkers { + for _, warn := range warnings[i] { + p.foundIssues = true + loc := p.ctx.FileSet.Position(warn.Node.Pos()).String() + if p.shorterErrLocation { + loc = p.shortenLocation(loc) + } + printWarning(p, c.Info.Name, loc, warn.Text) + } + } + +} + +func (p *program) initCheckers() error { + parseKeys := func(keys []string, byName, byTag map[string]bool) { + for _, key := range keys { + if strings.HasPrefix(key, "#") { + byTag[key[len("#"):]] = true + } else { + byName[key] = true + } + } + } + + enabledByName := make(map[string]bool) + enabledTags := make(map[string]bool) + parseKeys(p.filters.enable, enabledByName, enabledTags) + disabledByName := make(map[string]bool) + disabledTags := make(map[string]bool) + parseKeys(p.filters.disable, disabledByName, disabledTags) + + enabledByTag := func(info *linter.CheckerInfo) bool { + for _, tag := range info.Tags { + if enabledTags[tag] { + return true + } + } + return false + } + disabledByTag := func(info *linter.CheckerInfo) string { + for _, tag := range info.Tags { + if disabledTags[tag] { + return tag + } + } + return "" + } + + for _, info := range p.infoList { + enabled := p.filters.enableAll || + enabledByName[info.Name] || + enabledByTag(info) + notice := "" + + switch { + case !enabled: + notice = "not enabled by name or tag (-enable)" + case disabledByName[info.Name]: + enabled = false + notice = "disabled by name (-disable)" + default: + if tag := disabledByTag(info); tag != "" { + enabled = false + notice = fmt.Sprintf("disabled by %q tag (-disable)", tag) + } + } + + if p.verbose && !enabled { + log.Printf("\tdebug: %s: %s", info.Name, notice) + } + if enabled { + p.checkers = append(p.checkers, linter.NewChecker(p.ctx, info)) + } + } + if p.verbose { + for _, c := range p.checkers { + log.Printf("\tdebug: %s is enabled", c.Info.Name) + } + } + + if len(p.checkers) == 0 { + return errors.New("empty checkers set selected") + } + return nil +} + +func (p *program) loadProgram() error { + sizes := types.SizesFor("gc", runtime.GOARCH) + if sizes == nil { + return fmt.Errorf("can't find sizes info for %s", runtime.GOARCH) + } + + p.fset = token.NewFileSet() + cfg := packages.Config{ + Mode: packages.LoadSyntax, + Tests: true, + Fset: p.fset, + } + pkgs, err := loadPackages(&cfg, p.packages) + if err != nil { + log.Fatalf("load packages: %v", err) + } + sort.SliceStable(pkgs, func(i, j int) bool { + return pkgs[i].PkgPath < pkgs[j].PkgPath + }) + + p.loadedPackages = pkgs + p.ctx = linter.NewContext(p.fset, sizes) + + return nil +} + +func (p *program) loadPlugin() error { + const pluginFilename = "gocritic-plugin.so" + if _, err := os.Stat(pluginFilename); os.IsNotExist(err) { + return nil + } + infoList, err := hotload.CheckersFromDylib(p.infoList, pluginFilename) + p.infoList = infoList + return err +} + +type boundCheckerParams struct { + ints map[string]*int + bools map[string]*bool + strings map[string]*string +} + +// bindCheckerParams registers command-line flags for every checker parameter. +func (p *program) bindCheckerParams() error { + intParams := make(map[string]*int) + boolParams := make(map[string]*bool) + stringParams := make(map[string]*string) + + for _, info := range p.infoList { + for pname, param := range info.Params { + key := p.checkerParamKey(info, pname) + switch v := param.Value.(type) { + case int: + intParams[key] = flag.Int(key, v, param.Usage) + case bool: + boolParams[key] = flag.Bool(key, v, param.Usage) + case string: + stringParams[key] = flag.String(key, v, param.Usage) + default: + panic("unreachable") // Checked in AddChecker + } + } + } + + p.checkerParams.ints = intParams + p.checkerParams.bools = boolParams + p.checkerParams.strings = stringParams + + return nil +} + +func (p *program) checkerParamKey(info *linter.CheckerInfo, pname string) string { + return "@" + info.Name + "." + pname +} + +// bindDefaultEnabledList calculates the default value for -enable param. +func (p *program) bindDefaultEnabledList() error { + var enabled []string + for _, info := range p.infoList { + enable := !info.HasTag("experimental") && + !info.HasTag("opinionated") && + !info.HasTag("performance") + if enable { + enabled = append(enabled, info.Name) + } + } + p.filters.defaultCheckers = enabled + return nil +} + +func (p *program) parseArgs() error { + flag.BoolVar(&p.filters.enableAll, "enableAll", false, + `identical to -enable with all checkers listed. If true, -enable is ignored`) + enable := flag.String("enable", strings.Join(p.filters.defaultCheckers, ","), + `comma-separated list of enabled checkers. Can include #tags`) + disable := flag.String("disable", "", + `comma-separated list of checkers to be disabled. Can include #tags`) + flag.IntVar(&p.exitCode, "exitCode", 1, + `exit code to be used when lint issues are found`) + flag.BoolVar(&p.checkTests, "checkTests", true, + `whether to check test files`) + flag.BoolVar(&p.shorterErrLocation, `shorterErrLocation`, true, + `whether to replace error location prefix with $GOROOT and $GOPATH`) + flag.BoolVar(&p.coloredOutput, `coloredOutput`, false, + `whether to use colored output`) + flag.BoolVar(&p.verbose, "v", false, + `whether to print output useful during linter debugging`) + + flag.Parse() + + p.packages = flag.Args() + p.filters.enable = strings.Split(*enable, ",") + p.filters.disable = strings.Split(*disable, ",") + + if p.shorterErrLocation { + wd, err := os.Getwd() + if err != nil { + log.Printf("getwd: %v", err) + } + p.workDir = addTrailingSlash(wd) + p.gopath = addTrailingSlash(build.Default.GOPATH) + p.goroot = addTrailingSlash(build.Default.GOROOT) + } + + return nil +} + +func addTrailingSlash(s string) string { + if strings.HasSuffix(s, string(os.PathSeparator)) { + return s + } + return s + string(os.PathSeparator) +} + +// assignCheckerParams initializes checker parameter values using +// values that are coming from the command-line arguments. +func (p *program) assignCheckerParams() error { + intParams := p.checkerParams.ints + boolParams := p.checkerParams.bools + stringParams := p.checkerParams.strings + + for _, info := range p.infoList { + for pname, param := range info.Params { + key := p.checkerParamKey(info, pname) + switch param.Value.(type) { + case int: + info.Params[pname].Value = *intParams[key] + case bool: + info.Params[pname].Value = *boolParams[key] + case string: + info.Params[pname].Value = *stringParams[key] + default: + panic("unreachable") // Checked in AddChecker + } + } + } + + return nil +} + +var generatedFileCommentRE = regexp.MustCompile("Code generated .* DO NOT EDIT.") + +func (p *program) isGenerated(f *ast.File) bool { + return len(f.Comments) != 0 && + generatedFileCommentRE.MatchString(f.Comments[0].Text()) +} + +func (p *program) getFilename(f *ast.File) string { + // See https://github.com/golang/go/issues/24498. + return filepath.Base(p.fset.Position(f.Pos()).Filename) +} + +func (p *program) shortenLocation(loc string) string { + // If possible, construct relative path. + relLoc := loc + if p.workDir != "" { + relLoc = strings.Replace(loc, p.workDir, "./", 1) + } + + switch { + case strings.HasPrefix(loc, p.gopath): + loc = strings.Replace(loc, p.gopath, "$GOPATH"+string(os.PathSeparator), 1) + case strings.HasPrefix(loc, p.goroot): + loc = strings.Replace(loc, p.goroot, "$GOROOT"+string(os.PathSeparator), 1) + } + + // Return the representation that is shorter. + if len(relLoc) < len(loc) { + return relLoc + } + return loc +} + +func printWarning(p *program, rule, loc, warn string) { + switch { + case p.coloredOutput: + log.Printf("%v: %v: %v\n", + aurora.Magenta(aurora.Bold(loc)), + aurora.Red(rule), + warn) + + default: + log.Printf("%s: %s: %s\n", loc, rule, warn) + } +} + +func loadPackages(cfg *packages.Config, patterns []string) ([]*packages.Package, error) { + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return nil, err + } + + result := pkgs[:0] + pkgload.VisitUnits(pkgs, func(u *pkgload.Unit) { + if u.ExternalTest != nil { + result = append(result, u.ExternalTest) + } + + if u.Test != nil { + // Prefer tests to the base package, if present. + result = append(result, u.Test) + } else { + result = append(result, u.Base) + } + }) + return result, nil +} diff --git a/framework/lintmain/internal/check/check_test.go b/framework/lintmain/internal/check/check_test.go new file mode 100644 index 000000000..4ef78b359 --- /dev/null +++ b/framework/lintmain/internal/check/check_test.go @@ -0,0 +1,41 @@ +package check + +import ( + "testing" +) + +func TestShortenLocation(t *testing.T) { + testGopath := "/home/queen/go/" + testGoroot := "/usr/lib/go/" + tests := []struct { + wd string + input string + out string + }{ + {"", "/home/queen/go/file.go", "$GOPATH/file.go"}, + {"", "/home/queen/go-file.go", "/home/queen/go-file.go"}, + + {"", "/usr/lib/go/file.go", "$GOROOT/file.go"}, + {"", "/usr/lib/go-file.go", "/usr/lib/go-file.go"}, + + {"/home/queen/go/src/", "/home/queen/go/src/file.go", "./file.go"}, + {"/home/queen/", "/home/queen-src-file.go", "/home/queen-src-file.go"}, + {"/home/", "/home/queen/go/src/file.go", "$GOPATH/src/file.go"}, + + {`C:\home\queen\go\src\`, `C:\home\queen\go\src\file.go`, "./file.go"}, + } + + l := &linter{ + gopath: testGopath, + goroot: testGoroot, + } + for _, test := range tests { + l.workDir = test.wd + have := l.shortenLocation(test.input) + want := test.out + if have != want { + t.Errorf("shorten(%q):\nhave: %q\nwant: %q", + test.input, have, want) + } + } +} diff --git a/framework/lintmain/internal/hotload/hotload.go b/framework/lintmain/internal/hotload/hotload.go new file mode 100644 index 000000000..324d7e78f --- /dev/null +++ b/framework/lintmain/internal/hotload/hotload.go @@ -0,0 +1,30 @@ +package hotload + +import ( + "fmt" + "plugin" + + "github.com/go-critic/go-critic/framework/linter" +) + +// CheckersFromDylib loads checkers provided by a dynamic lybrary found under path. +// +// The returned info slice must be re-assigned to the original info slice, +// since there will be new entries there. +func CheckersFromDylib(infoList []*linter.CheckerInfo, path string) ([]*linter.CheckerInfo, error) { + if path == "" { + return infoList, nil // Nothing to do + } + checkersBefore := len(infoList) + // Open plugin only for side-effects (init functions). + _, err := plugin.Open(path) + if err != nil { + return infoList, err + } + maybeUpdatedList := linter.GetCheckersInfo() + checkersAfter := len(maybeUpdatedList) + if checkersBefore == checkersAfter { + return infoList, fmt.Errorf("loaded plugin doesn't provide any gocritic-compatible checkers") + } + return maybeUpdatedList, nil +} diff --git a/framework/lintmain/internal/lintdoc/doc.go b/framework/lintmain/internal/lintdoc/doc.go new file mode 100644 index 000000000..f868bee2b --- /dev/null +++ b/framework/lintmain/internal/lintdoc/doc.go @@ -0,0 +1,89 @@ +package lintdoc + +import ( + "flag" + "fmt" + "log" + "os" + "text/template" + + "github.com/go-critic/go-critic/framework/linter" +) + +// Main implements sub-command entry point. +func Main() { + flag.Parse() + + switch args := flag.Args(); len(args) { + case 0: + printShortDoc() + case 1: + printDoc(args[0]) + default: + log.Fatalf("expected 0 or 1 positional arguments") + } +} + +func printShortDoc() { + for _, info := range linter.GetCheckersInfo() { + fmt.Printf("%s %v\n", info.Name, info.Tags) + } +} + +func printDoc(name string) { + info := findInfoByName(name) + if info == nil { + log.Fatalf("checker with name %q not found", name) + } + + tmplString := `{{.Checker.Name}} checker documentation +URL: {{.Checker.Collection.URL}} +Tags: {{.Checker.Tags}} + +{{.Checker.Summary}}. +{{ if .Checker.Details }} +{{.Checker.Details}} +{{ end }} +Non-compliant code: +{{.Checker.Before}} + +Compliant code: +{{.Checker.After}} +{{- if .Checker.Note }} + +{{.Checker.Note}} +{{- end }} +{{- if .Checker.Params }} + +Checker parameters: +{{- range $key, $_ := .Checker.Params }} + -@{{$.Checker.Name}}.{{$key}} {{index $.ParamTypes $key}} + {{.Usage}} (default {{.Value}}) +{{- end }} +{{- end }} +` + + var templateData struct { + Checker *linter.CheckerInfo + ParamTypes map[string]string + } + templateData.Checker = info + templateData.ParamTypes = make(map[string]string) + for pname, p := range info.Params { + templateData.ParamTypes[pname] = fmt.Sprintf("%T", p.Value) + } + + tmpl := template.Must(template.New("doc").Parse(tmplString)) + if err := tmpl.Execute(os.Stdout, templateData); err != nil { + panic(fmt.Sprintf("executing checker doc template: %v", err)) + } +} + +func findInfoByName(name string) *linter.CheckerInfo { + for _, info := range linter.GetCheckersInfo() { + if info.Name == name { + return info + } + } + return nil +} diff --git a/framework/lintmain/lintmain.go b/framework/lintmain/lintmain.go new file mode 100644 index 000000000..8a49559db --- /dev/null +++ b/framework/lintmain/lintmain.go @@ -0,0 +1,68 @@ +package lintmain + +import ( + "fmt" + "log" + + "github.com/go-critic/go-critic/framework/cmdutil" + "github.com/go-critic/go-critic/framework/lintmain/internal/check" + "github.com/go-critic/go-critic/framework/lintmain/internal/lintdoc" +) + +// Config is used to parametrize the linter. +type Config struct { + Version string + Name string +} + +var config *Config + +// Run executes corresponding main after sub-command resolving. +// Does not return. +func Run(cfg Config) { + config = &cfg // TODO(quasilyte): don't use global var for this + log.SetFlags(0) + + // makeExample replaces all ${linter} placeholders to a bound linter name. + makeExamples := func(examples ...string) []string { + for i := range examples { + examples[i] = fmt.Sprintf(examples[i], cfg.Name) + } + return examples + } + + subCommands := []*cmdutil.SubCommand{ + { + Main: check.Main, + Name: "check", + Short: "run linter over specified targets", + Examples: makeExamples( + "%s check -help", + "%s check -enable='paramTypeCombine,unslice' strings bytes", + "%s check -v -enable='#diagnostic' -disable='#experimental,#opinionated' ./...", + ), + }, + { + Main: printVersion, + Name: "version", + Short: "print linter version", + Examples: makeExamples("%s version"), + }, + { + Main: lintdoc.Main, + Name: "doc", + Short: "get installed checkers documentation", + Examples: makeExamples( + "%s doc -help", + "%s doc", + "%s doc checkerName", + ), + }, + } + + cmdutil.DispatchCommand(subCommands) +} + +func printVersion() { + log.Println(config.Version) +} diff --git a/framework/linttest/end2end.go b/framework/linttest/end2end.go new file mode 100644 index 000000000..5ca2e451a --- /dev/null +++ b/framework/linttest/end2end.go @@ -0,0 +1,46 @@ +package linttest + +import ( + "bufio" + "fmt" + "io" + "regexp" +) + +var ( + warningDirectiveRE = regexp.MustCompile(`^\s*/\*! (.*) \*/`) + commentRE = regexp.MustCompile(`^\s*//`) +) + +type warnings map[int][]string + +func newWarnings(r io.Reader) (warnings, error) { + ws := make(warnings) + var pending []string + + s := bufio.NewScanner(r) + for i := 0; s.Scan(); i++ { + if m := warningDirectiveRE.FindStringSubmatch(s.Text()); m != nil { + pending = append(pending, m[1]) + } else if len(pending) != 0 { + line := i + 1 + ws[line] = pending + pending = nil + } + } + + if err := s.Err(); err != nil { + return nil, fmt.Errorf("read test file data: %w", err) + } + + return ws, nil +} + +func (ws warnings) find(line int, text string) *string { + for i := range ws[line] { + if text == ws[line][i] { + return &ws[line][i] + } + } + return nil +} diff --git a/framework/linttest/integration.go b/framework/linttest/integration.go new file mode 100644 index 000000000..5572462ec --- /dev/null +++ b/framework/linttest/integration.go @@ -0,0 +1,122 @@ +package linttest + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +// Run executes integration tests. +func (cfg *IntegrationTest) Run(t *testing.T) { + absDir, err := filepath.Abs(cfg.Dir) + if err != nil { + t.Fatalf("can't get dir abs path: %v", err) + } + + gocritic, err := cfg.buildLinter() + if err != nil { + t.Fatalf("build linter: %v", err) + } + + files, err := ioutil.ReadDir(absDir) + if err != nil { + t.Fatalf("list test files: %v", err) + } + + for _, f := range files { + if !f.IsDir() { + continue + } + + t.Run(f.Name(), func(t *testing.T) { + wd := filepath.Join(absDir, f.Name()) + if err := os.Chdir(wd); err != nil { + t.Fatalf("enter test dir: %v", err) + } + cfg.runTest(t, gocritic, wd) + }) + } +} + +func (cfg *IntegrationTest) runTest(t *testing.T, gocritic, gopath string) { + data, err := ioutil.ReadFile("linttest.params") + if err != nil { + t.Fatalf("reading linter run params: %v", err) + } + + // If several tests re-use a single golden file, + // don't read it repeatedly, just re-use its contents. + goldenDataCache := make(map[string]string) + + for i, line := range strings.Split(string(data), "\n") { + if line == "" { + continue + } + + // The format is: + // runParams ... "|" goldenFile + parts := strings.Split(line, "|") + runParams := strings.Split(strings.TrimSpace(parts[0]), " ") + goldenFile := strings.TrimSpace(parts[1]) + + // Read from a golden file or contents cache. + var want string + if data, ok := goldenDataCache[goldenFile]; ok { + want = data + } else { + data, err := ioutil.ReadFile(goldenFile) + if err != nil { + t.Errorf("read golden file: %v", err) + } + want = string(data) + goldenDataCache[goldenFile] = want + } + + // Get the actual execution output. + cmd := exec.Command(gocritic, runParams...) + cmd.Env = append([]string{}, os.Environ()...) // Copy parent env + cmd.Env = append(cmd.Env, + // Override GOPATH. + "GOPATH="+gopath, + // Disable modules. See #62. + "GO111MODULE=off") + + out, err := cmd.CombinedOutput() + out = bytes.TrimSpace(out) + var have string + if err != nil { + // Error is prepended to the beginning. + have = err.Error() + "\n" + string(out) + } else { + have = string(out) + } + + // To get line-by-line diff, split is required. + wantLines := strings.Split(want, "\n") + haveLines := strings.Split(have, "\n") + if diff := cmp.Diff(wantLines, haveLines); diff != "" { + t.Errorf("linttest.params:%d: output mismatch:\n%s", i+1, diff) + t.Logf("linter output was: %s\n", have) + } + } +} + +func (cfg *IntegrationTest) buildLinter() (string, error) { + tmpDir := os.TempDir() + filename := filepath.Join(tmpDir, "_gocritic_inttest_") + + args := []string{"build", "-o", filename, cfg.Main} + out, err := exec.Command("go", args...).CombinedOutput() + if err != nil { + return "", fmt.Errorf("%v: %s", err, out) + } + + return filename, nil +} diff --git a/framework/linttest/linttest.go b/framework/linttest/linttest.go new file mode 100644 index 000000000..a7838bb96 --- /dev/null +++ b/framework/linttest/linttest.go @@ -0,0 +1,190 @@ +package linttest + +import ( + "go/ast" + "go/token" + "go/types" + "os" + "path/filepath" + "runtime" + "runtime/debug" + "strings" + "testing" + + "github.com/go-critic/go-critic/framework/linter" + "github.com/go-toolsmith/pkgload" + "golang.org/x/tools/go/packages" +) + +var sizes = types.SizesFor("gc", runtime.GOARCH) + +func saneCheckersList(t *testing.T) []*linter.CheckerInfo { + var saneList []*linter.CheckerInfo + + for _, info := range linter.GetCheckersInfo() { + pkgPath := "github.com/go-critic/go-critic/framework/linttest/testdata/sanity" + t.Run(info.Name+"/sanity", func(t *testing.T) { + fset := token.NewFileSet() + pkgs := newPackages(t, pkgPath, fset) + for _, pkg := range pkgs { + ctx := &linter.Context{ + SizesInfo: sizes, + FileSet: fset, + TypesInfo: pkg.TypesInfo, + Pkg: pkg.Types, + } + c := linter.NewChecker(ctx, info) + defer func() { + r := recover() + if r != nil { + t.Errorf("unexpected panic: %v\n%s", r, debug.Stack()) + } else { + saneList = append(saneList, info) + } + }() + for _, f := range pkg.Syntax { + ctx.SetFileInfo(getFilename(fset, f), f) + _ = c.Check(f) + } + } + }) + } + + return saneList +} + +// IntegrationTest specifies integration test options. +type IntegrationTest struct { + Main string + + // Dir specifies a path to integration tests. + Dir string +} + +// TestCheckers runs end2end tests over all registered checkers using default options. +// +// TODO(Quasilyte): document default options. +// TODO(Quasilyte): make it possible to run tests with different options. +func TestCheckers(t *testing.T) { + for _, info := range saneCheckersList(t) { + t.Run(info.Name, func(t *testing.T) { + pkgPath := "./testdata/" + info.Name + + fset := token.NewFileSet() + pkgs := newPackages(t, pkgPath, fset) + for _, pkg := range pkgs { + ctx := &linter.Context{ + SizesInfo: sizes, + FileSet: fset, + TypesInfo: pkg.TypesInfo, + Pkg: pkg.Types, + } + c := linter.NewChecker(ctx, info) + for _, f := range pkg.Syntax { + checkFile(t, c, ctx, f) + } + } + }) + } +} + +func checkFile(t *testing.T, c *linter.Checker, ctx *linter.Context, f *ast.File) { + filename := getFilename(ctx.FileSet, f) + testFilename := filepath.Join("testdata", c.Info.Name, filename) + + rc, err := os.Open(testFilename) + if err != nil { + t.Fatalf("read file %q: %w", testFilename, err) + } + defer rc.Close() + + ws, err := newWarnings(rc) + if err != nil { + t.Fatal(err) + } + + stripDirectives(f) + ctx.SetFileInfo(filename, f) + + matched := make(map[*string]struct{}) + for _, warn := range c.Check(f) { + line := ctx.FileSet.Position(warn.Node.Pos()).Line + + if w := ws.find(line, warn.Text); w != nil { + if _, seen := matched[w]; seen { + t.Errorf("%s:%d: multiple matches for %s", + testFilename, line, *w) + } + matched[w] = struct{}{} + } else { + t.Errorf("%s:%d: unexpected warn: %s", + testFilename, line, warn.Text) + } + } + + checkUnmatched(ws, matched, t, testFilename) +} + +// stripDirectives replaces "///" comments with empty single-line +// comments, so the checkers that inspect comments see ordinary +// comment groups (with extra newlines, but that's not important). +func stripDirectives(f *ast.File) { + for _, cg := range f.Comments { + for _, c := range cg.List { + if strings.HasPrefix(c.Text, "/// ") { + c.Text = "//" + } + } + } +} + +func getFilename(fset *token.FileSet, f *ast.File) string { + // see https://github.com/golang/go/issues/24498 + return filepath.Base(fset.Position(f.Pos()).Filename) +} + +func checkUnmatched(ws warnings, matched map[*string]struct{}, t *testing.T, testFilename string) { + for line, sl := range ws { + for i, w := range sl { + if _, ok := matched[&sl[i]]; !ok { + t.Errorf("%s:%d: unmatched `%s`", testFilename, line, w) + } + } + } +} + +func newPackages(t *testing.T, pattern string, fset *token.FileSet) []*packages.Package { + cfg := packages.Config{ + Mode: packages.LoadSyntax, + Tests: true, + Fset: fset, + } + pkgs, err := loadPackages(&cfg, []string{pattern}) + if err != nil { + t.Fatalf("load package: %v", err) + } + return pkgs +} + +// TODO(Quasilyte): copied from check.go. Should it be added to pkgload? +func loadPackages(cfg *packages.Config, patterns []string) ([]*packages.Package, error) { + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return nil, err + } + + result := pkgs[:0] + pkgload.VisitUnits(pkgs, func(u *pkgload.Unit) { + if u.ExternalTest != nil { + result = append(result, u.ExternalTest) + } + + if u.Test != nil { + // Prefer tests to the base package, if present. + result = append(result, u.Test) + } else { + result = append(result, u.Base) + } + }) + return result, nil +} diff --git a/framework/linttest/testdata/sanity/tests.go b/framework/linttest/testdata/sanity/tests.go new file mode 100644 index 000000000..98531f6ea --- /dev/null +++ b/framework/linttest/testdata/sanity/tests.go @@ -0,0 +1,213 @@ +package sanity_test + +import ( + "errors" + . "errors" + _ "errors" + errorspkg1 "errors" + errorspkg2 "errors" + "unsafe" +) + +var ( + _ = New + _, _ = errorspkg1.New, errorspkg2.New + _ = errors.New + _ = unsafe.Sizeof(int(0)) +) + +func empty1() {} + +func empty2() { + { + } + { + } +} + +func external() + +const () + +var () + +type () + +func emptySpecs() { + const () + var () + type () +} + +func forRange() { + var xs []int + + for range xs { + } + for _ = range xs { + } + for _, _ = range xs { + } +} + +func emptyFor1() { + for { + } +} + +func emptyFor2() { + for { + continue + } +} + +func emptySelect() { + select {} +} + +func emptyStatements() { + + for { + break + } + + switch { + } + switch { + case false: + case true: + default: + } + switch { + case false: + fallthrough + case true: + break + default: + } + + if true { + } + if false { + } else { + } + if false { + } else if false { + } else { + } + + goto L0 +L0: +} + +func initStatements() { + for _ = 0; ; { + break + } + for _, _ = 0, 0; ; { + break + } + + switch _ = 0; { + } + + if _ = 0; true { + } + + if variadicArg(1, 2, 3); false { + } + + switch variadicArg(1, 2, 3); true { + } + + for variadicArg(1, 2, 3); false; { + } + + // select can't have init statement. +} + +type intAlias = int + +type structType struct { + x int `tag1:"1"` + y int `tag2:"1,2"` + z struct{ value int } +} + +type typeWithEmbedding struct { + structType + intAlias +} + +type emptyIface interface{} + +type embeddingIface interface { + emptyIface + ifaceType +} + +type ifaceType interface { + A() func() + B() func() func() + c(func(func()) func()) func(func() func() func()) func() +} + +type ( + _ chan [2]int + _ chan chan int + _ chan<- int + _ <-chan int + _ <-chan <-chan bool + _ chan []chan []chan<- int +) + +type myString string + +func convertPtr(x string) *myString { + return (*myString)(&x) +} + +func (myString) noReceiverName1(a, b string) {} + +func (*myString) noReceiverName2() (a, b string) { return "", "" } + +var noInit1, noInit2 int + +func variadicArg(xs ...interface{}) {} + +func funcCalls() { + f0 := func() {} + f1 := func(x int) {} + f2 := func(x, y int) {} + f3 := func(x, y, z int) {} + fVariadic := func(xs ...int) {} + + f0() + f1(1) + f2(1, 2) + f3(1, 2, 3) + fVariadic() + fVariadic(1, 2) + fVariadic([]int{1, 2}...) +} + +func sliceExpressions(xs []int) { + _ = xs[:] + _ = xs[0:] + _ = xs[:0] + _ = xs[0:0] + _ = xs[:0:0] + _ = xs[0:0:0] +} + +type myStruct struct { + field string +} + +func (m myStruct) method(a string) {} + +func methodExprCall() { + m := myStruct{} + + myStruct.method(m, "field") +} diff --git a/go.mod b/go.mod index 28d142dbf..4975017ae 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,11 @@ require ( github.com/go-toolsmith/astequal v1.0.0 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/strparse v1.0.0 github.com/go-toolsmith/typep v1.0.2 + github.com/google/go-cmp v0.2.0 + 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 diff --git a/naming_conventions.json b/naming_conventions.json index 7c5dd0a07..5533d9d11 100644 --- a/naming_conventions.json +++ b/naming_conventions.json @@ -1,6 +1,6 @@ { "ast\\.Node": {"param": {"node": "n"}}, - "lintpack.CheckerContext": { + "linter.CheckerContext": { "param+local+field": {"ctxt": "ctx"} } }