From fcc6d71be2c3ce7d9305c04fc2e87af554571bac Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 22 Feb 2021 20:37:25 +0100 Subject: go.mod: update golangci-lint to v1.37 --- .../go-critic/checkers/appendAssign_checker.go | 6 +- .../go-critic/checkers/appendCombine_checker.go | 4 +- .../go-critic/checkers/argOrder_checker.go | 17 ++- .../go-critic/checkers/assignOp_checker.go | 4 +- .../go-critic/checkers/badCall_checker.go | 4 +- .../go-critic/checkers/badCond_checker.go | 8 +- .../go-critic/checkers/badLock_checker.go | 116 +++++++++++++++++++++ .../go-critic/checkers/badRegexp_checker.go | 4 +- .../go-critic/checkers/boolExprSimplify_checker.go | 18 ++-- .../checkers/builtinShadowDecl_checker.go | 63 +++++++++++ .../go-critic/checkers/builtinShadow_checker.go | 6 +- .../go-critic/checkers/captLocal_checker.go | 4 +- .../go-critic/checkers/caseOrder_checker.go | 14 +-- .../go-critic/checkers/codegenComment_checker.go | 6 +- .../checkers/commentFormatting_checker.go | 6 +- .../go-critic/checkers/commentedOutCode_checker.go | 4 +- .../checkers/commentedOutImport_checker.go | 6 +- .../go-critic/checkers/defaultCaseOrder_checker.go | 4 +- .../go-critic/checkers/deferUnlambda_checker.go | 4 +- .../checkers/deprecatedComment_checker.go | 4 +- .../go-critic/checkers/docStub_checker.go | 4 +- .../go-critic/go-critic/checkers/dupArg_checker.go | 4 +- .../go-critic/checkers/dupBranchBody_checker.go | 4 +- .../go-critic/checkers/dupCase_checker.go | 4 +- .../go-critic/checkers/dupImports_checker.go | 4 +- .../go-critic/checkers/dupSubExpr_checker.go | 6 +- .../go-critic/go-critic/checkers/elseif_checker.go | 4 +- .../go-critic/checkers/emptyFallthrough_checker.go | 4 +- .../go-critic/checkers/emptyStringTest_checker.go | 6 +- .../go-critic/checkers/equalFold_checker.go | 4 +- .../go-critic/checkers/evalOrder_checker.go | 6 +- .../go-critic/checkers/exitAfterDefer_checker.go | 16 ++- .../go-critic/checkers/filepathJoin_checker.go | 4 +- .../go-critic/checkers/flagDeref_checker.go | 4 +- .../go-critic/checkers/flagName_checker.go | 28 ++++- .../go-critic/checkers/hexLiteral_checker.go | 4 +- .../go-critic/checkers/hugeParam_checker.go | 6 +- .../go-critic/checkers/ifElseChain_checker.go | 4 +- .../go-critic/checkers/importShadow_checker.go | 4 +- .../go-critic/checkers/indexAlloc_checker.go | 4 +- .../go-critic/checkers/initClause_checker.go | 4 +- .../checkers/internal/astwalk/expr_walker.go | 4 +- .../checkers/internal/astwalk/func_decl_walker.go | 4 +- .../checkers/internal/astwalk/local_expr_walker.go | 4 +- .../checkers/internal/astwalk/stmt_list_walker.go | 4 +- .../checkers/internal/astwalk/stmt_walker.go | 4 +- .../go-critic/go-critic/checkers/mapKey_checker.go | 6 +- .../go-critic/checkers/methodExprCall_checker.go | 4 +- .../go-critic/checkers/nestingReduce_checker.go | 4 +- .../go-critic/checkers/newDeref_checker.go | 6 +- .../go-critic/checkers/nilValReturn_checker.go | 4 +- .../go-critic/checkers/octalLiteral_checker.go | 4 +- .../go-critic/go-critic/checkers/offBy1_checker.go | 10 +- .../go-critic/checkers/paramTypeCombine_checker.go | 4 +- .../go-critic/checkers/ptrToRefParam_checker.go | 6 +- .../go-critic/checkers/rangeExprCopy_checker.go | 4 +- .../go-critic/checkers/rangeValCopy_checker.go | 6 +- .../go-critic/checkers/regexpMust_checker.go | 4 +- .../go-critic/checkers/regexpPattern_checker.go | 4 +- .../go-critic/checkers/regexpSimplify_checker.go | 4 +- .../go-critic/checkers/ruleguard_checker.go | 91 ++++++++++++---- .../go-critic/checkers/singleCaseSwitch_checker.go | 4 +- .../go-critic/checkers/sloppyLen_checker.go | 4 +- .../go-critic/checkers/sloppyReassign_checker.go | 10 +- .../go-critic/checkers/sloppyTypeAssert_checker.go | 8 +- .../go-critic/checkers/sortSlice_checker.go | 6 +- .../go-critic/checkers/sqlQuery_checker.go | 8 +- .../go-critic/checkers/stringXbytes_checker.go | 8 +- .../go-critic/checkers/switchTrue_checker.go | 4 +- .../go-critic/checkers/truncateCmp_checker.go | 8 +- .../go-critic/checkers/typeAssertChain_checker.go | 4 +- .../go-critic/checkers/typeDefFirst_checker.go | 88 ++++++++++++++++ .../go-critic/checkers/typeSwitchVar_checker.go | 4 +- .../go-critic/checkers/typeUnparen_checker.go | 4 +- .../go-critic/checkers/underef_checker.go | 10 +- .../go-critic/checkers/unlabelStmt_checker.go | 6 +- .../go-critic/checkers/unlambda_checker.go | 37 +++++-- .../go-critic/checkers/unnamedResult_checker.go | 6 +- .../go-critic/checkers/unnecessaryBlock_checker.go | 4 +- .../go-critic/checkers/unnecessaryDefer_checker.go | 4 +- .../go-critic/checkers/unslice_checker.go | 6 +- .../go-critic/checkers/valSwap_checker.go | 4 +- .../go-critic/checkers/weakCond_checker.go | 6 +- .../go-critic/checkers/whyNoLint_checker.go | 6 +- .../go-critic/checkers/wrapperFunc_checker.go | 6 +- .../go-critic/checkers/yodaStyleExpr_checker.go | 4 +- .../go-critic/framework/linter/checkers_db.go | 15 +-- .../go-critic/framework/linter/lintpack.go | 28 ++++- 88 files changed, 654 insertions(+), 259 deletions(-) create mode 100644 vendor/github.com/go-critic/go-critic/checkers/badLock_checker.go create mode 100644 vendor/github.com/go-critic/go-critic/checkers/builtinShadowDecl_checker.go create mode 100644 vendor/github.com/go-critic/go-critic/checkers/typeDefFirst_checker.go (limited to 'vendor/github.com/go-critic') 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 d26921770..42fa97a54 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 @@ -24,8 +24,8 @@ p.negatives = append(p.negatives, y)` p.positives = append(p.positives, x) p.negatives = append(p.negatives, y)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&appendAssignChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&appendAssignChecker{ctx: ctx}), nil }) } @@ -81,7 +81,7 @@ func (c *appendAssignChecker) checkAppend(x ast.Expr, call *ast.CallExpr) { switch y := call.Args[0].(type) { case *ast.SliceExpr: - if _, ok := c.ctx.TypesInfo.TypeOf(y.X).(*types.Array); ok { + if _, ok := c.ctx.TypeOf(y.X).(*types.Array); ok { // Arrays are frequently used as scratch storages. return } 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 a761f2a8f..03662fc21 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 @@ -20,8 +20,8 @@ xs = append(xs, 1) xs = append(xs, 2)` info.After = `xs = append(xs, 1, 2)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmtList(&appendCombineChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmtList(&appendCombineChecker{ctx: ctx}), nil }) } 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 2eb7cf7d8..98cabc54f 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 @@ -20,8 +20,8 @@ func init() { info.Before = `strings.HasPrefix("#", userpass)` info.After = `strings.HasPrefix(userpass, "#")` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&argOrderChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&argOrderChecker{ctx: ctx}), nil }) } @@ -34,7 +34,7 @@ func (c *argOrderChecker) VisitExpr(expr ast.Expr) { call := astcast.ToCallExpr(expr) // For now only handle functions of 2 args. - // TODO(Quasilyte): generalize the algorithm and add more patterns. + // TODO(quasilyte): generalize the algorithm and add more patterns. if len(call.Args) != 2 { return } @@ -59,23 +59,22 @@ func (c *argOrderChecker) VisitExpr(expr ast.Expr) { } func (c *argOrderChecker) isConstLiteral(x ast.Expr) bool { - if c.ctx.TypesInfo.Types[x].Value != nil { - return true - } - // Also permit byte slices. switch x := x.(type) { + case *ast.BasicLit: + return true + case *ast.CallExpr: // Handle `[]byte("abc")` as well. if len(x.Args) != 1 || !astp.IsBasicLit(x.Args[0]) { return false } - typ, ok := c.ctx.TypesInfo.TypeOf(x.Fun).(*types.Slice) + typ, ok := c.ctx.TypeOf(x.Fun).(*types.Slice) return ok && typep.HasUint8Kind(typ.Elem()) case *ast.CompositeLit: // Check if it's a const byte slice. - typ, ok := c.ctx.TypesInfo.TypeOf(x).(*types.Slice) + typ, ok := c.ctx.TypeOf(x).(*types.Slice) if !ok || !typep.HasUint8Kind(typ.Elem()) { return false } 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 e3acd09ef..d0bf64417 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 @@ -19,8 +19,8 @@ func init() { info.Before = `x = x * 2` info.After = `x *= 2` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&assignOpChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&assignOpChecker{ctx: ctx}), nil }) } 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 3e96a39cb..7435ee57b 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 @@ -17,8 +17,8 @@ func init() { info.Before = `strings.Replace(s, from, to, 0)` info.After = `strings.Replace(s, from, to, -1)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&badCallChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&badCallChecker{ctx: ctx}), nil }) } 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 6ce81f358..149f0ac88 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 @@ -29,8 +29,8 @@ for i := 0; i < n; i++ { xs[i] = 0 }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForFuncDecl(&badCondChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForFuncDecl(&badCondChecker{ctx: ctx}), nil }) } @@ -52,7 +52,7 @@ func (c *badCondChecker) VisitFuncDecl(decl *ast.FuncDecl) { } func (c *badCondChecker) checkExpr(expr ast.Expr) { - // TODO(Quasilyte): recognize more patterns. + // TODO(quasilyte): recognize more patterns. cond := astcast.ToBinaryExpr(expr) lhs := astcast.ToBinaryExpr(astutil.Unparen(cond.X)) @@ -102,7 +102,7 @@ func (c *badCondChecker) lessAndGreater(lhs, rhs *ast.BinaryExpr) bool { } func (c *badCondChecker) checkForStmt(stmt *ast.ForStmt) { - // TODO(Quasilyte): handle other kinds of bad conditionals. + // TODO(quasilyte): handle other kinds of bad conditionals. init := astcast.ToAssignStmt(stmt.Init) if init.Tok != token.DEFINE || len(init.Lhs) != 1 || len(init.Rhs) != 1 { diff --git a/vendor/github.com/go-critic/go-critic/checkers/badLock_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badLock_checker.go new file mode 100644 index 000000000..8628ff2d7 --- /dev/null +++ b/vendor/github.com/go-critic/go-critic/checkers/badLock_checker.go @@ -0,0 +1,116 @@ +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/astequal" +) + +func init() { + var info linter.CheckerInfo + info.Name = "badLock" + info.Tags = []string{"diagnostic", "experimental"} + info.Summary = "Detects suspicious mutex lock/unlock operations" + info.Before = ` +mu.Lock() +mu.Unlock()` + info.After = ` +mu.Lock() +defer mu.Unlock()` + + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmtList(&badLockChecker{ctx: ctx}), nil + }) +} + +type badLockChecker struct { + astwalk.WalkHandler + ctx *linter.CheckerContext +} + +func (c *badLockChecker) VisitStmtList(list []ast.Stmt) { + if len(list) < 2 { + return + } + + for i := 0; i < len(list)-1; i++ { + current, ok := list[i].(*ast.ExprStmt) + if !ok { + continue + } + deferred := false + var next ast.Expr + switch x := list[i+1].(type) { + case *ast.ExprStmt: + next = x.X + case *ast.DeferStmt: + next = x.Call + deferred = true + default: + continue + } + + mutex1, lockFunc, ok := c.asLockedMutex(current.X) + if !ok { + continue + } + mutex2, unlockFunc, ok := c.asUnlockedMutex(next) + if !ok { + continue + } + if !astequal.Expr(mutex1, mutex2) { + continue + } + + switch { + case !deferred: + c.warnImmediateUnlock(mutex2) + case lockFunc == "Lock" && unlockFunc == "RUnlock": + c.warnMismatchingUnlock(mutex2, "Unlock") + case lockFunc == "RLock" && unlockFunc == "Unlock": + c.warnMismatchingUnlock(mutex2, "RUnlock") + } + } +} + +func (c *badLockChecker) asLockedMutex(e ast.Expr) (ast.Expr, string, bool) { + call, ok := e.(*ast.CallExpr) + if !ok || len(call.Args) != 0 { + return nil, "", false + } + switch fn := call.Fun.(type) { + case *ast.SelectorExpr: + if fn.Sel.Name == "Lock" || fn.Sel.Name == "RLock" { + return fn.X, fn.Sel.Name, true + } + return nil, "", false + default: + return nil, "", false + } +} + +func (c *badLockChecker) asUnlockedMutex(e ast.Expr) (ast.Expr, string, bool) { + call, ok := e.(*ast.CallExpr) + if !ok || len(call.Args) != 0 { + return nil, "", false + } + switch fn := call.Fun.(type) { + case *ast.SelectorExpr: + if fn.Sel.Name == "Unlock" || fn.Sel.Name == "RUnlock" { + return fn.X, fn.Sel.Name, true + } + return nil, "", false + default: + return nil, "", false + } +} + +func (c *badLockChecker) warnImmediateUnlock(cause ast.Node) { + c.ctx.Warn(cause, "defer is missing, mutex is unlocked immediately") +} + +func (c *badLockChecker) warnMismatchingUnlock(cause ast.Node, suggestion string) { + c.ctx.Warn(cause, "suspicious unlock, maybe %s was intended?", suggestion) +} 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 index 1025454df..e0d4b7487 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go @@ -21,13 +21,13 @@ func init() { 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 { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { opts := &syntax.ParserOptions{} c := &badRegexpChecker{ ctx: ctx, parser: syntax.NewParser(opts), } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 8c599031d..325fb56a3 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 @@ -29,8 +29,8 @@ b := !(x) == !(y)` a := elapsed < expectElapsedMin b := (x) == (y)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&boolExprSimplifyChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&boolExprSimplifyChecker{ctx: ctx}), nil }) } @@ -47,7 +47,7 @@ func (c *boolExprSimplifyChecker) VisitExpr(x ast.Expr) { // Throw away non-bool expressions and avoid redundant // AST copying below. - if typ := c.ctx.TypesInfo.TypeOf(x); typ == nil || !typep.HasBoolKind(typ.Underlying()) { + if typ := c.ctx.TypeOf(x); typ == nil || !typep.HasBoolKind(typ.Underlying()) { return } @@ -55,8 +55,8 @@ func (c *boolExprSimplifyChecker) VisitExpr(x ast.Expr) { // this is why we record valuable info before doing it. c.hasFloats = lintutil.ContainsNode(x, func(n ast.Node) bool { if x, ok := n.(*ast.BinaryExpr); ok { - return typep.HasFloatProp(c.ctx.TypesInfo.TypeOf(x.X).Underlying()) || - typep.HasFloatProp(c.ctx.TypesInfo.TypeOf(x.Y).Underlying()) + return typep.HasFloatProp(c.ctx.TypeOf(x.X).Underlying()) || + typep.HasFloatProp(c.ctx.TypeOf(x.Y).Underlying()) } return false }) @@ -289,7 +289,8 @@ func (c *boolExprSimplifyChecker) foldRanges(cur *astutil.Cursor) bool { // `x >= c && x <= c` => `x == c` {token.GEQ, token.LEQ, 0, 0}, } - for _, comb := range combTable { + for i := range combTable { + comb := combTable[i] if match(&comb) { lhs.Op = token.EQL v := c1 + comb.resDelta @@ -310,7 +311,8 @@ func (c *boolExprSimplifyChecker) foldRanges(cur *astutil.Cursor) bool { // `x <= c || x >= c+2` => `x != c+1` {token.LEQ, token.GEQ, 2, 1}, } - for _, comb := range combTable { + for i := range combTable { + comb := combTable[i] if match(&comb) { lhs.Op = token.NEQ v := c1 + comb.resDelta @@ -325,7 +327,7 @@ func (c *boolExprSimplifyChecker) foldRanges(cur *astutil.Cursor) bool { } func (c *boolExprSimplifyChecker) int64val(x ast.Expr) (int64, bool) { - // TODO(Quasilyte): if we had types info, we could use TypesInfo.Types[x].Value, + // TODO(quasilyte): if we had types info, we could use TypesInfo.Types[x].Value, // but since copying erases leaves us without it, only basic literals are handled. lit, ok := x.(*ast.BasicLit) if !ok { diff --git a/vendor/github.com/go-critic/go-critic/checkers/builtinShadowDecl_checker.go b/vendor/github.com/go-critic/go-critic/checkers/builtinShadowDecl_checker.go new file mode 100644 index 000000000..94d51a996 --- /dev/null +++ b/vendor/github.com/go-critic/go-critic/checkers/builtinShadowDecl_checker.go @@ -0,0 +1,63 @@ +package checkers + +import ( + "go/ast" + + "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" +) + +func init() { + var info linter.CheckerInfo + info.Name = "builtinShadowDecl" + info.Tags = []string{"diagnostic", "experimental"} + info.Summary = "Detects top-level declarations that shadow the predeclared identifiers" + info.Before = `type int struct {}` + info.After = `type myInt struct {}` + + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return &builtinShadowDeclChecker{ctx: ctx}, nil + }) +} + +type builtinShadowDeclChecker struct { + astwalk.WalkHandler + ctx *linter.CheckerContext +} + +func (c *builtinShadowDeclChecker) WalkFile(f *ast.File) { + for _, decl := range f.Decls { + switch decl := decl.(type) { + case *ast.FuncDecl: + // Don't check methods. They can shadow anything safely. + if decl.Recv == nil { + c.checkName(decl.Name) + } + case *ast.GenDecl: + c.visitGenDecl(decl) + } + } +} + +func (c *builtinShadowDeclChecker) visitGenDecl(decl *ast.GenDecl) { + for _, spec := range decl.Specs { + switch spec := spec.(type) { + case *ast.ValueSpec: + for _, name := range spec.Names { + c.checkName(name) + } + case *ast.TypeSpec: + c.checkName(spec.Name) + } + } +} + +func (c *builtinShadowDeclChecker) checkName(name *ast.Ident) { + if isBuiltin(name.Name) { + c.warn(name) + } +} + +func (c *builtinShadowDeclChecker) warn(ident *ast.Ident) { + c.ctx.Warn(ident, "shadowing of predeclared identifier: %s", ident) +} 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 ff5e51746..1e1661deb 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 @@ -11,12 +11,12 @@ func init() { var info linter.CheckerInfo info.Name = "builtinShadow" info.Tags = []string{"style", "opinionated"} - info.Summary = "Detects when predeclared identifiers shadowed in assignments" + info.Summary = "Detects when predeclared identifiers are shadowed in assignments" info.Before = `len := 10` info.After = `length := 10` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForLocalDef(&builtinShadowChecker{ctx: ctx}, ctx.TypesInfo) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForLocalDef(&builtinShadowChecker{ctx: ctx}, ctx.TypesInfo), nil }) } 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 76b6fb4fc..d9b4b7e75 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 @@ -21,10 +21,10 @@ 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 *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &captLocalChecker{ctx: ctx} c.paramsOnly = info.Params.Bool("paramsOnly") - return astwalk.WalkerForLocalDef(c, ctx.TypesInfo) + return astwalk.WalkerForLocalDef(c, ctx.TypesInfo), nil }) } 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 950367520..047ea4fee 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 @@ -28,8 +28,8 @@ case ast.Expr: fmt.Println("expr") }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&caseOrderChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&caseOrderChecker{ctx: ctx}), nil }) } @@ -56,9 +56,9 @@ func (c *caseOrderChecker) checkTypeSwitch(s *ast.TypeSwitchStmt) { for _, cc := range s.Body.List { cc := cc.(*ast.CaseClause) for _, x := range cc.List { - typ := c.ctx.TypesInfo.TypeOf(x) - if typ == nil { - c.warnTypeImpl(cc, x) + typ := c.ctx.TypeOf(x) + if typ == linter.UnknownType { + c.warnUnknownType(cc, x) return } for _, iface := range ifaces { @@ -78,11 +78,11 @@ func (c *caseOrderChecker) warnTypeSwitch(cause, concrete, iface ast.Node) { c.ctx.Warn(cause, "case %s must go before the %s case", concrete, iface) } -func (c *caseOrderChecker) warnTypeImpl(cause, concrete ast.Node) { +func (c *caseOrderChecker) warnUnknownType(cause, concrete ast.Node) { c.ctx.Warn(cause, "type is not defined %s", concrete) } func (c *caseOrderChecker) checkSwitch(s *ast.SwitchStmt) { - // TODO(Quasilyte): can handle expression cases that overlap. + // TODO(quasilyte): can handle expression cases that overlap. // Cases that have narrower value range should go before wider ones. } 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 ecadba10e..52a72d28c 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 @@ -17,7 +17,7 @@ func init() { info.Before = `// This file was automatically generated by foogen` info.After = `// Code generated by foogen. DO NOT EDIT.` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { patterns := []string{ "this (?:file|code) (?:was|is) auto(?:matically)? generated", "this (?:file|code) (?:was|is) generated automatically", @@ -26,13 +26,13 @@ func init() { "this (?:file|code) (?:was|is) generated", "code in this file (?:was|is) auto(?:matically)? generated", "generated (?:file|code) - do not edit", - // TODO(Quasilyte): more of these. + // TODO(quasilyte): more of these. } re := regexp.MustCompile("(?i)" + strings.Join(patterns, "|")) return &codegenCommentChecker{ ctx: ctx, badCommentRE: re, - } + }, nil }) } 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 de7bfc198..83b6d506e 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 @@ -19,11 +19,11 @@ func init() { info.Before = `//This is a comment` info.After = `// This is a comment` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { parts := []string{ `^//go:generate .*$`, // e.g.: go:generate value `^//\w+:.*$`, // e.g.: key: value - `^//nolint$`, // e.g.: nolint + `^//nolint\b`, // e.g.: nolint `^//line /.*:\d+`, // e.g.: line /path/to/file:123 `^//export \w+$`, // e.g.: export Foo } @@ -32,7 +32,7 @@ func init() { return astwalk.WalkerForComment(&commentFormattingChecker{ ctx: ctx, pragmaRE: pragmaRE, - }) + }), nil }) } 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 8d9387045..554e0621f 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 @@ -22,11 +22,11 @@ func init() { foo(1, 2)` info.After = `foo(1, 2)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { return astwalk.WalkerForLocalComment(&commentedOutCodeChecker{ ctx: ctx, notQuiteFuncCall: regexp.MustCompile(`\w+\s+\([^)]*\)\s*$`), - }) + }), nil }) } 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 096a90241..3c086569b 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 @@ -24,12 +24,12 @@ import ( "fmt" )` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { const pattern = `(?m)^(?://|/\*)?\s*"([a-zA-Z0-9_/]+)"\s*(?:\*/)?$` return &commentedOutImportChecker{ ctx: ctx, importStringRE: regexp.MustCompile(pattern), - } + }, nil }) } @@ -41,7 +41,7 @@ type commentedOutImportChecker struct { } func (c *commentedOutImportChecker) WalkFile(f *ast.File) { - // TODO(Quasilyte): handle commented-out import spec, + // TODO(quasilyte): handle commented-out import spec, // for example: // import "errors". for _, decl := range f.Decls { 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 755449e07..e06944d62 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 @@ -31,8 +31,8 @@ default: // <- last case (could also be the first one) // ... }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&defaultCaseOrderChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&defaultCaseOrderChecker{ctx: ctx}), nil }) } 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 index 3cab7827c..b312bfb68 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/deferUnlambda_checker.go @@ -17,8 +17,8 @@ func init() { info.Before = `defer func() { f() }()` info.After = `f()` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&deferUnlambdaChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&deferUnlambdaChecker{ctx: ctx}), nil }) } 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 82f300b37..f60e58b58 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 @@ -21,7 +21,7 @@ func FuncOld() int` // Deprecated: use FuncNew instead func FuncOld() int` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &deprecatedCommentChecker{ctx: ctx} c.commonPatterns = []*regexp.Regexp{ @@ -55,7 +55,7 @@ func FuncOld() int` c.commonTypos[i] = strings.ToUpper(c.commonTypos[i]) } - return astwalk.WalkerForDocComment(c) + return astwalk.WalkerForDocComment(c), nil }) } 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 2a3b393a0..d8aaaf743 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 @@ -26,13 +26,13 @@ func Foo() {} // Foo is a demonstration-only function. func Foo() {}` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { re := `(?i)^\.\.\.$|^\.$|^xxx\.?$|^whatever\.?$` c := &docStubChecker{ ctx: ctx, stubCommentRE: regexp.MustCompile(re), } - return c + return c, nil }) } 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 24e921b09..9f116d781 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 @@ -18,7 +18,7 @@ func init() { info.Before = `copy(dst, dst)` info.After = `copy(dst, src)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &dupArgChecker{ctx: ctx} // newMatcherFunc returns a function that matches a call if // args[xIndex] and args[yIndex] are equal. @@ -95,7 +95,7 @@ func init() { // TODO(quasilyte): more of these. } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 3399f0531..83de50528 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 @@ -26,8 +26,8 @@ if cond { println("cond=false") }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&dupBranchBodyChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&dupBranchBodyChecker{ctx: ctx}), nil }) } 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 89ec66bbf..0c1962682 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 @@ -22,8 +22,8 @@ switch x { case ys[0], ys[1], ys[2], ys[3], ys[4]: }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&dupCaseChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&dupCaseChecker{ctx: ctx}), nil }) } 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 27b796cdc..54658eb9f 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 @@ -22,8 +22,8 @@ import( "fmt" )` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return &dupImportChecker{ctx: ctx} + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return &dupImportChecker{ctx: ctx}, nil }) } 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 4966cd2a5..00f8fd0eb 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 @@ -25,7 +25,7 @@ sort.Slice(xs, func(i, j int) bool { return xs[i].v < xs[j].v })` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &dupSubExprChecker{ctx: ctx} ops := []struct { @@ -59,7 +59,7 @@ sort.Slice(xs, func(i, j int) bool { } } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } @@ -93,7 +93,7 @@ func (c *dupSubExprChecker) checkBinaryExpr(expr *ast.BinaryExpr) { } func (c *dupSubExprChecker) resultIsFloat(expr ast.Expr) bool { - typ, ok := c.ctx.TypesInfo.TypeOf(expr).(*types.Basic) + typ, ok := c.ctx.TypeOf(expr).(*types.Basic) return ok && typ.Info()&types.IsFloat != 0 } 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 9e56d1c40..d017ee6ca 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 @@ -30,10 +30,10 @@ if cond1 { } else if x := cond2; x { }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &elseifChecker{ctx: ctx} c.skipBalanced = info.Params.Bool("skipBalanced") - return astwalk.WalkerForStmt(c) + return astwalk.WalkerForStmt(c), nil }) } 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 16bfa7e45..2a995b758 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 @@ -24,8 +24,8 @@ case reflect.Int, reflect.Int32: return Int }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&emptyFallthroughChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&emptyFallthroughChecker{ctx: ctx}), nil }) } 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 20d647ffa..27ccbd2f2 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 @@ -20,8 +20,8 @@ func init() { info.After = `s == ""` info.Note = "See https://dmitri.shuralyov.com/idiomatic-go#empty-string-check." - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&emptyStringTestChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&emptyStringTestChecker{ctx: ctx}), nil }) } @@ -40,7 +40,7 @@ func (c *emptyStringTestChecker) VisitExpr(e ast.Expr) { return } s := lenCall.Args[0] - if !typep.HasStringProp(c.ctx.TypesInfo.TypeOf(s)) { + if !typep.HasStringProp(c.ctx.TypeOf(s)) { return } zero := astcast.ToBasicLit(cmp.Y) 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 b8dfdc02f..13f7fdbe2 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 @@ -18,8 +18,8 @@ func init() { info.Before = `strings.ToLower(x) == strings.ToLower(y)` info.After = `strings.EqualFold(x, y)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&equalFoldChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&equalFoldChecker{ctx: ctx}), nil }) } 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 0bec0e83a..6ba07fe86 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 @@ -24,8 +24,8 @@ err := f(&x) return x, err ` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&evalOrderChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&evalOrderChecker{ctx: ctx}), nil }) } @@ -75,7 +75,7 @@ func (c *evalOrderChecker) VisitStmt(stmt ast.Stmt) { } func (c *evalOrderChecker) hasPtrRecv(fn *ast.Ident) bool { - sig, ok := c.ctx.TypesInfo.TypeOf(fn).(*types.Signature) + sig, ok := c.ctx.TypeOf(fn).(*types.Signature) if !ok { return false } 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 65800fc54..63e0049f2 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 @@ -27,8 +27,8 @@ if bad { return }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForFuncDecl(&exitAfterDeferChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForFuncDecl(&exitAfterDeferChecker{ctx: ctx}), nil }) } @@ -38,7 +38,7 @@ type exitAfterDeferChecker struct { } func (c *exitAfterDeferChecker) VisitFuncDecl(fn *ast.FuncDecl) { - // TODO(Quasilyte): handle goto and other kinds of flow that break + // TODO(quasilyte): handle goto and other kinds of flow that break // the algorithm below that expects the latter statement to be // executed after the ones that come before it. @@ -52,6 +52,14 @@ func (c *exitAfterDeferChecker) VisitFuncDecl(fn *ast.FuncDecl) { case *ast.DeferStmt: deferStmt = n case *ast.CallExpr: + // See #995. We allow `defer os.Exit()` calls + // as it's harder to determine whether they're going + // to clutter anything without actually trying to + // simulate the defer stack + understanding the control flow. + // TODO: can we use CFG here? + if _, ok := cur.Parent().(*ast.DeferStmt); ok { + return true + } if deferStmt != nil { switch qualifiedName(n.Fun) { case "log.Fatal", "log.Fatalf", "log.Fatalln", "os.Exit": @@ -72,5 +80,5 @@ func (c *exitAfterDeferChecker) warn(cause *ast.CallExpr, deferStmt *ast.DeferSt // collapse the function literals. s = "defer " + astfmt.Sprint(fnlit.Type) + "{...}(...)" } - c.ctx.Warn(cause, "%s clutters `%s`", cause.Fun, s) + c.ctx.Warn(cause, "%s will exit, and `%s` will not run", 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 index b11dc2470..698f5366d 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/filepathJoin_checker.go @@ -17,8 +17,8 @@ func init() { 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}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&filepathJoinChecker{ctx: ctx}), nil }) } 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 393274c43..3fe5e52fb 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 @@ -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 *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &flagDerefChecker{ ctx: ctx, flagPtrFuncs: map[string]bool{ @@ -35,7 +35,7 @@ where flag values are not updated after flag.Parse().` "flag.Uint64": true, }, } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 36d2e4506..7f6ce3c01 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 @@ -15,12 +15,13 @@ func init() { var info linter.CheckerInfo info.Name = "flagName" info.Tags = []string{"diagnostic"} - info.Summary = "Detects flag names with whitespace" + info.Summary = "Detects suspicious flag names" info.Before = `b := flag.Bool(" foo ", false, "description")` info.After = `b := flag.Bool("foo", false, "description")` + info.Note = "https://github.com/golang/go/issues/41792" - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&flagNameChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&flagNameChecker{ctx: ctx}), nil }) } @@ -58,11 +59,30 @@ func (c *flagNameChecker) checkFlagName(call *ast.CallExpr, arg ast.Expr) { return // Non-constant name } name := constant.StringVal(cv) - if strings.Contains(name, " ") { + switch { + case name == "": + c.warnEmpty(call) + case strings.HasPrefix(name, "-"): + c.warnHypenPrefix(call, name) + case strings.Contains(name, "="): + c.warnEq(call, name) + case strings.Contains(name, " "): c.warnWhitespace(call, name) } } +func (c *flagNameChecker) warnEmpty(cause ast.Node) { + c.ctx.Warn(cause, "empty flag name") +} + +func (c *flagNameChecker) warnHypenPrefix(cause ast.Node, name string) { + c.ctx.Warn(cause, "flag name %q should not start with a hypen", name) +} + +func (c *flagNameChecker) warnEq(cause ast.Node, name string) { + c.ctx.Warn(cause, "flag name %q should not contain '='", name) +} + func (c *flagNameChecker) warnWhitespace(cause ast.Node, name string) { c.ctx.Warn(cause, "flag name %q contains whitespace", name) } 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 f3f9c535c..ae61a1125 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 @@ -25,8 +25,8 @@ y := 0xff // (B) y := 0xFF` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&hexLiteralChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&hexLiteralChecker{ctx: ctx}), nil }) } 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 54be77638..c430431a7 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 @@ -21,11 +21,11 @@ func init() { info.Before = `func f(x [1024]int) {}` info.After = `func f(x *[1024]int) {}` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { return astwalk.WalkerForFuncDecl(&hugeParamChecker{ ctx: ctx, sizeThreshold: int64(info.Params.Int("sizeThreshold")), - }) + }), nil }) } @@ -48,7 +48,7 @@ func (c *hugeParamChecker) VisitFuncDecl(decl *ast.FuncDecl) { func (c *hugeParamChecker) checkParams(params []*ast.Field) { for _, p := range params { for _, id := range p.Names { - typ := c.ctx.TypesInfo.TypeOf(id) + typ := c.ctx.TypeOf(id) size := c.ctx.SizesInfo.Sizeof(typ) if size >= c.sizeThreshold { c.warn(id, size) 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 91e1cfb39..b1fcf4147 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 @@ -34,8 +34,8 @@ 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 *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&ifElseChainChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&ifElseChainChecker{ctx: ctx}), nil }) } 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 60c0ab21e..5ac711fc1 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 @@ -19,9 +19,9 @@ filepath := "foo.txt"` info.After = ` filename := "foo.txt"` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { ctx.Require.PkgObjects = true - return astwalk.WalkerForLocalDef(&importShadowChecker{ctx: ctx}, ctx.TypesInfo) + return astwalk.WalkerForLocalDef(&importShadowChecker{ctx: ctx}, ctx.TypesInfo), nil }) } 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 733998873..908285c03 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 @@ -18,8 +18,8 @@ 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 *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&indexAllocChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&indexAllocChecker{ctx: ctx}), nil }) } 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 91e8816d2..a1b6b2a8a 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 @@ -19,8 +19,8 @@ func init() { if cond { }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&initClauseChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&initClauseChecker{ctx: ctx}), nil }) } 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 index 64098b2b7..de66c1081 100644 --- 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 @@ -1,6 +1,8 @@ package astwalk -import "go/ast" +import ( + "go/ast" +) type exprWalker struct { visitor ExprVisitor 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 index 90d921f6f..c7e3a4371 100644 --- 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 @@ -1,6 +1,8 @@ package astwalk -import "go/ast" +import ( + "go/ast" +) type funcDeclWalker struct { visitor FuncDeclVisitor 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 index 951fd97e5..e455b3f8b 100644 --- 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 @@ -1,6 +1,8 @@ package astwalk -import "go/ast" +import ( + "go/ast" +) type localExprWalker struct { visitor LocalExprVisitor 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 index 1cc0493a4..45c406e7e 100644 --- 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 @@ -1,6 +1,8 @@ package astwalk -import "go/ast" +import ( + "go/ast" +) type stmtListWalker struct { visitor StmtListVisitor 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 index 722eeb116..912de867d 100644 --- 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 @@ -1,6 +1,8 @@ package astwalk -import "go/ast" +import ( + "go/ast" +) type stmtWalker struct { visitor StmtVisitor 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 fdbbb45a2..64c2821dd 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 @@ -29,8 +29,8 @@ _ = map[string]int{ "bar": 2, }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&mapKeyChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&mapKeyChecker{ctx: ctx}), nil }) } @@ -47,7 +47,7 @@ func (c *mapKeyChecker) VisitExpr(expr ast.Expr) { return } - typ, ok := c.ctx.TypesInfo.TypeOf(lit).Underlying().(*types.Map) + typ, ok := c.ctx.TypeOf(lit).Underlying().(*types.Map) if !ok { return } 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 efd631143..2553def14 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 @@ -21,8 +21,8 @@ foo.bar(f)` info.After = `f := foo{} f.bar()` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&methodExprCallChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&methodExprCallChecker{ctx: ctx}), nil }) } 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 de02c7eec..a68acecca 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 @@ -32,10 +32,10 @@ for _, v := range a { body() }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &nestingReduceChecker{ctx: ctx} c.bodyWidth = info.Params.Int("bodyWidth") - return astwalk.WalkerForStmt(c) + return astwalk.WalkerForStmt(c), nil }) } 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 7b9f02bd3..7e564b70f 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 @@ -18,8 +18,8 @@ func init() { info.Before = `x := *new(bool)` info.After = `x := false` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&newDerefChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&newDerefChecker{ctx: ctx}), nil }) } @@ -32,7 +32,7 @@ func (c *newDerefChecker) VisitExpr(expr ast.Expr) { deref := astcast.ToStarExpr(expr) call := astcast.ToCallExpr(deref.X) if astcast.ToIdent(call.Fun).Name == "new" { - typ := c.ctx.TypesInfo.TypeOf(call.Args[0]) + typ := c.ctx.TypeOf(call.Args[0]) zv := lintutil.ZeroValueOf(astutil.Unparen(call.Args[0]), typ) if zv != nil { c.warn(expr, zv) 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 37f964f70..e53ca0cc0 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 @@ -29,8 +29,8 @@ if err != nil { return err }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&nilValReturnChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&nilValReturnChecker{ctx: ctx}), nil }) } 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 a1d968043..486940452 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 @@ -18,7 +18,7 @@ func init() { info.Before = `foo(02)` info.After = `foo(2)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &octalLiteralChecker{ ctx: ctx, octFriendlyPkg: map[string]bool{ @@ -26,7 +26,7 @@ func init() { "io/ioutil": true, }, } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 df20b429a..ece3fdfdb 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 @@ -20,8 +20,8 @@ func init() { info.Before = `xs[len(xs)]` info.After = `xs[len(xs)-1]` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&offBy1Checker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&offBy1Checker{ctx: ctx}), nil }) } @@ -31,15 +31,15 @@ type offBy1Checker struct { } func (c *offBy1Checker) VisitExpr(e ast.Expr) { - // TODO(Quasilyte): handle more off-by-1 patterns. - // TODO(Quasilyte): check whether go/analysis can help here. + // TODO(quasilyte): handle more off-by-1 patterns. + // TODO(quasilyte): check whether go/analysis can help here. // Detect s[len(s)] expressions that always panic. // The correct form is s[len(s)-1]. indexExpr := astcast.ToIndexExpr(e) indexed := indexExpr.X - if !typep.IsSlice(c.ctx.TypesInfo.TypeOf(indexed)) { + if !typep.IsSlice(c.ctx.TypeOf(indexed)) { return } if !typep.SideEffectFree(c.ctx.TypesInfo, indexed) { 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 f9f9d6c5a..8cdad4eee 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 @@ -16,8 +16,8 @@ func init() { 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 *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForFuncDecl(¶mTypeCombineChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForFuncDecl(¶mTypeCombineChecker{ctx: ctx}), nil }) } 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 2716fe04b..88c8f4cb3 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 @@ -16,8 +16,8 @@ func init() { 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 *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForFuncDecl(&ptrToRefParamChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForFuncDecl(&ptrToRefParamChecker{ctx: ctx}), nil }) } @@ -35,7 +35,7 @@ func (c *ptrToRefParamChecker) VisitFuncDecl(fn *ast.FuncDecl) { func (c *ptrToRefParamChecker) checkParams(params []*ast.Field) { for _, param := range params { - ptr, ok := c.ctx.TypesInfo.TypeOf(param.Type).(*types.Pointer) + ptr, ok := c.ctx.TypeOf(param.Type).(*types.Pointer) if !ok { continue } 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 90b5987ab..5615af467 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 @@ -36,11 +36,11 @@ 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 *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &rangeExprCopyChecker{ctx: ctx} c.sizeThreshold = int64(info.Params.Int("sizeThreshold")) c.skipTestFuncs = info.Params.Bool("skipTestFuncs") - return astwalk.WalkerForStmt(c) + return astwalk.WalkerForStmt(c), nil }) } 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 57dcc3151..b34aa5c28 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 @@ -35,11 +35,11 @@ for i := range xs { // Loop body. }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &rangeValCopyChecker{ctx: ctx} c.sizeThreshold = int64(info.Params.Int("sizeThreshold")) c.skipTestFuncs = info.Params.Bool("skipTestFuncs") - return astwalk.WalkerForStmt(c) + return astwalk.WalkerForStmt(c), nil }) } @@ -61,7 +61,7 @@ func (c *rangeValCopyChecker) VisitStmt(stmt ast.Stmt) { if !ok || rng.Value == nil { return } - typ := c.ctx.TypesInfo.TypeOf(rng.Value) + typ := c.ctx.TypeOf(rng.Value) if typ == nil { return } 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 411932ee5..600aa73d0 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 @@ -18,8 +18,8 @@ func init() { info.Before = `re, _ := regexp.Compile("const pattern")` info.After = `re := regexp.MustCompile("const pattern")` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(®expMustChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(®expMustChecker{ctx: ctx}), nil }) } 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 018ab42d1..31dc4aad3 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 @@ -18,7 +18,7 @@ func init() { info.Before = "regexp.MustCompile(`google.com|yandex.ru`)" info.After = "regexp.MustCompile(`google\\.com|yandex\\.ru`)" - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { domains := []string{ "com", "org", @@ -33,7 +33,7 @@ func init() { return astwalk.WalkerForExpr(®expPatternChecker{ ctx: ctx, domainRE: domainRE, - }) + }), nil }) } 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 index 10dcb327f..b7dd15948 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/regexpSimplify_checker.go @@ -26,7 +26,7 @@ func init() { // `[[:digit:]] -> \d` // `[A-Za-z0-9_]` -> `\w` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { opts := &syntax.ParserOptions{ NoLiterals: true, } @@ -35,7 +35,7 @@ func init() { parser: syntax.NewParser(opts), out: &strings.Builder{}, } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 index d9799102d..19e265887 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go @@ -2,10 +2,14 @@ package checkers import ( "bytes" + "fmt" "go/ast" "go/token" "io/ioutil" "log" + "os" + "path/filepath" + "strings" "github.com/go-critic/go-critic/framework/linter" "github.com/quasilyte/go-ruleguard/ruleguard" @@ -18,7 +22,15 @@ func init() { info.Params = linter.CheckerParams{ "rules": { Value: "", - Usage: "path to a gorules file", + Usage: "comma-separated list of gorule file paths. Glob patterns such as 'rules-*.go' may be specified", + }, + "debug": { + Value: "", + Usage: "enable debug for the specified named rules group", + }, + "failOnError": { + Value: false, + Usage: "If true, panic when the gorule files contain a syntax error. If false, log and skip rules that contain an error", }, } info.Summary = "Runs user-defined rules using ruleguard linter" @@ -27,17 +39,21 @@ func init() { info.After = `N/A` info.Note = "See https://github.com/quasilyte/go-ruleguard." - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { 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 +func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) (*ruleguardChecker, error) { + c := &ruleguardChecker{ + ctx: ctx, + debugGroup: info.Params.String("debug"), } + rulesFlag := info.Params.String("rules") + if rulesFlag == "" { + return c, nil + } + failOnErrorFlag := info.Params.Bool("failOnError") // TODO(quasilyte): handle initialization errors better when we make // a transition to the go/analysis framework. @@ -45,35 +61,65 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) * // 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 + engine := ruleguard.NewEngine() + fset := token.NewFileSet() + filePatterns := strings.Split(rulesFlag, ",") + + parseContext := &ruleguard.ParseContext{ + Fset: fset, } - fset := token.NewFileSet() - rset, err := ruleguard.ParseRules(rulesFilename, fset, bytes.NewReader(data)) - if err != nil { - log.Printf("ruleguard init error: %+v", err) - return c + loaded := 0 + for _, filePattern := range filePatterns { + filenames, err := filepath.Glob(strings.TrimSpace(filePattern)) + if err != nil { + // The only possible returned error is ErrBadPattern, when pattern is malformed. + log.Printf("ruleguard init error: %+v", err) + continue + } + for _, filename := range filenames { + data, err := ioutil.ReadFile(filename) + if err != nil { + if failOnErrorFlag { + return nil, fmt.Errorf("ruleguard init error: %+v", err) + } + log.Printf("ruleguard init error: %+v", err) + continue + } + if err := engine.Load(parseContext, filename, bytes.NewReader(data)); err != nil { + if failOnErrorFlag { + return nil, fmt.Errorf("ruleguard init error: %+v", err) + } + log.Printf("ruleguard init error: %+v", err) + continue + } + loaded++ + } } - c.rset = rset - return c + if loaded != 0 { + c.engine = engine + } + return c, nil } type ruleguardChecker struct { ctx *linter.CheckerContext - rset *ruleguard.GoRuleSet + debugGroup string + engine *ruleguard.Engine } func (c *ruleguardChecker) WalkFile(f *ast.File) { - if c.rset == nil { + if c.engine == nil { return } - ctx := &ruleguard.Context{ + ctx := &ruleguard.RunContext{ + Debug: c.debugGroup, + DebugPrint: func(s string) { + fmt.Fprintln(os.Stderr, s) + }, Pkg: c.ctx.Pkg, Types: c.ctx.TypesInfo, Sizes: c.ctx.SizesInfo, @@ -85,8 +131,7 @@ func (c *ruleguardChecker) WalkFile(f *ast.File) { }, } - err := ruleguard.RunRules(ctx, f, c.rset) - if err != nil { + if err := c.engine.Run(ctx, f); err != nil { // Normally this should never happen, but since // we don't have a better mechanism to report errors, // emit a warning. 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 abead3fa2..b369a4344 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 @@ -24,8 +24,8 @@ if x, ok := x.(int); ok { body() }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&singleCaseSwitchChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&singleCaseSwitchChecker{ctx: ctx}), nil }) } 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 e12545ffe..a08ef0a5c 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 @@ -23,8 +23,8 @@ len(arr) < 0 // Doesn't make sense at all` len(arr) > 0 len(arr) == 0` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&sloppyLenChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&sloppyLenChecker{ctx: ctx}), nil }) } 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 d099450d1..2f9ac62e1 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 @@ -19,8 +19,8 @@ func init() { info.Before = `if err = f(); err != nil { return err }` info.After = `if err := f(); err != nil { return err }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&sloppyReassignChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&sloppyReassignChecker{ctx: ctx}), nil }) } @@ -37,12 +37,12 @@ func (c *sloppyReassignChecker) VisitStmt(stmt ast.Stmt) { return } - // TODO(Quasilyte): is handling of multi-value assignments worthwhile? + // TODO(quasilyte): is handling of multi-value assignments worthwhile? if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 { return } - // TODO(Quasilyte): handle not only the simplest, return-only case. + // TODO(quasilyte): handle not only the simplest, return-only case. body := ifStmt.Body.List if len(body) != 1 { return @@ -54,7 +54,7 @@ func (c *sloppyReassignChecker) VisitStmt(stmt ast.Stmt) { return } - // TODO(Quasilyte): handle not only nil comparisons. + // TODO(quasilyte): handle not only nil comparisons. eqToNil := &ast.BinaryExpr{ Op: token.NEQ, X: reAssigned, 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 index 4abfcbab4..39b968898 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/sloppyTypeAssert_checker.go @@ -25,8 +25,8 @@ function f(r io.Reader) interface{} { } ` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&sloppyTypeAssertChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&sloppyTypeAssertChecker{ctx: ctx}), nil }) } @@ -41,8 +41,8 @@ func (c *sloppyTypeAssertChecker) VisitExpr(expr ast.Expr) { return } - toType := c.ctx.TypesInfo.TypeOf(expr) - fromType := c.ctx.TypesInfo.TypeOf(assert.X) + toType := c.ctx.TypeOf(expr) + fromType := c.ctx.TypeOf(assert.X) if types.Identical(toType, fromType) { c.warnIdentical(expr) 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 index b80c17873..29550da3f 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/sortSlice_checker.go @@ -21,8 +21,8 @@ func init() { 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}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&sortSliceChecker{ctx: ctx}), nil }) } @@ -87,7 +87,7 @@ func (c *sortSliceChecker) VisitExpr(expr ast.Expr) { } } -func (c *sortSliceChecker) paramIdents(e *ast.FuncType) (*ast.Ident, *ast.Ident) { +func (c *sortSliceChecker) paramIdents(e *ast.FuncType) (ivar, jvar *ast.Ident) { // Covers both `i, j int` and `i int, j int`. idents := make([]*ast.Ident, 0, 2) for _, field := range e.Params.List { 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 index 697a82ccf..eb3b49d88 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/sqlQuery_checker.go @@ -17,8 +17,8 @@ func init() { 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}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&sqlQueryChecker{ctx: ctx}), nil }) } @@ -49,7 +49,7 @@ func (c *sqlQueryChecker) VisitStmt(stmt ast.Stmt) { return } - if c.typeHasExecMethod(c.ctx.TypesInfo.TypeOf(funcExpr.X)) { + if c.typeHasExecMethod(c.ctx.TypeOf(funcExpr.X)) { c.warnAndSuggestExec(funcExpr) } else { c.warnRowsIgnored(funcExpr) @@ -71,7 +71,7 @@ func (c *sqlQueryChecker) funcIsQuery(funcExpr *ast.SelectorExpr) bool { // 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) + typ, ok := c.ctx.TypeOf(funcExpr).Underlying().(*types.Signature) if !ok || typ.Results() == nil || typ.Results().Len() != 2 { return false } 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 57e4084f6..bb9f16c07 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 @@ -16,8 +16,8 @@ func init() { info.Before = `copy(b, []byte(s))` info.After = `copy(b, s)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&stringXbytes{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&stringXbytes{ctx: ctx}), nil }) } @@ -28,7 +28,7 @@ type stringXbytes struct { func (c *stringXbytes) VisitExpr(expr ast.Expr) { x, ok := expr.(*ast.CallExpr) - if !ok || qualifiedName(x.Fun) != "copy" { + if !ok || qualifiedName(x.Fun) != "copy" || len(x.Args) != 2 { return } @@ -36,7 +36,7 @@ func (c *stringXbytes) VisitExpr(expr ast.Expr) { byteCast, ok := src.(*ast.CallExpr) if ok && typep.IsTypeExpr(c.ctx.TypesInfo, byteCast.Fun) && - typep.HasStringProp(c.ctx.TypesInfo.TypeOf(byteCast.Args[0])) { + typep.HasStringProp(c.ctx.TypeOf(byteCast.Args[0])) { c.warn(byteCast, byteCast.Args[0]) } 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 5390360c5..0501a0ba1 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 @@ -21,8 +21,8 @@ switch { case x > y: }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&switchTrueChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&switchTrueChecker{ctx: ctx}), nil }) } 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 a5b7bdd32..cd2346c78 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 @@ -31,10 +31,10 @@ func f(x int32, int16) bool { return x < int32(y) }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &truncateCmpChecker{ctx: ctx} c.skipArchDependent = info.Params.Bool("skipArchDependent") - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } @@ -87,11 +87,11 @@ func (c *truncateCmpChecker) checkCmp(cmpX, cmpY ast.Expr) { y := cmpY // Check that both x and y are signed or unsigned int-typed. - xtyp, ok := c.ctx.TypesInfo.TypeOf(x).Underlying().(*types.Basic) + xtyp, ok := c.ctx.TypeOf(x).Underlying().(*types.Basic) if !ok || xtyp.Info()&types.IsInteger == 0 { return } - ytyp, ok := c.ctx.TypesInfo.TypeOf(y).Underlying().(*types.Basic) + ytyp, ok := c.ctx.TypeOf(y).Underlying().(*types.Basic) if !ok || xtyp.Info() != ytyp.Info() { return } 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 2940e57f9..d87657c3b 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 @@ -35,8 +35,8 @@ default: // Code C, uses x. }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&typeAssertChainChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&typeAssertChainChecker{ctx: ctx}), nil }) } diff --git a/vendor/github.com/go-critic/go-critic/checkers/typeDefFirst_checker.go b/vendor/github.com/go-critic/go-critic/checkers/typeDefFirst_checker.go new file mode 100644 index 000000000..491e71dfd --- /dev/null +++ b/vendor/github.com/go-critic/go-critic/checkers/typeDefFirst_checker.go @@ -0,0 +1,88 @@ +package checkers + +import ( + "go/ast" + "go/token" + + "github.com/go-critic/go-critic/checkers/internal/astwalk" + "github.com/go-critic/go-critic/framework/linter" +) + +func init() { + var info linter.CheckerInfo + info.Name = "typeDefFirst" + info.Tags = []string{"style", "experimental"} + info.Summary = "Detects method declarations preceding the type definition itself" + info.Before = ` +func (r rec) Method() {} +type rec struct{} +` + info.After = ` +type rec struct{} +func (r rec) Method() {} +` + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return &typeDefFirstChecker{ + ctx: ctx, + }, nil + }) +} + +type typeDefFirstChecker struct { + astwalk.WalkHandler + ctx *linter.CheckerContext + trackedTypes map[string]bool +} + +func (c *typeDefFirstChecker) WalkFile(f *ast.File) { + if len(f.Decls) == 0 { + return + } + + c.trackedTypes = make(map[string]bool) + for _, decl := range f.Decls { + c.walkDecl(decl) + } +} + +func (c *typeDefFirstChecker) walkDecl(decl ast.Decl) { + switch decl := decl.(type) { + case *ast.FuncDecl: + if decl.Recv == nil { + return + } + receiver := decl.Recv.List[0] + typeName := c.receiverType(receiver.Type) + c.trackedTypes[typeName] = true + + case *ast.GenDecl: + if decl.Tok != token.TYPE { + return + } + for _, spec := range decl.Specs { + spec, ok := spec.(*ast.TypeSpec) + if !ok { + return + } + typeName := spec.Name.Name + if val, ok := c.trackedTypes[typeName]; ok && val { + c.warn(decl, typeName) + } + } + } +} + +func (c *typeDefFirstChecker) receiverType(e ast.Expr) string { + switch e := e.(type) { + case *ast.StarExpr: + return c.receiverType(e.X) + case *ast.Ident: + return e.Name + default: + panic("unreachable") + } +} + +func (c *typeDefFirstChecker) warn(cause ast.Node, typeName string) { + c.ctx.Warn(cause, "definition of type '%s' should appear before its methods", typeName) +} 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 2ade4a954..6bbec5037 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 @@ -34,8 +34,8 @@ default: return 0 }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&typeSwitchVarChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&typeSwitchVarChecker{ctx: ctx}), nil }) } 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 620d2d797..a3f02e14c 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 @@ -19,8 +19,8 @@ func init() { info.Before = `type foo [](func([](func())))` info.After = `type foo []func([]func())` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForTypeExpr(&typeUnparenChecker{ctx: ctx}, ctx.TypesInfo) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForTypeExpr(&typeUnparenChecker{ctx: ctx}, ctx.TypesInfo), nil }) } 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 561270c7c..d0426a9a5 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 @@ -28,10 +28,10 @@ v := (*a)[5] // only if a is array` k.field = 5 v := a[5]` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &underefChecker{ctx: ctx} c.skipRecvDeref = info.Params.Bool("skipRecvDeref") - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } @@ -69,7 +69,7 @@ func (c *underefChecker) VisitExpr(expr ast.Expr) { } func (c *underefChecker) isPtrRecvMethodCall(fn *ast.Ident) bool { - typ, ok := c.ctx.TypesInfo.TypeOf(fn).(*types.Signature) + typ, ok := c.ctx.TypeOf(fn).(*types.Signature) if ok && typ != nil && typ.Recv() != nil { _, ok := typ.Recv().Type().(*types.Pointer) return ok @@ -104,7 +104,7 @@ func (c *underefChecker) warnArray(expr *ast.IndexExpr) { // checkStarExpr checks if ast.StarExpr could be simplified. func (c *underefChecker) checkStarExpr(expr *ast.StarExpr) bool { - typ, ok := c.ctx.TypesInfo.TypeOf(expr.X).Underlying().(*types.Pointer) + typ, ok := c.ctx.TypeOf(expr.X).Underlying().(*types.Pointer) if !ok { return false } @@ -118,7 +118,7 @@ func (c *underefChecker) checkStarExpr(expr *ast.StarExpr) bool { } func (c *underefChecker) checkArray(expr *ast.StarExpr) bool { - typ, ok := c.ctx.TypesInfo.TypeOf(expr.X).(*types.Pointer) + typ, ok := c.ctx.TypeOf(expr.X).(*types.Pointer) if !ok { return false } 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 83c5b1484..fab864ec5 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 @@ -28,8 +28,8 @@ for x := range xs { } }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmt(&unlabelStmtChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmt(&unlabelStmtChecker{ctx: ctx}), nil }) } @@ -42,7 +42,7 @@ func (c *unlabelStmtChecker) EnterFunc(fn *ast.FuncDecl) bool { if fn.Body == nil { return false } - // TODO(Quasilyte): should not do additional traversal here. + // TODO(quasilyte): should not do additional traversal here. // For now, skip all functions that contain goto statement. return !lintutil.ContainsNode(fn.Body, func(n ast.Node) bool { br, ok := n.(*ast.BranchStmt) 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 946227c2f..cce995d7a 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 @@ -2,12 +2,15 @@ package checkers import ( "go/ast" + "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-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" "github.com/go-toolsmith/astequal" + "github.com/go-toolsmith/typep" ) func init() { @@ -18,8 +21,8 @@ func init() { info.Before = `func(x int) int { return fn(x) }` info.After = `fn` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&unlambdaChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&unlambdaChecker{ctx: ctx}), nil }) } @@ -47,20 +50,38 @@ func (c *unlambdaChecker) VisitExpr(x ast.Expr) { if isBuiltin(callable) { return // See #762 } - if id, ok := result.Fun.(*ast.Ident); ok { - obj := c.ctx.TypesInfo.ObjectOf(id) - if _, ok := obj.(*types.Var); ok { - return // See #888 + hasVars := lintutil.ContainsNode(result.Fun, func(n ast.Node) bool { + id, ok := n.(*ast.Ident) + if !ok { + return false } + obj, ok := c.ctx.TypesInfo.ObjectOf(id).(*types.Var) + if !ok { + return false + } + // Permit only non-pointer struct method values. + return !typep.IsStruct(obj.Type().Underlying()) + }) + if hasVars { + return // See #888 #1007 } - fnType := c.ctx.TypesInfo.TypeOf(fn) - resultType := c.ctx.TypesInfo.TypeOf(result.Fun) + + fnType := c.ctx.TypeOf(fn) + resultType := c.ctx.TypeOf(result.Fun) if !types.Identical(fnType, resultType) { return } // Now check that all arguments match the parameters. n := 0 for _, params := range fn.Type.Params.List { + if _, ok := params.Type.(*ast.Ellipsis); ok { + if result.Ellipsis == token.NoPos { + return + } + n++ + continue + } + for _, id := range params.Names { if !astequal.Expr(id, result.Args[n]) { return 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 f053842ec..3149d9e87 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 @@ -22,10 +22,10 @@ func init() { info.Before = `func f() (float64, float64)` info.After = `func f() (x, y float64)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { c := &unnamedResultChecker{ctx: ctx} c.checkExported = info.Params.Bool("checkExported") - return astwalk.WalkerForFuncDecl(c) + return astwalk.WalkerForFuncDecl(c), nil }) } @@ -48,7 +48,7 @@ func (c *unnamedResultChecker) VisitFuncDecl(decl *ast.FuncDecl) { return // Skip named results } - typeName := func(x ast.Expr) string { return c.typeName(c.ctx.TypesInfo.TypeOf(x)) } + typeName := func(x ast.Expr) string { return c.typeName(c.ctx.TypeOf(x)) } isError := func(x ast.Expr) bool { return qualifiedName(x) == "error" } isBool := func(x ast.Expr) bool { return qualifiedName(x) == "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 acc9fadbf..72807ddbf 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 @@ -22,8 +22,8 @@ x := 1 x := 1 print(x)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmtList(&unnecessaryBlockChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmtList(&unnecessaryBlockChecker{ctx: ctx}), nil }) } 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 index ee706e099..ef72142a1 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/unnecessaryDefer_checker.go @@ -22,8 +22,8 @@ func() { os.Remove(filename) }` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForFuncDecl(&unnecessaryDeferChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForFuncDecl(&unnecessaryDeferChecker{ctx: ctx}), nil }) } 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 73f67bc8e..26a4de061 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 @@ -21,8 +21,8 @@ copy(b[:], values...) // b is []byte` f(s) copy(b, values...)` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&unsliceChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&unsliceChecker{ctx: ctx}), nil }) } @@ -46,7 +46,7 @@ func (c *unsliceChecker) unslice(expr ast.Expr) ast.Expr { // because it's only permitted if expr.High is not nil. return expr } - switch c.ctx.TypesInfo.TypeOf(slice.X).(type) { + switch c.ctx.TypeOf(slice.X).(type) { case *types.Slice, *types.Basic: // Basic kind catches strings, Slice cathes everything else. return c.unslice(slice.X) 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 4dd494ecf..d03e11223 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 @@ -21,8 +21,8 @@ tmp := *x *y = tmp` info.After = `*x, *y = *y, *x` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForStmtList(&valSwapChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForStmtList(&valSwapChecker{ctx: ctx}), nil }) } 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 1d6ee58ef..831857c41 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 @@ -21,8 +21,8 @@ func init() { info.Before = `xs != nil && xs[0] != nil` info.After = `len(xs) != 0 && xs[0] != nil` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForExpr(&weakCondChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForExpr(&weakCondChecker{ctx: ctx}), nil }) } @@ -46,7 +46,7 @@ func (c *weakCondChecker) VisitExpr(expr ast.Expr) { // lhs is `x nil` x := lhs.X - if !typep.IsSlice(c.ctx.TypesInfo.TypeOf(x)) { + if !typep.IsSlice(c.ctx.TypeOf(x)) { return } if astcast.ToIdent(lhs.Y).Name != "nil" { 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 cc5c5172e..260039f2b 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 @@ -19,11 +19,11 @@ func init() { } re := regexp.MustCompile(`^// *nolint(?::[^ ]+)? *(.*)$`) - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { return astwalk.WalkerForComment(&whyNoLintChecker{ ctx: ctx, re: re, - }) + }), nil }) } @@ -44,7 +44,7 @@ func (c whyNoLintChecker) VisitComment(cg *ast.CommentGroup) { continue } - if s := sl[1]; !strings.HasPrefix(s, "//") || len(strings.TrimPrefix(s, "//")) == 0 { + if s := sl[1]; !strings.HasPrefix(s, "//") || strings.TrimPrefix(s, "//") == "" { c.ctx.Warn(cg, "include an explanation for nolint directive") return } 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 bc543e648..d474989d0 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 @@ -19,7 +19,7 @@ func init() { info.Before = `wg.Add(-1)` info.After = `wg.Done()` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { type arg struct { index int value string @@ -190,7 +190,7 @@ func init() { } } - typ := c.ctx.TypesInfo.TypeOf(x) + typ := c.ctx.TypeOf(x) tn, ok := typ.(*types.Named) if !ok { return "" @@ -202,7 +202,7 @@ func init() { m.typPatterns) } - return astwalk.WalkerForExpr(c) + return astwalk.WalkerForExpr(c), nil }) } 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 b4672fcca..c533d143b 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 @@ -18,8 +18,8 @@ func init() { info.Before = `return nil != ptr` info.After = `return ptr != nil` - collection.AddChecker(&info, func(ctx *linter.CheckerContext) linter.FileWalker { - return astwalk.WalkerForLocalExpr(&yodaStyleExprChecker{ctx: ctx}) + collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { + return astwalk.WalkerForLocalExpr(&yodaStyleExprChecker{ctx: ctx}), nil }) } 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 index b4bebe443..0a3fc0292 100644 --- 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 @@ -11,7 +11,7 @@ import ( type checkerProto struct { info *CheckerInfo - constructor func(*Context) *Checker + constructor func(*Context) (*Checker, error) } // prototypes is a set of registered checkers that are not yet instantiated. @@ -31,7 +31,7 @@ func getCheckersInfo() []*CheckerInfo { return infoList } -func addChecker(info *CheckerInfo, constructor func(*CheckerContext) FileWalker) { +func addChecker(info *CheckerInfo, constructor func(*CheckerContext) (FileWalker, error)) { if _, ok := prototypes[info.Name]; ok { panic(fmt.Sprintf("checker with name %q already registered", info.Name)) } @@ -68,22 +68,23 @@ func addChecker(info *CheckerInfo, constructor func(*CheckerContext) FileWalker) proto := checkerProto{ info: info, - constructor: func(ctx *Context) *Checker { + constructor: func(ctx *Context) (*Checker, error) { var c Checker c.Info = info c.ctx = CheckerContext{ Context: ctx, printer: astfmt.NewPrinter(ctx.FileSet), } - c.fileWalker = constructor(&c.ctx) - return &c + var err error + c.fileWalker, err = constructor(&c.ctx) + return &c, err }, } prototypes[info.Name] = proto } -func newChecker(ctx *Context, info *CheckerInfo) *Checker { +func newChecker(ctx *Context, info *CheckerInfo) (*Checker, error) { proto, ok := prototypes[info.Name] if !ok { panic(fmt.Sprintf("checker with name %q not registered", info.Name)) @@ -116,7 +117,7 @@ func validateCheckerName(info *CheckerInfo) error { } func validateCheckerDocumentation(info *CheckerInfo) error { - // TODO(Quasilyte): validate documentation. + // TODO(quasilyte): validate documentation. return nil } 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 index 1f984d146..5c8662c69 100644 --- a/vendor/github.com/go-critic/go-critic/framework/linter/lintpack.go +++ b/vendor/github.com/go-critic/go-critic/framework/linter/lintpack.go @@ -22,7 +22,7 @@ type CheckerCollection struct { // // 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) { +func (coll *CheckerCollection) AddChecker(info *CheckerInfo, constructor func(*CheckerContext) (FileWalker, error)) { if coll == nil { panic("adding checker to a nil collection") } @@ -138,8 +138,9 @@ type Warning struct { // 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 { +// Returns an error if info describes a checker that was not properly registered, +// or if checker fails to initialize. +func NewChecker(ctx *Context, info *CheckerInfo) (*Checker, error) { return newChecker(ctx, info) } @@ -238,6 +239,27 @@ func (ctx *CheckerContext) Warn(node ast.Node, format string, args ...interface{ }) } +// UnknownType is a special sentinel value that is returned from the CheckerContext.TypeOf +// method instead of the nil type. +var UnknownType types.Type = types.Typ[types.Invalid] + +// TypeOf returns the type of expression x. +// +// Unlike TypesInfo.TypeOf, it never returns nil. +// Instead, it returns the Invalid type as a sentinel UnknownType value. +func (ctx *CheckerContext) TypeOf(x ast.Expr) types.Type { + typ := ctx.TypesInfo.TypeOf(x) + if typ != nil { + return typ + } + // Usually it means that some incorrect type info was loaded + // or the analyzed package was only partially (?) correct. + // To avoid nil pointer panics we can return a sentinel value + // that will fail most type assertions as well as kind checks + // (if the call side expects a *types.Basic). + return UnknownType +} + // FileWalker is an interface every checker should implement. // // The WalkFile method is executed for every Go file inside the -- cgit mrf-deployment