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)
This commit is contained in:
parent
b3bad285d0
commit
b31cfd6c78
.golangci.ymlREADME.mdgo.modgo.sum
vendor
github.com/go-critic/go-critic
LICENSE
checkers
appendCombine_checker.goargOrder_checker.goboolExprSimplify_checker.gobuiltinShadow_checker.gocodegenComment_checker.gocommentFormatting_checker.godeprecatedComment_checker.godupArg_checker.goequalFold_checker.goflagName_checker.gohexLiteral_checker.go
internal/lintutil
octalLiteral_checker.gostringXbytes_checker.gotypeAssertChain_checker.gounderef_checker.gounlambda_checker.gounnamedResult_checker.goutils.gogolang.org/x/tools/go/internal/gcimporter
modules.txt@ -31,7 +31,6 @@ linters-settings:
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- wrapperFunc
|
||||
- commentFormatting # https://github.com/go-critic/go-critic/issues/755
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
|
@ -779,7 +779,6 @@ linters-settings:
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- wrapperFunc
|
||||
- commentFormatting # https://github.com/go-critic/go-critic/issues/755
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
|
2
go.mod
2
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
|
||||
|
5
go.sum
5
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=
|
||||
|
4
vendor/github.com/go-critic/go-critic/LICENSE
generated
vendored
4
vendor/github.com/go-critic/go-critic/LICENSE
generated
vendored
@ -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
|
||||
|
4
vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
generated
vendored
4
vendor/github.com/go-critic/go-critic/checkers/appendCombine_checker.go
generated
vendored
@ -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
|
||||
}
|
||||
|
98
vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
generated
vendored
Normal file
98
vendor/github.com/go-critic/go-critic/checkers/argOrder_checker.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
203
vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go
generated
vendored
203
vendor/github.com/go-critic/go-critic/checkers/boolExprSimplify_checker.go
generated
vendored
@ -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)
|
||||
|
55
vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go
generated
vendored
55
vendor/github.com/go-critic/go-critic/checkers/builtinShadow_checker.go
generated
vendored
@ -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)
|
||||
}
|
||||
}
|
||||
|
61
vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
generated
vendored
Normal file
61
vendor/github.com/go-critic/go-critic/checkers/codegenComment_checker.go
generated
vendored
Normal file
@ -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")
|
||||
}
|
8
vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
generated
vendored
8
vendor/github.com/go-critic/go-critic/checkers/commentFormatting_checker.go
generated
vendored
@ -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,
|
||||
|
3
vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go
generated
vendored
3
vendor/github.com/go-critic/go-critic/checkers/deprecatedComment_checker.go
generated
vendored
@ -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])
|
||||
|
3
vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go
generated
vendored
3
vendor/github.com/go-critic/go-critic/checkers/dupArg_checker.go
generated
vendored
@ -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, ...)"],
|
||||
|
||||
|
9
vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go
generated
vendored
9
vendor/github.com/go-critic/go-critic/checkers/equalFold_checker.go
generated
vendored
@ -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) {
|
||||
|
12
vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go
generated
vendored
12
vendor/github.com/go-critic/go-critic/checkers/flagName_checker.go
generated
vendored
@ -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
|
||||
}
|
||||
|
||||
|
60
vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
generated
vendored
Normal file
60
vendor/github.com/go-critic/go-critic/checkers/hexLiteral_checker.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
121
vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go
generated
vendored
121
vendor/github.com/go-critic/go-critic/checkers/internal/lintutil/coerce.go
generated
vendored
@ -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
|
||||
}
|
82
vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
generated
vendored
Normal file
82
vendor/github.com/go-critic/go-critic/checkers/octalLiteral_checker.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
47
vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
generated
vendored
Normal file
47
vendor/github.com/go-critic/go-critic/checkers/stringXbytes_checker.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
132
vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
generated
vendored
Normal file
132
vendor/github.com/go-critic/go-critic/checkers/typeAssertChain_checker.go
generated
vendored
Normal file
@ -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")
|
||||
}
|
6
vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
generated
vendored
6
vendor/github.com/go-critic/go-critic/checkers/underef_checker.go
generated
vendored
@ -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
|
||||
|
7
vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
generated
vendored
7
vendor/github.com/go-critic/go-critic/checkers/unlambda_checker.go
generated
vendored
@ -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) {
|
||||
|
2
vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go
generated
vendored
2
vendor/github.com/go-critic/go-critic/checkers/unnamedResult_checker.go
generated
vendored
@ -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
|
||||
}
|
||||
|
||||
|
54
vendor/github.com/go-critic/go-critic/checkers/utils.go
generated
vendored
54
vendor/github.com/go-critic/go-critic/checkers/utils.go
generated
vendored
@ -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()
|
||||
|
723
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
Normal file
723
vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go
generated
vendored
Normal file
@ -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
|
||||
}
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user