mirror of
https://github.com/scratchfoundation/golangci-lint.git
synced 2025-08-28 22:28:43 -04:00
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
26 changed files with 1492 additions and 213 deletions
|
@ -31,7 +31,6 @@ linters-settings:
|
||||||
- experimental
|
- experimental
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
- wrapperFunc
|
- wrapperFunc
|
||||||
- commentFormatting # https://github.com/go-critic/go-critic/issues/755
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable-all: true
|
enable-all: true
|
||||||
|
|
|
@ -779,7 +779,6 @@ linters-settings:
|
||||||
- experimental
|
- experimental
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
- wrapperFunc
|
- wrapperFunc
|
||||||
- commentFormatting # https://github.com/go-critic/go-critic/issues/755
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable-all: true
|
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/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||||
github.com/fatih/color v1.6.0
|
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-lintpack/lintpack v0.5.2
|
||||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // 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/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 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
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-ee9bf5809ead h1:qwmAYufKDopQnFdeMw+iHJVxAd2CbF+VFKHyJJwnPKk=
|
||||||
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/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 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0=
|
||||||
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
||||||
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
|
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-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 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
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 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
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=
|
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
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 Alekseev Artem
|
Copyright (c) 2018-2019 Alekseev Artem
|
||||||
Copyright (c) 2018 Ravil Bikbulatov
|
Copyright (c) 2018-2019 Ravil Bikbulatov
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
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/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"github.com/go-critic/go-critic/checkers/internal/lintutil"
|
|
||||||
"github.com/go-lintpack/lintpack"
|
"github.com/go-lintpack/lintpack"
|
||||||
"github.com/go-lintpack/lintpack/astwalk"
|
"github.com/go-lintpack/lintpack/astwalk"
|
||||||
|
"github.com/go-toolsmith/astcast"
|
||||||
"github.com/go-toolsmith/astequal"
|
"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,
|
// xs are 0-N append arguments, but not variadic argument,
|
||||||
// because it makes append combining impossible.
|
// because it makes append combining impossible.
|
||||||
|
|
||||||
assign := lintutil.AsAssignStmt(stmt)
|
assign := astcast.ToAssignStmt(stmt)
|
||||||
if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
|
if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
|
||||||
return nil
|
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
|
package checkers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-critic/go-critic/checkers/internal/lintutil"
|
"github.com/go-critic/go-critic/checkers/internal/lintutil"
|
||||||
"github.com/go-lintpack/lintpack"
|
"github.com/go-lintpack/lintpack"
|
||||||
"github.com/go-lintpack/lintpack/astwalk"
|
"github.com/go-lintpack/lintpack/astwalk"
|
||||||
|
"github.com/go-toolsmith/astcast"
|
||||||
"github.com/go-toolsmith/astcopy"
|
"github.com/go-toolsmith/astcopy"
|
||||||
"github.com/go-toolsmith/astequal"
|
"github.com/go-toolsmith/astequal"
|
||||||
|
"github.com/go-toolsmith/astp"
|
||||||
"github.com/go-toolsmith/typep"
|
"github.com/go-toolsmith/typep"
|
||||||
"golang.org/x/tools/go/ast/astutil"
|
"golang.org/x/tools/go/ast/astutil"
|
||||||
)
|
)
|
||||||
|
@ -37,6 +41,10 @@ type boolExprSimplifyChecker struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *boolExprSimplifyChecker) VisitExpr(x ast.Expr) {
|
func (c *boolExprSimplifyChecker) VisitExpr(x ast.Expr) {
|
||||||
|
if !astp.IsBinaryExpr(x) && !astp.IsUnaryExpr(x) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Throw away non-bool expressions and avoid redundant
|
// Throw away non-bool expressions and avoid redundant
|
||||||
// AST copying below.
|
// AST copying below.
|
||||||
if typ := c.ctx.TypesInfo.TypeOf(x); typ == nil || !typep.HasBoolKind(typ.Underlying()) {
|
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.negatedEquals(cur) ||
|
||||||
c.invertComparison(cur) ||
|
c.invertComparison(cur) ||
|
||||||
c.combineChecks(cur) ||
|
c.combineChecks(cur) ||
|
||||||
|
c.removeIncDec(cur) ||
|
||||||
|
c.foldRanges(cur) ||
|
||||||
true
|
true
|
||||||
}).(ast.Expr)
|
}).(ast.Expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *boolExprSimplifyChecker) doubleNegation(cur *astutil.Cursor) bool {
|
func (c *boolExprSimplifyChecker) doubleNegation(cur *astutil.Cursor) bool {
|
||||||
neg1 := lintutil.AsUnaryExprOp(cur.Node(), token.NOT)
|
neg1 := astcast.ToUnaryExpr(cur.Node())
|
||||||
neg2 := lintutil.AsUnaryExprOp(astutil.Unparen(neg1.X), token.NOT)
|
neg2 := astcast.ToUnaryExpr(astutil.Unparen(neg1.X))
|
||||||
if !lintutil.IsNil(neg1) && !lintutil.IsNil(neg2) {
|
if neg1.Op == token.NOT && neg2.Op == token.NOT {
|
||||||
cur.Replace(astutil.Unparen(neg2.X))
|
cur.Replace(astutil.Unparen(neg2.X))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -84,9 +94,9 @@ func (c *boolExprSimplifyChecker) negatedEquals(cur *astutil.Cursor) bool {
|
||||||
if !ok || x.Op != token.EQL {
|
if !ok || x.Op != token.EQL {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
neg1 := lintutil.AsUnaryExprOp(x.X, token.NOT)
|
neg1 := astcast.ToUnaryExpr(x.X)
|
||||||
neg2 := lintutil.AsUnaryExprOp(x.Y, token.NOT)
|
neg2 := astcast.ToUnaryExpr(x.Y)
|
||||||
if !lintutil.IsNil(neg1) && !lintutil.IsNil(neg2) {
|
if neg1.Op == token.NOT && neg2.Op == token.NOT {
|
||||||
x.X = neg1.X
|
x.X = neg1.X
|
||||||
x.Y = neg2.X
|
x.Y = neg2.X
|
||||||
return true
|
return true
|
||||||
|
@ -99,9 +109,9 @@ func (c *boolExprSimplifyChecker) invertComparison(cur *astutil.Cursor) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
neg := lintutil.AsUnaryExprOp(cur.Node(), token.NOT)
|
neg := astcast.ToUnaryExpr(cur.Node())
|
||||||
cmp := lintutil.AsBinaryExpr(astutil.Unparen(neg.X))
|
cmp := astcast.ToBinaryExpr(astutil.Unparen(neg.X))
|
||||||
if lintutil.IsNil(neg) || lintutil.IsNil(cmp) {
|
if neg.Op != token.NOT {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,17 +137,23 @@ func (c *boolExprSimplifyChecker) invertComparison(cur *astutil.Cursor) bool {
|
||||||
return true
|
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 {
|
func (c *boolExprSimplifyChecker) combineChecks(cur *astutil.Cursor) bool {
|
||||||
or := lintutil.AsBinaryExprOp(cur.Node(), token.LOR)
|
or, ok := cur.Node().(*ast.BinaryExpr)
|
||||||
lhs := lintutil.AsBinaryExpr(astutil.Unparen(or.X))
|
if !ok || or.Op != token.LOR {
|
||||||
rhs := lintutil.AsBinaryExpr(astutil.Unparen(or.Y))
|
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) {
|
if !astequal.Expr(lhs.X, rhs.X) || !astequal.Expr(lhs.Y, rhs.Y) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
safe := typep.SideEffectFree(c.ctx.TypesInfo, lhs.X) &&
|
if !c.isSafe(lhs.X) || !c.isSafe(lhs.Y) {
|
||||||
typep.SideEffectFree(c.ctx.TypesInfo, lhs.Y)
|
|
||||||
if !safe {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +177,163 @@ func (c *boolExprSimplifyChecker) combineChecks(cur *astutil.Cursor) bool {
|
||||||
return false
|
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) {
|
func (c *boolExprSimplifyChecker) warn(cause, suggestion ast.Expr) {
|
||||||
c.SkipChilds = true
|
c.SkipChilds = true
|
||||||
c.ctx.Warn(cause, "can simplify `%s` to `%s`", cause, suggestion)
|
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`
|
info.After = `length := 10`
|
||||||
|
|
||||||
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
||||||
builtins := map[string]bool{
|
return astwalk.WalkerForLocalDef(&builtinShadowChecker{ctx: ctx}, ctx.TypesInfo)
|
||||||
// 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)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type builtinShadowChecker struct {
|
type builtinShadowChecker struct {
|
||||||
astwalk.WalkHandler
|
astwalk.WalkHandler
|
||||||
ctx *lintpack.CheckerContext
|
ctx *lintpack.CheckerContext
|
||||||
|
|
||||||
builtins map[string]bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *builtinShadowChecker) VisitLocalDef(name astwalk.Name, _ ast.Expr) {
|
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)
|
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`
|
info.After = `// This is a comment`
|
||||||
|
|
||||||
collection.AddChecker(&info, func(ctx *lintpack.CheckerContext) lintpack.FileWalker {
|
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{
|
return astwalk.WalkerForComment(&commentFormattingChecker{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
pragmaRE: pragmaRE,
|
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{
|
c.commonPatterns = []*regexp.Regexp{
|
||||||
regexp.MustCompile(`(?i)this (?:function|type) is deprecated`),
|
regexp.MustCompile(`(?i)this (?:function|type) is deprecated`),
|
||||||
regexp.MustCompile(`(?i)deprecated[.!]? use \S* instead`),
|
regexp.MustCompile(`(?i)deprecated[.!]? use \S* instead`),
|
||||||
|
regexp.MustCompile(`(?i)\[\[deprecated\]\].*`),
|
||||||
|
regexp.MustCompile(`(?i)note: deprecated\b.*`),
|
||||||
// TODO(quasilyte): more of these?
|
// TODO(quasilyte): more of these?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ func FuncOld() int`
|
||||||
"Deprecate: ",
|
"Deprecate: ",
|
||||||
"Derpecate: ",
|
"Derpecate: ",
|
||||||
"Derpecated: ",
|
"Derpecated: ",
|
||||||
|
"Depreacted: ",
|
||||||
}
|
}
|
||||||
for i := range c.commonTypos {
|
for i := range c.commonTypos {
|
||||||
c.commonTypos[i] = strings.ToUpper(c.commonTypos[i])
|
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{
|
c.matchers = map[string]func(*ast.CallExpr) bool{
|
||||||
"copy": m["(x, x, ...)"],
|
"copy": m["(x, x, ...)"],
|
||||||
|
|
||||||
|
"math.Max": m["(x, x, ...)"],
|
||||||
|
"math.Min": m["(x, x, ...)"],
|
||||||
|
|
||||||
"reflect.Copy": m["(x, x, ...)"],
|
"reflect.Copy": m["(x, x, ...)"],
|
||||||
"reflect.DeepEqual": 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"
|
||||||
"github.com/go-lintpack/lintpack/astwalk"
|
"github.com/go-lintpack/lintpack/astwalk"
|
||||||
"github.com/go-toolsmith/astcast"
|
"github.com/go-toolsmith/astcast"
|
||||||
|
"github.com/go-toolsmith/astequal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -57,7 +58,9 @@ func (c *equalFoldChecker) checkBytes(expr *ast.CallExpr) {
|
||||||
if !ok1 && !ok2 {
|
if !ok1 && !ok2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.warnBytes(expr, x, y)
|
if !astequal.Expr(x, y) {
|
||||||
|
c.warnBytes(expr, x, y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
|
func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
|
||||||
|
@ -70,7 +73,9 @@ func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
|
||||||
if !ok1 && !ok2 {
|
if !ok1 && !ok2 {
|
||||||
return
|
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) {
|
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 (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
|
"go/types"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-lintpack/lintpack"
|
"github.com/go-lintpack/lintpack"
|
||||||
|
@ -30,13 +31,14 @@ type flagNameChecker struct {
|
||||||
|
|
||||||
func (c *flagNameChecker) VisitExpr(expr ast.Expr) {
|
func (c *flagNameChecker) VisitExpr(expr ast.Expr) {
|
||||||
call := astcast.ToCallExpr(expr)
|
call := astcast.ToCallExpr(expr)
|
||||||
sym := astcast.ToIdent(astcast.ToSelectorExpr(call.Fun).Sel)
|
calledExpr := astcast.ToSelectorExpr(call.Fun)
|
||||||
obj := c.ctx.TypesInfo.ObjectOf(sym)
|
obj, ok := c.ctx.TypesInfo.ObjectOf(astcast.ToIdent(calledExpr.X)).(*types.PkgName)
|
||||||
if obj == nil {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pkg := obj.Pkg()
|
sym := calledExpr.Sel
|
||||||
if !isStdlibPkg(pkg) || pkg.Name() != "flag" {
|
pkg := obj.Imported()
|
||||||
|
if pkg.Path() != "flag" {
|
||||||
return
|
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/ast"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/go-critic/go-critic/checkers/internal/lintutil"
|
|
||||||
"github.com/go-lintpack/lintpack"
|
"github.com/go-lintpack/lintpack"
|
||||||
"github.com/go-lintpack/lintpack/astwalk"
|
"github.com/go-lintpack/lintpack/astwalk"
|
||||||
|
"github.com/go-toolsmith/astcast"
|
||||||
"github.com/go-toolsmith/astp"
|
"github.com/go-toolsmith/astp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ type underefChecker struct {
|
||||||
func (c *underefChecker) VisitExpr(expr ast.Expr) {
|
func (c *underefChecker) VisitExpr(expr ast.Expr) {
|
||||||
switch n := expr.(type) {
|
switch n := expr.(type) {
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
expr := lintutil.AsParenExpr(n.X)
|
expr := astcast.ToParenExpr(n.X)
|
||||||
if c.skipRecvDeref && c.isPtrRecvMethodCall(n.Sel) {
|
if c.skipRecvDeref && c.isPtrRecvMethodCall(n.Sel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func (c *underefChecker) VisitExpr(expr ast.Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
expr := lintutil.AsParenExpr(n.X)
|
expr := astcast.ToParenExpr(n.X)
|
||||||
if expr, ok := expr.X.(*ast.StarExpr); ok {
|
if expr, ok := expr.X.(*ast.StarExpr); ok {
|
||||||
if !c.checkStarExpr(expr) {
|
if !c.checkStarExpr(expr) {
|
||||||
return
|
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/ast"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/go-critic/go-critic/checkers/internal/lintutil"
|
|
||||||
"github.com/go-lintpack/lintpack"
|
"github.com/go-lintpack/lintpack"
|
||||||
"github.com/go-lintpack/lintpack/astwalk"
|
"github.com/go-lintpack/lintpack/astwalk"
|
||||||
|
"github.com/go-toolsmith/astcast"
|
||||||
"github.com/go-toolsmith/astequal"
|
"github.com/go-toolsmith/astequal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,11 +39,14 @@ func (c *unlambdaChecker) VisitExpr(x ast.Expr) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := lintutil.AsCallExpr(ret.Results[0])
|
result := astcast.ToCallExpr(ret.Results[0])
|
||||||
callable := qualifiedName(result.Fun)
|
callable := qualifiedName(result.Fun)
|
||||||
if callable == "" {
|
if callable == "" {
|
||||||
return // Skip tricky cases; only handle simple calls
|
return // Skip tricky cases; only handle simple calls
|
||||||
}
|
}
|
||||||
|
if isBuiltin(callable) {
|
||||||
|
return // See #762
|
||||||
|
}
|
||||||
fnType := c.ctx.TypesInfo.TypeOf(fn)
|
fnType := c.ctx.TypesInfo.TypeOf(fn)
|
||||||
resultType := c.ctx.TypesInfo.TypeOf(result.Fun)
|
resultType := c.ctx.TypesInfo.TypeOf(result.Fun)
|
||||||
if !types.Identical(fnType, resultType) {
|
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 {
|
switch {
|
||||||
case results == nil:
|
case results == nil:
|
||||||
return // Function has no results
|
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
|
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"
|
"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.
|
// isStdlibPkg reports whether pkg is a package from the Go standard library.
|
||||||
func isStdlibPkg(pkg *types.Package) bool {
|
func isStdlibPkg(pkg *types.Package) bool {
|
||||||
return pkg != nil && pkg.Path() == pkg.Name()
|
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/fatih/color
|
||||||
# github.com/fsnotify/fsnotify v1.4.7
|
# github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/fsnotify/fsnotify
|
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
|
||||||
github.com/go-critic/go-critic/checkers/internal/lintutil
|
github.com/go-critic/go-critic/checkers/internal/lintutil
|
||||||
# github.com/go-lintpack/lintpack v0.5.2
|
# github.com/go-lintpack/lintpack v0.5.2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue