From b31cfd6c78e2bc66ac13e7402150439e4dbc8ac1 Mon Sep 17 00:00:00 2001
From: Denis Isaev <denis@golangci.com>
Date: Mon, 11 Feb 2019 09:33:43 +0300
Subject: [PATCH] update go-critic

$ git cherry --abbrev -v 0af0999fabfb ee9bf5809ead
+ abd8436 all: enable Go modules on CI (#753)
+ 3c9d0fb checkers: recognize //line and //nolint in commentFormatting (#756)
+ 0b517d7 checkers: extend deprecatedComment patterns (#757)
+ 09100f6 checkers: use astcast package instead of coerce.go (#758)
+ 2e9e97f checker: simplify boolExprSimplify (#759)
+ 575701e make: add go-consistent to CI checks list (#761)
+ b55f431 checkers: fix unlambda handling of builtins (#763)
+ 5a7dee3 checker: handle lambdas properly in boolExprSimplify (#765)
+ 5ce3939 checkers: teach boolExprSimplify a few new tricks (#766)
+ 04d160f checkers: add new patterns to boolExprSimplify (#768)
+ 09582e2 make: collect coverprofile separately from goveralls (#769)
+ d8d0ee4 checkers: recognize NOTE pattern in deprecatedComment (#770)
+ 12f0f85 Update copyright notice to 2019 (#771)
+ f54bdb6 checkers: add stringXbytes checker
+ 170d65c checkers: followup for #773 (#774)
+ 84e9e83 checkers: make stringXbytes more linear (#775)
+ a800815 checkers: add Depreacted typo pattern (#776)
+ 6751be9 checkers: add hexLiterals (#772)
+ ac61906 checkers: add typeAssertChain checker (#782)
+ d19dbf1 checkers: add codegenComment checker (#783)
+ d82b576 checkers: proper pkg/obj check for flagName (#786)
+ dfcf754 ci: enable integration tests (#787)
+ 5dafc45 checkers: fix equalFold false positive (#788)
+ ed5e8e7 checkers: refactor and fix hexLiteral checker (#789)
+ e704e07 checkers: add argOrder checker (#790)
+ 34c1dc8 checkers: add Split handling to argOrder checker (#791)
+ cbe095d checkers: add math.Max and math.Min to dupArg (#792)
+ c986ee5 checkers: add checkers info fields test (#794)
+ 66e5832 cmd/makedocs: use lintpack, fix build (#793)
+ 6bce9d0 cmd/makedocs: add enabled/disabled by default info (#795)
+ 4adbf9a checkers: simplify flagName (#799)
+ 07de34a checkers: add octalLiteral checker (#798)
+ 765907a cmd/makedocs: add checker param docs (#796)
+ ee9bf58 cmd/makedocs: fix headers formatting (#803)
---
 .golangci.yml                                 |   1 -
 README.md                                     |   1 -
 go.mod                                        |   2 +-
 go.sum                                        |   5 +-
 vendor/github.com/go-critic/go-critic/LICENSE |   4 +-
 .../checkers/appendCombine_checker.go         |   4 +-
 .../go-critic/checkers/argOrder_checker.go    |  98 +++
 .../checkers/boolExprSimplify_checker.go      | 203 ++++-
 .../checkers/builtinShadow_checker.go         |  55 +-
 .../checkers/codegenComment_checker.go        |  61 ++
 .../checkers/commentFormatting_checker.go     |   8 +-
 .../checkers/deprecatedComment_checker.go     |   3 +
 .../go-critic/checkers/dupArg_checker.go      |   3 +
 .../go-critic/checkers/equalFold_checker.go   |   9 +-
 .../go-critic/checkers/flagName_checker.go    |  12 +-
 .../go-critic/checkers/hexLiteral_checker.go  |  60 ++
 .../checkers/internal/lintutil/coerce.go      | 121 ---
 .../checkers/octalLiteral_checker.go          |  82 ++
 .../checkers/stringXbytes_checker.go          |  47 ++
 .../checkers/typeAssertChain_checker.go       | 132 ++++
 .../go-critic/checkers/underef_checker.go     |   6 +-
 .../go-critic/checkers/unlambda_checker.go    |   7 +-
 .../checkers/unnamedResult_checker.go         |   2 +-
 .../go-critic/go-critic/checkers/utils.go     |  54 ++
 .../x/tools/go/internal/gcimporter/iexport.go | 723 ++++++++++++++++++
 vendor/modules.txt                            |   2 +-
 26 files changed, 1492 insertions(+), 213 deletions(-)
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
 delete mode 100644 vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
 create mode 100644 vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
 create mode 100644 vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go

diff --git a/.golangci.yml b/.golangci.yml
index 7934cc7e..16bfba3e 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -31,7 +31,6 @@ linters-settings:
       - experimental
     disabled-checks:
       - wrapperFunc
-      - commentFormatting # https://github.com/go-critic/go-critic/issues/755
 
 linters:
   enable-all: true
diff --git a/README.md b/README.md
index 8ea78fa8..70d74896 100644
--- a/README.md
+++ b/README.md
@@ -779,7 +779,6 @@ linters-settings:
       - experimental
     disabled-checks:
       - wrapperFunc
-      - commentFormatting # https://github.com/go-critic/go-critic/issues/755
 
 linters:
   enable-all: true
diff --git a/go.mod b/go.mod
index 20ab1bf2..79daab9f 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
 	github.com/davecgh/go-spew v1.1.0 // indirect
 	github.com/fatih/color v1.6.0
-	github.com/go-critic/go-critic v0.0.0-20181204210945-0af0999fabfb
+	github.com/go-critic/go-critic v0.0.0-20181204210945-ee9bf5809ead
 	github.com/go-lintpack/lintpack v0.5.2
 	github.com/go-ole/go-ole v1.2.1 // indirect
 	github.com/gobwas/glob v0.2.3 // indirect
diff --git a/go.sum b/go.sum
index 579b13d1..7a029979 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,8 @@ github.com/fatih/color v1.6.0 h1:66qjqZk8kalYAvDRtM1AdAJQI0tj4Wrue3Eq3B3pmFU=
 github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/go-critic/go-critic v0.0.0-20181204210945-0af0999fabfb h1:faOtDYqSVJsFEJAW+SwEMvh7alhYsb42fER6tt8yXfA=
-github.com/go-critic/go-critic v0.0.0-20181204210945-0af0999fabfb/go.mod h1:PSww+HOJZQ3TN2hi6sphNiW1PhwELxbsK8+Jy1sjML8=
+github.com/go-critic/go-critic v0.0.0-20181204210945-ee9bf5809ead h1:qwmAYufKDopQnFdeMw+iHJVxAd2CbF+VFKHyJJwnPKk=
+github.com/go-critic/go-critic v0.0.0-20181204210945-ee9bf5809ead/go.mod h1:3MzXZKJdeXqdU9cj+rvZdNiN7SZ8V9OjybF8loZDmHU=
 github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
 github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
 github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
@@ -96,6 +96,7 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
 github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 h1:kw1v0NlnN+GZcU8Ma8CLF2Zzgjfx95gs3/GN3vYAPpo=
diff --git a/vendor/github.com/go-critic/go-critic/LICENSE b/vendor/github.com/go-critic/go-critic/LICENSE
index f677137d..b944b4bb 100644
--- a/vendor/github.com/go-critic/go-critic/LICENSE
+++ b/vendor/github.com/go-critic/go-critic/LICENSE
@@ -1,7 +1,7 @@
 MIT License
 
-Copyright (c) 2018 Alekseev Artem
-Copyright (c) 2018 Ravil Bikbulatov
+Copyright (c) 2018-2019 Alekseev Artem
+Copyright (c) 2018-2019 Ravil Bikbulatov
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
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 a81fdab6..63f5d9fe 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
@@ -4,9 +4,9 @@ import (
 	"go/ast"
 	"go/token"
 
-	"github.com/go-critic/go-critic/checkers/internal/lintutil"
 	"github.com/go-lintpack/lintpack"
 	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
 	"github.com/go-toolsmith/astequal"
 )
 
@@ -73,7 +73,7 @@ func (c *appendCombineChecker) matchAppend(stmt ast.Stmt, slice ast.Expr) *ast.C
 	// xs are 0-N append arguments, but not variadic argument,
 	// because it makes append combining impossible.
 
-	assign := lintutil.AsAssignStmt(stmt)
+	assign := astcast.ToAssignStmt(stmt)
 	if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
 		return 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
new file mode 100644
index 00000000..85a6f7c6
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
@@ -0,0 +1,98 @@
+package checkers
+
+import (
+	"go/ast"
+	"go/types"
+
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
+	"github.com/go-toolsmith/astcopy"
+	"github.com/go-toolsmith/astp"
+	"github.com/go-toolsmith/typep"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "argOrder"
+	info.Tags = []string{"diagnostic", "experimental"}
+	info.Summary = "Detects suspicious arguments order"
+	info.Before = `strings.HasPrefix("#", userpass)`
+	info.After = `strings.HasPrefix(userpass, "#")`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		return astwalk.WalkerForExpr(&argOrderChecker{ctx: ctx})
+	})
+}
+
+type argOrderChecker struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+}
+
+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.
+	if len(call.Args) != 2 {
+		return
+	}
+
+	calledExpr := astcast.ToSelectorExpr(call.Fun)
+	obj, ok := c.ctx.TypesInfo.ObjectOf(astcast.ToIdent(calledExpr.X)).(*types.PkgName)
+	if !ok || !isStdlibPkg(obj.Imported()) {
+		return
+	}
+
+	x := call.Args[0]
+	y := call.Args[1]
+	switch calledExpr.Sel.Name {
+	case "HasPrefix", "HasSuffix", "Contains", "TrimPrefix", "TrimSuffix", "Split":
+		if obj.Name() != "bytes" && obj.Name() != "strings" {
+			return
+		}
+		if c.isConstLiteral(x) && !c.isConstLiteral(y) {
+			c.warn(call)
+		}
+	}
+}
+
+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.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)
+		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)
+		if !ok || !typep.HasUint8Kind(typ.Elem()) {
+			return false
+		}
+		for _, elt := range x.Elts {
+			if !astp.IsBasicLit(elt) {
+				return false
+			}
+		}
+		return true
+
+	default:
+		return false
+	}
+}
+
+func (c *argOrderChecker) warn(call *ast.CallExpr) {
+	fixed := astcopy.CallExpr(call)
+	fixed.Args[0], fixed.Args[1] = fixed.Args[1], fixed.Args[0]
+	c.ctx.Warn(call, "probably meant `%s`", fixed)
+}
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 65b08143..81fbc2db 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
@@ -1,14 +1,18 @@
 package checkers
 
 import (
+	"fmt"
 	"go/ast"
 	"go/token"
+	"strconv"
 
 	"github.com/go-critic/go-critic/checkers/internal/lintutil"
 	"github.com/go-lintpack/lintpack"
 	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
 	"github.com/go-toolsmith/astcopy"
 	"github.com/go-toolsmith/astequal"
+	"github.com/go-toolsmith/astp"
 	"github.com/go-toolsmith/typep"
 	"golang.org/x/tools/go/ast/astutil"
 )
@@ -37,6 +41,10 @@ type boolExprSimplifyChecker struct {
 }
 
 func (c *boolExprSimplifyChecker) VisitExpr(x ast.Expr) {
+	if !astp.IsBinaryExpr(x) && !astp.IsUnaryExpr(x) {
+		return
+	}
+
 	// Throw away non-bool expressions and avoid redundant
 	// AST copying below.
 	if typ := c.ctx.TypesInfo.TypeOf(x); typ == nil || !typep.HasBoolKind(typ.Underlying()) {
@@ -65,14 +73,16 @@ func (c *boolExprSimplifyChecker) simplifyBool(x ast.Expr) ast.Expr {
 			c.negatedEquals(cur) ||
 			c.invertComparison(cur) ||
 			c.combineChecks(cur) ||
+			c.removeIncDec(cur) ||
+			c.foldRanges(cur) ||
 			true
 	}).(ast.Expr)
 }
 
 func (c *boolExprSimplifyChecker) doubleNegation(cur *astutil.Cursor) bool {
-	neg1 := lintutil.AsUnaryExprOp(cur.Node(), token.NOT)
-	neg2 := lintutil.AsUnaryExprOp(astutil.Unparen(neg1.X), token.NOT)
-	if !lintutil.IsNil(neg1) && !lintutil.IsNil(neg2) {
+	neg1 := astcast.ToUnaryExpr(cur.Node())
+	neg2 := astcast.ToUnaryExpr(astutil.Unparen(neg1.X))
+	if neg1.Op == token.NOT && neg2.Op == token.NOT {
 		cur.Replace(astutil.Unparen(neg2.X))
 		return true
 	}
@@ -84,9 +94,9 @@ func (c *boolExprSimplifyChecker) negatedEquals(cur *astutil.Cursor) bool {
 	if !ok || x.Op != token.EQL {
 		return false
 	}
-	neg1 := lintutil.AsUnaryExprOp(x.X, token.NOT)
-	neg2 := lintutil.AsUnaryExprOp(x.Y, token.NOT)
-	if !lintutil.IsNil(neg1) && !lintutil.IsNil(neg2) {
+	neg1 := astcast.ToUnaryExpr(x.X)
+	neg2 := astcast.ToUnaryExpr(x.Y)
+	if neg1.Op == token.NOT && neg2.Op == token.NOT {
 		x.X = neg1.X
 		x.Y = neg2.X
 		return true
@@ -99,9 +109,9 @@ func (c *boolExprSimplifyChecker) invertComparison(cur *astutil.Cursor) bool {
 		return false
 	}
 
-	neg := lintutil.AsUnaryExprOp(cur.Node(), token.NOT)
-	cmp := lintutil.AsBinaryExpr(astutil.Unparen(neg.X))
-	if lintutil.IsNil(neg) || lintutil.IsNil(cmp) {
+	neg := astcast.ToUnaryExpr(cur.Node())
+	cmp := astcast.ToBinaryExpr(astutil.Unparen(neg.X))
+	if neg.Op != token.NOT {
 		return false
 	}
 
@@ -127,17 +137,23 @@ func (c *boolExprSimplifyChecker) invertComparison(cur *astutil.Cursor) bool {
 	return true
 }
 
+func (c *boolExprSimplifyChecker) isSafe(x ast.Expr) bool {
+	return typep.SideEffectFree(c.ctx.TypesInfo, x)
+}
+
 func (c *boolExprSimplifyChecker) combineChecks(cur *astutil.Cursor) bool {
-	or := lintutil.AsBinaryExprOp(cur.Node(), token.LOR)
-	lhs := lintutil.AsBinaryExpr(astutil.Unparen(or.X))
-	rhs := lintutil.AsBinaryExpr(astutil.Unparen(or.Y))
+	or, ok := cur.Node().(*ast.BinaryExpr)
+	if !ok || or.Op != token.LOR {
+		return false
+	}
+
+	lhs := astcast.ToBinaryExpr(astutil.Unparen(or.X))
+	rhs := astcast.ToBinaryExpr(astutil.Unparen(or.Y))
 
 	if !astequal.Expr(lhs.X, rhs.X) || !astequal.Expr(lhs.Y, rhs.Y) {
 		return false
 	}
-	safe := typep.SideEffectFree(c.ctx.TypesInfo, lhs.X) &&
-		typep.SideEffectFree(c.ctx.TypesInfo, lhs.Y)
-	if !safe {
+	if !c.isSafe(lhs.X) || !c.isSafe(lhs.Y) {
 		return false
 	}
 
@@ -161,6 +177,163 @@ func (c *boolExprSimplifyChecker) combineChecks(cur *astutil.Cursor) bool {
 	return false
 }
 
+func (c *boolExprSimplifyChecker) removeIncDec(cur *astutil.Cursor) bool {
+	cmp := astcast.ToBinaryExpr(cur.Node())
+
+	matchOneWay := func(op token.Token, x, y *ast.BinaryExpr) bool {
+		if x.Op != op || astcast.ToBasicLit(x.Y).Value != "1" {
+			return false
+		}
+		if y.Op == op && astcast.ToBasicLit(y.Y).Value == "1" {
+			return false
+		}
+		return true
+	}
+	replace := func(lhsOp, rhsOp, replacement token.Token) bool {
+		lhs := astcast.ToBinaryExpr(cmp.X)
+		rhs := astcast.ToBinaryExpr(cmp.Y)
+		switch {
+		case matchOneWay(lhsOp, lhs, rhs):
+			cmp.X = lhs.X
+			cmp.Op = replacement
+			cur.Replace(cmp)
+			return true
+		case matchOneWay(rhsOp, rhs, lhs):
+			cmp.Y = rhs.X
+			cmp.Op = replacement
+			cur.Replace(cmp)
+			return true
+		default:
+			return false
+		}
+	}
+
+	switch cmp.Op {
+	case token.GTR:
+		// `x > y-1` => `x >= y`
+		// `x+1 > y` => `x >= y`
+		return replace(token.ADD, token.SUB, token.GEQ)
+
+	case token.GEQ:
+		// `x >= y+1` => `x > y`
+		// `x-1 >= y` => `x > y`
+		return replace(token.SUB, token.ADD, token.GTR)
+
+	case token.LSS:
+		// `x < y+1` => `x <= y`
+		// `x-1 < y` => `x <= y`
+		return replace(token.SUB, token.ADD, token.LEQ)
+
+	case token.LEQ:
+		// `x <= y-1` => `x < y`
+		// `x+1 <= y` => `x < y`
+		return replace(token.ADD, token.SUB, token.LSS)
+
+	default:
+		return false
+	}
+}
+
+func (c *boolExprSimplifyChecker) foldRanges(cur *astutil.Cursor) bool {
+	e, ok := cur.Node().(*ast.BinaryExpr)
+	if !ok {
+		return false
+	}
+	lhs := astcast.ToBinaryExpr(e.X)
+	rhs := astcast.ToBinaryExpr(e.Y)
+	if !c.isSafe(lhs.X) || !c.isSafe(rhs.X) {
+		return false
+	}
+	if !astequal.Expr(lhs.X, rhs.X) {
+		return false
+	}
+
+	c1, ok := c.int64val(lhs.Y)
+	if !ok {
+		return false
+	}
+	c2, ok := c.int64val(rhs.Y)
+	if !ok {
+		return false
+	}
+
+	type combination struct {
+		lhsOp    token.Token
+		rhsOp    token.Token
+		rhsDiff  int64
+		resDelta int64
+	}
+	match := func(comb *combination) bool {
+		if lhs.Op != comb.lhsOp || rhs.Op != comb.rhsOp {
+			return false
+		}
+		if c2-c1 != comb.rhsDiff {
+			return false
+		}
+		return true
+	}
+
+	switch e.Op {
+	case token.LAND:
+		combTable := [...]combination{
+			// `x > c && x < c+2` => `x == c+1`
+			{token.GTR, token.LSS, 2, 1},
+			// `x >= c && x < c+1` => `x == c`
+			{token.GEQ, token.LSS, 1, 0},
+			// `x > c && x <= c+1` => `x == c+1`
+			{token.GTR, token.LEQ, 1, 1},
+			// `x >= c && x <= c` => `x == c`
+			{token.GEQ, token.LEQ, 0, 0},
+		}
+		for _, comb := range combTable {
+			if match(&comb) {
+				lhs.Op = token.EQL
+				v := c1 + comb.resDelta
+				lhs.Y.(*ast.BasicLit).Value = fmt.Sprint(v)
+				cur.Replace(lhs)
+				return true
+			}
+		}
+
+	case token.LOR:
+		combTable := [...]combination{
+			// `x < c || x > c` => `x != c`
+			{token.LSS, token.GTR, 0, 0},
+			// `x <= c || x > c+1` => `x != c+1`
+			{token.LEQ, token.GTR, 1, 1},
+			// `x < c || x >= c+1` => `x != c`
+			{token.LSS, token.GEQ, 1, 0},
+			// `x <= c || x >= c+2` => `x != c+1`
+			{token.LEQ, token.GEQ, 2, 1},
+		}
+		for _, comb := range combTable {
+			if match(&comb) {
+				lhs.Op = token.NEQ
+				v := c1 + comb.resDelta
+				lhs.Y.(*ast.BasicLit).Value = fmt.Sprint(v)
+				cur.Replace(lhs)
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+func (c *boolExprSimplifyChecker) int64val(x ast.Expr) (int64, bool) {
+	// 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 {
+		return 0, false
+	}
+	v, err := strconv.ParseInt(lit.Value, 10, 64)
+	if err != nil {
+		return 0, false
+	}
+	return v, true
+}
+
 func (c *boolExprSimplifyChecker) warn(cause, suggestion ast.Expr) {
 	c.SkipChilds = true
 	c.ctx.Warn(cause, "can simplify `%s` to `%s`", cause, suggestion)
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 f7928f8f..24d8b7ff 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
@@ -16,68 +16,17 @@ func init() {
 	info.After = `length := 10`
 
 	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
-		builtins := map[string]bool{
-			// Types
-			"bool":       true,
-			"byte":       true,
-			"complex64":  true,
-			"complex128": true,
-			"error":      true,
-			"float32":    true,
-			"float64":    true,
-			"int":        true,
-			"int8":       true,
-			"int16":      true,
-			"int32":      true,
-			"int64":      true,
-			"rune":       true,
-			"string":     true,
-			"uint":       true,
-			"uint8":      true,
-			"uint16":     true,
-			"uint32":     true,
-			"uint64":     true,
-			"uintptr":    true,
-
-			// Constants
-			"true":  true,
-			"false": true,
-			"iota":  true,
-
-			// Zero value
-			"nil": true,
-
-			// Functions
-			"append":  true,
-			"cap":     true,
-			"close":   true,
-			"complex": true,
-			"copy":    true,
-			"delete":  true,
-			"imag":    true,
-			"len":     true,
-			"make":    true,
-			"new":     true,
-			"panic":   true,
-			"print":   true,
-			"println": true,
-			"real":    true,
-			"recover": true,
-		}
-		c := &builtinShadowChecker{ctx: ctx, builtins: builtins}
-		return astwalk.WalkerForLocalDef(c, ctx.TypesInfo)
+		return astwalk.WalkerForLocalDef(&builtinShadowChecker{ctx: ctx}, ctx.TypesInfo)
 	})
 }
 
 type builtinShadowChecker struct {
 	astwalk.WalkHandler
 	ctx *lintpack.CheckerContext
-
-	builtins map[string]bool
 }
 
 func (c *builtinShadowChecker) VisitLocalDef(name astwalk.Name, _ ast.Expr) {
-	if _, isBuiltin := c.builtins[name.ID.String()]; isBuiltin {
+	if isBuiltin(name.ID.Name) {
 		c.warn(name.ID)
 	}
 }
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
new file mode 100644
index 00000000..14d89da3
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
@@ -0,0 +1,61 @@
+package checkers
+
+import (
+	"go/ast"
+	"regexp"
+	"strings"
+
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "codegenComment"
+	info.Tags = []string{"diagnostic", "experimental"}
+	info.Summary = "Detects malformed 'code generated' file comments"
+	info.Before = `// This file was automatically generated by foogen`
+	info.After = `// Code generated by foogen. DO NOT EDIT.`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		patterns := []string{
+			"this (?:file|code) (?:was|is) auto(?:matically)? generated",
+			"this (?:file|code) (?:was|is) generated automatically",
+			"this (?:file|code) (?:was|is) generated by",
+			"this (?:file|code) (?:was|is) (?:auto(?:matically)? )?generated",
+			"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.
+		}
+		re := regexp.MustCompile("(?i)" + strings.Join(patterns, "|"))
+		return &codegenCommentChecker{
+			ctx:          ctx,
+			badCommentRE: re,
+		}
+	})
+}
+
+type codegenCommentChecker struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+
+	badCommentRE *regexp.Regexp
+}
+
+func (c *codegenCommentChecker) WalkFile(f *ast.File) {
+	if f.Doc == nil {
+		return
+	}
+
+	for _, comment := range f.Doc.List {
+		if c.badCommentRE.MatchString(comment.Text) {
+			c.warn(comment)
+			return
+		}
+	}
+}
+
+func (c *codegenCommentChecker) warn(cause ast.Node) {
+	c.ctx.Warn(cause, "comment should match `Code generated .* DO NOT EDIT.` regexp")
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go b/vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
index b5dc17e4..ed75015e 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
@@ -20,7 +20,13 @@ func init() {
 	info.After = `// This is a comment`
 
 	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
-		pragmaRE := regexp.MustCompile(`(?m)^//\w+:.*$`)
+		parts := []string{
+			`^//\w+:.*$`,      //key: value
+			`^//nolint$`,      //nolint
+			`^//line /.*:\d+`, //line /path/to/file:123
+		}
+		pat := "(?m)" + strings.Join(parts, "|")
+		pragmaRE := regexp.MustCompile(pat)
 		return astwalk.WalkerForComment(&commentFormattingChecker{
 			ctx:      ctx,
 			pragmaRE: pragmaRE,
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 f8b3e562..d68e32fa 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
@@ -27,6 +27,8 @@ func FuncOld() int`
 		c.commonPatterns = []*regexp.Regexp{
 			regexp.MustCompile(`(?i)this (?:function|type) is deprecated`),
 			regexp.MustCompile(`(?i)deprecated[.!]? use \S* instead`),
+			regexp.MustCompile(`(?i)\[\[deprecated\]\].*`),
+			regexp.MustCompile(`(?i)note: deprecated\b.*`),
 			// TODO(quasilyte): more of these?
 		}
 
@@ -46,6 +48,7 @@ func FuncOld() int`
 			"Deprecate: ",
 			"Derpecate: ",
 			"Derpecated: ",
+			"Depreacted: ",
 		}
 		for i := range c.commonTypos {
 			c.commonTypos[i] = strings.ToUpper(c.commonTypos[i])
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 3eb885aa..431522d8 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
@@ -48,6 +48,9 @@ func init() {
 		c.matchers = map[string]func(*ast.CallExpr) bool{
 			"copy": m["(x, x, ...)"],
 
+			"math.Max": m["(x, x, ...)"],
+			"math.Min": m["(x, x, ...)"],
+
 			"reflect.Copy":      m["(x, x, ...)"],
 			"reflect.DeepEqual": m["(x, x, ...)"],
 
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 3f4fb914..265b2f79 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
@@ -7,6 +7,7 @@ import (
 	"github.com/go-lintpack/lintpack"
 	"github.com/go-lintpack/lintpack/astwalk"
 	"github.com/go-toolsmith/astcast"
+	"github.com/go-toolsmith/astequal"
 )
 
 func init() {
@@ -57,7 +58,9 @@ func (c *equalFoldChecker) checkBytes(expr *ast.CallExpr) {
 	if !ok1 && !ok2 {
 		return
 	}
-	c.warnBytes(expr, x, y)
+	if !astequal.Expr(x, y) {
+		c.warnBytes(expr, x, y)
+	}
 }
 
 func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
@@ -70,7 +73,9 @@ func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
 	if !ok1 && !ok2 {
 		return
 	}
-	c.warnStrings(expr, x, y)
+	if !astequal.Expr(x, y) {
+		c.warnStrings(expr, x, y)
+	}
 }
 
 func (c *equalFoldChecker) warnStrings(cause ast.Node, x, y ast.Expr) {
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 f8d8fc67..1d43ba52 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
@@ -3,6 +3,7 @@ package checkers
 import (
 	"go/ast"
 	"go/constant"
+	"go/types"
 	"strings"
 
 	"github.com/go-lintpack/lintpack"
@@ -30,13 +31,14 @@ type flagNameChecker struct {
 
 func (c *flagNameChecker) VisitExpr(expr ast.Expr) {
 	call := astcast.ToCallExpr(expr)
-	sym := astcast.ToIdent(astcast.ToSelectorExpr(call.Fun).Sel)
-	obj := c.ctx.TypesInfo.ObjectOf(sym)
-	if obj == nil {
+	calledExpr := astcast.ToSelectorExpr(call.Fun)
+	obj, ok := c.ctx.TypesInfo.ObjectOf(astcast.ToIdent(calledExpr.X)).(*types.PkgName)
+	if !ok {
 		return
 	}
-	pkg := obj.Pkg()
-	if !isStdlibPkg(pkg) || pkg.Name() != "flag" {
+	sym := calledExpr.Sel
+	pkg := obj.Imported()
+	if pkg.Path() != "flag" {
 		return
 	}
 
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
new file mode 100644
index 00000000..a700314c
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
@@ -0,0 +1,60 @@
+package checkers
+
+import (
+	"go/ast"
+	"go/token"
+	"strings"
+
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "hexLiteral"
+	info.Tags = []string{"style", "experimental"}
+	info.Summary = "Detects hex literals that have mixed case letter digits"
+	info.Before = `
+x := 0X12
+y := 0xfF`
+	info.After = `
+x := 0x12
+// (A)
+y := 0xff
+// (B)
+y := 0xFF`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		return astwalk.WalkerForExpr(&hexLiteralChecker{ctx: ctx})
+	})
+}
+
+type hexLiteralChecker struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+}
+
+func (c *hexLiteralChecker) warn0X(lit *ast.BasicLit) {
+	suggest := "0x" + lit.Value[len("0X"):]
+	c.ctx.Warn(lit, "prefer 0x over 0X, s/%s/%s/", lit.Value, suggest)
+}
+
+func (c *hexLiteralChecker) warnMixedDigits(lit *ast.BasicLit) {
+	c.ctx.Warn(lit, "don't mix hex literal letter digits casing")
+}
+
+func (c *hexLiteralChecker) VisitExpr(expr ast.Expr) {
+	lit := astcast.ToBasicLit(expr)
+	if lit.Kind != token.INT || len(lit.Value) < 3 {
+		return
+	}
+	if strings.HasPrefix(lit.Value, "0X") {
+		c.warn0X(lit)
+		return
+	}
+	digits := lit.Value[len("0x"):]
+	if strings.ToLower(digits) != digits && strings.ToUpper(digits) != digits {
+		c.warnMixedDigits(lit)
+	}
+}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go b/vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go
deleted file mode 100644
index 8a3e3568..00000000
--- a/vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package lintutil
-
-import (
-	"go/ast"
-	"go/token"
-)
-
-var (
-	nilIdent        = &ast.Ident{}
-	nilSelectorExpr = &ast.SelectorExpr{}
-	nilUnaryExpr    = &ast.UnaryExpr{}
-	nilBinaryExpr   = &ast.BinaryExpr{}
-	nilCallExpr     = &ast.CallExpr{}
-	nilParenExpr    = &ast.ParenExpr{}
-	nilAssignStmt   = &ast.AssignStmt{}
-)
-
-// IsNil reports whether x is nil.
-// Unlike simple nil check, also detects nil AST sentinels.
-func IsNil(x ast.Node) bool {
-	switch x := x.(type) {
-	case *ast.Ident:
-		return x == nilIdent || x == nil
-	case *ast.SelectorExpr:
-		return x == nilSelectorExpr || x == nil
-	case *ast.UnaryExpr:
-		return x == nilUnaryExpr || x == nil
-	case *ast.BinaryExpr:
-		return x == nilBinaryExpr || x == nil
-	case *ast.CallExpr:
-		return x == nilCallExpr || x == nil
-	case *ast.ParenExpr:
-		return x == nilParenExpr || x == nil
-	case *ast.AssignStmt:
-		return x == nilAssignStmt || x == nil
-
-	default:
-		return x == nil
-	}
-}
-
-// AsIdent coerces x into non-nil ident.
-func AsIdent(x ast.Node) *ast.Ident {
-	e, ok := x.(*ast.Ident)
-	if !ok {
-		return nilIdent
-	}
-	return e
-}
-
-// AsSelectorExpr coerces x into non-nil selector expr.
-func AsSelectorExpr(x ast.Node) *ast.SelectorExpr {
-	e, ok := x.(*ast.SelectorExpr)
-	if !ok {
-		return nilSelectorExpr
-	}
-	return e
-}
-
-// AsUnaryExpr coerces x into non-nil unary expr.
-func AsUnaryExpr(x ast.Node) *ast.UnaryExpr {
-	e, ok := x.(*ast.UnaryExpr)
-	if !ok {
-		return nilUnaryExpr
-	}
-	return e
-}
-
-// AsUnaryExprOp is like AsUnaryExpr, but also checks for op token.
-func AsUnaryExprOp(x ast.Node, op token.Token) *ast.UnaryExpr {
-	e, ok := x.(*ast.UnaryExpr)
-	if !ok || e.Op != op {
-		return nilUnaryExpr
-	}
-	return e
-}
-
-// AsBinaryExpr coerces x into non-nil binary expr.
-func AsBinaryExpr(x ast.Node) *ast.BinaryExpr {
-	e, ok := x.(*ast.BinaryExpr)
-	if !ok {
-		return nilBinaryExpr
-	}
-	return e
-}
-
-// AsBinaryExprOp is like AsBinaryExpr, but also checks for op token.
-func AsBinaryExprOp(x ast.Node, op token.Token) *ast.BinaryExpr {
-	e, ok := x.(*ast.BinaryExpr)
-	if !ok || e.Op != op {
-		return nilBinaryExpr
-	}
-	return e
-}
-
-// AsCallExpr coerces x into non-nil call expr.
-func AsCallExpr(x ast.Node) *ast.CallExpr {
-	e, ok := x.(*ast.CallExpr)
-	if !ok {
-		return nilCallExpr
-	}
-	return e
-}
-
-// AsParenExpr coerces x into non-nil paren expr.
-func AsParenExpr(x ast.Node) *ast.ParenExpr {
-	e, ok := x.(*ast.ParenExpr)
-	if !ok {
-		return nilParenExpr
-	}
-	return e
-}
-
-// AsAssignStmt coerces x into non-nil assign stmt.
-func AsAssignStmt(x ast.Node) *ast.AssignStmt {
-	stmt, ok := x.(*ast.AssignStmt)
-	if !ok {
-		return nilAssignStmt
-	}
-	return stmt
-}
diff --git a/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go b/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
new file mode 100644
index 00000000..e40ec6db
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
@@ -0,0 +1,82 @@
+package checkers
+
+import (
+	"go/ast"
+	"go/token"
+	"go/types"
+
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "octalLiteral"
+	info.Tags = []string{"diagnostic", "experimental"}
+	info.Summary = "Detects octal literals passed to functions"
+	info.Before = `foo(02)`
+	info.After = `foo(2)`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		c := &octalLiteralChecker{
+			ctx: ctx,
+			octFriendlyPkg: map[string]bool{
+				"os":        true,
+				"io/ioutil": true,
+			},
+		}
+		return astwalk.WalkerForExpr(c)
+	})
+}
+
+type octalLiteralChecker struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+
+	octFriendlyPkg map[string]bool
+}
+
+func (c *octalLiteralChecker) VisitExpr(expr ast.Expr) {
+	call := astcast.ToCallExpr(expr)
+	calledExpr := astcast.ToSelectorExpr(call.Fun)
+	ident := astcast.ToIdent(calledExpr.X)
+
+	if obj, ok := c.ctx.TypesInfo.ObjectOf(ident).(*types.PkgName); ok {
+		pkg := obj.Imported()
+		if c.octFriendlyPkg[pkg.Path()] {
+			return
+		}
+	}
+
+	for _, arg := range call.Args {
+		if lit := astcast.ToBasicLit(c.unsign(arg)); len(lit.Value) > 1 &&
+			c.isIntLiteral(lit) &&
+			c.isOctalLiteral(lit) {
+			c.warn(call)
+			return
+		}
+	}
+}
+
+func (c *octalLiteralChecker) unsign(e ast.Expr) ast.Expr {
+	u, ok := e.(*ast.UnaryExpr)
+	if !ok {
+		return e
+	}
+	return u.X
+}
+
+func (c *octalLiteralChecker) isIntLiteral(lit *ast.BasicLit) bool {
+	return lit.Kind == token.INT
+}
+
+func (c *octalLiteralChecker) isOctalLiteral(lit *ast.BasicLit) bool {
+	return lit.Value[0] == '0' &&
+		lit.Value[1] != 'x' &&
+		lit.Value[1] != 'X'
+}
+
+func (c *octalLiteralChecker) warn(expr ast.Expr) {
+	c.ctx.Warn(expr, "suspicious octal args in `%s`", expr)
+}
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
new file mode 100644
index 00000000..74570108
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
@@ -0,0 +1,47 @@
+package checkers
+
+import (
+	"go/ast"
+
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/typep"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "stringXbytes"
+	info.Tags = []string{"style", "experimental"}
+	info.Summary = "Detects redundant conversions between string and []byte"
+	info.Before = `copy(b, []byte(s))`
+	info.After = `copy(b, s)`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		return astwalk.WalkerForExpr(&stringXbytes{ctx: ctx})
+	})
+}
+
+type stringXbytes struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+}
+
+func (c *stringXbytes) VisitExpr(expr ast.Expr) {
+	x, ok := expr.(*ast.CallExpr)
+	if !ok || qualifiedName(x.Fun) != "copy" {
+		return
+	}
+
+	src := x.Args[1]
+
+	byteCast, ok := src.(*ast.CallExpr)
+	if ok && typep.IsTypeExpr(c.ctx.TypesInfo, byteCast.Fun) &&
+		typep.HasStringProp(c.ctx.TypesInfo.TypeOf(byteCast.Args[0])) {
+
+		c.warn(byteCast, byteCast.Args[0])
+	}
+}
+
+func (c *stringXbytes) warn(cause *ast.CallExpr, suggestion ast.Expr) {
+	c.ctx.Warn(cause, "can simplify `%s` to `%s`", cause, suggestion)
+}
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
new file mode 100644
index 00000000..c0c42e35
--- /dev/null
+++ b/vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
@@ -0,0 +1,132 @@
+package checkers
+
+import (
+	"go/ast"
+	"go/token"
+
+	"github.com/go-critic/go-critic/checkers/internal/lintutil"
+	"github.com/go-lintpack/lintpack"
+	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
+	"github.com/go-toolsmith/astequal"
+	"github.com/go-toolsmith/astp"
+)
+
+func init() {
+	var info lintpack.CheckerInfo
+	info.Name = "typeAssertChain"
+	info.Tags = []string{"style", "experimental"}
+	info.Summary = "Detects repeated type assertions and suggests to replace them with type switch statement"
+	info.Before = `
+if x, ok := v.(T1); ok {
+	// Code A, uses x.
+} else if x, ok := v.(T2); ok {
+	// Code B, uses x.
+} else if x, ok := v.(T3); ok {
+	// Code C, uses x.
+}`
+	info.After = `
+switch x := v.(T1) {
+case cond1:
+	// Code A, uses x.
+case cond2:
+	// Code B, uses x.
+default:
+	// Code C, uses x.
+}`
+
+	collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
+		return astwalk.WalkerForStmt(&typeAssertChainChecker{ctx: ctx})
+	})
+}
+
+type typeAssertChainChecker struct {
+	astwalk.WalkHandler
+	ctx *lintpack.CheckerContext
+
+	cause   *ast.IfStmt
+	visited map[*ast.IfStmt]bool
+	typeSet lintutil.AstSet
+}
+
+func (c *typeAssertChainChecker) EnterFunc(fn *ast.FuncDecl) bool {
+	if fn.Body == nil {
+		return false
+	}
+	c.visited = make(map[*ast.IfStmt]bool)
+	return true
+}
+
+func (c *typeAssertChainChecker) VisitStmt(stmt ast.Stmt) {
+	ifstmt, ok := stmt.(*ast.IfStmt)
+	if !ok || c.visited[ifstmt] || ifstmt.Init == nil {
+		return
+	}
+	assertion := c.getTypeAssert(ifstmt)
+	if assertion == nil {
+		return
+	}
+	c.cause = ifstmt
+	c.checkIfStmt(ifstmt, assertion)
+}
+
+func (c *typeAssertChainChecker) getTypeAssert(ifstmt *ast.IfStmt) *ast.TypeAssertExpr {
+	assign := astcast.ToAssignStmt(ifstmt.Init)
+	if len(assign.Lhs) != 2 || len(assign.Rhs) != 1 {
+		return nil
+	}
+	if !astp.IsIdent(assign.Lhs[0]) || assign.Tok != token.DEFINE {
+		return nil
+	}
+	if !astequal.Expr(assign.Lhs[1], ifstmt.Cond) {
+		return nil
+	}
+
+	assertion, ok := assign.Rhs[0].(*ast.TypeAssertExpr)
+	if !ok {
+		return nil
+	}
+	return assertion
+}
+
+func (c *typeAssertChainChecker) checkIfStmt(stmt *ast.IfStmt, assertion *ast.TypeAssertExpr) {
+	if c.countTypeAssertions(stmt, assertion) >= 2 {
+		c.warn()
+	}
+}
+
+func (c *typeAssertChainChecker) countTypeAssertions(stmt *ast.IfStmt, assertion *ast.TypeAssertExpr) int {
+	c.typeSet.Clear()
+
+	count := 1
+	x := assertion.X
+	c.typeSet.Insert(assertion.Type)
+	for {
+		e, ok := stmt.Else.(*ast.IfStmt)
+		if !ok {
+			return count
+		}
+		assertion = c.getTypeAssert(e)
+		if assertion == nil {
+			return count
+		}
+		if !c.typeSet.Insert(assertion.Type) {
+			// Asserted type is duplicated.
+			// Type switch does not permit duplicate cases,
+			// so give up.
+			return 0
+		}
+		if !astequal.Expr(x, assertion.X) {
+			// Mixed type asserting chain.
+			// Can't be easily translated to a type switch.
+			return 0
+		}
+		stmt = e
+		count++
+		c.visited[e] = true
+	}
+}
+
+func (c *typeAssertChainChecker) warn() {
+	c.ctx.Warn(c.cause, "rewrite if-else to type switch statement")
+}
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 3c248ba8..dfc6077b 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
@@ -4,9 +4,9 @@ import (
 	"go/ast"
 	"go/types"
 
-	"github.com/go-critic/go-critic/checkers/internal/lintutil"
 	"github.com/go-lintpack/lintpack"
 	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
 	"github.com/go-toolsmith/astp"
 )
 
@@ -45,7 +45,7 @@ type underefChecker struct {
 func (c *underefChecker) VisitExpr(expr ast.Expr) {
 	switch n := expr.(type) {
 	case *ast.SelectorExpr:
-		expr := lintutil.AsParenExpr(n.X)
+		expr := astcast.ToParenExpr(n.X)
 		if c.skipRecvDeref && c.isPtrRecvMethodCall(n.Sel) {
 			return
 		}
@@ -56,7 +56,7 @@ func (c *underefChecker) VisitExpr(expr ast.Expr) {
 			}
 		}
 	case *ast.IndexExpr:
-		expr := lintutil.AsParenExpr(n.X)
+		expr := astcast.ToParenExpr(n.X)
 		if expr, ok := expr.X.(*ast.StarExpr); ok {
 			if !c.checkStarExpr(expr) {
 				return
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 e7231ce8..846bb14d 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
@@ -4,9 +4,9 @@ import (
 	"go/ast"
 	"go/types"
 
-	"github.com/go-critic/go-critic/checkers/internal/lintutil"
 	"github.com/go-lintpack/lintpack"
 	"github.com/go-lintpack/lintpack/astwalk"
+	"github.com/go-toolsmith/astcast"
 	"github.com/go-toolsmith/astequal"
 )
 
@@ -39,11 +39,14 @@ func (c *unlambdaChecker) VisitExpr(x ast.Expr) {
 		return
 	}
 
-	result := lintutil.AsCallExpr(ret.Results[0])
+	result := astcast.ToCallExpr(ret.Results[0])
 	callable := qualifiedName(result.Fun)
 	if callable == "" {
 		return // Skip tricky cases; only handle simple calls
 	}
+	if isBuiltin(callable) {
+		return // See #762
+	}
 	fnType := c.ctx.TypesInfo.TypeOf(fn)
 	resultType := c.ctx.TypesInfo.TypeOf(result.Fun)
 	if !types.Identical(fnType, resultType) {
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 0a575e81..09423250 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
@@ -44,7 +44,7 @@ func (c *unnamedResultChecker) VisitFuncDecl(decl *ast.FuncDecl) {
 	switch {
 	case results == nil:
 		return // Function has no results
-	case len(results.List) > 0 && results.List[0].Names != nil:
+	case len(results.List) != 0 && results.List[0].Names != nil:
 		return // Skip named results
 	}
 
diff --git a/vendor/github.com/go-critic/go-critic/checkers/utils.go b/vendor/github.com/go-critic/go-critic/checkers/utils.go
index b59e9188..f25a82ef 100644
--- a/vendor/github.com/go-critic/go-critic/checkers/utils.go
+++ b/vendor/github.com/go-critic/go-critic/checkers/utils.go
@@ -8,6 +8,60 @@ import (
 	"github.com/go-lintpack/lintpack"
 )
 
+var goBuiltins = map[string]bool{
+	// Types
+	"bool":       true,
+	"byte":       true,
+	"complex64":  true,
+	"complex128": true,
+	"error":      true,
+	"float32":    true,
+	"float64":    true,
+	"int":        true,
+	"int8":       true,
+	"int16":      true,
+	"int32":      true,
+	"int64":      true,
+	"rune":       true,
+	"string":     true,
+	"uint":       true,
+	"uint8":      true,
+	"uint16":     true,
+	"uint32":     true,
+	"uint64":     true,
+	"uintptr":    true,
+
+	// Constants
+	"true":  true,
+	"false": true,
+	"iota":  true,
+
+	// Zero value
+	"nil": true,
+
+	// Functions
+	"append":  true,
+	"cap":     true,
+	"close":   true,
+	"complex": true,
+	"copy":    true,
+	"delete":  true,
+	"imag":    true,
+	"len":     true,
+	"make":    true,
+	"new":     true,
+	"panic":   true,
+	"print":   true,
+	"println": true,
+	"real":    true,
+	"recover": true,
+}
+
+// isBuiltin reports whether sym belongs to a predefined identifier set.
+func isBuiltin(sym string) bool {
+	return goBuiltins[sym]
+}
+
 // isStdlibPkg reports whether pkg is a package from the Go standard library.
 func isStdlibPkg(pkg *types.Package) bool {
 	return pkg != nil && pkg.Path() == pkg.Name()
diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
new file mode 100644
index 00000000..be671c79
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
@@ -0,0 +1,723 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Indexed binary package export.
+// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go;
+// see that file for specification of the format.
+
+// +build go1.11
+
+package gcimporter
+
+import (
+	"bytes"
+	"encoding/binary"
+	"go/ast"
+	"go/constant"
+	"go/token"
+	"go/types"
+	"io"
+	"math/big"
+	"reflect"
+	"sort"
+)
+
+// Current indexed export format version. Increase with each format change.
+// 0: Go1.11 encoding
+const iexportVersion = 0
+
+// IExportData returns the binary export data for pkg.
+// If no file set is provided, position info will be missing.
+func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
+	defer func() {
+		if e := recover(); e != nil {
+			if ierr, ok := e.(internalError); ok {
+				err = ierr
+				return
+			}
+			// Not an internal error; panic again.
+			panic(e)
+		}
+	}()
+
+	p := iexporter{
+		out:         bytes.NewBuffer(nil),
+		fset:        fset,
+		allPkgs:     map[*types.Package]bool{},
+		stringIndex: map[string]uint64{},
+		declIndex:   map[types.Object]uint64{},
+		typIndex:    map[types.Type]uint64{},
+	}
+
+	for i, pt := range predeclared() {
+		p.typIndex[pt] = uint64(i)
+	}
+	if len(p.typIndex) > predeclReserved {
+		panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
+	}
+
+	// Initialize work queue with exported declarations.
+	scope := pkg.Scope()
+	for _, name := range scope.Names() {
+		if ast.IsExported(name) {
+			p.pushDecl(scope.Lookup(name))
+		}
+	}
+
+	// Loop until no more work.
+	for !p.declTodo.empty() {
+		p.doDecl(p.declTodo.popHead())
+	}
+
+	// Append indices to data0 section.
+	dataLen := uint64(p.data0.Len())
+	w := p.newWriter()
+	w.writeIndex(p.declIndex, pkg)
+	w.flush()
+
+	// Assemble header.
+	var hdr intWriter
+	hdr.WriteByte('i')
+	hdr.uint64(iexportVersion)
+	hdr.uint64(uint64(p.strings.Len()))
+	hdr.uint64(dataLen)
+
+	// Flush output.
+	io.Copy(p.out, &hdr)
+	io.Copy(p.out, &p.strings)
+	io.Copy(p.out, &p.data0)
+
+	return p.out.Bytes(), nil
+}
+
+// writeIndex writes out an object index. mainIndex indicates whether
+// we're writing out the main index, which is also read by
+// non-compiler tools and includes a complete package description
+// (i.e., name and height).
+func (w *exportWriter) writeIndex(index map[types.Object]uint64, localpkg *types.Package) {
+	// Build a map from packages to objects from that package.
+	pkgObjs := map[*types.Package][]types.Object{}
+
+	// For the main index, make sure to include every package that
+	// we reference, even if we're not exporting (or reexporting)
+	// any symbols from it.
+	pkgObjs[localpkg] = nil
+	for pkg := range w.p.allPkgs {
+		pkgObjs[pkg] = nil
+	}
+
+	for obj := range index {
+		pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], obj)
+	}
+
+	var pkgs []*types.Package
+	for pkg, objs := range pkgObjs {
+		pkgs = append(pkgs, pkg)
+
+		sort.Slice(objs, func(i, j int) bool {
+			return objs[i].Name() < objs[j].Name()
+		})
+	}
+
+	sort.Slice(pkgs, func(i, j int) bool {
+		return pkgs[i].Path() < pkgs[j].Path()
+	})
+
+	w.uint64(uint64(len(pkgs)))
+	for _, pkg := range pkgs {
+		w.string(pkg.Path())
+		w.string(pkg.Name())
+		w.uint64(uint64(0)) // package height is not needed for go/types
+
+		objs := pkgObjs[pkg]
+		w.uint64(uint64(len(objs)))
+		for _, obj := range objs {
+			w.string(obj.Name())
+			w.uint64(index[obj])
+		}
+	}
+}
+
+type iexporter struct {
+	fset *token.FileSet
+	out  *bytes.Buffer
+
+	// allPkgs tracks all packages that have been referenced by
+	// the export data, so we can ensure to include them in the
+	// main index.
+	allPkgs map[*types.Package]bool
+
+	declTodo objQueue
+
+	strings     intWriter
+	stringIndex map[string]uint64
+
+	data0     intWriter
+	declIndex map[types.Object]uint64
+	typIndex  map[types.Type]uint64
+}
+
+// stringOff returns the offset of s within the string section.
+// If not already present, it's added to the end.
+func (p *iexporter) stringOff(s string) uint64 {
+	off, ok := p.stringIndex[s]
+	if !ok {
+		off = uint64(p.strings.Len())
+		p.stringIndex[s] = off
+
+		p.strings.uint64(uint64(len(s)))
+		p.strings.WriteString(s)
+	}
+	return off
+}
+
+// pushDecl adds n to the declaration work queue, if not already present.
+func (p *iexporter) pushDecl(obj types.Object) {
+	// Package unsafe is known to the compiler and predeclared.
+	assert(obj.Pkg() != types.Unsafe)
+
+	if _, ok := p.declIndex[obj]; ok {
+		return
+	}
+
+	p.declIndex[obj] = ^uint64(0) // mark n present in work queue
+	p.declTodo.pushTail(obj)
+}
+
+// exportWriter handles writing out individual data section chunks.
+type exportWriter struct {
+	p *iexporter
+
+	data     intWriter
+	currPkg  *types.Package
+	prevFile string
+	prevLine int64
+}
+
+func (p *iexporter) doDecl(obj types.Object) {
+	w := p.newWriter()
+	w.setPkg(obj.Pkg(), false)
+
+	switch obj := obj.(type) {
+	case *types.Var:
+		w.tag('V')
+		w.pos(obj.Pos())
+		w.typ(obj.Type(), obj.Pkg())
+
+	case *types.Func:
+		sig, _ := obj.Type().(*types.Signature)
+		if sig.Recv() != nil {
+			panic(internalErrorf("unexpected method: %v", sig))
+		}
+		w.tag('F')
+		w.pos(obj.Pos())
+		w.signature(sig)
+
+	case *types.Const:
+		w.tag('C')
+		w.pos(obj.Pos())
+		w.value(obj.Type(), obj.Val())
+
+	case *types.TypeName:
+		if obj.IsAlias() {
+			w.tag('A')
+			w.pos(obj.Pos())
+			w.typ(obj.Type(), obj.Pkg())
+			break
+		}
+
+		// Defined type.
+		w.tag('T')
+		w.pos(obj.Pos())
+
+		underlying := obj.Type().Underlying()
+		w.typ(underlying, obj.Pkg())
+
+		t := obj.Type()
+		if types.IsInterface(t) {
+			break
+		}
+
+		named, ok := t.(*types.Named)
+		if !ok {
+			panic(internalErrorf("%s is not a defined type", t))
+		}
+
+		n := named.NumMethods()
+		w.uint64(uint64(n))
+		for i := 0; i < n; i++ {
+			m := named.Method(i)
+			w.pos(m.Pos())
+			w.string(m.Name())
+			sig, _ := m.Type().(*types.Signature)
+			w.param(sig.Recv())
+			w.signature(sig)
+		}
+
+	default:
+		panic(internalErrorf("unexpected object: %v", obj))
+	}
+
+	p.declIndex[obj] = w.flush()
+}
+
+func (w *exportWriter) tag(tag byte) {
+	w.data.WriteByte(tag)
+}
+
+func (w *exportWriter) pos(pos token.Pos) {
+	p := w.p.fset.Position(pos)
+	file := p.Filename
+	line := int64(p.Line)
+
+	// When file is the same as the last position (common case),
+	// we can save a few bytes by delta encoding just the line
+	// number.
+	//
+	// Note: Because data objects may be read out of order (or not
+	// at all), we can only apply delta encoding within a single
+	// object. This is handled implicitly by tracking prevFile and
+	// prevLine as fields of exportWriter.
+
+	if file == w.prevFile {
+		delta := line - w.prevLine
+		w.int64(delta)
+		if delta == deltaNewFile {
+			w.int64(-1)
+		}
+	} else {
+		w.int64(deltaNewFile)
+		w.int64(line) // line >= 0
+		w.string(file)
+		w.prevFile = file
+	}
+	w.prevLine = line
+}
+
+func (w *exportWriter) pkg(pkg *types.Package) {
+	// Ensure any referenced packages are declared in the main index.
+	w.p.allPkgs[pkg] = true
+
+	w.string(pkg.Path())
+}
+
+func (w *exportWriter) qualifiedIdent(obj types.Object) {
+	// Ensure any referenced declarations are written out too.
+	w.p.pushDecl(obj)
+
+	w.string(obj.Name())
+	w.pkg(obj.Pkg())
+}
+
+func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
+	w.data.uint64(w.p.typOff(t, pkg))
+}
+
+func (p *iexporter) newWriter() *exportWriter {
+	return &exportWriter{p: p}
+}
+
+func (w *exportWriter) flush() uint64 {
+	off := uint64(w.p.data0.Len())
+	io.Copy(&w.p.data0, &w.data)
+	return off
+}
+
+func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
+	off, ok := p.typIndex[t]
+	if !ok {
+		w := p.newWriter()
+		w.doTyp(t, pkg)
+		off = predeclReserved + w.flush()
+		p.typIndex[t] = off
+	}
+	return off
+}
+
+func (w *exportWriter) startType(k itag) {
+	w.data.uint64(uint64(k))
+}
+
+func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
+	switch t := t.(type) {
+	case *types.Named:
+		w.startType(definedType)
+		w.qualifiedIdent(t.Obj())
+
+	case *types.Pointer:
+		w.startType(pointerType)
+		w.typ(t.Elem(), pkg)
+
+	case *types.Slice:
+		w.startType(sliceType)
+		w.typ(t.Elem(), pkg)
+
+	case *types.Array:
+		w.startType(arrayType)
+		w.uint64(uint64(t.Len()))
+		w.typ(t.Elem(), pkg)
+
+	case *types.Chan:
+		w.startType(chanType)
+		// 1 RecvOnly; 2 SendOnly; 3 SendRecv
+		var dir uint64
+		switch t.Dir() {
+		case types.RecvOnly:
+			dir = 1
+		case types.SendOnly:
+			dir = 2
+		case types.SendRecv:
+			dir = 3
+		}
+		w.uint64(dir)
+		w.typ(t.Elem(), pkg)
+
+	case *types.Map:
+		w.startType(mapType)
+		w.typ(t.Key(), pkg)
+		w.typ(t.Elem(), pkg)
+
+	case *types.Signature:
+		w.startType(signatureType)
+		w.setPkg(pkg, true)
+		w.signature(t)
+
+	case *types.Struct:
+		w.startType(structType)
+		w.setPkg(pkg, true)
+
+		n := t.NumFields()
+		w.uint64(uint64(n))
+		for i := 0; i < n; i++ {
+			f := t.Field(i)
+			w.pos(f.Pos())
+			w.string(f.Name())
+			w.typ(f.Type(), pkg)
+			w.bool(f.Embedded())
+			w.string(t.Tag(i)) // note (or tag)
+		}
+
+	case *types.Interface:
+		w.startType(interfaceType)
+		w.setPkg(pkg, true)
+
+		n := t.NumEmbeddeds()
+		w.uint64(uint64(n))
+		for i := 0; i < n; i++ {
+			f := t.Embedded(i)
+			w.pos(f.Obj().Pos())
+			w.typ(f.Obj().Type(), f.Obj().Pkg())
+		}
+
+		n = t.NumExplicitMethods()
+		w.uint64(uint64(n))
+		for i := 0; i < n; i++ {
+			m := t.ExplicitMethod(i)
+			w.pos(m.Pos())
+			w.string(m.Name())
+			sig, _ := m.Type().(*types.Signature)
+			w.signature(sig)
+		}
+
+	default:
+		panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
+	}
+}
+
+func (w *exportWriter) setPkg(pkg *types.Package, write bool) {
+	if write {
+		w.pkg(pkg)
+	}
+
+	w.currPkg = pkg
+}
+
+func (w *exportWriter) signature(sig *types.Signature) {
+	w.paramList(sig.Params())
+	w.paramList(sig.Results())
+	if sig.Params().Len() > 0 {
+		w.bool(sig.Variadic())
+	}
+}
+
+func (w *exportWriter) paramList(tup *types.Tuple) {
+	n := tup.Len()
+	w.uint64(uint64(n))
+	for i := 0; i < n; i++ {
+		w.param(tup.At(i))
+	}
+}
+
+func (w *exportWriter) param(obj types.Object) {
+	w.pos(obj.Pos())
+	w.localIdent(obj)
+	w.typ(obj.Type(), obj.Pkg())
+}
+
+func (w *exportWriter) value(typ types.Type, v constant.Value) {
+	w.typ(typ, nil)
+
+	switch v.Kind() {
+	case constant.Bool:
+		w.bool(constant.BoolVal(v))
+	case constant.Int:
+		var i big.Int
+		if i64, exact := constant.Int64Val(v); exact {
+			i.SetInt64(i64)
+		} else if ui64, exact := constant.Uint64Val(v); exact {
+			i.SetUint64(ui64)
+		} else {
+			i.SetString(v.ExactString(), 10)
+		}
+		w.mpint(&i, typ)
+	case constant.Float:
+		f := constantToFloat(v)
+		w.mpfloat(f, typ)
+	case constant.Complex:
+		w.mpfloat(constantToFloat(constant.Real(v)), typ)
+		w.mpfloat(constantToFloat(constant.Imag(v)), typ)
+	case constant.String:
+		w.string(constant.StringVal(v))
+	case constant.Unknown:
+		// package contains type errors
+	default:
+		panic(internalErrorf("unexpected value %v (%T)", v, v))
+	}
+}
+
+// constantToFloat converts a constant.Value with kind constant.Float to a
+// big.Float.
+func constantToFloat(x constant.Value) *big.Float {
+	assert(x.Kind() == constant.Float)
+	// Use the same floating-point precision (512) as cmd/compile
+	// (see Mpprec in cmd/compile/internal/gc/mpfloat.go).
+	const mpprec = 512
+	var f big.Float
+	f.SetPrec(mpprec)
+	if v, exact := constant.Float64Val(x); exact {
+		// float64
+		f.SetFloat64(v)
+	} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
+		// TODO(gri): add big.Rat accessor to constant.Value.
+		n := valueToRat(num)
+		d := valueToRat(denom)
+		f.SetRat(n.Quo(n, d))
+	} else {
+		// Value too large to represent as a fraction => inaccessible.
+		// TODO(gri): add big.Float accessor to constant.Value.
+		_, ok := f.SetString(x.ExactString())
+		assert(ok)
+	}
+	return &f
+}
+
+// mpint exports a multi-precision integer.
+//
+// For unsigned types, small values are written out as a single
+// byte. Larger values are written out as a length-prefixed big-endian
+// byte string, where the length prefix is encoded as its complement.
+// For example, bytes 0, 1, and 2 directly represent the integer
+// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
+// 2-, and 3-byte big-endian string follow.
+//
+// Encoding for signed types use the same general approach as for
+// unsigned types, except small values use zig-zag encoding and the
+// bottom bit of length prefix byte for large values is reserved as a
+// sign bit.
+//
+// The exact boundary between small and large encodings varies
+// according to the maximum number of bytes needed to encode a value
+// of type typ. As a special case, 8-bit types are always encoded as a
+// single byte.
+//
+// TODO(mdempsky): Is this level of complexity really worthwhile?
+func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
+	basic, ok := typ.Underlying().(*types.Basic)
+	if !ok {
+		panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
+	}
+
+	signed, maxBytes := intSize(basic)
+
+	negative := x.Sign() < 0
+	if !signed && negative {
+		panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
+	}
+
+	b := x.Bytes()
+	if len(b) > 0 && b[0] == 0 {
+		panic(internalErrorf("leading zeros"))
+	}
+	if uint(len(b)) > maxBytes {
+		panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
+	}
+
+	maxSmall := 256 - maxBytes
+	if signed {
+		maxSmall = 256 - 2*maxBytes
+	}
+	if maxBytes == 1 {
+		maxSmall = 256
+	}
+
+	// Check if x can use small value encoding.
+	if len(b) <= 1 {
+		var ux uint
+		if len(b) == 1 {
+			ux = uint(b[0])
+		}
+		if signed {
+			ux <<= 1
+			if negative {
+				ux--
+			}
+		}
+		if ux < maxSmall {
+			w.data.WriteByte(byte(ux))
+			return
+		}
+	}
+
+	n := 256 - uint(len(b))
+	if signed {
+		n = 256 - 2*uint(len(b))
+		if negative {
+			n |= 1
+		}
+	}
+	if n < maxSmall || n >= 256 {
+		panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
+	}
+
+	w.data.WriteByte(byte(n))
+	w.data.Write(b)
+}
+
+// mpfloat exports a multi-precision floating point number.
+//
+// The number's value is decomposed into mantissa × 2**exponent, where
+// mantissa is an integer. The value is written out as mantissa (as a
+// multi-precision integer) and then the exponent, except exponent is
+// omitted if mantissa is zero.
+func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
+	if f.IsInf() {
+		panic("infinite constant")
+	}
+
+	// Break into f = mant × 2**exp, with 0.5 <= mant < 1.
+	var mant big.Float
+	exp := int64(f.MantExp(&mant))
+
+	// Scale so that mant is an integer.
+	prec := mant.MinPrec()
+	mant.SetMantExp(&mant, int(prec))
+	exp -= int64(prec)
+
+	manti, acc := mant.Int(nil)
+	if acc != big.Exact {
+		panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
+	}
+	w.mpint(manti, typ)
+	if manti.Sign() != 0 {
+		w.int64(exp)
+	}
+}
+
+func (w *exportWriter) bool(b bool) bool {
+	var x uint64
+	if b {
+		x = 1
+	}
+	w.uint64(x)
+	return b
+}
+
+func (w *exportWriter) int64(x int64)   { w.data.int64(x) }
+func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
+func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
+
+func (w *exportWriter) localIdent(obj types.Object) {
+	// Anonymous parameters.
+	if obj == nil {
+		w.string("")
+		return
+	}
+
+	name := obj.Name()
+	if name == "_" {
+		w.string("_")
+		return
+	}
+
+	w.string(name)
+}
+
+type intWriter struct {
+	bytes.Buffer
+}
+
+func (w *intWriter) int64(x int64) {
+	var buf [binary.MaxVarintLen64]byte
+	n := binary.PutVarint(buf[:], x)
+	w.Write(buf[:n])
+}
+
+func (w *intWriter) uint64(x uint64) {
+	var buf [binary.MaxVarintLen64]byte
+	n := binary.PutUvarint(buf[:], x)
+	w.Write(buf[:n])
+}
+
+func assert(cond bool) {
+	if !cond {
+		panic("internal error: assertion failed")
+	}
+}
+
+// The below is copied from go/src/cmd/compile/internal/gc/syntax.go.
+
+// objQueue is a FIFO queue of types.Object. The zero value of objQueue is
+// a ready-to-use empty queue.
+type objQueue struct {
+	ring       []types.Object
+	head, tail int
+}
+
+// empty returns true if q contains no Nodes.
+func (q *objQueue) empty() bool {
+	return q.head == q.tail
+}
+
+// pushTail appends n to the tail of the queue.
+func (q *objQueue) pushTail(obj types.Object) {
+	if len(q.ring) == 0 {
+		q.ring = make([]types.Object, 16)
+	} else if q.head+len(q.ring) == q.tail {
+		// Grow the ring.
+		nring := make([]types.Object, len(q.ring)*2)
+		// Copy the old elements.
+		part := q.ring[q.head%len(q.ring):]
+		if q.tail-q.head <= len(part) {
+			part = part[:q.tail-q.head]
+			copy(nring, part)
+		} else {
+			pos := copy(nring, part)
+			copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
+		}
+		q.ring, q.head, q.tail = nring, 0, q.tail-q.head
+	}
+
+	q.ring[q.tail%len(q.ring)] = obj
+	q.tail++
+}
+
+// popHead pops a node from the head of the queue. It panics if q is empty.
+func (q *objQueue) popHead() types.Object {
+	if q.empty() {
+		panic("dequeue empty")
+	}
+	obj := q.ring[q.head%len(q.ring)]
+	q.head++
+	return obj
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 24d145cb..4347427c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -10,7 +10,7 @@ github.com/davecgh/go-spew/spew
 github.com/fatih/color
 # github.com/fsnotify/fsnotify v1.4.7
 github.com/fsnotify/fsnotify
-# github.com/go-critic/go-critic v0.0.0-20181204210945-0af0999fabfb
+# github.com/go-critic/go-critic v0.0.0-20181204210945-ee9bf5809ead
 github.com/go-critic/go-critic/checkers
 github.com/go-critic/go-critic/checkers/internal/lintutil
 # github.com/go-lintpack/lintpack v0.5.2