aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/go-critic
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-09-15 18:05:35 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-09-15 19:34:30 +0200
commit712de1c63d9db97c81af68cd0dc4372c53d2e57a (patch)
treeae1761fec52c3ae4ddd003a4130ddbda8d0a2d69 /vendor/github.com/go-critic
parent298a69c38dd5c8a9bbd7a022e88f4ddbcf885e16 (diff)
vendor/github.com/golangci/golangci-lint: update to v1.31
Diffstat (limited to 'vendor/github.com/go-critic')
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/appendAssign_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/assignOp_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/badCall_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go445
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/captLocal_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/caseOrder_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/checkers.go13
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go20
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/commentedOutImport_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/defaultCaseOrder_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go94
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/docStub_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/dupCase_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/dupImports_checker.go8
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/dupSubExpr_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/elseif_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/emptyFallthrough_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/emptyStringTest_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/evalOrder_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go16
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go50
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/flagDeref_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/importShadow_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/indexAlloc_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/initClause_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/comment_walker.go41
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/doc_comment_walker.go48
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/expr_walker.go29
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/func_decl_walker.go21
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_comment_walker.go32
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go51
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_walker.go118
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_expr_walker.go27
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_list_walker.go31
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_walker.go27
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go114
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/visitor.go80
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walk_handler.go34
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walker.go57
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/mapKey_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/methodExprCall_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/nestingReduce_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/nilValReturn_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/offBy1_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/paramTypeCombine_checker.go19
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/ptrToRefParam_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/rangeExprCopy_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/regexpMust_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/regexpPattern_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go511
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go95
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/singleCaseSwitch_checker.go47
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/sloppyLen_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/sloppyReassign_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go75
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go135
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go167
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/switchTrue_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/truncateCmp_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/typeSwitchVar_checker.go27
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/typeUnparen_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/underef_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unlabelStmt_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unnecessaryBlock_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go111
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/unslice_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/utils.go4
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/valSwap_checker.go12
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/weakCond_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/whyNoLint_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/wrapperFunc_checker.go17
-rw-r--r--vendor/github.com/go-critic/go-critic/checkers/yodaStyleExpr_checker.go10
-rw-r--r--vendor/github.com/go-critic/go-critic/framework/linter/checkers_db.go135
-rw-r--r--vendor/github.com/go-critic/go-critic/framework/linter/context.go35
-rw-r--r--vendor/github.com/go-critic/go-critic/framework/linter/lintpack.go247
97 files changed, 3252 insertions, 389 deletions
diff --git a/vendor/github.com/go-critic/go-critic/checkers/appendAssign_checker.go b/vendor/github.com/go-critic/go-critic/checkers/appendAssign_checker.go
index 47d12f014..d26921770 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/appendAssign_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/appendAssign_checker.go
@@ -5,15 +5,15 @@ import (
"go/token"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go b/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
index 63f5d9fea..a761f2a8f 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
@@ -4,14 +4,14 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go b/vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
index 85a6f7c66..2eb7cf7d8 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
@@ -4,8 +4,8 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
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/vendor/github.com/go-critic/go-critic/checkers/assignOp_checker.go b/vendor/github.com/go-critic/go-critic/checkers/assignOp_checker.go
index eb3428663..e3acd09ef 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/assignOp_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/assignOp_checker.go
@@ -4,29 +4,29 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/badCall_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badCall_checker.go
index 150cc6904..3e96a39cb 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/badCall_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/badCall_checker.go
@@ -3,28 +3,28 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
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/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go
index 466a89cc3..6ce81f358 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go
@@ -5,9 +5,9 @@ import (
"go/constant"
"go/token"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astequal"
@@ -16,9 +16,9 @@ import (
)
func init() {
- var info lintpack.CheckerInfo
+ var info linter.CheckerInfo
info.Name = "badCond"
- info.Tags = []string{"diagnostic", "experimental"}
+ info.Tags = []string{"diagnostic"}
info.Summary = "Detects suspicious condition expressions"
info.Before = `
for i := 0; i > n; i++ {
@@ -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/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go
new file mode 100644
index 000000000..1025454df
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go
@@ -0,0 +1,445 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/constant"
+ "sort"
+ "strconv"
+ "unicode"
+ "unicode/utf8"
+
+ "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 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 *linter.CheckerContext) linter.FileWalker {
+ opts := &syntax.ParserOptions{}
+ c := &badRegexpChecker{
+ ctx: ctx,
+ parser: syntax.NewParser(opts),
+ }
+ return astwalk.WalkerForExpr(c)
+ })
+}
+
+type badRegexpChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+
+ parser *syntax.Parser
+ cause ast.Expr
+
+ flagStates []regexpFlagState
+ goodAnchors []syntax.Position
+}
+
+type regexpFlagState [utf8.RuneSelf]bool
+
+func (c *badRegexpChecker) VisitExpr(x ast.Expr) {
+ call, ok := x.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ switch qualifiedName(call.Fun) {
+ case "regexp.Compile", "regexp.MustCompile":
+ cv := c.ctx.TypesInfo.Types[call.Args[0]].Value
+ if cv == nil || cv.Kind() != constant.String {
+ return
+ }
+ pat := constant.StringVal(cv)
+ c.cause = call.Args[0]
+ c.checkPattern(pat)
+ }
+}
+
+func (c *badRegexpChecker) checkPattern(pat string) {
+ re, err := c.parser.Parse(pat)
+ if err != nil {
+ return
+ }
+
+ c.flagStates = c.flagStates[:0]
+ c.goodAnchors = c.goodAnchors[:0]
+
+ // In Go all flags (modifiers) are set to false by default,
+ // so we start from the empty flag set.
+ c.flagStates = append(c.flagStates, regexpFlagState{})
+
+ c.markGoodCarets(re.Expr)
+ c.walk(re.Expr)
+}
+
+func (c *badRegexpChecker) markGoodCarets(e syntax.Expr) {
+ canSkip := func(e syntax.Expr) bool {
+ switch e.Op {
+ case syntax.OpFlagOnlyGroup:
+ return true
+ case syntax.OpGroup:
+ x := e.Args[0]
+ return x.Op == syntax.OpConcat && len(x.Args) == 0
+ }
+ return false
+ }
+
+ if e.Op == syntax.OpConcat && len(e.Args) > 1 {
+ i := 0
+ for i < len(e.Args) && canSkip(e.Args[i]) {
+ i++
+ }
+ if i < len(e.Args) {
+ c.markGoodCarets(e.Args[i])
+ }
+ return
+ }
+ if e.Op == syntax.OpCaret {
+ c.addGoodAnchor(e.Pos)
+ }
+ for _, a := range e.Args {
+ c.markGoodCarets(a)
+ }
+}
+
+func (c *badRegexpChecker) walk(e syntax.Expr) {
+ switch e.Op {
+ case syntax.OpAlt:
+ c.checkAltAnchor(e)
+ c.checkAltDups(e)
+ for _, a := range e.Args {
+ c.walk(a)
+ }
+
+ case syntax.OpCharClass, syntax.OpNegCharClass:
+ if c.checkCharClassRanges(e) {
+ c.checkCharClassDups(e)
+ }
+
+ case syntax.OpStar, syntax.OpPlus:
+ c.checkNestedQuantifier(e)
+ c.walk(e.Args[0])
+
+ case syntax.OpFlagOnlyGroup:
+ c.updateFlagState(c.currentFlagState(), e, e.Args[0].Value)
+ case syntax.OpGroupWithFlags:
+ // Creates a new context using the current context copy.
+ // New flags are evaluated inside a new context.
+ // After nested expressions are processed, previous context is restored.
+ nflags := len(c.flagStates)
+ c.flagStates = append(c.flagStates, *c.currentFlagState())
+ c.updateFlagState(c.currentFlagState(), e, e.Args[1].Value)
+ c.walk(e.Args[0])
+ c.flagStates = c.flagStates[:nflags]
+ case syntax.OpGroup, syntax.OpCapture, syntax.OpNamedCapture:
+ // Like with OpGroupWithFlags, but doesn't evaluate any new flags.
+ nflags := len(c.flagStates)
+ c.flagStates = append(c.flagStates, *c.currentFlagState())
+ c.walk(e.Args[0])
+ c.flagStates = c.flagStates[:nflags]
+
+ case syntax.OpCaret:
+ if !c.isGoodAnchor(e) {
+ c.warn("dangling or redundant ^, maybe \\^ is intended?")
+ }
+
+ default:
+ for _, a := range e.Args {
+ c.walk(a)
+ }
+ }
+}
+
+func (c *badRegexpChecker) currentFlagState() *regexpFlagState {
+ return &c.flagStates[len(c.flagStates)-1]
+}
+
+func (c *badRegexpChecker) updateFlagState(state *regexpFlagState, e syntax.Expr, flagString string) {
+ clearing := false
+ for i := 0; i < len(flagString); i++ {
+ ch := flagString[i]
+ if ch == '-' {
+ clearing = true
+ continue
+ }
+ if int(ch) >= len(state) {
+ continue // Should never happen in practice, but we don't want a panic
+ }
+
+ if clearing {
+ if !state[ch] {
+ c.warn("clearing unset flag %c in %s", ch, e.Value)
+ }
+ } else {
+ if state[ch] {
+ c.warn("redundant flag %c in %s", ch, e.Value)
+ }
+ }
+ state[ch] = !clearing
+ }
+}
+
+func (c *badRegexpChecker) checkNestedQuantifier(e syntax.Expr) {
+ x := e.Args[0]
+ switch x.Op {
+ case syntax.OpGroup, syntax.OpCapture, syntax.OpGroupWithFlags:
+ if len(e.Args) == 1 {
+ x = x.Args[0]
+ }
+ }
+
+ switch x.Op {
+ case syntax.OpPlus, syntax.OpStar:
+ c.warn("repeated greedy quantifier in %s", e.Value)
+ }
+}
+
+func (c *badRegexpChecker) checkAltDups(alt syntax.Expr) {
+ // Seek duplicated alternation expressions.
+
+ set := make(map[string]struct{}, len(alt.Args))
+ for _, a := range alt.Args {
+ if _, ok := set[a.Value]; ok {
+ c.warn("`%s` is duplicated in %s", a.Value, alt.Value)
+ }
+ set[a.Value] = struct{}{}
+ }
+}
+
+func (c *badRegexpChecker) isCharOrLit(e syntax.Expr) bool {
+ return e.Op == syntax.OpChar || e.Op == syntax.OpLiteral
+}
+
+func (c *badRegexpChecker) checkAltAnchor(alt syntax.Expr) {
+ // Seek suspicious anchors.
+
+ // Case 1: an alternation of literals where 1st expr begins with ^ anchor.
+ first := alt.Args[0]
+ if first.Op == syntax.OpConcat && len(first.Args) == 2 && first.Args[0].Op == syntax.OpCaret && c.isCharOrLit(first.Args[1]) {
+ matched := true
+ for _, a := range alt.Args[1:] {
+ if !c.isCharOrLit(a) {
+ matched = false
+ break
+ }
+ }
+ if matched {
+ c.warn("^ applied only to `%s` in %s", first.Value[len(`^`):], alt.Value)
+ }
+ }
+
+ // Case 2: an alternation of literals where last expr ends with $ anchor.
+ last := alt.Args[len(alt.Args)-1]
+ if last.Op == syntax.OpConcat && len(last.Args) == 2 && last.Args[1].Op == syntax.OpDollar && c.isCharOrLit(last.Args[0]) {
+ matched := true
+ for _, a := range alt.Args[:len(alt.Args)-1] {
+ if !c.isCharOrLit(a) {
+ matched = false
+ break
+ }
+ }
+ if matched {
+ c.warn("$ applied only to `%s` in %s", last.Value[:len(last.Value)-len(`$`)], alt.Value)
+ }
+ }
+}
+
+func (c *badRegexpChecker) checkCharClassRanges(cc syntax.Expr) bool {
+ // Seek for suspicious ranges like `!-_`.
+ //
+ // We permit numerical ranges (0-9, hex and octal literals)
+ // and simple ascii letter ranges.
+
+ for _, e := range cc.Args {
+ if e.Op != syntax.OpCharRange {
+ continue
+ }
+ switch e.Args[0].Op {
+ case syntax.OpEscapeOctal, syntax.OpEscapeHex:
+ continue
+ }
+ ch := c.charClassBoundRune(e.Args[0])
+ if ch == 0 {
+ return false
+ }
+ good := unicode.IsLetter(ch) || (ch >= '0' && ch <= '9')
+ if !good {
+ c.warnSloppyCharRange(e.Value, cc.Value)
+ }
+ }
+
+ return true
+}
+
+func (c *badRegexpChecker) checkCharClassDups(cc syntax.Expr) {
+ // Seek for excessive elements inside a character class.
+ // Report them as intersections.
+
+ if len(cc.Args) == 1 {
+ return // Can't had duplicates.
+ }
+
+ type charRange struct {
+ low rune
+ high rune
+ source string
+ }
+ ranges := make([]charRange, 0, 8)
+ addRange := func(source string, low, high rune) {
+ ranges = append(ranges, charRange{source: source, low: low, high: high})
+ }
+ addRange1 := func(source string, ch rune) {
+ addRange(source, ch, ch)
+ }
+
+ // 1. Collect ranges, O(n).
+ for _, e := range cc.Args {
+ switch e.Op {
+ case syntax.OpEscapeOctal:
+ addRange1(e.Value, c.octalToRune(e))
+ case syntax.OpEscapeHex:
+ addRange1(e.Value, c.hexToRune(e))
+ case syntax.OpChar:
+ addRange1(e.Value, c.stringToRune(e.Value))
+ case syntax.OpCharRange:
+ addRange(e.Value, c.charClassBoundRune(e.Args[0]), c.charClassBoundRune(e.Args[1]))
+ case syntax.OpEscapeMeta:
+ addRange1(e.Value, rune(e.Value[1]))
+ case syntax.OpEscapeChar:
+ ch := c.stringToRune(e.Value[len(`\`):])
+ if unicode.IsPunct(ch) {
+ addRange1(e.Value, ch)
+ break
+ }
+ switch e.Value {
+ case `\|`, `\<`, `\>`, `\+`, `\=`: // How to cover all symbols?
+ addRange1(e.Value, c.stringToRune(e.Value[len(`\`):]))
+ case `\t`:
+ addRange1(e.Value, '\t')
+ case `\n`:
+ addRange1(e.Value, '\n')
+ case `\r`:
+ addRange1(e.Value, '\r')
+ case `\v`:
+ addRange1(e.Value, '\v')
+ case `\d`:
+ addRange(e.Value, '0', '9')
+ case `\D`:
+ addRange(e.Value, 0, '0'-1)
+ addRange(e.Value, '9'+1, utf8.MaxRune)
+ case `\s`:
+ addRange(e.Value, '\t', '\n') // 9-10
+ addRange(e.Value, '\f', '\r') // 12-13
+ addRange1(e.Value, ' ') // 32
+ case `\S`:
+ addRange(e.Value, 0, '\t'-1)
+ addRange(e.Value, '\n'+1, '\f'-1)
+ addRange(e.Value, '\r'+1, ' '-1)
+ addRange(e.Value, ' '+1, utf8.MaxRune)
+ case `\w`:
+ addRange(e.Value, '0', '9') // 48-57
+ addRange(e.Value, 'A', 'Z') // 65-90
+ addRange1(e.Value, '_') // 95
+ addRange(e.Value, 'a', 'z') // 97-122
+ case `\W`:
+ addRange(e.Value, 0, '0'-1)
+ addRange(e.Value, '9'+1, 'A'-1)
+ addRange(e.Value, 'Z'+1, '_'-1)
+ addRange(e.Value, '_'+1, 'a'-1)
+ addRange(e.Value, 'z'+1, utf8.MaxRune)
+ default:
+ // Give up: unknown escape sequence.
+ return
+ }
+ default:
+ // Give up: unexpected operation inside char class.
+ return
+ }
+ }
+
+ // 2. Sort ranges, O(nlogn).
+ sort.Slice(ranges, func(i, j int) bool {
+ return ranges[i].low < ranges[j].low
+ })
+
+ // 3. Search for duplicates, O(n).
+ for i := 0; i < len(ranges)-1; i++ {
+ x := ranges[i+0]
+ y := ranges[i+1]
+ if x.high >= y.low {
+ c.warnCharClassDup(x.source, y.source, cc.Value)
+ break
+ }
+ }
+}
+
+func (c *badRegexpChecker) charClassBoundRune(e syntax.Expr) rune {
+ switch e.Op {
+ case syntax.OpChar:
+ return c.stringToRune(e.Value)
+ case syntax.OpEscapeHex:
+ return c.hexToRune(e)
+ case syntax.OpEscapeOctal:
+ return c.octalToRune(e)
+ default:
+ return 0
+ }
+}
+
+func (c *badRegexpChecker) octalToRune(e syntax.Expr) rune {
+ v, _ := strconv.ParseInt(e.Value[len(`\`):], 8, 32)
+ return rune(v)
+}
+
+func (c *badRegexpChecker) hexToRune(e syntax.Expr) rune {
+ var s string
+ switch e.Form {
+ case syntax.FormEscapeHexFull:
+ s = e.Value[len(`\x{`) : len(e.Value)-len(`}`)]
+ default:
+ s = e.Value[len(`\x`):]
+ }
+ v, _ := strconv.ParseInt(s, 16, 32)
+ return rune(v)
+}
+
+func (c *badRegexpChecker) stringToRune(s string) rune {
+ ch, _ := utf8.DecodeRuneInString(s)
+ return ch
+}
+
+func (c *badRegexpChecker) addGoodAnchor(pos syntax.Position) {
+ c.goodAnchors = append(c.goodAnchors, pos)
+}
+
+func (c *badRegexpChecker) isGoodAnchor(e syntax.Expr) bool {
+ for _, pos := range c.goodAnchors {
+ if e.Pos == pos {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *badRegexpChecker) warn(format string, args ...interface{}) {
+ c.ctx.Warn(c.cause, format, args...)
+}
+
+func (c *badRegexpChecker) warnSloppyCharRange(rng, charClass string) {
+ c.ctx.Warn(c.cause, "suspicious char range `%s` in %s", rng, charClass)
+}
+
+func (c *badRegexpChecker) warnCharClassDup(x, y, charClass string) {
+ if x == y {
+ c.ctx.Warn(c.cause, "`%s` is duplicated in %s", x, charClass)
+ } else {
+ c.ctx.Warn(c.cause, "`%s` intersects with `%s` in %s", x, y, charClass)
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go b/vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go
index f4eb9ed73..8c599031d 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go
@@ -6,9 +6,9 @@ import (
"go/token"
"strconv"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go b/vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go
index 24d8b7fff..ff5e51746 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go
@@ -3,26 +3,26 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/captLocal_checker.go b/vendor/github.com/go-critic/go-critic/checkers/captLocal_checker.go
index bc9a2115f..76b6fb4fc 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/captLocal_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/captLocal_checker.go
@@ -3,15 +3,15 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/caseOrder_checker.go b/vendor/github.com/go-critic/go-critic/checkers/caseOrder_checker.go
index 1ef4b53b7..950367520 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/caseOrder_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/caseOrder_checker.go
@@ -4,12 +4,12 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/checkers.go b/vendor/github.com/go-critic/go-critic/checkers/checkers.go
index 96202221e..0c2ebc00c 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/checkers.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/checkers.go
@@ -2,9 +2,18 @@
package checkers
import (
- "github.com/go-lintpack/lintpack"
+ "os"
+
+ "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",
}
+
+var debug = func() func() bool {
+ v := os.Getenv("DEBUG") != ""
+ return func() bool {
+ return v
+ }
+}()
diff --git a/vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go b/vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
index 14d89da37..ecadba10e 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
@@ -5,19 +5,19 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
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/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go b/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
index ed75015e0..de7bfc198 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
@@ -7,23 +7,25 @@ import (
"unicode"
"unicode/utf8"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"style"}
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{
- `^//\w+:.*$`, //key: value
- `^//nolint$`, //nolint
- `^//line /.*:\d+`, //line /path/to/file:123
+ `^//go:generate .*$`, // e.g.: go:generate value
+ `^//\w+:.*$`, // e.g.: key: value
+ `^//nolint$`, // e.g.: nolint
+ `^//line /.*:\d+`, // e.g.: line /path/to/file:123
+ `^//export \w+$`, // e.g.: export Foo
}
pat := "(?m)" + strings.Join(parts, "|")
pragmaRE := regexp.MustCompile(pat)
@@ -36,7 +38,7 @@ func init() {
type commentFormattingChecker struct {
astwalk.WalkHandler
- ctx *lintpack.CheckerContext
+ ctx *linter.CheckerContext
pragmaRE *regexp.Regexp
}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go b/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go
index 0554e365e..8d9387045 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/commentedOutCode_checker.go
@@ -7,13 +7,13 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/commentedOutImport_checker.go b/vendor/github.com/go-critic/go-critic/checkers/commentedOutImport_checker.go
index 5aeb86c07..096a90241 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/commentedOutImport_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/commentedOutImport_checker.go
@@ -5,12 +5,12 @@ import (
"go/token"
"regexp"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/defaultCaseOrder_checker.go b/vendor/github.com/go-critic/go-critic/checkers/defaultCaseOrder_checker.go
index caa0de657..755449e07 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/defaultCaseOrder_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/defaultCaseOrder_checker.go
@@ -3,12 +3,12 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go b/vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go
new file mode 100644
index 000000000..3cab7827c
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go
@@ -0,0 +1,94 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/types"
+
+ "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 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 *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForStmt(&deferUnlambdaChecker{ctx: ctx})
+ })
+}
+
+type deferUnlambdaChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+}
+
+func (c *deferUnlambdaChecker) VisitStmt(x ast.Stmt) {
+ def, ok := x.(*ast.DeferStmt)
+ if !ok {
+ return
+ }
+
+ // We don't analyze deferred function args.
+ // Most deferred calls don't have them, so it's not a big deal to skip them.
+ if len(def.Call.Args) != 0 {
+ return
+ }
+
+ fn, ok := def.Call.Fun.(*ast.FuncLit)
+ if !ok {
+ return
+ }
+
+ if len(fn.Body.List) != 1 {
+ return
+ }
+
+ call, ok := astcast.ToExprStmt(fn.Body.List[0]).X.(*ast.CallExpr)
+ if !ok || !c.isFunctionCall(call) {
+ return
+ }
+
+ // Skip recover() as it can't be moved outside of the lambda.
+ // Skip panic() to avoid affecting the stack trace.
+ switch qualifiedName(call.Fun) {
+ case "recover", "panic":
+ return
+ }
+
+ for _, arg := range call.Args {
+ if !c.isConstExpr(arg) {
+ return
+ }
+ }
+
+ c.warn(def, call)
+}
+
+func (c *deferUnlambdaChecker) isFunctionCall(e *ast.CallExpr) bool {
+ switch fnExpr := e.Fun.(type) {
+ case *ast.Ident:
+ return true
+ case *ast.SelectorExpr:
+ x, ok := fnExpr.X.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ _, ok = c.ctx.TypesInfo.ObjectOf(x).(*types.PkgName)
+ return ok
+ default:
+ return false
+ }
+}
+
+func (c *deferUnlambdaChecker) isConstExpr(e ast.Expr) bool {
+ return c.ctx.TypesInfo.Types[e].Value != nil
+}
+
+func (c *deferUnlambdaChecker) warn(cause, suggestion ast.Node) {
+ c.ctx.Warn(cause, "can rewrite as `defer %s`", suggestion)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go b/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go
index 37675735b..82f300b37 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go
@@ -5,14 +5,14 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
info.Summary = "Detects malformed 'deprecated' doc-comments"
info.Before = `
// deprecated, use FuncNew instead
@@ -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/vendor/github.com/go-critic/go-critic/checkers/docStub_checker.go b/vendor/github.com/go-critic/go-critic/checkers/docStub_checker.go
index 5c771b31c..2a3b393a0 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/docStub_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/docStub_checker.go
@@ -6,12 +6,12 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go
index 819759403..24e921b09 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go
@@ -4,21 +4,21 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go
index a13884873..3399f0531 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go
@@ -3,13 +3,13 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/dupCase_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupCase_checker.go
index 26ef17398..89ec66bbf 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/dupCase_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/dupCase_checker.go
@@ -3,13 +3,13 @@ package checkers
import (
"go/ast"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/dupImports_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupImports_checker.go
index d531413a1..27b796cdc 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/dupImports_checker.go
+++ b/vendor/github.com/go-critic/go-critic/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/vendor/github.com/go-critic/go-critic/checkers/dupSubExpr_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupSubExpr_checker.go
index 24bb52434..4966cd2a5 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/dupSubExpr_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/dupSubExpr_checker.go
@@ -5,14 +5,14 @@ import (
"go/token"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/elseif_checker.go b/vendor/github.com/go-critic/go-critic/checkers/elseif_checker.go
index c3a9546bf..9e56d1c40 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/elseif_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/elseif_checker.go
@@ -3,16 +3,16 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/emptyFallthrough_checker.go b/vendor/github.com/go-critic/go-critic/checkers/emptyFallthrough_checker.go
index 5908dfa31..16bfa7e45 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/emptyFallthrough_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/emptyFallthrough_checker.go
@@ -4,12 +4,12 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/emptyStringTest_checker.go b/vendor/github.com/go-critic/go-critic/checkers/emptyStringTest_checker.go
index a7be906ed..20d647ffa 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/emptyStringTest_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/emptyStringTest_checker.go
@@ -4,15 +4,15 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go b/vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go
index 265b2f79b..b8dfdc02f 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go
@@ -4,28 +4,28 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/evalOrder_checker.go b/vendor/github.com/go-critic/go-critic/checkers/evalOrder_checker.go
index f76519cd7..0bec0e83a 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/evalOrder_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/evalOrder_checker.go
@@ -5,16 +5,16 @@ import (
"go/token"
"go/types"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go b/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go
index 05ed6ae9e..65800fc54 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/exitAfterDefer_checker.go
@@ -3,17 +3,17 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
info.Summary = "Detects calls to exit/fatal inside functions that use defer"
info.Before = `
defer os.Remove(filename)
@@ -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) {
@@ -66,13 +66,11 @@ func (c *exitAfterDeferChecker) VisitFuncDecl(fn *ast.FuncDecl) {
}
func (c *exitAfterDeferChecker) warn(cause *ast.CallExpr, deferStmt *ast.DeferStmt) {
- var s string
+ s := astfmt.Sprint(deferStmt)
if fnlit, ok := deferStmt.Call.Fun.(*ast.FuncLit); ok {
// To avoid long and multi-line warning messages,
// collapse the function literals.
s = "defer " + astfmt.Sprint(fnlit.Type) + "{...}(...)"
- } else {
- s = astfmt.Sprint(deferStmt)
}
c.ctx.Warn(cause, "%s clutters `%s`", cause.Fun, s)
}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go b/vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go
new file mode 100644
index 000000000..b11dc2470
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go
@@ -0,0 +1,50 @@
+package checkers
+
+import (
+ "go/ast"
+ "strings"
+
+ "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 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 *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForExpr(&filepathJoinChecker{ctx: ctx})
+ })
+}
+
+type filepathJoinChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+}
+
+func (c *filepathJoinChecker) VisitExpr(expr ast.Expr) {
+ call := astcast.ToCallExpr(expr)
+ if qualifiedName(call.Fun) != "filepath.Join" {
+ return
+ }
+
+ for _, arg := range call.Args {
+ arg, ok := arg.(*ast.BasicLit)
+ if ok && c.hasSeparator(arg) {
+ c.warnSeparator(arg)
+ }
+ }
+}
+
+func (c *filepathJoinChecker) hasSeparator(v *ast.BasicLit) bool {
+ return strings.ContainsAny(v.Value, `/\`)
+}
+
+func (c *filepathJoinChecker) warnSeparator(sep ast.Expr) {
+ c.ctx.Warn(sep, "%s contains a path separator", sep)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/flagDeref_checker.go b/vendor/github.com/go-critic/go-critic/checkers/flagDeref_checker.go
index cb9faee71..393274c43 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/flagDeref_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/flagDeref_checker.go
@@ -3,12 +3,12 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go b/vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go
index 1d43ba521..36d2e4506 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go
@@ -6,27 +6,27 @@ import (
"go/types"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
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/vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go b/vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
index a700314cf..f3f9c535c 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
@@ -5,13 +5,13 @@ import (
"go/token"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go
index 656b4cc2d..54be77638 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go
@@ -3,15 +3,15 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go b/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go
index c0a456afd..91e1cfb39 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go
@@ -3,12 +3,12 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/importShadow_checker.go b/vendor/github.com/go-critic/go-critic/checkers/importShadow_checker.go
index 9a2ccc55e..60c0ab21e 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/importShadow_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/importShadow_checker.go
@@ -4,12 +4,12 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/indexAlloc_checker.go b/vendor/github.com/go-critic/go-critic/checkers/indexAlloc_checker.go
index 8fbe98c9d..733998873 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/indexAlloc_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/indexAlloc_checker.go
@@ -3,14 +3,14 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/initClause_checker.go b/vendor/github.com/go-critic/go-critic/checkers/initClause_checker.go
index bfbd661b2..91e8816d2 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/initClause_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/initClause_checker.go
@@ -3,13 +3,13 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/comment_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/comment_walker.go
new file mode 100644
index 000000000..6c60e3fed
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/comment_walker.go
@@ -0,0 +1,41 @@
+package astwalk
+
+import (
+ "go/ast"
+ "strings"
+)
+
+type commentWalker struct {
+ visitor CommentVisitor
+}
+
+func (w *commentWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, cg := range f.Comments {
+ visitCommentGroups(cg, w.visitor.VisitComment)
+ }
+}
+
+func visitCommentGroups(cg *ast.CommentGroup, visit func(*ast.CommentGroup)) {
+ var group []*ast.Comment
+ visitGroup := func(list []*ast.Comment) {
+ if len(list) == 0 {
+ return
+ }
+ cg := &ast.CommentGroup{List: list}
+ visit(cg)
+ }
+ for _, comment := range cg.List {
+ if strings.HasPrefix(comment.Text, "/*") {
+ visitGroup(group)
+ group = group[:0]
+ visitGroup([]*ast.Comment{comment})
+ } else {
+ group = append(group, comment)
+ }
+ }
+ visitGroup(group)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/doc_comment_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/doc_comment_walker.go
new file mode 100644
index 000000000..39b536508
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/doc_comment_walker.go
@@ -0,0 +1,48 @@
+package astwalk
+
+import (
+ "go/ast"
+)
+
+type docCommentWalker struct {
+ visitor DocCommentVisitor
+}
+
+func (w *docCommentWalker) WalkFile(f *ast.File) {
+ for _, decl := range f.Decls {
+ switch decl := decl.(type) {
+ case *ast.FuncDecl:
+ if decl.Doc != nil {
+ w.visitor.VisitDocComment(decl.Doc)
+ }
+ case *ast.GenDecl:
+ if decl.Doc != nil {
+ w.visitor.VisitDocComment(decl.Doc)
+ }
+ for _, spec := range decl.Specs {
+ switch spec := spec.(type) {
+ case *ast.ImportSpec:
+ if spec.Doc != nil {
+ w.visitor.VisitDocComment(spec.Doc)
+ }
+ case *ast.ValueSpec:
+ if spec.Doc != nil {
+ w.visitor.VisitDocComment(spec.Doc)
+ }
+ case *ast.TypeSpec:
+ if spec.Doc != nil {
+ w.visitor.VisitDocComment(spec.Doc)
+ }
+ ast.Inspect(spec.Type, func(n ast.Node) bool {
+ if n, ok := n.(*ast.Field); ok {
+ if n.Doc != nil {
+ w.visitor.VisitDocComment(n.Doc)
+ }
+ }
+ return true
+ })
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/expr_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/expr_walker.go
new file mode 100644
index 000000000..64098b2b7
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/expr_walker.go
@@ -0,0 +1,29 @@
+package astwalk
+
+import "go/ast"
+
+type exprWalker struct {
+ visitor ExprVisitor
+}
+
+func (w *exprWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok {
+ if !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ }
+
+ ast.Inspect(decl, func(x ast.Node) bool {
+ if x, ok := x.(ast.Expr); ok {
+ w.visitor.VisitExpr(x)
+ return !w.visitor.skipChilds()
+ }
+ return true
+ })
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/func_decl_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/func_decl_walker.go
new file mode 100644
index 000000000..90d921f6f
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/func_decl_walker.go
@@ -0,0 +1,21 @@
+package astwalk
+
+import "go/ast"
+
+type funcDeclWalker struct {
+ visitor FuncDeclVisitor
+}
+
+func (w *funcDeclWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ w.visitor.VisitFuncDecl(decl)
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_comment_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_comment_walker.go
new file mode 100644
index 000000000..e042f0d5e
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_comment_walker.go
@@ -0,0 +1,32 @@
+package astwalk
+
+import (
+ "go/ast"
+)
+
+type localCommentWalker struct {
+ visitor LocalCommentVisitor
+}
+
+func (w *localCommentWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+
+ for _, cg := range f.Comments {
+ // Not sure that decls/comments are sorted
+ // by positions, so do a naive full scan for now.
+ if cg.Pos() < decl.Pos() || cg.Pos() > decl.End() {
+ continue
+ }
+
+ visitCommentGroups(cg, w.visitor.VisitLocalComment)
+ }
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go
new file mode 100644
index 000000000..bed0f44ab
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go
@@ -0,0 +1,51 @@
+package astwalk
+
+import (
+ "go/ast"
+)
+
+// LocalDefVisitor visits every name definitions inside a function.
+//
+// Next elements are considered as name definitions:
+// - Function parameters (input, output, receiver)
+// - Every LHS of ":=" assignment that defines a new name
+// - Every local var/const declaration.
+//
+// NOTE: this visitor is experimental.
+// This is also why it lives in a separate file.
+type LocalDefVisitor interface {
+ walkerEvents
+ VisitLocalDef(Name, ast.Expr)
+}
+
+type (
+ // NameKind describes what kind of name Name object holds.
+ NameKind int
+
+ // Name holds ver/const/param definition symbol info.
+ Name struct {
+ ID *ast.Ident
+ Kind NameKind
+
+ // Index is NameVar-specific field that is used to
+ // specify nth tuple element being assigned to the name.
+ Index int
+ }
+)
+
+// NOTE: set of name kinds is not stable and may change over time.
+//
+// TODO(quasilyte): is NameRecv/NameParam/NameResult granularity desired?
+// TODO(quasilyte): is NameVar/NameBind (var vs :=) granularity desired?
+const (
+ // NameParam is function/method receiver/input/output name.
+ // Initializing expression is always nil.
+ NameParam NameKind = iota
+ // NameVar is var or ":=" declared name.
+ // Initizlizing expression may be nil for var-declared names
+ // without explicit initializing expression.
+ NameVar
+ // NameConst is const-declared name.
+ // Initializing expression is never nil.
+ NameConst
+)
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_walker.go
new file mode 100644
index 000000000..f6808cbb4
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_walker.go
@@ -0,0 +1,118 @@
+package astwalk
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+)
+
+type localDefWalker struct {
+ visitor LocalDefVisitor
+ info *types.Info
+}
+
+func (w *localDefWalker) WalkFile(f *ast.File) {
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ w.walkFunc(decl)
+ }
+}
+
+func (w *localDefWalker) walkFunc(decl *ast.FuncDecl) {
+ w.walkSignature(decl)
+ w.walkFuncBody(decl)
+}
+
+func (w *localDefWalker) walkFuncBody(decl *ast.FuncDecl) {
+ ast.Inspect(decl.Body, func(x ast.Node) bool {
+ switch x := x.(type) {
+ case *ast.AssignStmt:
+ if x.Tok != token.DEFINE {
+ return false
+ }
+ if len(x.Lhs) != len(x.Rhs) {
+ // Multi-value assignment.
+ // Invariant: there is only 1 RHS.
+ for i, lhs := range x.Lhs {
+ id, ok := lhs.(*ast.Ident)
+ if !ok || w.info.Defs[id] == nil {
+ continue
+ }
+ def := Name{ID: id, Kind: NameVar, Index: i}
+ w.visitor.VisitLocalDef(def, x.Rhs[0])
+ }
+ } else {
+ // Simple 1-1 assignments.
+ for i, lhs := range x.Lhs {
+ id, ok := lhs.(*ast.Ident)
+ if !ok || w.info.Defs[id] == nil {
+ continue
+ }
+ def := Name{ID: id, Kind: NameVar}
+ w.visitor.VisitLocalDef(def, x.Rhs[i])
+ }
+ }
+ return false
+
+ case *ast.GenDecl:
+ // Decls always introduce new names.
+ for _, spec := range x.Specs {
+ spec, ok := spec.(*ast.ValueSpec)
+ if !ok { // Ignore type/import specs
+ return false
+ }
+ switch {
+ case len(spec.Values) == 0:
+ // var-specific decls without explicit init.
+ for _, id := range spec.Names {
+ def := Name{ID: id, Kind: NameVar}
+ w.visitor.VisitLocalDef(def, nil)
+ }
+ case len(spec.Names) != len(spec.Values):
+ // var-specific decls that assign tuple results.
+ for i, id := range spec.Names {
+ def := Name{ID: id, Kind: NameVar, Index: i}
+ w.visitor.VisitLocalDef(def, spec.Values[0])
+ }
+ default:
+ // Can be either var or const decl.
+ kind := NameVar
+ if x.Tok == token.CONST {
+ kind = NameConst
+ }
+ for i, id := range spec.Names {
+ def := Name{ID: id, Kind: kind}
+ w.visitor.VisitLocalDef(def, spec.Values[i])
+ }
+ }
+ }
+ return false
+ }
+
+ return true
+ })
+}
+
+func (w *localDefWalker) walkSignature(decl *ast.FuncDecl) {
+ for _, p := range decl.Type.Params.List {
+ for _, id := range p.Names {
+ def := Name{ID: id, Kind: NameParam}
+ w.visitor.VisitLocalDef(def, nil)
+ }
+ }
+ if decl.Type.Results != nil {
+ for _, p := range decl.Type.Results.List {
+ for _, id := range p.Names {
+ def := Name{ID: id, Kind: NameParam}
+ w.visitor.VisitLocalDef(def, nil)
+ }
+ }
+ }
+ if decl.Recv != nil && len(decl.Recv.List[0].Names) != 0 {
+ def := Name{ID: decl.Recv.List[0].Names[0], Kind: NameParam}
+ w.visitor.VisitLocalDef(def, nil)
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_expr_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_expr_walker.go
new file mode 100644
index 000000000..951fd97e5
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_expr_walker.go
@@ -0,0 +1,27 @@
+package astwalk
+
+import "go/ast"
+
+type localExprWalker struct {
+ visitor LocalExprVisitor
+}
+
+func (w *localExprWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ ast.Inspect(decl.Body, func(x ast.Node) bool {
+ if x, ok := x.(ast.Expr); ok {
+ w.visitor.VisitLocalExpr(x)
+ return !w.visitor.skipChilds()
+ }
+ return true
+ })
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_list_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_list_walker.go
new file mode 100644
index 000000000..1cc0493a4
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_list_walker.go
@@ -0,0 +1,31 @@
+package astwalk
+
+import "go/ast"
+
+type stmtListWalker struct {
+ visitor StmtListVisitor
+}
+
+func (w *stmtListWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ ast.Inspect(decl.Body, func(x ast.Node) bool {
+ switch x := x.(type) {
+ case *ast.BlockStmt:
+ w.visitor.VisitStmtList(x.List)
+ case *ast.CaseClause:
+ w.visitor.VisitStmtList(x.Body)
+ case *ast.CommClause:
+ w.visitor.VisitStmtList(x.Body)
+ }
+ return !w.visitor.skipChilds()
+ })
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_walker.go
new file mode 100644
index 000000000..722eeb116
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/stmt_walker.go
@@ -0,0 +1,27 @@
+package astwalk
+
+import "go/ast"
+
+type stmtWalker struct {
+ visitor StmtVisitor
+}
+
+func (w *stmtWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ decl, ok := decl.(*ast.FuncDecl)
+ if !ok || !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ ast.Inspect(decl.Body, func(x ast.Node) bool {
+ if x, ok := x.(ast.Stmt); ok {
+ w.visitor.VisitStmt(x)
+ return !w.visitor.skipChilds()
+ }
+ return true
+ })
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go
new file mode 100644
index 000000000..24c150084
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go
@@ -0,0 +1,114 @@
+package astwalk
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "github.com/go-toolsmith/astp"
+ "github.com/go-toolsmith/typep"
+)
+
+type typeExprWalker struct {
+ visitor TypeExprVisitor
+ info *types.Info
+}
+
+func (w *typeExprWalker) WalkFile(f *ast.File) {
+ if !w.visitor.EnterFile(f) {
+ return
+ }
+
+ for _, decl := range f.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok {
+ if !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ }
+ switch decl := decl.(type) {
+ case *ast.FuncDecl:
+ if !w.visitor.EnterFunc(decl) {
+ continue
+ }
+ w.walkSignature(decl.Type)
+ ast.Inspect(decl.Body, w.walk)
+ case *ast.GenDecl:
+ if decl.Tok == token.IMPORT {
+ continue
+ }
+ ast.Inspect(decl, w.walk)
+ }
+ }
+}
+
+func (w *typeExprWalker) visit(x ast.Expr) bool {
+ w.visitor.VisitTypeExpr(x)
+ return !w.visitor.skipChilds()
+}
+
+func (w *typeExprWalker) walk(x ast.Node) bool {
+ switch x := x.(type) {
+ case *ast.ParenExpr:
+ if typep.IsTypeExpr(w.info, x.X) {
+ return w.visit(x)
+ }
+ return true
+ case *ast.CallExpr:
+ // Pointer conversions require parenthesis around pointer type.
+ // These casts are represented as call expressions.
+ // Because it's impossible for the visitor to distinguish such
+ // "required" parenthesis, walker skips outmost parenthesis in such cases.
+ return w.inspectInner(x.Fun)
+ case *ast.SelectorExpr:
+ // Like with conversions, method expressions are another special.
+ return w.inspectInner(x.X)
+ case *ast.StarExpr:
+ if typep.IsTypeExpr(w.info, x.X) {
+ return w.visit(x)
+ }
+ return true
+ case *ast.MapType:
+ return w.visit(x)
+ case *ast.FuncType:
+ return w.visit(x)
+ case *ast.StructType:
+ return w.visit(x)
+ case *ast.InterfaceType:
+ if !w.visit(x) {
+ return false
+ }
+ for _, method := range x.Methods.List {
+ switch x := method.Type.(type) {
+ case *ast.FuncType:
+ w.walkSignature(x)
+ default:
+ // Embedded interface.
+ w.walk(x)
+ }
+ }
+ return false
+ case *ast.ArrayType:
+ return w.visit(x)
+ }
+ return true
+}
+
+func (w *typeExprWalker) inspectInner(x ast.Expr) bool {
+ parens, ok := x.(*ast.ParenExpr)
+ if ok && typep.IsTypeExpr(w.info, parens.X) && astp.IsStarExpr(parens.X) {
+ ast.Inspect(parens.X, w.walk)
+ return false
+ }
+ return true
+}
+
+func (w *typeExprWalker) walkSignature(typ *ast.FuncType) {
+ for _, p := range typ.Params.List {
+ ast.Inspect(p.Type, w.walk)
+ }
+ if typ.Results != nil {
+ for _, p := range typ.Results.List {
+ ast.Inspect(p.Type, w.walk)
+ }
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/visitor.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/visitor.go
new file mode 100644
index 000000000..9f973a2b3
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/visitor.go
@@ -0,0 +1,80 @@
+package astwalk
+
+import (
+ "go/ast"
+)
+
+// Visitor interfaces.
+type (
+ // DocCommentVisitor visits every doc-comment.
+ // Does not visit doc-comments for function-local definitions (types, etc).
+ // Also does not visit package doc-comment (file-level doc-comments).
+ DocCommentVisitor interface {
+ VisitDocComment(*ast.CommentGroup)
+ }
+
+ // FuncDeclVisitor visits every top-level function declaration.
+ FuncDeclVisitor interface {
+ walkerEvents
+ VisitFuncDecl(*ast.FuncDecl)
+ }
+
+ // ExprVisitor visits every expression inside AST file.
+ ExprVisitor interface {
+ walkerEvents
+ VisitExpr(ast.Expr)
+ }
+
+ // LocalExprVisitor visits every expression inside function body.
+ LocalExprVisitor interface {
+ walkerEvents
+ VisitLocalExpr(ast.Expr)
+ }
+
+ // StmtListVisitor visits every statement list inside function body.
+ // This includes block statement bodies as well as implicit blocks
+ // introduced by case clauses and alike.
+ StmtListVisitor interface {
+ walkerEvents
+ VisitStmtList([]ast.Stmt)
+ }
+
+ // StmtVisitor visits every statement inside function body.
+ StmtVisitor interface {
+ walkerEvents
+ VisitStmt(ast.Stmt)
+ }
+
+ // TypeExprVisitor visits every type describing expression.
+ // It also traverses struct types and interface types to run
+ // checker over their fields/method signatures.
+ TypeExprVisitor interface {
+ walkerEvents
+ VisitTypeExpr(ast.Expr)
+ }
+
+ // LocalCommentVisitor visits every comment inside function body.
+ LocalCommentVisitor interface {
+ walkerEvents
+ VisitLocalComment(*ast.CommentGroup)
+ }
+
+ // CommentVisitor visits every comment.
+ CommentVisitor interface {
+ walkerEvents
+ VisitComment(*ast.CommentGroup)
+ }
+)
+
+// walkerEvents describes common hooks available for most visitor types.
+type walkerEvents interface {
+ // EnterFile is called for every file that is about to be traversed.
+ // If false is returned, file is not visited.
+ EnterFile(*ast.File) bool
+
+ // EnterFunc is called for every function declaration that is about
+ // to be traversed. If false is returned, function is not visited.
+ EnterFunc(*ast.FuncDecl) bool
+
+ skipChilds() bool
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walk_handler.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walk_handler.go
new file mode 100644
index 000000000..1f6e948d5
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walk_handler.go
@@ -0,0 +1,34 @@
+package astwalk
+
+import (
+ "go/ast"
+)
+
+// WalkHandler is a type to be embedded into every checker
+// that uses astwalk walkers.
+type WalkHandler struct {
+ // SkipChilds controls whether currently analyzed
+ // node childs should be traversed.
+ //
+ // Value is reset after each visitor invocation,
+ // so there is no need to set value back to false.
+ SkipChilds bool
+}
+
+// EnterFile is a default walkerEvents.EnterFile implementation
+// that reports every file as accepted candidate for checking.
+func (w *WalkHandler) EnterFile(f *ast.File) bool {
+ return true
+}
+
+// EnterFunc is a default walkerEvents.EnterFunc implementation
+// that skips extern function (ones that do not have body).
+func (w *WalkHandler) EnterFunc(decl *ast.FuncDecl) bool {
+ return decl.Body != nil
+}
+
+func (w *WalkHandler) skipChilds() bool {
+ v := w.SkipChilds
+ w.SkipChilds = false
+ return v
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walker.go
new file mode 100644
index 000000000..cd5e1c979
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/walker.go
@@ -0,0 +1,57 @@
+package astwalk
+
+import (
+ "go/types"
+
+ "github.com/go-critic/go-critic/framework/linter"
+)
+
+// WalkerForFuncDecl returns file walker implementation for FuncDeclVisitor.
+func WalkerForFuncDecl(v FuncDeclVisitor) linter.FileWalker {
+ return &funcDeclWalker{visitor: v}
+}
+
+// WalkerForExpr returns file walker implementation for ExprVisitor.
+func WalkerForExpr(v ExprVisitor) linter.FileWalker {
+ return &exprWalker{visitor: v}
+}
+
+// WalkerForLocalExpr returns file walker implementation for LocalExprVisitor.
+func WalkerForLocalExpr(v LocalExprVisitor) linter.FileWalker {
+ return &localExprWalker{visitor: v}
+}
+
+// WalkerForStmtList returns file walker implementation for StmtListVisitor.
+func WalkerForStmtList(v StmtListVisitor) linter.FileWalker {
+ return &stmtListWalker{visitor: v}
+}
+
+// WalkerForStmt returns file walker implementation for StmtVisitor.
+func WalkerForStmt(v StmtVisitor) linter.FileWalker {
+ return &stmtWalker{visitor: v}
+}
+
+// WalkerForTypeExpr returns file walker implementation for TypeExprVisitor.
+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) linter.FileWalker {
+ return &localCommentWalker{visitor: v}
+}
+
+// WalkerForComment returns file walker implementation for CommentVisitor.
+func WalkerForComment(v CommentVisitor) linter.FileWalker {
+ return &commentWalker{visitor: v}
+}
+
+// WalkerForDocComment returns file walker implementation for DocCommentVisitor.
+func WalkerForDocComment(v DocCommentVisitor) linter.FileWalker {
+ return &docCommentWalker{visitor: v}
+}
+
+// WalkerForLocalDef returns file walker implementation for LocalDefVisitor.
+func WalkerForLocalDef(v LocalDefVisitor, info *types.Info) linter.FileWalker {
+ return &localDefWalker{visitor: v, info: info}
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/mapKey_checker.go b/vendor/github.com/go-critic/go-critic/checkers/mapKey_checker.go
index de3e781e5..fdbbb45a2 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/mapKey_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/mapKey_checker.go
@@ -5,18 +5,18 @@ import (
"go/types"
"strings"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
info.Summary = "Detects suspicious map literal keys"
info.Before = `
_ = map[string]int{
@@ -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/vendor/github.com/go-critic/go-critic/checkers/methodExprCall_checker.go b/vendor/github.com/go-critic/go-critic/checkers/methodExprCall_checker.go
index 60da11655..efd631143 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/methodExprCall_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/methodExprCall_checker.go
@@ -4,15 +4,15 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/nestingReduce_checker.go b/vendor/github.com/go-critic/go-critic/checkers/nestingReduce_checker.go
index 4a0331d5c..de02c7eec 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/nestingReduce_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/nestingReduce_checker.go
@@ -3,15 +3,15 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go b/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go
index 75e7f6428..7b9f02bd3 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go
@@ -3,29 +3,29 @@ package checkers
import (
"go/ast"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"style"}
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/vendor/github.com/go-critic/go-critic/checkers/nilValReturn_checker.go b/vendor/github.com/go-critic/go-critic/checkers/nilValReturn_checker.go
index 231e25800..37f964f70 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/nilValReturn_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/nilValReturn_checker.go
@@ -4,14 +4,14 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go b/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
index e40ec6db5..a1d968043 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
@@ -5,20 +5,20 @@ import (
"go/token"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/offBy1_checker.go b/vendor/github.com/go-critic/go-critic/checkers/offBy1_checker.go
index d5c8de0b7..df20b429a 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/offBy1_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/offBy1_checker.go
@@ -4,8 +4,8 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"diagnostic"}
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/vendor/github.com/go-critic/go-critic/checkers/paramTypeCombine_checker.go b/vendor/github.com/go-critic/go-critic/checkers/paramTypeCombine_checker.go
index ffa74061e..f9f9d6c5a 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/paramTypeCombine_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/paramTypeCombine_checker.go
@@ -3,27 +3,27 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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(&paramTypeCombineChecker{ctx: ctx})
})
}
type paramTypeCombineChecker struct {
astwalk.WalkHandler
- ctx *lintpack.CheckerContext
+ ctx *linter.CheckerContext
}
func (c *paramTypeCombineChecker) EnterFunc(*ast.FuncDecl) bool {
@@ -51,7 +51,8 @@ func (c *paramTypeCombineChecker) optimizeParams(params *ast.FieldList) *ast.Fie
// ast.Field have empty name list.
skip := params == nil ||
len(params.List) < 2 ||
- len(params.List[0].Names) == 0
+ len(params.List[0].Names) == 0 ||
+ c.paramsAreMultiLine(params)
if skip {
return params
}
@@ -84,3 +85,9 @@ func (c *paramTypeCombineChecker) optimizeParams(params *ast.FieldList) *ast.Fie
func (c *paramTypeCombineChecker) warn(f1, f2 *ast.FuncType) {
c.ctx.Warn(f1, "%s could be replaced with %s", f1, f2)
}
+
+func (c *paramTypeCombineChecker) paramsAreMultiLine(params *ast.FieldList) bool {
+ startPos := c.ctx.FileSet.Position(params.Opening)
+ endPos := c.ctx.FileSet.Position(params.Closing)
+ return startPos.Line != endPos.Line
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/ptrToRefParam_checker.go b/vendor/github.com/go-critic/go-critic/checkers/ptrToRefParam_checker.go
index dacffc85a..2716fe04b 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/ptrToRefParam_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/ptrToRefParam_checker.go
@@ -4,26 +4,26 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/rangeExprCopy_checker.go b/vendor/github.com/go-critic/go-critic/checkers/rangeExprCopy_checker.go
index 387d1bbbc..90b5987ab 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/rangeExprCopy_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/rangeExprCopy_checker.go
@@ -4,15 +4,15 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go b/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go
index 182538a9f..57dcc3151 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go
@@ -3,15 +3,15 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/regexpMust_checker.go b/vendor/github.com/go-critic/go-critic/checkers/regexpMust_checker.go
index ef7a39787..411932ee5 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/regexpMust_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/regexpMust_checker.go
@@ -4,28 +4,28 @@ import (
"go/ast"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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(&regexpMustChecker{ctx: ctx})
})
}
type regexpMustChecker struct {
astwalk.WalkHandler
- ctx *lintpack.CheckerContext
+ ctx *linter.CheckerContext
}
func (c *regexpMustChecker) VisitExpr(x ast.Expr) {
diff --git a/vendor/github.com/go-critic/go-critic/checkers/regexpPattern_checker.go b/vendor/github.com/go-critic/go-critic/checkers/regexpPattern_checker.go
index 383deb5d4..018ab42d1 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/regexpPattern_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/regexpPattern_checker.go
@@ -6,19 +6,19 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go b/vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go
new file mode 100644
index 000000000..10dcb327f
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go
@@ -0,0 +1,511 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+ "go/constant"
+ "log"
+ "strings"
+ "unicode/utf8"
+
+ "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 linter.CheckerInfo
+ info.Name = "regexpSimplify"
+ info.Tags = []string{"style", "experimental", "opinionated"}
+ info.Summary = "Detects regexp patterns that can be simplified"
+ info.Before = "regexp.MustCompile(`(?:a|b|c) [a-z][a-z]*`)"
+ info.After = "regexp.MustCompile(`[abc] {3}[a-z]+`)"
+
+ // TODO(quasilyte): add params to control most opinionated replacements
+ // like `[0-9] -> \d`
+ // `[[:digit:]] -> \d`
+ // `[A-Za-z0-9_]` -> `\w`
+
+ collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker {
+ opts := &syntax.ParserOptions{
+ NoLiterals: true,
+ }
+ c := &regexpSimplifyChecker{
+ ctx: ctx,
+ parser: syntax.NewParser(opts),
+ out: &strings.Builder{},
+ }
+ return astwalk.WalkerForExpr(c)
+ })
+}
+
+type regexpSimplifyChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+ parser *syntax.Parser
+
+ // out is a tmp buffer where we build a simplified regexp pattern.
+ out *strings.Builder
+ // score is a number of applied simplifications
+ score int
+}
+
+func (c *regexpSimplifyChecker) VisitExpr(x ast.Expr) {
+ call, ok := x.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ switch qualifiedName(call.Fun) {
+ case "regexp.Compile", "regexp.MustCompile":
+ cv := c.ctx.TypesInfo.Types[call.Args[0]].Value
+ if cv == nil || cv.Kind() != constant.String {
+ return
+ }
+ pat := constant.StringVal(cv)
+ if len(pat) > 60 {
+ // Skip scary regexp patterns for now.
+ break
+ }
+
+ // Only do 2 passes.
+ simplified := pat
+ for pass := 0; pass < 2; pass++ {
+ candidate := c.simplify(pass, simplified)
+ if candidate == "" {
+ break
+ }
+ simplified = candidate
+ }
+ if simplified != "" && simplified != pat {
+ c.warn(call.Args[0], pat, simplified)
+ }
+ }
+}
+
+func (c *regexpSimplifyChecker) simplify(pass int, pat string) string {
+ re, err := c.parser.Parse(pat)
+ if err != nil {
+ return ""
+ }
+
+ c.score = 0
+ c.out.Reset()
+
+ // TODO(quasilyte): suggest char ranges for things like [012345689]?
+ // TODO(quasilyte): evaluate char range to suggest better replacements.
+ // TODO(quasilyte): (?:ab|ac) -> a[bc]
+ // TODO(quasilyte): suggest "s" and "." flag if things like [\w\W] are used.
+ // TODO(quasilyte): x{n}x? -> x{n,n+1}
+
+ c.walk(re.Expr)
+
+ if debug() {
+ // This happens only in one of two cases:
+ // 1. Parser has a bug and we got invalid AST for the given pattern.
+ // 2. Simplifier incorrectly built a replacement string from the AST.
+ if c.score == 0 && c.out.String() != pat {
+ log.Printf("pass %d: unexpected pattern diff:\n\thave: %q\n\twant: %q",
+ pass, c.out.String(), pat)
+ }
+ }
+
+ if c.score > 0 {
+ return c.out.String()
+ }
+ return ""
+}
+
+func (c *regexpSimplifyChecker) walk(e syntax.Expr) {
+ out := c.out
+
+ switch e.Op {
+ case syntax.OpConcat:
+ c.walkConcat(e)
+
+ case syntax.OpAlt:
+ c.walkAlt(e)
+
+ case syntax.OpCharRange:
+ s := c.simplifyCharRange(e)
+ if s != "" {
+ out.WriteString(s)
+ c.score++
+ } else {
+ out.WriteString(e.Value)
+ }
+
+ case syntax.OpGroupWithFlags:
+ out.WriteString("(")
+ out.WriteString(e.Args[1].Value)
+ out.WriteString(":")
+ c.walk(e.Args[0])
+ out.WriteString(")")
+ case syntax.OpGroup:
+ c.walkGroup(e)
+ case syntax.OpCapture:
+ out.WriteString("(")
+ c.walk(e.Args[0])
+ out.WriteString(")")
+ case syntax.OpNamedCapture:
+ out.WriteString("(?P<")
+ out.WriteString(e.Args[1].Value)
+ out.WriteString(">")
+ c.walk(e.Args[0])
+ out.WriteString(")")
+
+ case syntax.OpRepeat:
+ // TODO(quasilyte): is it worth it to analyze repeat argument
+ // more closely and handle `{n,n} -> {n}` cases?
+ rep := e.Args[1].Value
+ switch rep {
+ case "{0,1}":
+ c.walk(e.Args[0])
+ out.WriteString("?")
+ c.score++
+ case "{1,}":
+ c.walk(e.Args[0])
+ out.WriteString("+")
+ c.score++
+ case "{0,}":
+ c.walk(e.Args[0])
+ out.WriteString("*")
+ c.score++
+ case "{0}":
+ // Maybe {0} should be reported by another check, regexpLint?
+ c.score++
+ case "{1}":
+ c.walk(e.Args[0])
+ c.score++
+ default:
+ c.walk(e.Args[0])
+ out.WriteString(rep)
+ }
+
+ case syntax.OpPosixClass:
+ out.WriteString(e.Value)
+
+ case syntax.OpNegCharClass:
+ s := c.simplifyNegCharClass(e)
+ if s != "" {
+ c.out.WriteString(s)
+ c.score++
+ } else {
+ out.WriteString("[^")
+ for _, e := range e.Args {
+ c.walk(e)
+ }
+ out.WriteString("]")
+ }
+
+ case syntax.OpCharClass:
+ s := c.simplifyCharClass(e)
+ if s != "" {
+ c.out.WriteString(s)
+ c.score++
+ } else {
+ out.WriteString("[")
+ for _, e := range e.Args {
+ c.walk(e)
+ }
+ out.WriteString("]")
+ }
+
+ case syntax.OpEscapeChar:
+ switch e.Value {
+ case `\&`, `\#`, `\!`, `\@`, `\%`, `\<`, `\>`, `\:`, `\;`, `\/`, `\,`, `\=`, `\.`:
+ c.score++
+ out.WriteString(e.Value[len(`\`):])
+ default:
+ out.WriteString(e.Value)
+ }
+
+ case syntax.OpQuestion, syntax.OpNonGreedy:
+ c.walk(e.Args[0])
+ out.WriteString("?")
+ case syntax.OpStar:
+ c.walk(e.Args[0])
+ out.WriteString("*")
+ case syntax.OpPlus:
+ c.walk(e.Args[0])
+ out.WriteString("+")
+
+ default:
+ out.WriteString(e.Value)
+ }
+}
+
+func (c *regexpSimplifyChecker) walkGroup(g syntax.Expr) {
+ switch g.Args[0].Op {
+ case syntax.OpChar, syntax.OpEscapeChar, syntax.OpEscapeMeta, syntax.OpCharClass:
+ c.walk(g.Args[0])
+ c.score++
+ return
+ }
+
+ c.out.WriteString("(?:")
+ c.walk(g.Args[0])
+ c.out.WriteString(")")
+}
+
+func (c *regexpSimplifyChecker) simplifyNegCharClass(e syntax.Expr) string {
+ switch e.Value {
+ case `[^0-9]`:
+ return `\D`
+ case `[^\s]`:
+ return `\S`
+ case `[^\S]`:
+ return `\s`
+ case `[^\w]`:
+ return `\W`
+ case `[^\W]`:
+ return `\w`
+ case `[^\d]`:
+ return `\D`
+ case `[^\D]`:
+ return `\d`
+ case `[^[:^space:]]`:
+ return `\s`
+ case `[^[:space:]]`:
+ return `\S`
+ case `[^[:^word:]]`:
+ return `\w`
+ case `[^[:word:]]`:
+ return `\W`
+ case `[^[:^digit:]]`:
+ return `\d`
+ case `[^[:digit:]]`:
+ return `\D`
+ }
+
+ return ""
+}
+
+func (c *regexpSimplifyChecker) simplifyCharClass(e syntax.Expr) string {
+ switch e.Value {
+ case `[0-9]`:
+ return `\d`
+ case `[[:word:]]`:
+ return `\w`
+ case `[[:^word:]]`:
+ return `\W`
+ case `[[:digit:]]`:
+ return `\d`
+ case `[[:^digit:]]`:
+ return `\D`
+ case `[[:space:]]`:
+ return `\s`
+ case `[[:^space:]]`:
+ return `\S`
+ case `[][]`:
+ return `\]\[`
+ case `[]]`:
+ return `\]`
+ }
+
+ if len(e.Args) == 1 {
+ switch e.Args[0].Op {
+ case syntax.OpChar:
+ switch v := e.Args[0].Value; v {
+ case "|", "*", "+", "?", ".", "[", "^", "$", "(", ")":
+ // Can't take outside of the char group without escaping.
+ default:
+ return v
+ }
+ case syntax.OpEscapeChar:
+ return e.Args[0].Value
+ }
+ }
+
+ return ""
+}
+
+func (c *regexpSimplifyChecker) canMerge(x, y syntax.Expr) bool {
+ if x.Op != y.Op {
+ return false
+ }
+ switch x.Op {
+ case syntax.OpChar, syntax.OpCharClass, syntax.OpEscapeMeta, syntax.OpEscapeChar, syntax.OpNegCharClass, syntax.OpGroup:
+ return x.Value == y.Value
+ default:
+ return false
+ }
+}
+
+func (c *regexpSimplifyChecker) canCombine(x, y syntax.Expr) (threshold int, ok bool) {
+ if x.Op != y.Op {
+ return 0, false
+ }
+
+ switch x.Op {
+ case syntax.OpDot:
+ return 3, true
+
+ case syntax.OpChar:
+ if x.Value != y.Value {
+ return 0, false
+ }
+ if x.Value == " " {
+ return 1, true
+ }
+ return 4, true
+
+ case syntax.OpEscapeMeta, syntax.OpEscapeChar:
+ if x.Value == y.Value {
+ return 2, true
+ }
+
+ case syntax.OpCharClass, syntax.OpNegCharClass, syntax.OpGroup:
+ if x.Value == y.Value {
+ return 1, true
+ }
+ }
+
+ return 0, false
+}
+
+func (c *regexpSimplifyChecker) concatLiteral(e syntax.Expr) string {
+ if e.Op == syntax.OpConcat && c.allChars(e) {
+ return e.Value
+ }
+ return ""
+}
+
+func (c *regexpSimplifyChecker) allChars(e syntax.Expr) bool {
+ for _, a := range e.Args {
+ if a.Op != syntax.OpChar {
+ return false
+ }
+ }
+ return true
+}
+
+func (c *regexpSimplifyChecker) factorPrefixSuffix(alt syntax.Expr) bool {
+ // TODO: more forms of prefixes/suffixes?
+ //
+ // A more generalized algorithm could handle `fo|fo1|fo2` -> `fo[12]?`.
+ // but it's an open question whether the latter form universally better.
+ //
+ // Right now it handles only the simplest cases:
+ // `http|https` -> `https?`
+ // `xfoo|foo` -> `x?foo`
+ if len(alt.Args) != 2 {
+ return false
+ }
+ x := c.concatLiteral(alt.Args[0])
+ y := c.concatLiteral(alt.Args[1])
+ if x == y {
+ return false // Reject non-literals and identical strings early
+ }
+
+ // Let x be a shorter string.
+ if len(x) > len(y) {
+ x, y = y, x
+ }
+ // Do we have a common prefix?
+ tail := strings.TrimPrefix(y, x)
+ if len(tail) <= utf8.UTFMax && utf8.RuneCountInString(tail) == 1 {
+ c.out.WriteString(x + tail + "?")
+ c.score++
+ return true
+ }
+ // Do we have a common suffix?
+ head := strings.TrimSuffix(y, x)
+ if len(head) <= utf8.UTFMax && utf8.RuneCountInString(head) == 1 {
+ c.out.WriteString(head + "?" + x)
+ c.score++
+ return true
+ }
+ return false
+}
+
+func (c *regexpSimplifyChecker) walkAlt(alt syntax.Expr) {
+ // `x|y|z` -> `[xyz]`.
+ if c.allChars(alt) {
+ c.score++
+ c.out.WriteString("[")
+ for _, e := range alt.Args {
+ c.out.WriteString(e.Value)
+ }
+ c.out.WriteString("]")
+ return
+ }
+
+ if c.factorPrefixSuffix(alt) {
+ return
+ }
+
+ for i, e := range alt.Args {
+ c.walk(e)
+ if i != len(alt.Args)-1 {
+ c.out.WriteString("|")
+ }
+ }
+}
+
+func (c *regexpSimplifyChecker) walkConcat(concat syntax.Expr) {
+ i := 0
+ for i < len(concat.Args) {
+ x := concat.Args[i]
+ c.walk(x)
+ i++
+
+ if i >= len(concat.Args) {
+ break
+ }
+
+ // Try merging `xy*` into `x+` where x=y.
+ if concat.Args[i].Op == syntax.OpStar {
+ if c.canMerge(x, concat.Args[i].Args[0]) {
+ c.out.WriteString("+")
+ c.score++
+ i++
+ continue
+ }
+ }
+
+ // Try combining `xy` into `x{2}` where x=y.
+ threshold, ok := c.canCombine(x, concat.Args[i])
+ if !ok {
+ continue
+ }
+ n := 1 // Can combine at least 1 pair.
+ for j := i + 1; j < len(concat.Args); j++ {
+ _, ok := c.canCombine(x, concat.Args[j])
+ if !ok {
+ break
+ }
+ n++
+ }
+ if n >= threshold {
+ fmt.Fprintf(c.out, "{%d}", n+1)
+ c.score++
+ i += n
+ }
+ }
+}
+
+func (c *regexpSimplifyChecker) simplifyCharRange(rng syntax.Expr) string {
+ if rng.Args[0].Op != syntax.OpChar || rng.Args[1].Op != syntax.OpChar {
+ return ""
+ }
+
+ lo := rng.Args[0].Value
+ hi := rng.Args[1].Value
+ if len(lo) == 1 && len(hi) == 1 {
+ switch hi[0] - lo[0] {
+ case 0:
+ return lo
+ case 1:
+ return fmt.Sprintf("%s%s", lo, hi)
+ case 2:
+ return fmt.Sprintf("%s%s%s", lo, string(lo[0]+1), hi)
+ }
+ }
+
+ return ""
+}
+
+func (c *regexpSimplifyChecker) warn(cause ast.Expr, orig, suggest string) {
+ c.ctx.Warn(cause, "can re-write `%s` as `%s`", orig, suggest)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go b/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go
new file mode 100644
index 000000000..d9799102d
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go
@@ -0,0 +1,95 @@
+package checkers
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+ "io/ioutil"
+ "log"
+
+ "github.com/go-critic/go-critic/framework/linter"
+ "github.com/quasilyte/go-ruleguard/ruleguard"
+)
+
+func init() {
+ var info linter.CheckerInfo
+ info.Name = "ruleguard"
+ info.Tags = []string{"style", "experimental"}
+ info.Params = linter.CheckerParams{
+ "rules": {
+ Value: "",
+ Usage: "path to a gorules file",
+ },
+ }
+ info.Summary = "Runs user-defined rules using ruleguard linter"
+ info.Details = "Reads a rules file and turns them into go-critic checkers."
+ info.Before = `N/A`
+ info.After = `N/A`
+ info.Note = "See https://github.com/quasilyte/go-ruleguard."
+
+ collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker {
+ return newRuleguardChecker(&info, ctx)
+ })
+}
+
+func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) *ruleguardChecker {
+ c := &ruleguardChecker{ctx: ctx}
+ rulesFilename := info.Params.String("rules")
+ if rulesFilename == "" {
+ return c
+ }
+
+ // TODO(quasilyte): handle initialization errors better when we make
+ // a transition to the go/analysis framework.
+ //
+ // For now, we log error messages and return a ruleguard checker
+ // with an empty rules set.
+
+ data, err := ioutil.ReadFile(rulesFilename)
+ if err != nil {
+ log.Printf("ruleguard init error: %+v", err)
+ return c
+ }
+
+ fset := token.NewFileSet()
+ rset, err := ruleguard.ParseRules(rulesFilename, fset, bytes.NewReader(data))
+ if err != nil {
+ log.Printf("ruleguard init error: %+v", err)
+ return c
+ }
+
+ c.rset = rset
+ return c
+}
+
+type ruleguardChecker struct {
+ ctx *linter.CheckerContext
+
+ rset *ruleguard.GoRuleSet
+}
+
+func (c *ruleguardChecker) WalkFile(f *ast.File) {
+ if c.rset == nil {
+ return
+ }
+
+ ctx := &ruleguard.Context{
+ Pkg: c.ctx.Pkg,
+ Types: c.ctx.TypesInfo,
+ Sizes: c.ctx.SizesInfo,
+ Fset: c.ctx.FileSet,
+ Report: func(_ ruleguard.GoRuleInfo, n ast.Node, msg string, _ *ruleguard.Suggestion) {
+ // TODO(quasilyte): investigate whether we should add a rule name as
+ // a message prefix here.
+ c.ctx.Warn(n, msg)
+ },
+ }
+
+ err := ruleguard.RunRules(ctx, f, c.rset)
+ if err != nil {
+ // Normally this should never happen, but since
+ // we don't have a better mechanism to report errors,
+ // emit a warning.
+ c.ctx.Warn(f, "execution error: %v", err)
+ }
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/singleCaseSwitch_checker.go b/vendor/github.com/go-critic/go-critic/checkers/singleCaseSwitch_checker.go
index 6cdb06aef..abead3fa2 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/singleCaseSwitch_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/singleCaseSwitch_checker.go
@@ -2,13 +2,15 @@ package checkers
import (
"go/ast"
+ "go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
+ "github.com/go-critic/go-critic/framework/linter"
+ "golang.org/x/tools/go/ast/astutil"
)
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 +24,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) {
@@ -42,16 +44,37 @@ func (c *singleCaseSwitchChecker) VisitStmt(stmt ast.Stmt) {
}
func (c *singleCaseSwitchChecker) checkSwitchStmt(stmt ast.Stmt, body *ast.BlockStmt) {
- if len(body.List) == 1 {
- if body.List[0].(*ast.CaseClause).List == nil {
- // default case.
- c.warnDefault(stmt)
- } else if len(body.List[0].(*ast.CaseClause).List) == 1 {
- c.warn(stmt)
- }
+ if len(body.List) != 1 {
+ return
+ }
+ cc := body.List[0].(*ast.CaseClause)
+ if c.hasBreak(cc) {
+ return
+ }
+ switch {
+ case cc.List == nil:
+ c.warnDefault(stmt)
+ case len(cc.List) == 1:
+ c.warn(stmt)
}
}
+func (c *singleCaseSwitchChecker) hasBreak(stmt ast.Stmt) bool {
+ found := false
+ astutil.Apply(stmt, func(cur *astutil.Cursor) bool {
+ switch n := cur.Node().(type) {
+ case *ast.BranchStmt:
+ if n.Tok == token.BREAK {
+ found = true
+ }
+ case *ast.ForStmt, *ast.RangeStmt, *ast.SelectStmt, *ast.SwitchStmt:
+ return false
+ }
+ return true
+ }, nil)
+ return found
+}
+
func (c *singleCaseSwitchChecker) warn(stmt ast.Stmt) {
c.ctx.Warn(stmt, "should rewrite switch statement to if statement")
}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/sloppyLen_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sloppyLen_checker.go
index 45123ec6b..e12545ffe 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/sloppyLen_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/sloppyLen_checker.go
@@ -4,14 +4,14 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/sloppyReassign_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sloppyReassign_checker.go
index 1a7c19877..d099450d1 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/sloppyReassign_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/sloppyReassign_checker.go
@@ -4,29 +4,29 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go
new file mode 100644
index 000000000..4abfcbab4
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go
@@ -0,0 +1,75 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/types"
+
+ "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 linter.CheckerInfo
+ info.Name = "sloppyTypeAssert"
+ info.Tags = []string{"diagnostic", "experimental"}
+ info.Summary = "Detects redundant type assertions"
+ info.Before = `
+function f(r io.Reader) interface{} {
+ return r.(interface{})
+}
+`
+ info.After = `
+function f(r io.Reader) interface{} {
+ return r
+}
+`
+
+ collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForExpr(&sloppyTypeAssertChecker{ctx: ctx})
+ })
+}
+
+type sloppyTypeAssertChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+}
+
+func (c *sloppyTypeAssertChecker) VisitExpr(expr ast.Expr) {
+ assert := astcast.ToTypeAssertExpr(expr)
+ if assert.Type == nil {
+ return
+ }
+
+ toType := c.ctx.TypesInfo.TypeOf(expr)
+ fromType := c.ctx.TypesInfo.TypeOf(assert.X)
+
+ if types.Identical(toType, fromType) {
+ c.warnIdentical(expr)
+ return
+ }
+
+ toIface, ok := toType.Underlying().(*types.Interface)
+ if !ok {
+ return
+ }
+
+ switch {
+ case toIface.Empty():
+ c.warnEmpty(expr)
+ case types.Implements(fromType, toIface):
+ c.warnImplements(expr, assert.X)
+ }
+}
+
+func (c *sloppyTypeAssertChecker) warnIdentical(cause ast.Expr) {
+ c.ctx.Warn(cause, "type assertion from/to types are identical")
+}
+
+func (c *sloppyTypeAssertChecker) warnEmpty(cause ast.Expr) {
+ c.ctx.Warn(cause, "type assertion to interface{} may be redundant")
+}
+
+func (c *sloppyTypeAssertChecker) warnImplements(cause, val ast.Expr) {
+ c.ctx.Warn(cause, "type assertion may be redundant as %s always implements selected interface", val)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go
new file mode 100644
index 000000000..b80c17873
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go
@@ -0,0 +1,135 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/token"
+
+ "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"
+ "golang.org/x/tools/go/ast/astutil"
+)
+
+func init() {
+ 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 *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForExpr(&sortSliceChecker{ctx: ctx})
+ })
+}
+
+type sortSliceChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+}
+
+func (c *sortSliceChecker) VisitExpr(expr ast.Expr) {
+ call := astcast.ToCallExpr(expr)
+ if len(call.Args) != 2 {
+ return
+ }
+ switch qualifiedName(call.Fun) {
+ case "sort.Slice", "sort.SliceStable":
+ // OK.
+ default:
+ return
+ }
+
+ slice := c.unwrapSlice(call.Args[0])
+ lessFunc, ok := call.Args[1].(*ast.FuncLit)
+ if !ok {
+ return
+ }
+ if !typep.SideEffectFree(c.ctx.TypesInfo, slice) {
+ return // Don't check unpredictable slice values
+ }
+
+ ivar, jvar := c.paramIdents(lessFunc.Type)
+ if ivar == nil || jvar == nil {
+ return
+ }
+
+ if len(lessFunc.Body.List) != 1 {
+ return
+ }
+ ret, ok := lessFunc.Body.List[0].(*ast.ReturnStmt)
+ if !ok {
+ return
+ }
+ cmp := astcast.ToBinaryExpr(astutil.Unparen(ret.Results[0]))
+ if !typep.SideEffectFree(c.ctx.TypesInfo, cmp) {
+ return
+ }
+ switch cmp.Op {
+ case token.LSS, token.LEQ, token.GTR, token.GEQ:
+ // Both cmp.X and cmp.Y are expected to be some expressions
+ // over the `slice` expression. In the simplest case,
+ // it's a `slice[i] <op> slice[j]`.
+ if !c.containsSlice(cmp.X, slice) && !c.containsSlice(cmp.Y, slice) {
+ c.warnSlice(cmp, slice)
+ }
+
+ // This one is more about the style, but can reveal potential issue
+ // or misprint in sorting condition.
+ // We give a warn if X contains indexing with `i` index and Y
+ // contains indexing with `j`.
+ if c.containsIndex(cmp.X, jvar) && c.containsIndex(cmp.Y, ivar) {
+ c.warnIndex(cmp, ivar, jvar)
+ }
+ }
+}
+
+func (c *sortSliceChecker) paramIdents(e *ast.FuncType) (*ast.Ident, *ast.Ident) {
+ // Covers both `i, j int` and `i int, j int`.
+ idents := make([]*ast.Ident, 0, 2)
+ for _, field := range e.Params.List {
+ idents = append(idents, field.Names...)
+ }
+ if len(idents) == 2 {
+ return idents[0], idents[1]
+ }
+ return nil, nil
+}
+
+func (c *sortSliceChecker) unwrapSlice(e ast.Expr) ast.Expr {
+ switch e := e.(type) {
+ case *ast.ParenExpr:
+ return c.unwrapSlice(e.X)
+ case *ast.SliceExpr:
+ return e.X
+ default:
+ return e
+ }
+}
+
+func (c *sortSliceChecker) containsIndex(e, index ast.Expr) bool {
+ return lintutil.ContainsNode(e, func(n ast.Node) bool {
+ indexing, ok := n.(*ast.IndexExpr)
+ if !ok {
+ return false
+ }
+ return astequal.Expr(indexing.Index, index)
+ })
+}
+
+func (c *sortSliceChecker) containsSlice(e, slice ast.Expr) bool {
+ return lintutil.ContainsNode(e, func(n ast.Node) bool {
+ return astequal.Node(n, slice)
+ })
+}
+
+func (c *sortSliceChecker) warnSlice(cause ast.Node, slice ast.Expr) {
+ c.ctx.Warn(cause, "cmp func must use %s slice in comparison", slice)
+}
+
+func (c *sortSliceChecker) warnIndex(cause ast.Node, ivar, jvar *ast.Ident) {
+ c.ctx.Warn(cause, "unusual order of {%s,%s} params in comparison", ivar, jvar)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go b/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go
new file mode 100644
index 000000000..697a82ccf
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go
@@ -0,0 +1,167 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/types"
+
+ "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 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 *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForStmt(&sqlQueryChecker{ctx: ctx})
+ })
+}
+
+type sqlQueryChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+}
+
+func (c *sqlQueryChecker) VisitStmt(stmt ast.Stmt) {
+ assign := astcast.ToAssignStmt(stmt)
+ if len(assign.Lhs) != 2 { // Query() has 2 return values.
+ return
+ }
+ if len(assign.Rhs) != 1 {
+ return
+ }
+
+ // If Query() is called, but first return value is ignored,
+ // there is no way to close/read the returned rows.
+ // This can cause a connection leak.
+ if id, ok := assign.Lhs[0].(*ast.Ident); ok && id.Name != "_" {
+ return
+ }
+
+ call := astcast.ToCallExpr(assign.Rhs[0])
+ funcExpr := astcast.ToSelectorExpr(call.Fun)
+ if !c.funcIsQuery(funcExpr) {
+ return
+ }
+
+ if c.typeHasExecMethod(c.ctx.TypesInfo.TypeOf(funcExpr.X)) {
+ c.warnAndSuggestExec(funcExpr)
+ } else {
+ c.warnRowsIgnored(funcExpr)
+ }
+}
+
+func (c *sqlQueryChecker) funcIsQuery(funcExpr *ast.SelectorExpr) bool {
+ if funcExpr.Sel == nil {
+ return false
+ }
+ switch funcExpr.Sel.Name {
+ case "Query", "QueryContext":
+ // Stdlib and friends.
+ case "Queryx", "QueryxContext":
+ // sqlx.
+ default:
+ return false
+ }
+
+ // To avoid false positives (unrelated types can have Query method)
+ // check that the 1st returned type has Row-like name.
+ typ, ok := c.ctx.TypesInfo.TypeOf(funcExpr).Underlying().(*types.Signature)
+ if !ok || typ.Results() == nil || typ.Results().Len() != 2 {
+ return false
+ }
+ if !c.typeIsRowsLike(typ.Results().At(0).Type()) {
+ return false
+ }
+
+ return true
+}
+
+func (c *sqlQueryChecker) typeIsRowsLike(typ types.Type) bool {
+ switch typ := typ.(type) {
+ case *types.Pointer:
+ return c.typeIsRowsLike(typ.Elem())
+ case *types.Named:
+ return typ.Obj().Name() == "Rows"
+ default:
+ return false
+ }
+}
+
+func (c *sqlQueryChecker) funcIsExec(fn *types.Func) bool {
+ if fn.Name() != "Exec" {
+ return false
+ }
+
+ // Expect exactly 2 results.
+ sig := fn.Type().(*types.Signature)
+ if sig.Results() == nil || sig.Results().Len() != 2 {
+ return false
+ }
+
+ // Expect at least 1 param and it should be a string (query).
+ params := sig.Params()
+ if params == nil || params.Len() == 0 {
+ return false
+ }
+ if typ, ok := params.At(0).Type().(*types.Basic); !ok || typ.Kind() != types.String {
+ return false
+ }
+
+ return true
+}
+
+func (c *sqlQueryChecker) typeHasExecMethod(typ types.Type) bool {
+ switch typ := typ.(type) {
+ case *types.Struct:
+ for i := 0; i < typ.NumFields(); i++ {
+ if c.typeHasExecMethod(typ.Field(i).Type()) {
+ return true
+ }
+ }
+ case *types.Interface:
+ for i := 0; i < typ.NumMethods(); i++ {
+ if c.funcIsExec(typ.Method(i)) {
+ return true
+ }
+ }
+ case *types.Pointer:
+ return c.typeHasExecMethod(typ.Elem())
+ case *types.Named:
+ for i := 0; i < typ.NumMethods(); i++ {
+ if c.funcIsExec(typ.Method(i)) {
+ return true
+ }
+ }
+ switch ut := typ.Underlying().(type) {
+ case *types.Interface:
+ return c.typeHasExecMethod(ut)
+ case *types.Struct:
+ // Check embedded types.
+ for i := 0; i < ut.NumFields(); i++ {
+ field := ut.Field(i)
+ if !field.Embedded() {
+ continue
+ }
+ if c.typeHasExecMethod(field.Type()) {
+ return true
+ }
+ }
+ }
+ }
+
+ return false
+}
+
+func (c *sqlQueryChecker) warnAndSuggestExec(funcExpr *ast.SelectorExpr) {
+ c.ctx.Warn(funcExpr, "use %s.Exec() if returned result is not needed", funcExpr.X)
+}
+
+func (c *sqlQueryChecker) warnRowsIgnored(funcExpr *ast.SelectorExpr) {
+ c.ctx.Warn(funcExpr, "ignoring Query() rows result may lead to a connection leak")
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go b/vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
index 74570108e..57e4084f6 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
@@ -3,27 +3,27 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"style"}
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/vendor/github.com/go-critic/go-critic/checkers/switchTrue_checker.go b/vendor/github.com/go-critic/go-critic/checkers/switchTrue_checker.go
index 3b2766276..5390360c5 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/switchTrue_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/switchTrue_checker.go
@@ -3,12 +3,12 @@ package checkers
import (
"go/ast"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/truncateCmp_checker.go b/vendor/github.com/go-critic/go-critic/checkers/truncateCmp_checker.go
index f4cb9e866..a5b7bdd32 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/truncateCmp_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/truncateCmp_checker.go
@@ -5,17 +5,17 @@ import (
"go/token"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go b/vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
index c0c42e351..2940e57f9 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
@@ -4,16 +4,16 @@ import (
"go/ast"
"go/token"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/typeSwitchVar_checker.go b/vendor/github.com/go-critic/go-critic/checkers/typeSwitchVar_checker.go
index a113597b6..2ade4a954 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/typeSwitchVar_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/typeSwitchVar_checker.go
@@ -3,15 +3,15 @@ package checkers
import (
"go/ast"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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,18 +34,20 @@ 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
}
func (c *typeSwitchVarChecker) VisitStmt(stmt ast.Stmt) {
if stmt, ok := stmt.(*ast.TypeSwitchStmt); ok {
+ c.count = 0
c.checkTypeSwitch(stmt)
}
}
@@ -61,7 +63,7 @@ func (c *typeSwitchVarChecker) checkTypeSwitch(root *ast.TypeSwitchStmt) {
return // Give up: can't handle shadowing without object
}
- for i, clause := range root.Body.List {
+ for _, clause := range root.Body.List {
clause := clause.(*ast.CaseClause)
// Multiple types in a list mean that assert.X will have
// a type of interface{} inside clause body.
@@ -76,13 +78,20 @@ func (c *typeSwitchVarChecker) checkTypeSwitch(root *ast.TypeSwitchStmt) {
return astequal.Node(&assert1, x)
})
if object == c.ctx.TypesInfo.ObjectOf(identOf(assert2)) {
- c.warn(root, i)
+ c.count++
break
}
}
}
+ if c.count > 0 {
+ c.warn(root)
+ }
}
-func (c *typeSwitchVarChecker) warn(n ast.Node, caseIndex int) {
- c.ctx.Warn(n, "case %d can benefit from type switch with assignment", caseIndex)
+func (c *typeSwitchVarChecker) warn(n ast.Node) {
+ msg := "case"
+ if c.count > 1 {
+ msg = "cases"
+ }
+ c.ctx.Warn(n, "%d "+msg+" can benefit from type switch with assignment", c.count)
}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/typeUnparen_checker.go b/vendor/github.com/go-critic/go-critic/checkers/typeUnparen_checker.go
index a17c77b49..620d2d797 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/typeUnparen_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/typeUnparen_checker.go
@@ -3,30 +3,30 @@ package checkers
import (
"go/ast"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go b/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
index dfc6077bb..561270c7c 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
@@ -4,17 +4,17 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/unlabelStmt_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unlabelStmt_checker.go
index d90c65c2c..83c5b1484 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unlabelStmt_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unlabelStmt_checker.go
@@ -4,13 +4,13 @@ import (
"go/ast"
"go/token"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
index 9e01299bf..946227c2f 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
@@ -4,28 +4,28 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go
index 09423250a..f053842ec 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go
@@ -4,15 +4,15 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/unnecessaryBlock_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unnecessaryBlock_checker.go
index e5dc45f7e..acc9fadbf 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unnecessaryBlock_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unnecessaryBlock_checker.go
@@ -4,12 +4,12 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go
new file mode 100644
index 000000000..ee706e099
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go
@@ -0,0 +1,111 @@
+package checkers
+
+import (
+ "go/ast"
+
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
+ "github.com/go-critic/go-critic/framework/linter"
+ "github.com/go-toolsmith/astfmt"
+)
+
+func init() {
+ var info linter.CheckerInfo
+ info.Name = "unnecessaryDefer"
+ info.Tags = []string{"diagnostic", "experimental"}
+ info.Summary = "Detects redundantly deferred calls"
+ info.Before = `
+func() {
+ defer os.Remove(filename)
+}`
+ info.After = `
+func() {
+ os.Remove(filename)
+}`
+
+ collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker {
+ return astwalk.WalkerForFuncDecl(&unnecessaryDeferChecker{ctx: ctx})
+ })
+}
+
+type unnecessaryDeferChecker struct {
+ astwalk.WalkHandler
+ ctx *linter.CheckerContext
+ isFunc bool
+}
+
+// Visit implements the ast.Visitor. This visitor keeps track of the block
+// statement belongs to a function or any other block. If the block is not a
+// function and ends with a defer statement that should be OK since it's
+// defering the outer function.
+func (c *unnecessaryDeferChecker) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.FuncDecl, *ast.FuncLit:
+ c.isFunc = true
+ case *ast.BlockStmt:
+ c.checkDeferBeforeReturn(n)
+ default:
+ c.isFunc = false
+ }
+
+ return c
+}
+
+func (c *unnecessaryDeferChecker) VisitFuncDecl(funcDecl *ast.FuncDecl) {
+ // We always start as a function (*ast.FuncDecl.Body passed)
+ c.isFunc = true
+
+ ast.Walk(c, funcDecl.Body)
+}
+
+func (c *unnecessaryDeferChecker) checkDeferBeforeReturn(funcDecl *ast.BlockStmt) {
+ // Check if we have an explicit return or if it's just the end of the scope.
+ explicitReturn := false
+ retIndex := len(funcDecl.List)
+ for i, stmt := range funcDecl.List {
+ retStmt, ok := stmt.(*ast.ReturnStmt)
+ if !ok {
+ continue
+ }
+ explicitReturn = true
+ if !c.isTrivialReturn(retStmt) {
+ continue
+ }
+ retIndex = i
+ break
+ }
+ if retIndex == 0 {
+ return
+ }
+
+ if deferStmt, ok := funcDecl.List[retIndex-1].(*ast.DeferStmt); ok {
+ // If the block is a function and ending with return or if we have an
+ // explicit return in any other block we should warn about
+ // unnecessary defer.
+ if c.isFunc || explicitReturn {
+ c.warn(deferStmt)
+ }
+ }
+}
+
+func (c *unnecessaryDeferChecker) isTrivialReturn(ret *ast.ReturnStmt) bool {
+ for _, e := range ret.Results {
+ if !c.isConstExpr(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (c *unnecessaryDeferChecker) isConstExpr(e ast.Expr) bool {
+ return c.ctx.TypesInfo.Types[e].Value != nil
+}
+
+func (c *unnecessaryDeferChecker) warn(deferStmt *ast.DeferStmt) {
+ s := astfmt.Sprint(deferStmt)
+ if fnlit, ok := deferStmt.Call.Fun.(*ast.FuncLit); ok {
+ // To avoid long and multi-line warning messages,
+ // collapse the function literals.
+ s = "defer " + astfmt.Sprint(fnlit.Type) + "{...}(...)"
+ }
+ c.ctx.Warn(deferStmt, "%s is placed just before return", s)
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/unslice_checker.go b/vendor/github.com/go-critic/go-critic/checkers/unslice_checker.go
index 06d90819c..73f67bc8e 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unslice_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unslice_checker.go
@@ -4,13 +4,13 @@ import (
"go/ast"
"go/types"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/utils.go b/vendor/github.com/go-critic/go-critic/checkers/utils.go
index ba4777dbd..b71f24d74 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/utils.go
+++ b/vendor/github.com/go-critic/go-critic/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/vendor/github.com/go-critic/go-critic/checkers/valSwap_checker.go b/vendor/github.com/go-critic/go-critic/checkers/valSwap_checker.go
index ab27f9200..4dd494ecf 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/valSwap_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/valSwap_checker.go
@@ -4,16 +4,16 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"style"}
info.Summary = "Detects value swapping code that are not using parallel assignment"
info.Before = `
tmp := *x
@@ -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/vendor/github.com/go-critic/go-critic/checkers/weakCond_checker.go b/vendor/github.com/go-critic/go-critic/checkers/weakCond_checker.go
index fcd9aee52..1d6ee58ef 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/weakCond_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/weakCond_checker.go
@@ -4,9 +4,9 @@ import (
"go/ast"
"go/token"
+ "github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/whyNoLint_checker.go b/vendor/github.com/go-critic/go-critic/checkers/whyNoLint_checker.go
index 52fefb82c..cc5c5172e 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/whyNoLint_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/whyNoLint_checker.go
@@ -5,12 +5,12 @@ import (
"regexp"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/checkers/wrapperFunc_checker.go b/vendor/github.com/go-critic/go-critic/checkers/wrapperFunc_checker.go
index bba82e5ee..bc543e648 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/wrapperFunc_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/wrapperFunc_checker.go
@@ -6,20 +6,20 @@ import (
"go/types"
"strings"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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.Tags = []string{"style"}
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
@@ -81,6 +81,11 @@ func init() {
"bytes.Map => bytes.ToTitle": {
{0, "unicode.ToTitle"},
},
+
+ "draw.DrawMask => draw.Draw": {
+ {4, "nil"},
+ {5, "image.Point{}"},
+ },
}
matchers := make(map[string]*matcher)
@@ -203,7 +208,7 @@ func init() {
type wrapperFuncChecker struct {
astwalk.WalkHandler
- ctx *lintpack.CheckerContext
+ ctx *linter.CheckerContext
findSuggestion func(*ast.CallExpr) string
}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/yodaStyleExpr_checker.go b/vendor/github.com/go-critic/go-critic/checkers/yodaStyleExpr_checker.go
index ddd3099fd..b4672fcca 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/yodaStyleExpr_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/yodaStyleExpr_checker.go
@@ -4,28 +4,28 @@ import (
"go/ast"
"go/token"
- "github.com/go-lintpack/lintpack"
- "github.com/go-lintpack/lintpack/astwalk"
+ "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/vendor/github.com/go-critic/go-critic/framework/linter/checkers_db.go b/vendor/github.com/go-critic/go-critic/framework/linter/checkers_db.go
new file mode 100644
index 000000000..b4bebe443
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/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/vendor/github.com/go-critic/go-critic/framework/linter/context.go b/vendor/github.com/go-critic/go-critic/framework/linter/context.go
new file mode 100644
index 000000000..6e108ab6a
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/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/vendor/github.com/go-critic/go-critic/framework/linter/lintpack.go b/vendor/github.com/go-critic/go-critic/framework/linter/lintpack.go
new file mode 100644
index 000000000..1f984d146
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/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)
+}