Add linter bidichk to prevent malicios utf8 chars (#516)

bidichk checks for dangerous unicode character sequences

(https://github.com/golangci/golangci-lint/pull/2330)
This commit is contained in:
6543 2021-11-16 21:07:53 +01:00 committed by GitHub
parent 4891f104f0
commit 82fd65665f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
325 changed files with 15839 additions and 4755 deletions

View file

@ -8,3 +8,7 @@ linters:
- gofmt
- goimports
- govet
- bidichk
run:
timeout: 5m

3
go.mod
View file

@ -23,7 +23,7 @@ require (
github.com/go-sql-driver/mysql v1.6.0
github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v4 v4.1.0
github.com/golangci/golangci-lint v1.42.1
github.com/golangci/golangci-lint v1.43.0
github.com/google/go-github/v39 v39.2.0
github.com/gorilla/securecookie v1.1.1
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@ -51,7 +51,6 @@ require (
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20211027162914-98a5263abeca // indirect
google.golang.org/grpc v1.41.0

258
go.sum
View file

@ -1,5 +1,5 @@
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a h1:wFEQiK85fRsEVF0CRrPAos5LoAryUsIX1kPW/WrIqFw=
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo=
4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0=
4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo=
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
@ -23,6 +23,11 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -32,6 +37,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -50,8 +56,10 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EU
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/Antonboom/errname v0.1.4 h1:lGSlI42Gm4bI1e+IITtXJXvxFM8N7naWimVFKcb0McY=
github.com/Antonboom/errname v0.1.4/go.mod h1:jRXo3m0E0EuCnK3wbsSVH3X55Z4iTDLl6ZfCxwFj4TM=
github.com/Antonboom/errname v0.1.5 h1:IM+A/gz0pDhKmlt5KSNTVAvfLMb+65RxavBXpRtCUEg=
github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCqWCLp6Cifo=
github.com/Antonboom/nilnil v0.1.0 h1:DLDavmg0a6G/F4Lt9t7Enrbgb3Oph6LnDE6YVsmTt74=
github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H20D3IPZBo=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@ -120,7 +128,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
@ -130,6 +139,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/ashanbrown/forbidigo v1.2.0 h1:RMlEFupPCxQ1IogYOQUnIQwGEUGK8g5vAPMRyJoSxbc=
@ -151,22 +161,27 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A=
github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blizzy78/varnamelen v0.3.0 h1:80mYO7Y5ppeEefg1Jzu+NBg16iwToOQVnDnNIoWSShs=
github.com/blizzy78/varnamelen v0.3.0/go.mod h1:hbwRdBvoBqxk34XyQ6HA0UH3G0/1TKuv5AC4eaBT0Ec=
github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA=
github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM=
github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
github.com/breml/bidichk v0.1.1 h1:Qpy8Rmgos9qdJxhka0K7ADEE5bQZX9PQUthkgggHpFM=
github.com/breml/bidichk v0.1.1/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY=
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -174,8 +189,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charithe/durationcheck v0.0.8 h1:cnZrThioNW9gSV5JsRIXmkyHUbcDH7Y9hkzFDVc9/j0=
github.com/charithe/durationcheck v0.0.8/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk=
github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af h1:spmv8nSH9h5oCQf40jt/ufBCt9j0/58u4G+rkeMqXGI=
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
@ -283,7 +298,6 @@ github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgU
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
@ -373,16 +387,16 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/esimonov/ifshort v1.0.2 h1:K5s1W2fGfkoWXsFlxBNqT6J0ZCncPaKrGM5qe0bni68=
github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE=
github.com/esimonov/ifshort v1.0.3 h1:JD6x035opqGec5fZ0TLjXeROD2p5H7oLGn8MKfy9HTM=
github.com/esimonov/ifshort v1.0.3/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE=
github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
@ -394,8 +408,9 @@ github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZ
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM=
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
@ -408,8 +423,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-critic/go-critic v0.5.6 h1:siUR1+322iVikWXoV75I1YRfNaC/yaLzhdF9Zwd8Tus=
github.com/go-critic/go-critic v0.5.6/go.mod h1:cVjj0DfqewQVIlIAGexPCaGaZDAqGE29PYDDADIVNEo=
github.com/go-critic/go-critic v0.6.1 h1:lS8B9LH/VVsvQQP7Ao5TJyQqteVKVs3E4dXiHMyubtI=
github.com/go-critic/go-critic v0.6.1/go.mod h1:SdNCfU0yF3UBjtaZGw6586/WocupMOJuiqgom5DsQxM=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -424,6 +439,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
@ -453,8 +469,9 @@ github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ=
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc=
github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
@ -512,6 +529,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -531,8 +549,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
@ -541,16 +560,16 @@ github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZB
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks=
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
github.com/golangci/golangci-lint v1.42.1 h1:nC4WyrbdnNdohDVUoNKjy/4N4FTM1gCFaVeXecy6vzM=
github.com/golangci/golangci-lint v1.42.1/go.mod h1:MuInrVlgg2jq4do6XI1jbkErbVHVbwdrLLtGv6p2wPI=
github.com/golangci/golangci-lint v1.43.0 h1:SLwZFEmDgopqZpfP495zCtV9REUf551JJlJ51Ql7NZA=
github.com/golangci/golangci-lint v1.43.0/go.mod h1:VIFlUqidx5ggxDfQagdvd9E67UjMXtTHBkBQ7sHoC5Q=
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo=
github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
github.com/golangci/revgrep v0.0.0-20210208091834-cd28932614b5 h1:c9Mqqrm/Clj5biNaG7rABrmwUq88nHh0uABo2b/WYmc=
github.com/golangci/revgrep v0.0.0-20210208091834-cd28932614b5/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY=
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 h1:SgM7GDZTxtTTQPU84heOxy34iG5Du7F2jcoZnvp+fXI=
github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -580,6 +599,7 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@ -592,6 +612,9 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw=
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -599,11 +622,12 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 h1:Nb2aRlC404yz7gQIfRZxX9/MLvQiqXyiBTJtgAy6yrI=
@ -625,15 +649,20 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw=
github.com/gostaticanalysis/analysisutil v0.4.1 h1:/7clKqrVfiVwiBQLM0Uke4KvXnO6JcCTS7HwF2D6wG8=
github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0=
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI=
github.com/gostaticanalysis/comment v1.4.1 h1:xHopR5L2lRz6OsjH4R2HG5wRhW9ySl3FsHIvi5pcXwc=
github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q=
github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
github.com/gostaticanalysis/forcetypeassert v0.0.0-20200621232751-01d4955beaa5 h1:rx8127mFPqXXsfPSo8BwnIU97MKFZc89WHAHt8PwDVY=
github.com/gostaticanalysis/forcetypeassert v0.0.0-20200621232751-01d4955beaa5/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@ -646,25 +675,30 @@ github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqC
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@ -680,8 +714,11 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
@ -748,8 +785,8 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM=
github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
github.com/jingyugao/rowserrcheck v1.1.0 h1:u6h4eiNuCLqk73Ic5TXQq9yZS+uEXTdusn7c3w1Mr6A=
github.com/jingyugao/rowserrcheck v1.1.0/go.mod h1:TOQpc2SLx6huPfoFGK3UOnEG+u02D3C1GeosjupAKCA=
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -762,6 +799,7 @@ github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -772,7 +810,6 @@ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMW
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@ -789,10 +826,10 @@ github.com/kisielk/errcheck v1.6.0 h1:YTDO4pNy7AUN/021p+JGHycQyYNIyMoenM1YDVK6Rl
github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -811,8 +848,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kulti/thelper v0.4.0 h1:2Nx7XbdbE/BYZeoip2mURKUdtHQRuy6Ug+wR7K9ywNM=
github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U=
github.com/kunwardeep/paralleltest v1.0.2 h1:/jJRv0TiqPoEy/Y8dQxCFJhD56uS/pnvtatgTZBHokU=
github.com/kunwardeep/paralleltest v1.0.2/go.mod h1:ZPqNm1fVHPllh5LPVujzbVz1JN2GhLxSfY+oqUsvG30=
github.com/kunwardeep/paralleltest v1.0.3 h1:UdKIkImEAXjR1chUWLn+PNXqWUGs//7tzMeWuP7NhmI=
github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M=
github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg=
@ -836,9 +873,9 @@ github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@ -849,13 +886,17 @@ github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpAp
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA=
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@ -864,8 +905,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@ -883,16 +925,18 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo=
github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc=
github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 h1:QASJXOGm2RZ5Ardbc86qNFvby9AqkLDibfChMtAg5QM=
github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.1.1 h1:mkXNHP14Y6tfq+ocnQaiKEtgJDM41yaoyQq4qn6TD/4=
github.com/mgechev/revive v1.1.1/go.mod h1:PKqk4L74K6wVNwY2b6fr+9Qqr/3hIsHVfZCJdbvozrY=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.1.2 h1:MiYA/o9M7REjvOF20QN43U8OtXDDHQFKLCtJnxLGLog=
github.com/mgechev/revive v1.1.2/go.mod h1:bnXsMr+ZTH09V5rssEI+jHAZ4z+ZdyhgO/zsy3EhK+0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -903,8 +947,9 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@ -940,8 +985,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nakabonne/nestif v0.3.0 h1:+yOViDGhg8ygGrmII72nV9B/zGxY188TYpfolntsaPw=
github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c=
github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=
github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
@ -977,7 +1022,6 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
@ -987,8 +1031,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -1023,13 +1067,20 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA=
@ -1050,6 +1101,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349 h1:Kq/3kL0k033ds3tyez5lFPrfQ74fNJ+OqCclRipubwA=
github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@ -1097,12 +1149,12 @@ github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
github.com/quasilyte/go-ruleguard v0.3.4 h1:F6l5p6+7WBcTKS7foNQ4wqA39zjn2+RbdbyzGxIq1B0=
github.com/quasilyte/go-ruleguard v0.3.4/go.mod h1:57FZgMnoo6jqxkYKmVj5Fc8vOt0rVzoE/UNAmFFIPqA=
github.com/quasilyte/go-ruleguard v0.3.13 h1:O1G41cq1jUr3cJmqp7vOUT0SokqjzmS9aESWJuIDRaY=
github.com/quasilyte/go-ruleguard v0.3.13/go.mod h1:Ul8wwdqR6kBVOCt2dipDBkE+T6vAV/iixkrKuRTN1oQ=
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.2/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/dsl v0.3.10/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20210203162857-b223e0831f88/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
github.com/quasilyte/go-ruleguard/rules v0.0.0-20210428214800-545e0d2e0bf7/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY=
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@ -1133,18 +1185,19 @@ github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8
github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA=
github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/securego/gosec/v2 v2.8.1 h1:Tyy/nsH39TYCOkqf5HAgRE+7B5D8sHDwPdXRgFWokh8=
github.com/securego/gosec/v2 v2.8.1/go.mod h1:pUmsq6+VyFEElJMUX+QB3p3LWNHXg1R3xh2ssVJPs8Q=
github.com/securego/gosec/v2 v2.9.1 h1:anHKLS/ApTYU6NZkKa/5cQqqcbKZURjvc+MtR++S4EQ=
github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4=
github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -1160,10 +1213,10 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/sivchari/tenv v1.4.7 h1:FdTpgRlTue5eb5nXIYgS/lyVXSjugU8UUVDwhP1NLU8=
github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY=
@ -1177,8 +1230,9 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
@ -1196,11 +1250,11 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/ssgreg/nlreturn/v2 v2.1.0 h1:6/s4Rc49L6Uo6RLjhWZGBpWWjfzk2yrf1nIW8m4wgVA=
github.com/ssgreg/nlreturn/v2 v2.1.0/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@ -1223,6 +1277,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/sylvia7788/contextcheck v1.0.4 h1:MsiVqROAdr0efZc/fOCt0c235qm9XJqHtWwM+2h2B04=
github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -1231,19 +1287,23 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b h1:HxLVTlqcHhFAz3nWUcuvpH7WuOMv8LQoCWmruLfFH2U=
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
github.com/tetafro/godot v1.4.9 h1:wsNd0RuUxISqqudFqchsSsMqsM188DoZVPBeKl87tP0=
github.com/tetafro/godot v1.4.9/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw=
github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 h1:ig99OeTyDwQWhPe2iw9lwfQVF1KB3Q4fpP3X7/2VBG8=
github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4=
github.com/tklauser/numcpus v0.2.3/go.mod h1:vpEPS/JC+oZGGQ/My/vJnNsvMDQL6PwOqt8dsCw5j+E=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tomarrell/wrapcheck/v2 v2.3.0 h1:i3DNjtyyL1xwaBQOsPPk8LAcpayWfQv2rxNi9b/eEx4=
github.com/tomarrell/wrapcheck/v2 v2.3.0/go.mod h1:aF5rnkdtqNWP/gC7vPUO5pKsB0Oac2FDTQP4F+dpZMU=
github.com/tomarrell/wrapcheck/v2 v2.4.0 h1:mU4H9KsqqPZUALOUbVOpjy8qNQbWLoLI9fV68/1tq30=
github.com/tomarrell/wrapcheck/v2 v2.4.0/go.mod h1:68bQ/eJg55BROaRTbMjC7vuhL2OgfoG8bLp9ZyoBfyY=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
github.com/tommy-muehle/go-mnd/v2 v2.4.0 h1:1t0f8Uiaq+fqKteUR4N9Umr6E99R+lDnLnq7PwX2PPE=
github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
@ -1269,9 +1329,9 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X
github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4=
github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
@ -1306,6 +1366,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@ -1363,6 +1424,7 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -1412,8 +1474,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1454,7 +1517,6 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@ -1469,6 +1531,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1484,6 +1549,10 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1530,6 +1599,7 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1560,7 +1630,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1592,11 +1661,20 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -1646,6 +1724,7 @@ golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1718,11 +1797,16 @@ golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1755,6 +1839,12 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1817,7 +1907,18 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20211027162914-98a5263abeca h1:+e+aQDO4/c9KaG8PXWHTc6/+Du6kz+BKcXCSnV4SSTE=
google.golang.org/genproto v0.0.0-20211027162914-98a5263abeca/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@ -1848,10 +1949,15 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -1883,9 +1989,9 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=

View file

@ -48,10 +48,12 @@ func flags() flag.FlagSet {
return *flags
}
func isAllowed(v ast.Node) bool {
func isAllowed(cm ast.CommentMap, v ast.Node) bool {
switch i := v.(type) {
case *ast.GenDecl:
return hasEmbedComment(cm, i)
case *ast.Ident:
return i.Name == "_" || i.Name == "version" || looksLikeError(i)
return i.Name == "_" || i.Name == "version" || looksLikeError(i) || identHasEmbedComment(cm, i)
case *ast.CallExpr:
if expr, ok := i.Fun.(*ast.SelectorExpr); ok {
return isAllowedSelectorExpression(expr)
@ -96,6 +98,32 @@ func looksLikeError(i *ast.Ident) bool {
return strings.HasPrefix(i.Name, prefix)
}
func identHasEmbedComment(cm ast.CommentMap, i *ast.Ident) bool {
if i.Obj == nil {
return false
}
spec, ok := i.Obj.Decl.(*ast.ValueSpec)
if !ok {
return false
}
return hasEmbedComment(cm, spec)
}
// hasEmbedComment returns true if the AST node has
// a '//go:embed ' comment, or false otherwise.
func hasEmbedComment(cm ast.CommentMap, n ast.Node) bool {
for _, g := range cm[n] {
for _, c := range g.List {
if strings.HasPrefix(c.Text, "//go:embed ") {
return true
}
}
}
return false
}
func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
includeTests := pass.Analyzer.Flags.Lookup("t").Value.(flag.Getter).Get().(bool)
@ -108,6 +136,8 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
continue
}
fileCommentMap := ast.NewCommentMap(pass.Fset, file, file.Comments)
for _, decl := range file.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
@ -116,12 +146,15 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
if genDecl.Tok != token.VAR {
continue
}
if isAllowed(fileCommentMap, genDecl) {
continue
}
for _, spec := range genDecl.Specs {
valueSpec := spec.(*ast.ValueSpec)
onlyAllowedValues := false
for _, vn := range valueSpec.Values {
if isAllowed(vn) {
if isAllowed(fileCommentMap, vn) {
onlyAllowedValues = true
continue
}
@ -135,7 +168,7 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
}
for _, vn := range valueSpec.Names {
if isAllowed(vn) {
if isAllowed(fileCommentMap, vn) {
continue
}

21
vendor/github.com/Antonboom/nilnil/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Anton Telyshev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,148 @@
package analyzer
import (
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
const (
name = "nilnil"
doc = "Checks that there is no simultaneous return of `nil` error and an invalid value."
reportMsg = "return both the `nil` error and invalid value: use a sentinel error instead"
)
// New returns new nilnil analyzer.
func New() *analysis.Analyzer {
n := newNilNil()
a := &analysis.Analyzer{
Name: name,
Doc: doc,
Run: n.run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
a.Flags.Var(&n.checkedTypes, "checked-types", "coma separated list")
return a
}
type nilNil struct {
checkedTypes checkedTypes
}
func newNilNil() *nilNil {
return &nilNil{
checkedTypes: newDefaultCheckedTypes(),
}
}
var (
types = []ast.Node{(*ast.TypeSpec)(nil)}
funcAndReturns = []ast.Node{
(*ast.FuncDecl)(nil),
(*ast.FuncLit)(nil),
(*ast.ReturnStmt)(nil),
}
)
type typeSpecByName map[string]*ast.TypeSpec
func (n *nilNil) run(pass *analysis.Pass) (interface{}, error) {
insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
typeSpecs := typeSpecByName{}
insp.Preorder(types, func(node ast.Node) {
t := node.(*ast.TypeSpec)
typeSpecs[t.Name.Name] = t
})
var fs funcTypeStack
insp.Nodes(funcAndReturns, func(node ast.Node, push bool) (proceed bool) {
switch v := node.(type) {
case *ast.FuncLit:
if push {
fs.Push(v.Type)
} else {
fs.Pop()
}
case *ast.FuncDecl:
if push {
fs.Push(v.Type)
} else {
fs.Pop()
}
case *ast.ReturnStmt:
ft := fs.Top() // Current function.
if !push || len(v.Results) != 2 || ft == nil || ft.Results == nil || len(ft.Results.List) != 2 {
return false
}
fRes1, fRes2 := ft.Results.List[0], ft.Results.List[1]
if !(n.isDangerNilField(fRes1, typeSpecs) && n.isErrorField(fRes2)) {
return
}
rRes1, rRes2 := v.Results[0], v.Results[1]
if isNil(rRes1) && isNil(rRes2) {
pass.Reportf(v.Pos(), reportMsg)
}
}
return true
})
return nil, nil
}
func (n *nilNil) isDangerNilField(f *ast.Field, typeSpecs typeSpecByName) bool {
return n.isDangerNilType(f.Type, typeSpecs)
}
func (n *nilNil) isDangerNilType(t ast.Expr, typeSpecs typeSpecByName) bool {
switch v := t.(type) {
case *ast.StarExpr:
return n.checkedTypes.Contains(ptrType)
case *ast.FuncType:
return n.checkedTypes.Contains(funcType)
case *ast.InterfaceType:
return n.checkedTypes.Contains(ifaceType)
case *ast.MapType:
return n.checkedTypes.Contains(mapType)
case *ast.ChanType:
return n.checkedTypes.Contains(chanType)
case *ast.Ident:
if t, ok := typeSpecs[v.Name]; ok {
return n.isDangerNilType(t.Type, nil)
}
}
return false
}
func (n *nilNil) isErrorField(f *ast.Field) bool {
return isIdent(f.Type, "error")
}
func isNil(e ast.Expr) bool {
return isIdent(e, "nil")
}
func isIdent(n ast.Node, name string) bool {
i, ok := n.(*ast.Ident)
if !ok {
return false
}
return i.Name == name
}

View file

@ -0,0 +1,77 @@
package analyzer
import (
"fmt"
"sort"
"strings"
)
func newDefaultCheckedTypes() checkedTypes {
return checkedTypes{
ptrType: struct{}{},
funcType: struct{}{},
ifaceType: struct{}{},
mapType: struct{}{},
chanType: struct{}{},
}
}
const separator = ','
type typeName string
func (t typeName) S() string {
return string(t)
}
const (
ptrType typeName = "ptr"
funcType typeName = "func"
ifaceType typeName = "iface"
mapType typeName = "map"
chanType typeName = "chan"
)
var knownTypes = []typeName{ptrType, funcType, ifaceType, mapType, chanType}
type checkedTypes map[typeName]struct{}
func (c checkedTypes) Contains(t typeName) bool {
_, ok := c[t]
return ok
}
func (c checkedTypes) String() string {
result := make([]string, 0, len(c))
for t := range c {
result = append(result, t.S())
}
sort.Strings(result)
return strings.Join(result, string(separator))
}
func (c checkedTypes) Set(s string) error {
types := strings.FieldsFunc(s, func(c rune) bool { return c == separator })
if len(types) == 0 {
return nil
}
c.disableAll()
for _, t := range types {
switch tt := typeName(t); tt {
case ptrType, funcType, ifaceType, mapType, chanType:
c[tt] = struct{}{}
default:
return fmt.Errorf("unknown checked type name %q (see help)", t)
}
}
return nil
}
func (c checkedTypes) disableAll() {
for k := range c {
delete(c, k)
}
}

View file

@ -0,0 +1,29 @@
package analyzer
import (
"go/ast"
)
type funcTypeStack []*ast.FuncType
func (s *funcTypeStack) Push(f *ast.FuncType) {
*s = append(*s, f)
}
func (s *funcTypeStack) Pop() *ast.FuncType {
if len(*s) == 0 {
return nil
}
last := len(*s) - 1
f := (*s)[last]
*s = (*s)[:last]
return f
}
func (s *funcTypeStack) Top() *ast.FuncType {
if len(*s) == 0 {
return nil
}
return (*s)[len(*s)-1]
}

9
vendor/github.com/blizzy78/varnamelen/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,9 @@
root = true
[**]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

1
vendor/github.com/blizzy78/varnamelen/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
/cmd/__debug_bin

20
vendor/github.com/blizzy78/varnamelen/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,20 @@
linters:
enable:
- gocognit
- gocritic
- gocyclo
- goerr113
- golint
- interfacer
- nakedret
- prealloc
- unconvert
- unparam
linters-settings:
gocognit:
min-complexity: 15
gocyclo:
min-complexity: 10
nakedret:
max-func-lines: 0

7
vendor/github.com/blizzy78/varnamelen/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,7 @@
language: go
go:
- "1.15"
before_script:
- go get github.com/mattn/goveralls
after_script:
- goveralls -service=travis-ci

18
vendor/github.com/blizzy78/varnamelen/LICENSE generated vendored Normal file
View file

@ -0,0 +1,18 @@
Copyright 2021 Maik Schreiber
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

89
vendor/github.com/blizzy78/varnamelen/README.md generated vendored Normal file
View file

@ -0,0 +1,89 @@
[![Build Status](https://api.travis-ci.com/blizzy78/varnamelen.svg?branch=master)](https://app.travis-ci.com/github/blizzy78/varnamelen) [![Coverage Status](https://coveralls.io/repos/github/blizzy78/varnamelen/badge.svg?branch=master)](https://coveralls.io/github/blizzy78/varnamelen?branch=master) [![GoDoc](https://pkg.go.dev/badge/github.com/blizzy78/varnamelen)](https://pkg.go.dev/github.com/blizzy78/varnamelen)
varnamelen
==========
A Go Analyzer checking that the length of a variable's name matches its usage scope.
A variable with a short name can be hard to use if the variable is used over a longer span of lines of code.
A longer variable name may be easier to comprehend.
The analyzer can check variable names, method receiver names, as well as named return values.
Conventional Go parameters such as `ctx context.Context` or `t *testing.T` will always be ignored.
**Example output**
```
test.go:4:2: variable name 'x' is too short for the scope of its usage (varnamelen)
x := 123
^
test.go:6:2: variable name 'i' is too short for the scope of its usage (varnamelen)
i := 10
^
```
Standalone Usage
----------------
The `cmd/` folder provides a standalone command line utility. You can build it like this:
```
go build -o varnamelen ./cmd/
```
**Usage**
```
varnamelen: checks that the length of a variable's name matches its scope
Usage: varnamelen [-flag] [package]
A variable with a short name can be hard to use if the variable is used
over a longer span of lines of code. A longer variable name may be easier
to comprehend.
Flags:
-V print version and exit
-all
no effect (deprecated)
-c int
display offending line with this many lines of context (default -1)
-checkReceiver
check method receiver names
-checkReturn
check named return values
-cpuprofile string
write CPU profile to this file
-debug string
debug flags, any subset of "fpstv"
-fix
apply all suggested fixes
-flags
print analyzer flags in JSON
-ignoreNames value
comma-separated list of ignored variable names
-json
emit JSON output
-maxDistance int
maximum number of lines of variable usage scope considered 'short' (default 5)
-memprofile string
write memory profile to this file
-minNameLength int
minimum length of variable name considered 'long' (default 3)
-source
no effect (deprecated)
-tags string
no effect (deprecated)
-trace string
write trace log to this file
-v no effect (deprecated)
```
License
-------
This package is licensed under the MIT license.

10
vendor/github.com/blizzy78/varnamelen/go.mod generated vendored Normal file
View file

@ -0,0 +1,10 @@
module github.com/blizzy78/varnamelen
go 1.15
require (
github.com/matryer/is v1.4.0
golang.org/x/mod v0.5.0 // indirect
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
golang.org/x/tools v0.1.6
)

31
vendor/github.com/blizzy78/varnamelen/go.sum generated vendored Normal file
View file

@ -0,0 +1,31 @@
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.6 h1:SIasE1FVIQOWz2GEAHFOmoW7xchJcqlucjSULTL0Ag4=
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -0,0 +1,13 @@
{
"folders": [
{
"path": "."
}
],
"extensions": {
"recommendations": [
"EditorConfig.EditorConfig",
"golang.go"
]
}
}

342
vendor/github.com/blizzy78/varnamelen/varnamelen.go generated vendored Normal file
View file

@ -0,0 +1,342 @@
package varnamelen
import (
"go/ast"
"strings"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
// varNameLen is an analyzer that checks that the length of a variable's name matches its usage scope.
// It will create a report for a variable's assignment if that variable has a short name, but its
// usage scope is not considered "small."
type varNameLen struct {
// maxDistance is the longest distance, in source lines, that is being considered a "small scope."
maxDistance int
// minNameLength is the minimum length of a variable's name that is considered "long."
minNameLength int
// ignoreNames is an optional list of variable names that should be ignored completely.
ignoreNames stringsValue
// checkReceiver determines whether a method receiver's name should be checked.
checkReceiver bool
// checkReturn determines whether named return values should be checked.
checkReturn bool
}
// stringsValue is the value of a list-of-strings flag.
type stringsValue struct {
Values []string
}
// variable represents a declared variable.
type variable struct {
// name is the name of the variable.
name string
// assign is the assign statement that declares the variable.
assign *ast.AssignStmt
}
// parameter represents a declared function or method parameter.
type parameter struct {
// name is the name of the parameter.
name string
// field is the declaration of the parameter.
field *ast.Field
}
const (
// defaultMaxDistance is the default value for the maximum distance between the declaration of a variable and its usage
// that is considered a "small scope."
defaultMaxDistance = 5
// defaultMinNameLength is the default value for the minimum length of a variable's name that is considered "long."
defaultMinNameLength = 3
)
// NewAnalyzer returns a new analyzer that checks variable name length.
func NewAnalyzer() *analysis.Analyzer {
vnl := varNameLen{
maxDistance: defaultMaxDistance,
minNameLength: defaultMinNameLength,
ignoreNames: stringsValue{},
}
analyzer := analysis.Analyzer{
Name: "varnamelen",
Doc: "checks that the length of a variable's name matches its scope\n\n" +
"A variable with a short name can be hard to use if the variable is used\n" +
"over a longer span of lines of code. A longer variable name may be easier\n" +
"to comprehend.",
Run: func(pass *analysis.Pass) (interface{}, error) {
vnl.run(pass)
return nil, nil
},
Requires: []*analysis.Analyzer{
inspect.Analyzer,
},
}
analyzer.Flags.IntVar(&vnl.maxDistance, "maxDistance", defaultMaxDistance, "maximum number of lines of variable usage scope considered 'short'")
analyzer.Flags.IntVar(&vnl.minNameLength, "minNameLength", defaultMinNameLength, "minimum length of variable name considered 'long'")
analyzer.Flags.Var(&vnl.ignoreNames, "ignoreNames", "comma-separated list of ignored variable names")
analyzer.Flags.BoolVar(&vnl.checkReceiver, "checkReceiver", false, "check method receiver names")
analyzer.Flags.BoolVar(&vnl.checkReturn, "checkReturn", false, "check named return values")
return &analyzer
}
// Run applies v to a package, according to pass.
func (v *varNameLen) run(pass *analysis.Pass) {
varToDist, paramToDist, returnToDist := v.distances(pass)
for variable, dist := range varToDist {
if v.checkNameAndDistance(variable.name, dist) {
continue
}
pass.Reportf(variable.assign.Pos(), "variable name '%s' is too short for the scope of its usage", variable.name)
}
for param, dist := range paramToDist {
if param.isConventional() {
continue
}
if v.checkNameAndDistance(param.name, dist) {
continue
}
pass.Reportf(param.field.Pos(), "parameter name '%s' is too short for the scope of its usage", param.name)
}
for param, dist := range returnToDist {
if v.checkNameAndDistance(param.name, dist) {
continue
}
pass.Reportf(param.field.Pos(), "return value name '%s' is too short for the scope of its usage", param.name)
}
}
// checkNameAndDistance returns true when name or dist are considered "short", or when name is to be ignored.
func (v *varNameLen) checkNameAndDistance(name string, dist int) bool {
if len(name) >= v.minNameLength {
return true
}
if dist <= v.maxDistance {
return true
}
if v.ignoreNames.contains(name) {
return true
}
return false
}
// distances maps of variables or parameters and their longest usage distances.
func (v *varNameLen) distances(pass *analysis.Pass) (map[variable]int, map[parameter]int, map[parameter]int) {
assignIdents, paramIdents, returnIdents := v.idents(pass)
varToDist := map[variable]int{}
for _, ident := range assignIdents {
assign := ident.Obj.Decl.(*ast.AssignStmt)
variable := variable{
name: ident.Name,
assign: assign,
}
useLine := pass.Fset.Position(ident.NamePos).Line
declLine := pass.Fset.Position(assign.Pos()).Line
varToDist[variable] = useLine - declLine
}
paramToDist := map[parameter]int{}
for _, ident := range paramIdents {
field := ident.Obj.Decl.(*ast.Field)
param := parameter{
name: ident.Name,
field: field,
}
useLine := pass.Fset.Position(ident.NamePos).Line
declLine := pass.Fset.Position(field.Pos()).Line
paramToDist[param] = useLine - declLine
}
returnToDist := map[parameter]int{}
for _, ident := range returnIdents {
field := ident.Obj.Decl.(*ast.Field)
param := parameter{
name: ident.Name,
field: field,
}
useLine := pass.Fset.Position(ident.NamePos).Line
declLine := pass.Fset.Position(field.Pos()).Line
returnToDist[param] = useLine - declLine
}
return varToDist, paramToDist, returnToDist
}
// idents returns Idents referencing assign statements, parameters, and return values, respectively.
func (v *varNameLen) idents(pass *analysis.Pass) ([]*ast.Ident, []*ast.Ident, []*ast.Ident) { //nolint:gocognit
inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
filter := []ast.Node{
(*ast.Ident)(nil),
(*ast.FuncDecl)(nil),
}
funcs := []*ast.FuncDecl{}
methods := []*ast.FuncDecl{}
assignIdents := []*ast.Ident{}
paramIdents := []*ast.Ident{}
returnIdents := []*ast.Ident{}
inspector.Preorder(filter, func(node ast.Node) {
if f, ok := node.(*ast.FuncDecl); ok {
funcs = append(funcs, f)
if f.Recv != nil {
methods = append(methods, f)
}
return
}
ident := node.(*ast.Ident)
if ident.Obj == nil {
return
}
if _, ok := ident.Obj.Decl.(*ast.AssignStmt); ok {
assignIdents = append(assignIdents, ident)
return
}
if field, ok := ident.Obj.Decl.(*ast.Field); ok {
if isReceiver(field, methods) && !v.checkReceiver {
return
}
if isReturn(field, funcs) {
if !v.checkReturn {
return
}
returnIdents = append(returnIdents, ident)
return
}
paramIdents = append(paramIdents, ident)
}
})
return assignIdents, paramIdents, returnIdents
}
// isReceiver returns true when field is a receiver parameter of any of the given methods.
func isReceiver(field *ast.Field, methods []*ast.FuncDecl) bool {
for _, m := range methods {
for _, recv := range m.Recv.List {
if recv == field {
return true
}
}
}
return false
}
// isReturn returns true when field is a return value of any of the given funcs.
func isReturn(field *ast.Field, funcs []*ast.FuncDecl) bool {
for _, f := range funcs {
if f.Type.Results == nil {
continue
}
for _, r := range f.Type.Results.List {
if r == field {
return true
}
}
}
return false
}
// Set implements Value.
func (sv *stringsValue) Set(s string) error {
sv.Values = strings.Split(s, ",")
return nil
}
// String implements Value.
func (sv *stringsValue) String() string {
return strings.Join(sv.Values, ",")
}
// contains returns true when sv contains s.
func (sv *stringsValue) contains(s string) bool {
for _, v := range sv.Values {
if v == s {
return true
}
}
return false
}
// isConventional returns true when p is a conventional Go parameter, such as "ctx context.Context" or
// "t *testing.T".
func (p parameter) isConventional() bool { //nolint:gocyclo,gocognit
switch {
case p.name == "t" && p.isPointerType("testing.T"):
return true
case p.name == "b" && p.isPointerType("testing.B"):
return true
case p.name == "tb" && p.isType("testing.TB"):
return true
case p.name == "pb" && p.isPointerType("testing.PB"):
return true
case p.name == "m" && p.isPointerType("testing.M"):
return true
case p.name == "ctx" && p.isType("context.Context"):
return true
default:
return false
}
}
// isType returns true when p is of type typeName.
func (p parameter) isType(typeName string) bool {
sel, ok := p.field.Type.(*ast.SelectorExpr)
if !ok {
return false
}
return isType(sel, typeName)
}
// isPointerType returns true when p is a pointer type of type typeName.
func (p parameter) isPointerType(typeName string) bool {
star, ok := p.field.Type.(*ast.StarExpr)
if !ok {
return false
}
sel, ok := star.X.(*ast.SelectorExpr)
if !ok {
return false
}
return isType(sel, typeName)
}
// isType returns true when sel is a selector for type typeName.
func isType(sel *ast.SelectorExpr, typeName string) bool {
ident, ok := sel.X.(*ast.Ident)
if !ok {
return false
}
return typeName == ident.Name+"."+sel.Sel.Name
}

21
vendor/github.com/breml/bidichk/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Lucas Bremgartner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

67
vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go generated vendored Normal file
View file

@ -0,0 +1,67 @@
package bidichk
import (
"bytes"
"go/token"
"os"
"strings"
"unicode/utf8"
"golang.org/x/tools/go/analysis"
)
var Analyzer = &analysis.Analyzer{
Name: "bidichk",
Doc: "Checks for dangerous unicode character sequences",
Run: run,
}
func run(pass *analysis.Pass) (interface{}, error) {
var err error
pass.Fset.Iterate(func(f *token.File) bool {
if strings.HasPrefix(f.Name(), "$GOROOT") {
return true
}
return check(f.Name(), f.Pos(0), pass) == nil
})
return nil, err
}
var disallowedRunes = map[string]rune{
"LEFT-TO-RIGHT-EMBEDDING": '\u202A',
"RIGHT-TO-LEFT-EMBEDDING": '\u202B',
"POP-DIRECTIONAL-FORMATTING": '\u202C',
"LEFT-TO-RIGHT-OVERRIDE": '\u202D',
"RIGHT-TO-LEFT-OVERRIDE": '\u202E',
"LEFT-TO-RIGHT-ISOLATE": '\u2066',
"RIGHT-TO-LEFT-ISOLATE": '\u2067',
"FIRST-STRONG-ISOLATE": '\u2068',
"POP-DIRECTIONAL-ISOLATE": '\u2069',
}
func check(filename string, pos token.Pos, pass *analysis.Pass) error {
body, err := os.ReadFile(filename)
if err != nil {
return err
}
for name, r := range disallowedRunes {
start := 0
for {
idx := bytes.IndexRune(body[start:], r)
if idx == -1 {
break
}
start += idx
pass.Reportf(pos+token.Pos(start), "found dangerous unicode character sequence %s", name)
start += utf8.RuneLen(r)
}
}
return nil
}

21
vendor/github.com/butuzov/ireturn/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Oleg Butuzov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

193
vendor/github.com/butuzov/ireturn/analyzer/analyzer.go generated vendored Normal file
View file

@ -0,0 +1,193 @@
package analyzer
import (
"flag"
"fmt"
"go/ast"
gotypes "go/types"
"strings"
"sync"
"github.com/butuzov/ireturn/config"
"github.com/butuzov/ireturn/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
const name string = "ireturn" // linter name
type validator interface {
IsValid(types.IFace) bool
}
type analyzer struct {
once sync.Once
handler validator
err error
found []analysis.Diagnostic
}
func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {
// 00. Part 1. Handling Configuration Only Once.
a.once.Do(func() { a.readConfiguration(&pass.Analyzer.Flags) })
// 00. Part 2. Handling Errors
if a.err != nil {
return nil, a.err
}
// 01. Running Inspection.
ins, _ := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
ins.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) {
// 001. Casting to funcdecl
f, _ := node.(*ast.FuncDecl)
// 002. Does it return any results ?
if f.Type == nil || f.Type.Results == nil {
return
}
// 003. Is it allowed to be checked?
// TODO(butuzov): add inline comment
if hasDisallowDirective(f.Doc) {
return
}
// 004. Filtering Results.
for _, i := range filterInterfaces(pass, f.Type.Results) {
if a.handler.IsValid(i) {
continue
}
a.found = append(a.found, analysis.Diagnostic{ //nolint: exhaustivestruct
Pos: f.Pos(),
Message: fmt.Sprintf("%s returns interface (%s)", f.Name.Name, i.Name),
})
}
})
// 02. Printing reports.
for i := range a.found {
pass.Report(a.found[i])
}
return nil, nil
}
func (a *analyzer) readConfiguration(fs *flag.FlagSet) {
cnf, err := config.New(fs)
if err != nil {
a.err = err
return
}
if validatorImpl, ok := cnf.(validator); ok {
a.handler = validatorImpl
return
}
a.handler = config.DefaultValidatorConfig()
}
func NewAnalyzer() *analysis.Analyzer {
a := analyzer{} //nolint: exhaustivestruct
return &analysis.Analyzer{
Name: name,
Doc: "Accept Interfaces, Return Concrete Types",
Run: a.run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
Flags: flags(),
}
}
func flags() flag.FlagSet {
set := flag.NewFlagSet("", flag.PanicOnError)
set.String("allow", "", "accept-list of the comma-separated interfaces")
set.String("reject", "", "reject-list of the comma-separated interfaces")
return *set
}
func filterInterfaces(pass *analysis.Pass, fl *ast.FieldList) []types.IFace {
var results []types.IFace
for pos, el := range fl.List {
switch v := el.Type.(type) {
// ----- empty or anonymous interfaces
case *ast.InterfaceType:
if len(v.Methods.List) == 0 {
results = append(results, issue("interface{}", pos, types.EmptyInterface))
continue
}
results = append(results, issue("anonymous interface", pos, types.AnonInterface))
// ------ Errors and interfaces from same package
case *ast.Ident:
t1 := pass.TypesInfo.TypeOf(el.Type)
if !gotypes.IsInterface(t1.Underlying()) {
continue
}
word := t1.String()
// only build in interface is error
if obj := gotypes.Universe.Lookup(word); obj != nil {
results = append(results, issue(obj.Name(), pos, types.ErrorInterface))
continue
}
results = append(results, issue(word, pos, types.NamedInterface))
// ------- standard library and 3rd party interfaces
case *ast.SelectorExpr:
t1 := pass.TypesInfo.TypeOf(el.Type)
if !gotypes.IsInterface(t1.Underlying()) {
continue
}
word := t1.String()
if isStdLib(word) {
results = append(results, issue(word, pos, types.NamedStdInterface))
continue
}
results = append(results, issue(word, pos, types.NamedInterface))
}
}
return results
}
// isStdLib will run small checks against pkg to find out if named interface
// we lookling on comes from a standard library or not.
func isStdLib(named string) bool {
// find last dot index.
idx := strings.LastIndex(named, ".")
if idx == -1 {
return false
}
if _, ok := std[named[0:idx]]; ok {
return true
}
return false
}
// issue is shortcut that creates issue for next filtering.
func issue(name string, pos int, interfaceType types.IType) types.IFace {
return types.IFace{
Name: name,
Pos: pos,
Type: interfaceType,
}
}

45
vendor/github.com/butuzov/ireturn/analyzer/disallow.go generated vendored Normal file
View file

@ -0,0 +1,45 @@
package analyzer
import (
"go/ast"
"strings"
)
const nolintPrefix = "//nolint"
func hasDisallowDirective(cg *ast.CommentGroup) bool {
if cg == nil {
return false
}
return directiveFound(cg)
}
func directiveFound(cg *ast.CommentGroup) bool {
for i := len(cg.List) - 1; i >= 0; i-- {
comment := cg.List[i]
if !strings.HasPrefix(comment.Text, nolintPrefix) {
continue
}
startingIdx := len(nolintPrefix)
for {
idx := strings.Index(comment.Text[startingIdx:], name)
if idx == -1 {
break
}
if len(comment.Text[startingIdx+idx:]) == len(name) {
return true
}
c := comment.Text[startingIdx+idx+len(name)]
if c == '.' || c == ',' || c == ' ' || c == ' ' {
return true
}
startingIdx += idx + 1
}
}
return false
}

186
vendor/github.com/butuzov/ireturn/analyzer/std.go generated vendored Normal file
View file

@ -0,0 +1,186 @@
// Code generated using std.sh; DO NOT EDIT.
// We will ignore that fact that some of packages
// were removed from stdlib.
package analyzer
var std = map[string]struct{}{
// added in Go v1.2 in compare to v1.1 (docker image)
"archive/tar": {},
"archive/zip": {},
"bufio": {},
"bytes": {},
"cmd/cgo": {},
"cmd/fix": {},
"cmd/go": {},
"cmd/gofmt": {},
"cmd/yacc": {},
"compress/bzip2": {},
"compress/flate": {},
"compress/gzip": {},
"compress/lzw": {},
"compress/zlib": {},
"container/heap": {},
"container/list": {},
"container/ring": {},
"crypto": {},
"crypto/aes": {},
"crypto/cipher": {},
"crypto/des": {},
"crypto/dsa": {},
"crypto/ecdsa": {},
"crypto/elliptic": {},
"crypto/hmac": {},
"crypto/md5": {},
"crypto/rand": {},
"crypto/rc4": {},
"crypto/rsa": {},
"crypto/sha1": {},
"crypto/sha256": {},
"crypto/sha512": {},
"crypto/subtle": {},
"crypto/tls": {},
"crypto/x509": {},
"crypto/x509/pkix": {},
"database/sql": {},
"database/sql/driver": {},
"debug/dwarf": {},
"debug/elf": {},
"debug/gosym": {},
"debug/macho": {},
"debug/pe": {},
"encoding": {},
"encoding/ascii85": {},
"encoding/asn1": {},
"encoding/base32": {},
"encoding/base64": {},
"encoding/binary": {},
"encoding/csv": {},
"encoding/gob": {},
"encoding/hex": {},
"encoding/json": {},
"encoding/pem": {},
"encoding/xml": {},
"errors": {},
"expvar": {},
"flag": {},
"fmt": {},
"go/ast": {},
"go/build": {},
"go/doc": {},
"go/format": {},
"go/parser": {},
"go/printer": {},
"go/scanner": {},
"go/token": {},
"hash": {},
"hash/adler32": {},
"hash/crc32": {},
"hash/crc64": {},
"hash/fnv": {},
"html": {},
"html/template": {},
"image": {},
"image/color": {},
"image/color/palette": {},
"image/draw": {},
"image/gif": {},
"image/jpeg": {},
"image/png": {},
"index/suffixarray": {},
"io": {},
"io/ioutil": {},
"log": {},
"log/syslog": {},
"math": {},
"math/big": {},
"math/cmplx": {},
"math/rand": {},
"mime": {},
"mime/multipart": {},
"net": {},
"net/http": {},
"net/http/cgi": {},
"net/http/cookiejar": {},
"net/http/fcgi": {},
"net/http/httptest": {},
"net/http/httputil": {},
"net/http/pprof": {},
"net/mail": {},
"net/rpc": {},
"net/rpc/jsonrpc": {},
"net/smtp": {},
"net/textproto": {},
"net/url": {},
"os": {},
"os/exec": {},
"os/signal": {},
"os/user": {},
"path": {},
"path/filepath": {},
"reflect": {},
"regexp": {},
"regexp/syntax": {},
"runtime": {},
"runtime/cgo": {},
"runtime/debug": {},
"runtime/pprof": {},
"runtime/race": {},
"sort": {},
"strconv": {},
"strings": {},
"sync": {},
"sync/atomic": {},
"syscall": {},
"testing": {},
"testing/iotest": {},
"testing/quick": {},
"text/scanner": {},
"text/tabwriter": {},
"text/template": {},
"text/template/parse": {},
"time": {},
"unicode": {},
"unicode/utf16": {},
"unicode/utf8": {},
"unsafe": {},
// added in Go v1.3 in compare to v1.2 (docker image)
"cmd/addr2line": {},
"cmd/nm": {},
"cmd/objdump": {},
"cmd/pack": {},
"debug/plan9obj": {},
// added in Go v1.4 in compare to v1.3 (docker image)
"cmd/pprof": {},
// added in Go v1.5 in compare to v1.4 (docker image)
"go/constant": {},
"go/importer": {},
"go/types": {},
"mime/quotedprintable": {},
"runtime/trace": {},
// added in Go v1.6 in compare to v1.5 (docker image)
// added in Go v1.7 in compare to v1.6 (docker image)
"context": {},
"net/http/httptrace": {},
// added in Go v1.8 in compare to v1.7 (docker image)
"plugin": {},
// added in Go v1.9 in compare to v1.8 (docker image)
"math/bits": {},
// added in Go v1.10 in compare to v1.9 (docker image)
// added in Go v1.11 in compare to v1.10 (docker image)
// added in Go v1.12 in compare to v1.11 (docker image)
// added in Go v1.13 in compare to v1.12 (docker image)
"crypto/ed25519": {},
// added in Go v1.14 in compare to v1.13 (docker image)
"hash/maphash": {},
// added in Go v1.15 in compare to v1.14 (docker image)
"time/tzdata": {},
// added in Go v1.16 in compare to v1.15 (docker image)
"embed": {},
"go/build/constraint": {},
"io/fs": {},
"runtime/metrics": {},
"testing/fstest": {},
// added in Go v1.17 in compare to v1.16 (docker image)
}

17
vendor/github.com/butuzov/ireturn/config/allow.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
package config
import "github.com/butuzov/ireturn/types"
// allowConfig specifies a list of interfaces (keywords, patters and regular expressions)
// that are allowed by ireturn as valid to return, any non listed interface are rejected.
type allowConfig struct {
*defaultConfig
}
func allowAll(patterns []string) *allowConfig {
return &allowConfig{&defaultConfig{List: patterns}}
}
func (ac *allowConfig) IsValid(i types.IFace) bool {
return ac.Has(i)
}

66
vendor/github.com/butuzov/ireturn/config/config.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
package config
import (
"regexp"
"github.com/butuzov/ireturn/types"
)
// defaultConfig is core of the validation, ...
// todo(butuzov): write proper intro...
type defaultConfig struct {
List []string
// private fields (for search optimization look ups)
init bool
quick uint8
list []*regexp.Regexp
}
func (config *defaultConfig) Has(i types.IFace) bool {
if !config.init {
config.compileList()
config.init = true
}
if config.quick&uint8(i.Type) > 0 {
return true
}
// not a named interface (because error, interface{}, anon interface has keywords.)
if i.Type&types.NamedInterface == 0 && i.Type&types.NamedStdInterface == 0 {
return false
}
for _, re := range config.list {
if re.MatchString(i.Name) {
return true
}
}
return false
}
// compileList will transform text list into a bitmask for quick searches and
// slice of regular expressions for quick searches.
func (config *defaultConfig) compileList() {
for _, str := range config.List {
switch str {
case types.NameError:
config.quick |= uint8(types.ErrorInterface)
case types.NameEmpty:
config.quick |= uint8(types.EmptyInterface)
case types.NameAnon:
config.quick |= uint8(types.AnonInterface)
case types.NameStdLib:
config.quick |= uint8(types.NamedStdInterface)
}
// allow to parse regular expressions
// todo(butuzov): how can we log error in golangci-lint?
if re, err := regexp.Compile(str); err == nil {
config.list = append(config.list, re)
}
}
}

74
vendor/github.com/butuzov/ireturn/config/new.go generated vendored Normal file
View file

@ -0,0 +1,74 @@
package config
import (
"errors"
"flag"
"strings"
"github.com/butuzov/ireturn/types"
)
var ErrCollisionOfInterests = errors.New("can't have both `-accept` and `-reject` specified at same time")
//nolint: exhaustivestruct
func DefaultValidatorConfig() *allowConfig {
return allowAll([]string{
types.NameEmpty, // "empty": empty interfaces (interface{})
types.NameError, // "error": for all error's
types.NameAnon, // "anon": for all empty interfaces with methods (interface {Method()})
types.NameStdLib, // "std": for all standard library packages
})
}
// New is factory function that return allowConfig or rejectConfig depending
// on provided arguments.
func New(fs *flag.FlagSet) (interface{}, error) {
var (
allowList = toSlice(getFlagVal(fs, "allow"))
rejectList = toSlice(getFlagVal(fs, "reject"))
)
// can't have both at same time.
if len(allowList) != 0 && len(rejectList) != 0 {
return nil, ErrCollisionOfInterests
}
switch {
case len(allowList) > 0:
return allowAll(allowList), nil
case len(rejectList) > 0:
return rejectAll(rejectList), nil
}
// can have none at same time.
return nil, nil
}
// both constants used to cleanup items provided in comma separated list.
const (
SepTab string = " "
SepSpace string = " "
)
func toSlice(s string) []string {
var results []string
for _, pattern := range strings.Split(s, ",") {
pattern = strings.Trim(pattern, SepTab+SepSpace)
if pattern != "" {
results = append(results, pattern)
}
}
return results
}
func getFlagVal(fs *flag.FlagSet, name string) string {
flg := fs.Lookup(name)
if flg == nil {
return ""
}
return flg.Value.String()
}

17
vendor/github.com/butuzov/ireturn/config/reject.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
package config
import "github.com/butuzov/ireturn/types"
// rejectConfig specifies a list of interfaces (keywords, patters and regular expressions)
// that are rejected by ireturn as valid to return, any non listed interface are allowed.
type rejectConfig struct {
*defaultConfig
}
func rejectAll(patterns []string) *rejectConfig {
return &rejectConfig{&defaultConfig{List: patterns}}
}
func (rc *rejectConfig) IsValid(i types.IFace) bool {
return !rc.Has(i)
}

7
vendor/github.com/butuzov/ireturn/types/iface.go generated vendored Normal file
View file

@ -0,0 +1,7 @@
package types
type IFace struct {
Name string // Preserved for named interfaces
Pos int // Position in return tuple
Type IType // Type of the interface
}

8
vendor/github.com/butuzov/ireturn/types/names.go generated vendored Normal file
View file

@ -0,0 +1,8 @@
package types
const (
NameEmpty = "empty"
NameAnon = "anon"
NameError = "error"
NameStdLib = "stdlib"
)

11
vendor/github.com/butuzov/ireturn/types/types.go generated vendored Normal file
View file

@ -0,0 +1,11 @@
package types
type IType uint8
const (
EmptyInterface IType = 1 << iota // ref as empty
AnonInterface // ref as anon
ErrorInterface // ref as error
NamedInterface // ref as named
NamedStdInterface // ref as named stdlib
)

View file

@ -7,22 +7,25 @@ Duration Check
A Go linter to detect cases where two `time.Duration` values are being multiplied in possibly erroneous ways.
For example, consider the following (highly contrived) function:
Consider the following (highly contrived) code:
```go
func waitFor(someDuration time.Duration) {
timeToWait := someDuration * time.Second
time.Sleep(timeToWait)
func waitForSeconds(someDuration time.Duration) {
timeToWait := someDuration * time.Second
fmt.Printf("Waiting for %s\n", timeToWait)
}
func main() {
waitForSeconds(5) // waits for 5 seconds
waitForSeconds(5 * time.Second) // waits for 1388888h 53m 20s
}
```
Although the above code would compile without any errors, its runtime behaviour would almost certainly be incorrect.
A caller would reasonably expect `waitFor(5 * time.Seconds)` to wait for ~5 seconds but they would actually end up
waiting for ~1,388,889 hours.
Both invocations of the function are syntactically correct but the second one is probably not what most people want.
In this contrived example it is quite easy to spot the mistake. However, if the incorrect `waitForSeconds` invocation is
nested deep within a complex piece of code that runs in the background, the mistake could go unnoticed for months (which
is exactly what happened in a production backend system of fairly well-known software service).
The above example is just for illustration purposes only. The problem is glaringly obvious in such a simple function
and even the greenest Gopher would discover the issue immediately. However, imagine a much more complicated function
with many more lines and it is not inconceivable that such logic errors could go unnoticed.
See the [test cases](testdata/src/a/a.go) for more examples of the types of errors detected by the linter.

View file

@ -150,6 +150,9 @@ func isAcceptableNestedExpr(pass *analysis.Pass, n ast.Expr) bool {
case *ast.Ident:
return isAcceptableIdent(pass, e)
case *ast.CallExpr:
if isAcceptableCast(pass, e) {
return true
}
t := pass.TypesInfo.TypeOf(e)
return !isDuration(t)
case *ast.SelectorExpr:

View file

@ -85,8 +85,9 @@ func (nom namedOccurrenceMap) checkStatement(stmt ast.Stmt, ifPos token.Pos) {
nom.checkExpression(a, ifPos)
}
case *ast.ExprStmt:
if callExpr, ok := v.X.(*ast.CallExpr); ok {
nom.checkExpression(callExpr, ifPos)
switch v.X.(type) {
case *ast.CallExpr, *ast.UnaryExpr:
nom.checkExpression(v.X, ifPos)
}
case *ast.ForStmt:
for _, el := range v.Body.List {
@ -157,12 +158,11 @@ func (nom namedOccurrenceMap) checkStatement(stmt ast.Stmt, ifPos token.Pos) {
}
for _, c := range clauses.Body {
if est, ok := c.(*ast.ExprStmt); ok {
nom.checkExpression(est.X, ifPos)
}
switch v := c.(type) {
case *ast.AssignStmt:
for _, el := range v.Lhs {
nom.checkExpression(el, ifPos)
}
for _, el := range v.Rhs {
nom.checkExpression(el, ifPos)
}
@ -171,6 +171,28 @@ func (nom namedOccurrenceMap) checkStatement(stmt ast.Stmt, ifPos token.Pos) {
}
}
}
case *ast.SelectStmt:
for _, el := range v.Body.List {
clause := el.(*ast.CommClause)
nom.checkStatement(clause.Comm, ifPos)
for _, c := range clause.Body {
switch v := c.(type) {
case *ast.AssignStmt:
for _, el := range v.Lhs {
nom.checkExpression(el, ifPos)
}
for _, el := range v.Rhs {
nom.checkExpression(el, ifPos)
}
case *ast.ExprStmt:
nom.checkExpression(v.X, ifPos)
}
}
}
case *ast.LabeledStmt:
nom.checkStatement(v.Stmt, ifPos)
}
}
@ -190,7 +212,7 @@ func (nom namedOccurrenceMap) checkExpression(candidate ast.Expr, ifPos token.Po
case *ast.CompositeLit:
for _, el := range v.Elts {
switch v := el.(type) {
case *ast.Ident:
case *ast.Ident, *ast.CompositeLit:
nom.checkExpression(v, ifPos)
case *ast.KeyValueExpr:
nom.checkExpression(v.Key, ifPos)
@ -217,6 +239,8 @@ func (nom namedOccurrenceMap) checkExpression(candidate ast.Expr, ifPos token.Po
}
}
}
case *ast.StarExpr:
nom.checkExpression(v.X, ifPos)
case *ast.IndexExpr:
nom.checkExpression(v.X, ifPos)
switch index := v.Index.(type) {

View file

@ -78,7 +78,7 @@ notice("Don't forget this...")
### Custom fprint functions (FprintFunc)
```go
blue := color.New(FgBlue).FprintfFunc()
blue := color.New(color.FgBlue).FprintfFunc()
blue(myWriter, "important notice: %s", stars)
// Mix up with multiple attributes

View file

@ -3,6 +3,6 @@ module github.com/fatih/color
go 1.13
require (
github.com/mattn/go-colorable v0.1.8
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-colorable v0.1.9
github.com/mattn/go-isatty v0.0.14
)

10
vendor/github.com/fatih/color/go.sum generated vendored
View file

@ -1,7 +1,9 @@
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

2
vendor/github.com/fsnotify/fsnotify/.mailmap generated vendored Normal file
View file

@ -0,0 +1,2 @@
Chris Howey <howeyc@gmail.com> <chris@howey.me>
Nathan Youngman <git@nathany.com> <4566+nathany@users.noreply.github.com>

View file

@ -1,36 +0,0 @@
sudo: false
language: go
go:
- "stable"
- "1.11.x"
- "1.10.x"
- "1.9.x"
matrix:
include:
- go: "stable"
env: GOLINT=true
allow_failures:
- go: tip
fast_finish: true
before_install:
- if [ ! -z "${GOLINT}" ]; then go get -u golang.org/x/lint/golint; fi
script:
- go test --race ./...
after_script:
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
- if [ ! -z "${GOLINT}" ]; then echo running golint; golint --set_exit_status ./...; else echo skipping golint; fi
- go vet ./...
os:
- linux
- osx
- windows
notifications:
email: false

View file

@ -4,35 +4,44 @@
# You can update this list using the following command:
#
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
# $ (head -n10 AUTHORS && git shortlog -se | sed -E 's/^\s+[0-9]+\t//') | tee AUTHORS
# Please keep the list sorted.
Aaron L <aaron@bettercoder.net>
Adrien Bustany <adrien@bustany.org>
Alexey Kazakov <alkazako@redhat.com>
Amit Krishnan <amit.krishnan@oracle.com>
Anmol Sethi <me@anmol.io>
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Brian Goff <cpuguy83@gmail.com>
Bruno Bigras <bigras.bruno@gmail.com>
Caleb Spare <cespare@gmail.com>
Case Nelson <case@teammating.com>
Chris Howey <chris@howey.me> <howeyc@gmail.com>
Chris Howey <howeyc@gmail.com>
Christoffer Buchholz <christoffer.buchholz@gmail.com>
Daniel Wagner-Hall <dawagner@gmail.com>
Dave Cheney <dave@cheney.net>
Eric Lin <linxiulei@gmail.com>
Evan Phoenix <evan@fallingsnow.net>
Francisco Souza <f@souza.cc>
Gautam Dey <gautam.dey77@gmail.com>
Hari haran <hariharan.uno@gmail.com>
John C Barstow
Ichinose Shogo <shogo82148@gmail.com>
Johannes Ebke <johannes@ebke.org>
John C Barstow <jbowtie@amathaine.com>
Kelvin Fo <vmirage@gmail.com>
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
Matt Layher <mdlayher@gmail.com>
Matthias Stone <matthias@bellstone.ca>
Nathan Youngman <git@nathany.com>
Nickolai Zeldovich <nickolai@csail.mit.edu>
Oliver Bristow <evilumbrella+github@gmail.com>
Patrick <patrick@dropbox.com>
Paul Hammond <paul@paulhammond.org>
Pawel Knap <pawelknap88@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk>
Pratik Shinde <pratikshinde320@gmail.com>
Pursuit92 <JoshChase@techpursuit.net>
Riku Voipio <riku.voipio@linaro.org>
Rob Figueiredo <robfig@gmail.com>
@ -41,6 +50,7 @@ Slawek Ligus <root@ooz.ie>
Soge Zhang <zhssoge@gmail.com>
Tiffany Jernigan <tiffany.jernigan@intel.com>
Tilak Sharma <tilaks@google.com>
Tobias Klauser <tobias.klauser@gmail.com>
Tom Payne <twpayne@gmail.com>
Travis Cline <travis.cline@gmail.com>
Tudor Golubenco <tudor.g@gmail.com>

View file

@ -1,6 +1,28 @@
# Changelog
## v1.4.7 / 2018-01-09
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.5.1] - 2021-08-24
* Revert Add AddRaw to not follow symlinks
## [1.5.0] - 2021-08-20
* Go: Increase minimum required version to Go 1.12 [#381](https://github.com/fsnotify/fsnotify/pull/381)
* Feature: Add AddRaw method which does not follow symlinks when adding a watch [#289](https://github.com/fsnotify/fsnotify/pull/298)
* Windows: Follow symlinks by default like on all other systems [#289](https://github.com/fsnotify/fsnotify/pull/289)
* CI: Use GitHub Actions for CI and cover go 1.12-1.17
[#378](https://github.com/fsnotify/fsnotify/pull/378)
[#381](https://github.com/fsnotify/fsnotify/pull/381)
[#385](https://github.com/fsnotify/fsnotify/pull/385)
* Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325)
## [1.4.7] - 2018-01-09
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
* Tests: Fix missing verb on format string (thanks @rchiossi)
@ -10,62 +32,62 @@
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
* Docs: replace references to OS X with macOS
## v1.4.2 / 2016-10-10
## [1.4.2] - 2016-10-10
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
## v1.4.1 / 2016-10-04
## [1.4.1] - 2016-10-04
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
## v1.4.0 / 2016-10-01
## [1.4.0] - 2016-10-01
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
## v1.3.1 / 2016-06-28
## [1.3.1] - 2016-06-28
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
## v1.3.0 / 2016-04-19
## [1.3.0] - 2016-04-19
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
## v1.2.10 / 2016-03-02
## [1.2.10] - 2016-03-02
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
## v1.2.9 / 2016-01-13
## [1.2.9] - 2016-01-13
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
## v1.2.8 / 2015-12-17
## [1.2.8] - 2015-12-17
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
* inotify: fix race in test
* enable race detection for continuous integration (Linux, Mac, Windows)
## v1.2.5 / 2015-10-17
## [1.2.5] - 2015-10-17
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
## v1.2.1 / 2015-10-14
## [1.2.1] - 2015-10-14
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
## v1.2.0 / 2015-02-08
## [1.2.0] - 2015-02-08
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
## v1.1.1 / 2015-02-05
## [1.1.1] - 2015-02-05
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
## v1.1.0 / 2014-12-12
## [1.1.0] - 2014-12-12
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
* add low-level functions
@ -77,22 +99,22 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
## v1.0.4 / 2014-09-07
## [1.0.4] - 2014-09-07
* kqueue: add dragonfly to the build tags.
* Rename source code files, rearrange code so exported APIs are at the top.
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
## v1.0.3 / 2014-08-19
## [1.0.3] - 2014-08-19
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
## v1.0.2 / 2014-08-17
## [1.0.2] - 2014-08-17
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
## v1.0.0 / 2014-08-15
## [1.0.0] - 2014-08-15
* [API] Remove AddWatch on Windows, use Add.
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
@ -146,51 +168,51 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
* no tests for the current implementation
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
## v0.9.3 / 2014-12-31
## [0.9.3] - 2014-12-31
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
## v0.9.2 / 2014-08-17
## [0.9.2] - 2014-08-17
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
## v0.9.1 / 2014-06-12
## [0.9.1] - 2014-06-12
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
## v0.9.0 / 2014-01-17
## [0.9.0] - 2014-01-17
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
## v0.8.12 / 2013-11-13
## [0.8.12] - 2013-11-13
* [API] Remove FD_SET and friends from Linux adapter
## v0.8.11 / 2013-11-02
## [0.8.11] - 2013-11-02
* [Doc] Add Changelog [#72][] (thanks @nathany)
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
## v0.8.10 / 2013-10-19
## [0.8.10] - 2013-10-19
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
* [Doc] specify OS-specific limits in README (thanks @debrando)
## v0.8.9 / 2013-09-08
## [0.8.9] - 2013-09-08
* [Doc] Contributing (thanks @nathany)
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
* [Doc] GoCI badge in README (Linux only) [#60][]
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
## v0.8.8 / 2013-06-17
## [0.8.8] - 2013-06-17
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
## v0.8.7 / 2013-06-03
## [0.8.7] - 2013-06-03
* [API] Make syscall flags internal
* [Fix] inotify: ignore event changes
@ -198,74 +220,74 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
* [Fix] tests on Windows
* lower case error messages
## v0.8.6 / 2013-05-23
## [0.8.6] - 2013-05-23
* kqueue: Use EVT_ONLY flag on Darwin
* [Doc] Update README with full example
## v0.8.5 / 2013-05-09
## [0.8.5] - 2013-05-09
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
## v0.8.4 / 2013-04-07
## [0.8.4] - 2013-04-07
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
## v0.8.3 / 2013-03-13
## [0.8.3] - 2013-03-13
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
## v0.8.2 / 2013-02-07
## [0.8.2] - 2013-02-07
* [Doc] add Authors
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
## v0.8.1 / 2013-01-09
## [0.8.1] - 2013-01-09
* [Fix] Windows path separators
* [Doc] BSD License
## v0.8.0 / 2012-11-09
## [0.8.0] - 2012-11-09
* kqueue: directory watching improvements (thanks @vmirage)
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
## v0.7.4 / 2012-10-09
## [0.7.4] - 2012-10-09
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
* [Fix] kqueue: modify after recreation of file
## v0.7.3 / 2012-09-27
## [0.7.3] - 2012-09-27
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
* [Fix] kqueue: no longer get duplicate CREATE events
## v0.7.2 / 2012-09-01
## [0.7.2] - 2012-09-01
* kqueue: events for created directories
## v0.7.1 / 2012-07-14
## [0.7.1] - 2012-07-14
* [Fix] for renaming files
## v0.7.0 / 2012-07-02
## [0.7.0] - 2012-07-02
* [Feature] FSNotify flags
* [Fix] inotify: Added file name back to event path
## v0.6.0 / 2012-06-06
## [0.6.0] - 2012-06-06
* kqueue: watch files after directory created (thanks @tmc)
## v0.5.1 / 2012-05-22
## [0.5.1] - 2012-05-22
* [Fix] inotify: remove all watches before Close()
## v0.5.0 / 2012-05-03
## [0.5.0] - 2012-05-03
* [API] kqueue: return errors during watch instead of sending over channel
* kqueue: match symlink behavior on Linux
@ -273,22 +295,22 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn
* [Fix] kqueue: handle EINTR (reported by @robfig)
* [Doc] Godoc example [#1][] (thanks @davecheney)
## v0.4.0 / 2012-03-30
## [0.4.0] - 2012-03-30
* Go 1 released: build with go tool
* [Feature] Windows support using winfsnotify
* Windows does not have attribute change notifications
* Roll attribute notifications into IsModify
## v0.3.0 / 2012-02-19
## [0.3.0] - 2012-02-19
* kqueue: add files when watch directory
## v0.2.0 / 2011-12-30
## [0.2.0] - 2011-12-30
* update to latest Go weekly code
## v0.1.0 / 2011-10-19
## [0.1.0] - 2011-10-19
* kqueue: add watch on file creation to match inotify
* kqueue: create file event

View file

@ -12,9 +12,9 @@ Cross platform: Windows, Linux, BSD and macOS.
| Adapter | OS | Status |
| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| inotify | Linux 2.6.27 or later, Android\* | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) |
| kqueue | BSD, macOS, iOS\* | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) |
| ReadDirectoryChangesW | Windows | Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify) |
| inotify | Linux 2.6.27 or later, Android\* | Supported |
| kqueue | BSD, macOS, iOS\* | Supported |
| ReadDirectoryChangesW | Windows | Supported |
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build solaris
// +build solaris
package fsnotify

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !plan9
// +build !plan9
// Package fsnotify provides a platform-independent interface for file system notifications.

View file

@ -2,4 +2,6 @@ module github.com/fsnotify/fsnotify
go 1.13
require golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9
require golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
retract v1.5.0

View file

@ -1,2 +1,2 @@
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux
// +build linux
package fsnotify
@ -272,7 +273,7 @@ func (w *Watcher) readEvents() {
if nameLen > 0 {
// Point "bytes" at the first byte of the filename
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
}

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux
// +build linux
package fsnotify

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build freebsd || openbsd || netbsd || dragonfly || darwin
// +build freebsd openbsd netbsd dragonfly darwin
package fsnotify

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build freebsd || openbsd || netbsd || dragonfly
// +build freebsd openbsd netbsd dragonfly
package fsnotify

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin
// +build darwin
package fsnotify

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build windows
// +build windows
package fsnotify

View file

@ -1,7 +1,6 @@
MIT License
Copyright (c) 2018-2019 Alekseev Artem
Copyright (c) 2018-2019 Ravil Bikbulatov
Copyright (c) 2018-2021 go-critic team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -30,7 +30,7 @@ type appendCombineChecker struct {
ctx *linter.CheckerContext
}
func (c *appendCombineChecker) VisitStmtList(list []ast.Stmt) {
func (c *appendCombineChecker) VisitStmtList(_ ast.Node, list []ast.Stmt) {
var cause ast.Node // First append
var slice ast.Expr // Slice being appended to
chain := 0 // How much appends in a row we've seen

View file

@ -1,97 +0,0 @@
package checkers
import (
"go/ast"
"go/types"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astp"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "argOrder"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects suspicious arguments order"
info.Before = `strings.HasPrefix("#", userpass)`
info.After = `strings.HasPrefix(userpass, "#")`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&argOrderChecker{ctx: ctx}), nil
})
}
type argOrderChecker struct {
astwalk.WalkHandler
ctx *linter.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 {
// Also permit byte slices.
switch x := x.(type) {
case *ast.BasicLit:
return true
case *ast.CallExpr:
// Handle `[]byte("abc")` as well.
if len(x.Args) != 1 || !astp.IsBasicLit(x.Args[0]) {
return false
}
typ, ok := c.ctx.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.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)
}

View file

@ -1,102 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astequal"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "assignOp"
info.Tags = []string{"style"}
info.Summary = "Detects assignments that can be simplified by using assignment operators"
info.Before = `x = x * 2`
info.After = `x *= 2`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForStmt(&assignOpChecker{ctx: ctx}), nil
})
}
type assignOpChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *assignOpChecker) VisitStmt(stmt ast.Stmt) {
assign, ok := stmt.(*ast.AssignStmt)
cond := ok &&
assign.Tok == token.ASSIGN &&
len(assign.Lhs) == 1 &&
len(assign.Rhs) == 1 &&
typep.SideEffectFree(c.ctx.TypesInfo, assign.Lhs[0])
if !cond {
return
}
// TODO(quasilyte): can take commutativity into account.
expr, ok := assign.Rhs[0].(*ast.BinaryExpr)
if !ok || !astequal.Expr(assign.Lhs[0], expr.X) {
return
}
// TODO(quasilyte): perform unparen?
switch expr.Op {
case token.MUL:
c.warn(assign, token.MUL_ASSIGN, expr.Y)
case token.QUO:
c.warn(assign, token.QUO_ASSIGN, expr.Y)
case token.REM:
c.warn(assign, token.REM_ASSIGN, expr.Y)
case token.ADD:
c.warn(assign, token.ADD_ASSIGN, expr.Y)
case token.SUB:
c.warn(assign, token.SUB_ASSIGN, expr.Y)
case token.AND:
c.warn(assign, token.AND_ASSIGN, expr.Y)
case token.OR:
c.warn(assign, token.OR_ASSIGN, expr.Y)
case token.XOR:
c.warn(assign, token.XOR_ASSIGN, expr.Y)
case token.SHL:
c.warn(assign, token.SHL_ASSIGN, expr.Y)
case token.SHR:
c.warn(assign, token.SHR_ASSIGN, expr.Y)
case token.AND_NOT:
c.warn(assign, token.AND_NOT_ASSIGN, expr.Y)
}
}
func (c *assignOpChecker) warn(cause *ast.AssignStmt, op token.Token, rhs ast.Expr) {
suggestion := c.simplify(cause, op, rhs)
c.ctx.Warn(cause, "replace `%s` with `%s`", cause, suggestion)
}
func (c *assignOpChecker) simplify(cause *ast.AssignStmt, op token.Token, rhs ast.Expr) ast.Stmt {
if lit, ok := rhs.(*ast.BasicLit); ok && lit.Kind == token.INT && lit.Value == "1" {
switch op {
case token.ADD_ASSIGN:
return &ast.IncDecStmt{
X: cause.Lhs[0],
TokPos: cause.TokPos,
Tok: token.INC,
}
case token.SUB_ASSIGN:
return &ast.IncDecStmt{
X: cause.Lhs[0],
TokPos: cause.TokPos,
Tok: token.DEC,
}
}
}
suggestion := astcopy.AssignStmt(cause)
suggestion.Tok = op
suggestion.Rhs[0] = rhs
return suggestion
}

View file

@ -1,63 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
)
func init() {
var info linter.CheckerInfo
info.Name = "badCall"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects suspicious function calls"
info.Before = `strings.Replace(s, from, to, 0)`
info.After = `strings.Replace(s, from, to, -1)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&badCallChecker{ctx: ctx}), nil
})
}
type badCallChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *badCallChecker) VisitExpr(expr ast.Expr) {
call := astcast.ToCallExpr(expr)
if len(call.Args) == 0 {
return
}
// TODO(quasilyte): handle methods.
switch qualifiedName(call.Fun) {
case "strings.Replace", "bytes.Replace":
if n := astcast.ToBasicLit(call.Args[3]); n.Value == "0" {
c.warnBadArg(n, "-1")
}
case "strings.SplitN", "bytes.SplitN":
if n := astcast.ToBasicLit(call.Args[2]); n.Value == "0" {
c.warnBadArg(n, "-1")
}
case "append":
if len(call.Args) == 1 {
c.warnAppend(call)
}
}
}
func (c *badCallChecker) warnBadArg(badArg *ast.BasicLit, correction string) {
goodArg := astcopy.BasicLit(badArg)
goodArg.Value = correction
c.ctx.Warn(badArg, "suspicious arg %s, probably meant %s",
badArg, goodArg)
}
func (c *badCallChecker) warnAppend(call *ast.CallExpr) {
c.ctx.Warn(call, "no-op append call, probably missing arguments")
}

View file

@ -1,116 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astequal"
)
func init() {
var info linter.CheckerInfo
info.Name = "badLock"
info.Tags = []string{"diagnostic", "experimental"}
info.Summary = "Detects suspicious mutex lock/unlock operations"
info.Before = `
mu.Lock()
mu.Unlock()`
info.After = `
mu.Lock()
defer mu.Unlock()`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForStmtList(&badLockChecker{ctx: ctx}), nil
})
}
type badLockChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *badLockChecker) VisitStmtList(list []ast.Stmt) {
if len(list) < 2 {
return
}
for i := 0; i < len(list)-1; i++ {
current, ok := list[i].(*ast.ExprStmt)
if !ok {
continue
}
deferred := false
var next ast.Expr
switch x := list[i+1].(type) {
case *ast.ExprStmt:
next = x.X
case *ast.DeferStmt:
next = x.Call
deferred = true
default:
continue
}
mutex1, lockFunc, ok := c.asLockedMutex(current.X)
if !ok {
continue
}
mutex2, unlockFunc, ok := c.asUnlockedMutex(next)
if !ok {
continue
}
if !astequal.Expr(mutex1, mutex2) {
continue
}
switch {
case !deferred:
c.warnImmediateUnlock(mutex2)
case lockFunc == "Lock" && unlockFunc == "RUnlock":
c.warnMismatchingUnlock(mutex2, "Unlock")
case lockFunc == "RLock" && unlockFunc == "Unlock":
c.warnMismatchingUnlock(mutex2, "RUnlock")
}
}
}
func (c *badLockChecker) asLockedMutex(e ast.Expr) (ast.Expr, string, bool) {
call, ok := e.(*ast.CallExpr)
if !ok || len(call.Args) != 0 {
return nil, "", false
}
switch fn := call.Fun.(type) {
case *ast.SelectorExpr:
if fn.Sel.Name == "Lock" || fn.Sel.Name == "RLock" {
return fn.X, fn.Sel.Name, true
}
return nil, "", false
default:
return nil, "", false
}
}
func (c *badLockChecker) asUnlockedMutex(e ast.Expr) (ast.Expr, string, bool) {
call, ok := e.(*ast.CallExpr)
if !ok || len(call.Args) != 0 {
return nil, "", false
}
switch fn := call.Fun.(type) {
case *ast.SelectorExpr:
if fn.Sel.Name == "Unlock" || fn.Sel.Name == "RUnlock" {
return fn.X, fn.Sel.Name, true
}
return nil, "", false
default:
return nil, "", false
}
}
func (c *badLockChecker) warnImmediateUnlock(cause ast.Node) {
c.ctx.Warn(cause, "defer is missing, mutex is unlocked immediately")
}
func (c *badLockChecker) warnMismatchingUnlock(cause ast.Node, suggestion string) {
c.ctx.Warn(cause, "suspicious unlock, maybe %s was intended?", suggestion)
}

View file

@ -2,9 +2,15 @@
package checkers
import (
"fmt"
"go/ast"
"go/build"
"go/token"
"os"
"github.com/go-critic/go-critic/checkers/rulesdata"
"github.com/go-critic/go-critic/framework/linter"
"github.com/quasilyte/go-ruleguard/ruleguard"
)
var collection = &linter.CheckerCollection{
@ -17,3 +23,93 @@ var debug = func() func() bool {
return v
}
}()
//go:generate go run ./rules/precompile.go -rules ./rules/rules.go -o ./rulesdata/rulesdata.go
func init() {
filename := "rules/rules.go"
fset := token.NewFileSet()
var groups []ruleguard.GoRuleGroup
var buildContext *build.Context
ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != ""
// First we create an Engine to parse all rules.
// We need it to get the structured info about our rules
// that will be used to generate checkers.
// We introduce an extra scope in hope that rootEngine
// will be garbage-collected after we don't need it.
// LoadedGroups() returns a slice copy and that's all what we need.
{
rootEngine := ruleguard.NewEngine()
rootEngine.InferBuildContext()
buildContext = rootEngine.BuildContext
loadContext := &ruleguard.LoadContext{
Fset: fset,
DebugImports: ruleguardDebug,
DebugPrint: func(s string) {
fmt.Println("debug:", s)
},
}
if err := rootEngine.LoadFromIR(loadContext, filename, rulesdata.PrecompiledRules); err != nil {
panic(fmt.Sprintf("load embedded ruleguard rules: %v", err))
}
groups = rootEngine.LoadedGroups()
}
// For every rules group we create a new checker and a separate engine.
// That dedicated ruleguard engine will contain rules only from one group.
for i := range groups {
g := groups[i]
info := &linter.CheckerInfo{
Name: g.Name,
Summary: g.DocSummary,
Before: g.DocBefore,
After: g.DocAfter,
Note: g.DocNote,
Tags: g.DocTags,
EmbeddedRuleguard: true,
}
collection.AddChecker(info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
parseContext := &ruleguard.LoadContext{
Fset: fset,
GroupFilter: func(name string) bool {
return name == g.Name
},
DebugImports: ruleguardDebug,
DebugPrint: func(s string) {
fmt.Println("debug:", s)
},
}
engine := ruleguard.NewEngine()
engine.BuildContext = buildContext
err := engine.LoadFromIR(parseContext, filename, rulesdata.PrecompiledRules)
if err != nil {
return nil, err
}
c := &embeddedRuleguardChecker{
ctx: ctx,
engine: engine,
}
return c, nil
})
}
}
type embeddedRuleguardChecker struct {
ctx *linter.CheckerContext
engine *ruleguard.Engine
}
func (c *embeddedRuleguardChecker) WalkFile(f *ast.File) {
runRuleguardEngine(c.ctx, f, c.engine, &ruleguard.RunContext{
Pkg: c.ctx.Pkg,
Types: c.ctx.TypesInfo,
Sizes: c.ctx.SizesInfo,
Fset: c.ctx.FileSet,
})
}

View file

@ -26,6 +26,7 @@ func init() {
`^//nolint\b`, // e.g.: nolint
`^//line /.*:\d+`, // e.g.: line /path/to/file:123
`^//export \w+$`, // e.g.: export Foo
`^//[/+#-]+.*$`, // e.g.: vertical breaker /////////////
}
pat := "(?m)" + strings.Join(parts, "|")
pragmaRE := regexp.MustCompile(pat)

View file

@ -1,94 +0,0 @@
package checkers
import (
"go/ast"
"go/types"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
)
func init() {
var info linter.CheckerInfo
info.Name = "deferUnlambda"
info.Tags = []string{"style", "experimental"}
info.Summary = "Detects deferred function literals that can be simplified"
info.Before = `defer func() { f() }()`
info.After = `f()`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForStmt(&deferUnlambdaChecker{ctx: ctx}), nil
})
}
type deferUnlambdaChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *deferUnlambdaChecker) VisitStmt(x ast.Stmt) {
def, ok := x.(*ast.DeferStmt)
if !ok {
return
}
// We don't analyze deferred function args.
// Most deferred calls don't have them, so it's not a big deal to skip them.
if len(def.Call.Args) != 0 {
return
}
fn, ok := def.Call.Fun.(*ast.FuncLit)
if !ok {
return
}
if len(fn.Body.List) != 1 {
return
}
call, ok := astcast.ToExprStmt(fn.Body.List[0]).X.(*ast.CallExpr)
if !ok || !c.isFunctionCall(call) {
return
}
// Skip recover() as it can't be moved outside of the lambda.
// Skip panic() to avoid affecting the stack trace.
switch qualifiedName(call.Fun) {
case "recover", "panic":
return
}
for _, arg := range call.Args {
if !c.isConstExpr(arg) {
return
}
}
c.warn(def, call)
}
func (c *deferUnlambdaChecker) isFunctionCall(e *ast.CallExpr) bool {
switch fnExpr := e.Fun.(type) {
case *ast.Ident:
return true
case *ast.SelectorExpr:
x, ok := fnExpr.X.(*ast.Ident)
if !ok {
return false
}
_, ok = c.ctx.TypesInfo.ObjectOf(x).(*types.PkgName)
return ok
default:
return false
}
}
func (c *deferUnlambdaChecker) isConstExpr(e ast.Expr) bool {
return c.ctx.TypesInfo.Types[e].Value != nil
}
func (c *deferUnlambdaChecker) warn(cause, suggestion ast.Node) {
c.ctx.Warn(cause, "can rewrite as `defer %s`", suggestion)
}

View file

@ -1,133 +0,0 @@
package checkers
import (
"go/ast"
"go/types"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astequal"
)
func init() {
var info linter.CheckerInfo
info.Name = "dupArg"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects suspicious duplicated arguments"
info.Before = `copy(dst, dst)`
info.After = `copy(dst, src)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
c := &dupArgChecker{ctx: ctx}
// newMatcherFunc returns a function that matches a call if
// args[xIndex] and args[yIndex] are equal.
newMatcherFunc := func(xIndex, yIndex int) func(*ast.CallExpr) bool {
return func(call *ast.CallExpr) bool {
if len(call.Args) <= xIndex || len(call.Args) <= yIndex {
return false
}
x := call.Args[xIndex]
y := call.Args[yIndex]
return astequal.Expr(x, y)
}
}
// m maps pattern string to a matching function.
// String patterns are used for documentation purposes (readability).
m := map[string]func(*ast.CallExpr) bool{
"(x, x, ...)": newMatcherFunc(0, 1),
"(x, _, x, ...)": newMatcherFunc(0, 2),
"(_, x, x, ...)": newMatcherFunc(1, 2),
}
// TODO(quasilyte): handle x.Equal(x) cases.
// Example: *math/Big.Int.Cmp method.
// TODO(quasilyte): more perky mode that will also
// report things like io.Copy(x, x).
// Probably safe thing to do even without that option
// if `x` is not interface (requires type checks
// that are not incorporated into this checker yet).
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, ...)"],
"strings.Contains": m["(x, x, ...)"],
"strings.Compare": m["(x, x, ...)"],
"strings.EqualFold": m["(x, x, ...)"],
"strings.HasPrefix": m["(x, x, ...)"],
"strings.HasSuffix": m["(x, x, ...)"],
"strings.Index": m["(x, x, ...)"],
"strings.LastIndex": m["(x, x, ...)"],
"strings.Split": m["(x, x, ...)"],
"strings.SplitAfter": m["(x, x, ...)"],
"strings.SplitAfterN": m["(x, x, ...)"],
"strings.SplitN": m["(x, x, ...)"],
"strings.Replace": m["(_, x, x, ...)"],
"strings.ReplaceAll": m["(_, x, x, ...)"],
"bytes.Contains": m["(x, x, ...)"],
"bytes.Compare": m["(x, x, ...)"],
"bytes.Equal": m["(x, x, ...)"],
"bytes.EqualFold": m["(x, x, ...)"],
"bytes.HasPrefix": m["(x, x, ...)"],
"bytes.HasSuffix": m["(x, x, ...)"],
"bytes.Index": m["(x, x, ...)"],
"bytes.LastIndex": m["(x, x, ...)"],
"bytes.Split": m["(x, x, ...)"],
"bytes.SplitAfter": m["(x, x, ...)"],
"bytes.SplitAfterN": m["(x, x, ...)"],
"bytes.SplitN": m["(x, x, ...)"],
"bytes.Replace": m["(_, x, x, ...)"],
"bytes.ReplaceAll": m["(_, x, x, ...)"],
"types.Identical": m["(x, x, ...)"],
"types.IdenticalIgnoreTags": m["(x, x, ...)"],
"draw.Draw": m["(x, _, x, ...)"],
// TODO(quasilyte): more of these.
}
return astwalk.WalkerForExpr(c), nil
})
}
type dupArgChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
matchers map[string]func(*ast.CallExpr) bool
}
func (c *dupArgChecker) VisitExpr(expr ast.Expr) {
call, ok := expr.(*ast.CallExpr)
if !ok {
return
}
// TODO(quasilyte): this kind of check is needed in multiple
// places and the code is somewhat duplicated around.
// We probably need to stop using qualifiedName for non-experimental checkers.
if calledExpr, ok := call.Fun.(*ast.SelectorExpr); ok {
obj, ok := c.ctx.TypesInfo.ObjectOf(astcast.ToIdent(calledExpr.X)).(*types.PkgName)
if !ok || !isStdlibPkg(obj.Imported()) {
return
}
}
m := c.matchers[qualifiedName(call.Fun)]
if m != nil && m(call) {
c.warn(call)
}
}
func (c *dupArgChecker) warn(cause ast.Node) {
c.ctx.Warn(cause, "suspicious duplicated args in `%s`", cause)
}

View file

@ -12,7 +12,7 @@ func init() {
var info linter.CheckerInfo
info.Name = "dupCase"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects duplicated case clauses inside switch statements"
info.Summary = "Detects duplicated case clauses inside switch or select statements"
info.Before = `
switch x {
case ys[0], ys[1], ys[2], ys[0], ys[4]:
@ -35,8 +35,11 @@ type dupCaseChecker struct {
}
func (c *dupCaseChecker) VisitStmt(stmt ast.Stmt) {
if stmt, ok := stmt.(*ast.SwitchStmt); ok {
switch stmt := stmt.(type) {
case *ast.SwitchStmt:
c.checkSwitch(stmt)
case *ast.SelectStmt:
c.checkSelect(stmt)
}
}
@ -52,6 +55,16 @@ func (c *dupCaseChecker) checkSwitch(stmt *ast.SwitchStmt) {
}
}
func (c *dupCaseChecker) checkSelect(stmt *ast.SelectStmt) {
c.astSet.Clear()
for i := range stmt.Body.List {
x := stmt.Body.List[i].(*ast.CommClause).Comm
if !c.astSet.Insert(x) {
c.warn(x)
}
}
}
func (c *dupCaseChecker) warn(cause ast.Node) {
c.ctx.Warn(cause, "'case %s' is duplicated", cause)
}

View file

@ -59,7 +59,7 @@ func (c *elseifChecker) VisitStmt(stmt ast.Stmt) {
if balanced && c.skipBalanced {
return // Configured to skip balanced statements
}
if innerIfStmt.Else != nil {
if innerIfStmt.Else != nil || innerIfStmt.Init != nil {
return
}
c.warn(stmt.Else)

View file

@ -1,58 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "emptyStringTest"
info.Tags = []string{"style", "experimental"}
info.Summary = "Detects empty string checks that can be written more idiomatically"
info.Before = `len(s) == 0`
info.After = `s == ""`
info.Note = "See https://dmitri.shuralyov.com/idiomatic-go#empty-string-check."
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&emptyStringTestChecker{ctx: ctx}), nil
})
}
type emptyStringTestChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *emptyStringTestChecker) VisitExpr(e ast.Expr) {
cmp := astcast.ToBinaryExpr(e)
if cmp.Op != token.EQL && cmp.Op != token.NEQ {
return
}
lenCall := astcast.ToCallExpr(cmp.X)
if astcast.ToIdent(lenCall.Fun).Name != "len" {
return
}
s := lenCall.Args[0]
if !typep.HasStringProp(c.ctx.TypeOf(s)) {
return
}
zero := astcast.ToBasicLit(cmp.Y)
if zero.Value != "0" {
return
}
c.warn(cmp, s)
}
func (c *emptyStringTestChecker) warn(cmp *ast.BinaryExpr, s ast.Expr) {
suggest := astcopy.BinaryExpr(cmp)
suggest.X = s
suggest.Y = &ast.BasicLit{Value: `""`}
c.ctx.Warn(cmp, "replace `%s` with `%s`", cmp, suggest)
}

View file

@ -1,87 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astequal"
)
func init() {
var info linter.CheckerInfo
info.Name = "equalFold"
info.Tags = []string{"performance", "experimental"}
info.Summary = "Detects unoptimal strings/bytes case-insensitive comparison"
info.Before = `strings.ToLower(x) == strings.ToLower(y)`
info.After = `strings.EqualFold(x, y)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&equalFoldChecker{ctx: ctx}), nil
})
}
type equalFoldChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *equalFoldChecker) VisitExpr(e ast.Expr) {
switch e := e.(type) {
case *ast.CallExpr:
c.checkBytes(e)
case *ast.BinaryExpr:
c.checkStrings(e)
}
}
// uncaseCall simplifies lower(x) or upper(x) to x.
// If no simplification is applied, second return value is false.
func (c *equalFoldChecker) uncaseCall(x ast.Expr, lower, upper string) (ast.Expr, bool) {
call := astcast.ToCallExpr(x)
name := qualifiedName(call.Fun)
if name != lower && name != upper {
return x, false
}
return call.Args[0], true
}
func (c *equalFoldChecker) checkBytes(expr *ast.CallExpr) {
if qualifiedName(expr.Fun) != "bytes.Equal" {
return
}
x, ok1 := c.uncaseCall(expr.Args[0], "bytes.ToLower", "bytes.ToUpper")
y, ok2 := c.uncaseCall(expr.Args[1], "bytes.ToLower", "bytes.ToUpper")
if !ok1 && !ok2 {
return
}
if !astequal.Expr(x, y) {
c.warnBytes(expr, x, y)
}
}
func (c *equalFoldChecker) checkStrings(expr *ast.BinaryExpr) {
if expr.Op != token.EQL && expr.Op != token.NEQ {
return
}
x, ok1 := c.uncaseCall(expr.X, "strings.ToLower", "strings.ToUpper")
y, ok2 := c.uncaseCall(expr.Y, "strings.ToLower", "strings.ToUpper")
if !ok1 && !ok2 {
return
}
if !astequal.Expr(x, y) {
c.warnStrings(expr, x, y)
}
}
func (c *equalFoldChecker) warnStrings(cause ast.Node, x, y ast.Expr) {
c.ctx.Warn(cause, "consider replacing with strings.EqualFold(%s, %s)", x, y)
}
func (c *equalFoldChecker) warnBytes(cause ast.Node, x, y ast.Expr) {
c.ctx.Warn(cause, "consider replacing with bytes.EqualFold(%s, %s)", x, y)
}

View file

@ -1,65 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
)
func init() {
var info linter.CheckerInfo
info.Name = "flagDeref"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects immediate dereferencing of `flag` package pointers"
info.Details = "Suggests to use pointer to array to avoid the copy using `&` on range expression."
info.Before = `b := *flag.Bool("b", false, "b docs")`
info.After = `
var b bool
flag.BoolVar(&b, "b", false, "b docs")`
info.Note = `
Dereferencing returned pointers will lead to hard to find errors
where flag values are not updated after flag.Parse().`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
c := &flagDerefChecker{
ctx: ctx,
flagPtrFuncs: map[string]bool{
"flag.Bool": true,
"flag.Duration": true,
"flag.Float64": true,
"flag.Int": true,
"flag.Int64": true,
"flag.String": true,
"flag.Uint": true,
"flag.Uint64": true,
},
}
return astwalk.WalkerForExpr(c), nil
})
}
type flagDerefChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
flagPtrFuncs map[string]bool
}
func (c *flagDerefChecker) VisitExpr(expr ast.Expr) {
if expr, ok := expr.(*ast.StarExpr); ok {
call, ok := expr.X.(*ast.CallExpr)
if !ok {
return
}
called := qualifiedName(call.Fun)
if c.flagPtrFuncs[called] {
c.warn(expr, called+"Var")
}
}
}
func (c *flagDerefChecker) warn(x ast.Node, suggestion string) {
c.ctx.Warn(x, "immediate deref in %s is most likely an error; consider using %s",
x, suggestion)
}

View file

@ -1,50 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "indexAlloc"
info.Tags = []string{"performance"}
info.Summary = "Detects strings.Index calls that may cause unwanted allocs"
info.Before = `strings.Index(string(x), y)`
info.After = `bytes.Index(x, []byte(y))`
info.Note = `See Go issue for details: https://github.com/golang/go/issues/25864`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&indexAllocChecker{ctx: ctx}), nil
})
}
type indexAllocChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *indexAllocChecker) VisitExpr(e ast.Expr) {
call := astcast.ToCallExpr(e)
if qualifiedName(call.Fun) != "strings.Index" {
return
}
stringConv := astcast.ToCallExpr(call.Args[0])
if qualifiedName(stringConv.Fun) != "string" {
return
}
x := stringConv.Args[0]
y := call.Args[1]
if typep.SideEffectFree(c.ctx.TypesInfo, x) && typep.SideEffectFree(c.ctx.TypesInfo, y) {
c.warn(e, x, y)
}
}
func (c *indexAllocChecker) warn(cause ast.Node, x, y ast.Expr) {
c.ctx.Warn(cause, "consider replacing %s with bytes.Index(%s, []byte(%s))",
cause, x, y)
}

View file

@ -42,7 +42,7 @@ const (
// Initializing expression is always nil.
NameParam NameKind = iota
// NameVar is var or ":=" declared name.
// Initizlizing expression may be nil for var-declared names
// Initializing expression may be nil for var-declared names
// without explicit initializing expression.
NameVar
// NameConst is const-declared name.

View file

@ -21,11 +21,11 @@ func (w *stmtListWalker) WalkFile(f *ast.File) {
ast.Inspect(decl.Body, func(x ast.Node) bool {
switch x := x.(type) {
case *ast.BlockStmt:
w.visitor.VisitStmtList(x.List)
w.visitor.VisitStmtList(x, x.List)
case *ast.CaseClause:
w.visitor.VisitStmtList(x.Body)
w.visitor.VisitStmtList(x, x.Body)
case *ast.CommClause:
w.visitor.VisitStmtList(x.Body)
w.visitor.VisitStmtList(x, x.Body)
}
return !w.visitor.skipChilds()
})

View file

@ -48,6 +48,8 @@ func (w *typeExprWalker) visit(x ast.Expr) bool {
func (w *typeExprWalker) walk(x ast.Node) bool {
switch x := x.(type) {
case *ast.ChanType:
return w.visit(x)
case *ast.ParenExpr:
if typep.IsTypeExpr(w.info, x.X) {
return w.visit(x)

View file

@ -36,7 +36,7 @@ type (
// introduced by case clauses and alike.
StmtListVisitor interface {
walkerEvents
VisitStmtList([]ast.Stmt)
VisitStmtList(ast.Node, []ast.Stmt)
}
// StmtVisitor visits every statement inside function body.

View file

@ -3,7 +3,8 @@ package checkers
import (
"go/ast"
"go/token"
"go/types"
"strings"
"unicode"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
@ -13,70 +14,34 @@ import (
func init() {
var info linter.CheckerInfo
info.Name = "octalLiteral"
info.Tags = []string{"diagnostic", "experimental"}
info.Summary = "Detects octal literals passed to functions"
info.Tags = []string{"style", "experimental", "opinionated"}
info.Summary = "Detects old-style octal literals"
info.Before = `foo(02)`
info.After = `foo(2)`
info.After = `foo(0o2)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
c := &octalLiteralChecker{
ctx: ctx,
octFriendlyPkg: map[string]bool{
"os": true,
"io/ioutil": true,
},
}
return astwalk.WalkerForExpr(c), nil
return astwalk.WalkerForExpr(&octalLiteralChecker{ctx: ctx}), nil
})
}
type octalLiteralChecker struct {
astwalk.WalkHandler
ctx *linter.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
}
lit := astcast.ToBasicLit(expr)
if lit.Kind != token.INT {
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
}
if !strings.HasPrefix(lit.Value, "0") || len(lit.Value) == 1 {
return
}
if unicode.IsDigit(rune(lit.Value[1])) {
c.warn(lit)
}
}
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)
func (c *octalLiteralChecker) warn(lit *ast.BasicLit) {
c.ctx.Warn(lit, "use new octal literal style, 0o%s", lit.Value[len("0"):])
}

View file

@ -1,66 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astequal"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "offBy1"
info.Tags = []string{"diagnostic"}
info.Summary = "Detects various off-by-one kind of errors"
info.Before = `xs[len(xs)]`
info.After = `xs[len(xs)-1]`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&offBy1Checker{ctx: ctx}), nil
})
}
type offBy1Checker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *offBy1Checker) VisitExpr(e ast.Expr) {
// TODO(quasilyte): handle more off-by-1 patterns.
// TODO(quasilyte): check whether go/analysis can help here.
// Detect s[len(s)] expressions that always panic.
// The correct form is s[len(s)-1].
indexExpr := astcast.ToIndexExpr(e)
indexed := indexExpr.X
if !typep.IsSlice(c.ctx.TypeOf(indexed)) {
return
}
if !typep.SideEffectFree(c.ctx.TypesInfo, indexed) {
return
}
call := astcast.ToCallExpr(indexExpr.Index)
if astcast.ToIdent(call.Fun).Name != "len" {
return
}
if len(call.Args) != 1 || !astequal.Expr(call.Args[0], indexed) {
return
}
c.warnLenIndex(indexExpr)
}
func (c *offBy1Checker) warnLenIndex(cause *ast.IndexExpr) {
suggest := astcopy.IndexExpr(cause)
suggest.Index = &ast.BinaryExpr{
Op: token.SUB,
X: cause.Index,
Y: &ast.BasicLit{Value: "1"},
}
c.ctx.Warn(cause, "index expr always panics; maybe you wanted %s?", suggest)
}

View file

@ -1,47 +0,0 @@
package checkers
import (
"go/ast"
"strings"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astp"
"golang.org/x/tools/go/ast/astutil"
)
func init() {
var info linter.CheckerInfo
info.Name = "regexpMust"
info.Tags = []string{"style"}
info.Summary = "Detects `regexp.Compile*` that can be replaced with `regexp.MustCompile*`"
info.Before = `re, _ := regexp.Compile("const pattern")`
info.After = `re := regexp.MustCompile("const pattern")`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&regexpMustChecker{ctx: ctx}), nil
})
}
type regexpMustChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *regexpMustChecker) VisitExpr(x ast.Expr) {
if x, ok := x.(*ast.CallExpr); ok {
switch name := qualifiedName(x.Fun); name {
case "regexp.Compile", "regexp.CompilePOSIX":
// Only check for trivial string args, permit parenthesis.
if !astp.IsBasicLit(astutil.Unparen(x.Args[0])) {
return
}
c.warn(x, strings.Replace(name, "Compile", "MustCompile", 1))
}
}
}
func (c *regexpMustChecker) warn(cause *ast.CallExpr, suggestion string) {
c.ctx.Warn(cause, "for const patterns like %s, use %s",
cause.Args[0], suggestion)
}

View file

@ -2,10 +2,10 @@ package checkers
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/token"
"io/ioutil"
"log"
"os"
"path/filepath"
@ -31,7 +31,15 @@ func init() {
},
"failOnError": {
Value: false,
Usage: "If true, panic when the gorule files contain a syntax error. If false, log and skip rules that contain an error",
Usage: "deprecated, use failOn param; if set to true, identical to failOn='all', otherwise failOn=''",
},
"failOn": {
Value: "",
Usage: `Determines the behavior when an error occurs while parsing ruleguard files.
If flag is not set, log error and skip rule files that contain an error.
If flag is set, the value must be a comma-separated list of error conditions.
* 'import': rule refers to a package that cannot be loaded.
* 'dsl': gorule file does not comply with the ruleguard DSL.`,
},
}
info.Summary = "Runs user-defined rules using ruleguard linter"
@ -45,6 +53,52 @@ func init() {
})
}
// parseErrorHandler is used to determine whether to ignore or fail ruleguard parsing errors.
type parseErrorHandler struct {
// failureConditions is a map of predicates which are evaluated against a ruleguard parsing error.
// If at least one predicate returns true, then an error is returned.
// Otherwise, the ruleguard file is skipped.
failureConditions map[string]func(err error) bool
}
// failOnParseError returns true if a parseError occurred and that error should be not be ignored.
func (e parseErrorHandler) failOnParseError(parseError error) bool {
for _, p := range e.failureConditions {
if p(parseError) {
return true
}
}
return false
}
func newErrorHandler(failOnErrorFlag string) (*parseErrorHandler, error) {
h := parseErrorHandler{
failureConditions: make(map[string]func(err error) bool),
}
var failOnErrorPredicates = map[string]func(error) bool{
"dsl": func(err error) bool { var e *ruleguard.ImportError; return !errors.As(err, &e) },
"import": func(err error) bool { var e *ruleguard.ImportError; return errors.As(err, &e) },
"all": func(err error) bool { return true },
}
for _, k := range strings.Split(failOnErrorFlag, ",") {
if k == "" {
continue
}
if p, ok := failOnErrorPredicates[k]; ok {
h.failureConditions[k] = p
} else {
// Wrong flag value.
supportedValues := []string{}
for key := range failOnErrorPredicates {
supportedValues = append(supportedValues, key)
}
return nil, fmt.Errorf("ruleguard init error: 'failOnError' flag '%s' is invalid. It must be a comma-separated list and supported values are '%s'",
k, strings.Join(supportedValues, ","))
}
}
return &h, nil
}
func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) (*ruleguardChecker, error) {
c := &ruleguardChecker{
ctx: ctx,
@ -54,20 +108,30 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) (
if rulesFlag == "" {
return c, nil
}
failOnErrorFlag := info.Params.Bool("failOnError")
// TODO(quasilyte): handle initialization errors better when we make
// a transition to the go/analysis framework.
//
// For now, we log error messages and return a ruleguard checker
// with an empty rules set.
failOn := info.Params.String("failOn")
if failOn == "" {
if info.Params.Bool("failOnError") {
failOn = "all"
}
}
h, err := newErrorHandler(failOn)
if err != nil {
return nil, err
}
engine := ruleguard.NewEngine()
engine.InferBuildContext()
fset := token.NewFileSet()
filePatterns := strings.Split(rulesFlag, ",")
parseContext := &ruleguard.ParseContext{
Fset: fset,
ruleguardDebug := os.Getenv("GOCRITIC_RULEGUARD_DEBUG") != ""
loadContext := &ruleguard.LoadContext{
Fset: fset,
DebugImports: ruleguardDebug,
DebugPrint: func(s string) {
fmt.Println("debug:", s)
},
}
loaded := 0
@ -78,21 +142,22 @@ func newRuleguardChecker(info *linter.CheckerInfo, ctx *linter.CheckerContext) (
log.Printf("ruleguard init error: %+v", err)
continue
}
if len(filenames) == 0 {
return nil, fmt.Errorf("ruleguard init error: no file matching '%s'", strings.TrimSpace(filePattern))
}
for _, filename := range filenames {
data, err := ioutil.ReadFile(filename)
data, err := os.ReadFile(filename)
if err != nil {
if failOnErrorFlag {
if h.failOnParseError(err) {
return nil, fmt.Errorf("ruleguard init error: %+v", err)
}
log.Printf("ruleguard init error: %+v", err)
continue
log.Printf("ruleguard init error, skip %s: %+v", filename, err)
}
if err := engine.Load(parseContext, filename, bytes.NewReader(data)); err != nil {
if failOnErrorFlag {
if err := engine.Load(loadContext, filename, bytes.NewReader(data)); err != nil {
if h.failOnParseError(err) {
return nil, fmt.Errorf("ruleguard init error: %+v", err)
}
log.Printf("ruleguard init error: %+v", err)
continue
log.Printf("ruleguard init error, skip %s: %+v", filename, err)
}
loaded++
}
@ -116,13 +181,7 @@ func (c *ruleguardChecker) WalkFile(f *ast.File) {
return
}
type ruleguardReport struct {
node ast.Node
message string
}
var reports []ruleguardReport
ctx := &ruleguard.RunContext{
runRuleguardEngine(c.ctx, f, c.engine, &ruleguard.RunContext{
Debug: c.debugGroup,
DebugPrint: func(s string) {
fmt.Fprintln(os.Stderr, s)
@ -131,27 +190,49 @@ func (c *ruleguardChecker) WalkFile(f *ast.File) {
Types: c.ctx.TypesInfo,
Sizes: c.ctx.SizesInfo,
Fset: c.ctx.FileSet,
Report: func(_ ruleguard.GoRuleInfo, n ast.Node, msg string, _ *ruleguard.Suggestion) {
// TODO(quasilyte): investigate whether we should add a rule name as
// a message prefix here.
reports = append(reports, ruleguardReport{
node: n,
message: msg,
})
},
})
}
func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.Engine, runCtx *ruleguard.RunContext) {
type ruleguardReport struct {
node ast.Node
message string
fix linter.QuickFix
}
var reports []ruleguardReport
runCtx.Report = func(_ ruleguard.GoRuleInfo, n ast.Node, msg string, fix *ruleguard.Suggestion) {
// TODO(quasilyte): investigate whether we should add a rule name as
// a message prefix here.
r := ruleguardReport{
node: n,
message: msg,
}
if fix != nil {
r.fix = linter.QuickFix{
From: fix.From,
To: fix.To,
Replacement: fix.Replacement,
}
}
reports = append(reports, r)
}
if err := c.engine.Run(ctx, f); err != nil {
if err := e.Run(runCtx, f); err != nil {
// Normally this should never happen, but since
// we don't have a better mechanism to report errors,
// emit a warning.
c.ctx.Warn(f, "execution error: %v", err)
ctx.Warn(f, "execution error: %v", err)
}
sort.Slice(reports, func(i, j int) bool {
return reports[i].message < reports[j].message
})
for _, report := range reports {
c.ctx.Warn(report.node, report.message)
if report.fix.Replacement != nil {
ctx.WarnFixable(report.node, report.fix, "%s", report.message)
} else {
ctx.Warn(report.node, "%s", report.message)
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,72 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astfmt"
)
func init() {
var info linter.CheckerInfo
info.Name = "sloppyLen"
info.Tags = []string{"style"}
info.Summary = "Detects usage of `len` when result is obvious or doesn't make sense"
info.Before = `
len(arr) >= 0 // Sloppy
len(arr) <= 0 // Sloppy
len(arr) < 0 // Doesn't make sense at all`
info.After = `
len(arr) > 0
len(arr) == 0`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&sloppyLenChecker{ctx: ctx}), nil
})
}
type sloppyLenChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *sloppyLenChecker) VisitExpr(x ast.Expr) {
expr, ok := x.(*ast.BinaryExpr)
if !ok {
return
}
if expr.Op == token.LSS || expr.Op == token.GEQ || expr.Op == token.LEQ {
if c.isLenCall(expr.X) && c.isZero(expr.Y) {
c.warn(expr)
}
}
}
func (c *sloppyLenChecker) isLenCall(x ast.Expr) bool {
call, ok := x.(*ast.CallExpr)
return ok && qualifiedName(call.Fun) == "len" && len(call.Args) == 1
}
func (c *sloppyLenChecker) isZero(x ast.Expr) bool {
value, ok := x.(*ast.BasicLit)
return ok && value.Value == "0"
}
func (c *sloppyLenChecker) warn(cause *ast.BinaryExpr) {
info := ""
switch cause.Op {
case token.LSS:
info = "is always false"
case token.GEQ:
info = "is always true"
case token.LEQ:
expr := astcopy.BinaryExpr(cause)
expr.Op = token.EQL
info = astfmt.Sprintf("can be %s", expr)
}
c.ctx.Warn(cause, "%s %s", cause, info)
}

View file

@ -12,7 +12,7 @@ import (
func init() {
var info linter.CheckerInfo
info.Name = "sloppyTypeAssert"
info.Tags = []string{"diagnostic", "experimental"}
info.Tags = []string{"diagnostic"}
info.Summary = "Detects redundant type assertions"
info.Before = `
func f(r io.Reader) interface{} {
@ -48,28 +48,8 @@ func (c *sloppyTypeAssertChecker) VisitExpr(expr ast.Expr) {
c.warnIdentical(expr)
return
}
toIface, ok := toType.Underlying().(*types.Interface)
if !ok {
return
}
switch {
case toIface.Empty():
c.warnEmpty(expr)
case types.Implements(fromType, toIface):
c.warnImplements(expr, assert.X)
}
}
func (c *sloppyTypeAssertChecker) warnIdentical(cause ast.Expr) {
c.ctx.Warn(cause, "type assertion from/to types are identical")
}
func (c *sloppyTypeAssertChecker) warnEmpty(cause ast.Expr) {
c.ctx.Warn(cause, "type assertion to interface{} may be redundant")
}
func (c *sloppyTypeAssertChecker) warnImplements(cause, val ast.Expr) {
c.ctx.Warn(cause, "type assertion may be redundant as %s always implements selected interface", val)
}

View file

@ -1,47 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/typep"
)
func init() {
var info linter.CheckerInfo
info.Name = "stringXbytes"
info.Tags = []string{"style"}
info.Summary = "Detects redundant conversions between string and []byte"
info.Before = `copy(b, []byte(s))`
info.After = `copy(b, s)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&stringXbytes{ctx: ctx}), nil
})
}
type stringXbytes struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *stringXbytes) VisitExpr(expr ast.Expr) {
x, ok := expr.(*ast.CallExpr)
if !ok || qualifiedName(x.Fun) != "copy" || len(x.Args) != 2 {
return
}
src := x.Args[1]
byteCast, ok := src.(*ast.CallExpr)
if ok && typep.IsTypeExpr(c.ctx.TypesInfo, byteCast.Fun) &&
typep.HasStringProp(c.ctx.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)
}

View file

@ -1,49 +0,0 @@
package checkers
import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
)
func init() {
var info linter.CheckerInfo
info.Name = "switchTrue"
info.Tags = []string{"style"}
info.Summary = "Detects switch-over-bool statements that use explicit `true` tag value"
info.Before = `
switch true {
case x > y:
}`
info.After = `
switch {
case x > y:
}`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForStmt(&switchTrueChecker{ctx: ctx}), nil
})
}
type switchTrueChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *switchTrueChecker) VisitStmt(stmt ast.Stmt) {
if stmt, ok := stmt.(*ast.SwitchStmt); ok {
if qualifiedName(stmt.Tag) == "true" {
c.warn(stmt)
}
}
}
func (c *switchTrueChecker) warn(cause *ast.SwitchStmt) {
if cause.Init == nil {
c.ctx.Warn(cause, "replace 'switch true {}' with 'switch {}'")
} else {
c.ctx.Warn(cause, "replace 'switch %s; true {}' with 'switch %s; {}'",
cause.Init, cause.Init)
}
}

View file

@ -4,11 +4,9 @@ import (
"go/ast"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/checkers/internal/lintutil"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astp"
"golang.org/x/tools/go/ast/astutil"
"github.com/go-toolsmith/astequal"
)
func init() {
@ -29,58 +27,69 @@ type typeUnparenChecker struct {
ctx *linter.CheckerContext
}
func (c *typeUnparenChecker) VisitTypeExpr(x ast.Expr) {
switch x := x.(type) {
func (c *typeUnparenChecker) VisitTypeExpr(e ast.Expr) {
switch e := e.(type) {
case *ast.ParenExpr:
switch x.X.(type) {
switch e.X.(type) {
case *ast.StructType:
c.ctx.Warn(x, "could simplify (struct{...}) to struct{...}")
c.ctx.Warn(e, "could simplify (struct{...}) to struct{...}")
case *ast.InterfaceType:
c.ctx.Warn(x, "could simplify (interface{...}) to interface{...}")
c.ctx.Warn(e, "could simplify (interface{...}) to interface{...}")
default:
c.warn(x, c.unparenExpr(astcopy.Expr(x)))
c.checkType(e)
}
default:
c.checkTypeExpr(x)
}
}
func (c *typeUnparenChecker) checkTypeExpr(x ast.Expr) {
switch x := x.(type) {
case *ast.ArrayType:
// Arrays require extra care: we don't want to unparen
// length expression as they are not type expressions.
if !c.hasParens(x.Elt) {
return
}
noParens := astcopy.ArrayType(x)
noParens.Elt = c.unparenExpr(noParens.Elt)
c.warn(x, noParens)
case *ast.StructType, *ast.InterfaceType:
// Only nested fields are to be reported.
default:
if !c.hasParens(x) {
return
}
c.warn(x, c.unparenExpr(astcopy.Expr(x)))
c.checkType(e)
}
}
func (c *typeUnparenChecker) hasParens(x ast.Expr) bool {
return lintutil.ContainsNode(x, astp.IsParenExpr)
func (c *typeUnparenChecker) checkType(e ast.Expr) {
noParens := c.removeRedundantParens(astcopy.Expr(e))
if !astequal.Expr(e, noParens) {
c.warn(e, noParens)
}
c.SkipChilds = true
}
func (c *typeUnparenChecker) unparenExpr(x ast.Expr) ast.Expr {
// Replace every paren expr with expression it encloses.
return astutil.Apply(x, nil, func(cur *astutil.Cursor) bool {
if paren, ok := cur.Node().(*ast.ParenExpr); ok {
cur.Replace(paren.X)
func (c *typeUnparenChecker) removeRedundantParens(e ast.Expr) ast.Expr {
switch e := e.(type) {
case *ast.ParenExpr:
return c.removeRedundantParens(e.X)
case *ast.ArrayType:
e.Elt = c.removeRedundantParens(e.Elt)
case *ast.StarExpr:
e.X = c.removeRedundantParens(e.X)
case *ast.TypeAssertExpr:
e.Type = c.removeRedundantParens(e.Type)
case *ast.FuncType:
for _, field := range e.Params.List {
field.Type = c.removeRedundantParens(field.Type)
}
return true
}).(ast.Expr)
if e.Results != nil {
for _, field := range e.Results.List {
field.Type = c.removeRedundantParens(field.Type)
}
}
case *ast.MapType:
e.Key = c.removeRedundantParens(e.Key)
e.Value = c.removeRedundantParens(e.Value)
case *ast.ChanType:
if valueWithParens, ok := e.Value.(*ast.ParenExpr); ok {
if nestedChan, ok := valueWithParens.X.(*ast.ChanType); ok {
const anyDir = ast.SEND | ast.RECV
if nestedChan.Dir != anyDir || e.Dir != anyDir {
valueWithParens.X = c.removeRedundantParens(valueWithParens.X)
return e
}
}
}
e.Value = c.removeRedundantParens(e.Value)
}
return e
}
func (c *typeUnparenChecker) warn(cause, noParens ast.Expr) {
c.SkipChilds = true
c.ctx.Warn(cause, "could simplify %s to %s", cause, noParens)
}

View file

@ -6,6 +6,7 @@ import (
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astp"
)
func init() {
@ -32,12 +33,19 @@ type unnecessaryBlockChecker struct {
ctx *linter.CheckerContext
}
func (c *unnecessaryBlockChecker) VisitStmtList(statements []ast.Stmt) {
func (c *unnecessaryBlockChecker) VisitStmtList(x ast.Node, statements []ast.Stmt) {
// Using StmtListVisitor instead of StmtVisitor makes it easier to avoid
// false positives on IfStmt, RangeStmt, ForStmt and alike.
// We only inspect BlockStmt inside statement lists, so this method is not
// called for IfStmt itself, for example.
if (astp.IsCaseClause(x) || astp.IsCommClause(x)) && len(statements) == 1 {
if _, ok := statements[0].(*ast.BlockStmt); ok {
c.ctx.Warn(statements[0], "case statement doesn't require a block statement")
return
}
}
for _, stmt := range statements {
stmt, ok := stmt.(*ast.BlockStmt)
if ok && !c.hasDefinitions(stmt) {

View file

@ -1,59 +0,0 @@
package checkers
import (
"go/ast"
"go/types"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astequal"
)
func init() {
var info linter.CheckerInfo
info.Name = "unslice"
info.Tags = []string{"style"}
info.Summary = "Detects slice expressions that can be simplified to sliced expression itself"
info.Before = `
f(s[:]) // s is string
copy(b[:], values...) // b is []byte`
info.After = `
f(s)
copy(b, values...)`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForExpr(&unsliceChecker{ctx: ctx}), nil
})
}
type unsliceChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *unsliceChecker) VisitExpr(expr ast.Expr) {
unsliced := c.unslice(expr)
if !astequal.Expr(expr, unsliced) {
c.warn(expr, unsliced)
c.SkipChilds = true
}
}
func (c *unsliceChecker) unslice(expr ast.Expr) ast.Expr {
slice, ok := expr.(*ast.SliceExpr)
if !ok || slice.Low != nil || slice.High != nil {
// No need to worry about 3-index slicing,
// because it's only permitted if expr.High is not nil.
return expr
}
switch c.ctx.TypeOf(slice.X).(type) {
case *types.Slice, *types.Basic:
// Basic kind catches strings, Slice cathes everything else.
return c.unslice(slice.X)
}
return expr
}
func (c *unsliceChecker) warn(cause, unsliced ast.Expr) {
c.ctx.Warn(cause, "could simplify %s to %s", cause, unsliced)
}

View file

@ -1,64 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
"github.com/go-toolsmith/astequal"
)
func init() {
var info linter.CheckerInfo
info.Name = "valSwap"
info.Tags = []string{"style"}
info.Summary = "Detects value swapping code that are not using parallel assignment"
info.Before = `
tmp := *x
*x = *y
*y = tmp`
info.After = `*x, *y = *y, *x`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForStmtList(&valSwapChecker{ctx: ctx}), nil
})
}
type valSwapChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *valSwapChecker) VisitStmtList(list []ast.Stmt) {
for len(list) >= 3 {
tmpAssign := astcast.ToAssignStmt(list[0])
assignX := astcast.ToAssignStmt(list[1])
assignY := astcast.ToAssignStmt(list[2])
cond := c.isSimpleAssign(tmpAssign) &&
c.isSimpleAssign(assignX) &&
c.isSimpleAssign(assignY) &&
assignX.Tok == token.ASSIGN &&
assignY.Tok == token.ASSIGN &&
astequal.Expr(assignX.Lhs[0], tmpAssign.Rhs[0]) &&
astequal.Expr(assignX.Rhs[0], assignY.Lhs[0]) &&
astequal.Expr(assignY.Rhs[0], tmpAssign.Lhs[0])
if cond {
c.warn(tmpAssign, assignX.Lhs[0], assignY.Lhs[0])
list = list[3:]
} else {
list = list[1:]
}
}
}
func (c *valSwapChecker) isSimpleAssign(x *ast.AssignStmt) bool {
return len(x.Lhs) == 1 && len(x.Rhs) == 1
}
func (c *valSwapChecker) warn(cause, x, y ast.Node) {
c.ctx.Warn(cause, "can re-write as `%s, %s = %s, %s`",
x, y, y, x)
}

View file

@ -1,229 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"go/types"
"strings"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcast"
)
func init() {
var info linter.CheckerInfo
info.Name = "wrapperFunc"
info.Tags = []string{"style"}
info.Summary = "Detects function calls that can be replaced with convenience wrappers"
info.Before = `wg.Add(-1)`
info.After = `wg.Done()`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
type arg struct {
index int
value string
}
type pattern struct {
pkg string
typ string // Only for typ patterns
args []arg
suggestion string
}
type matcher struct {
pkgPatterns []pattern
typPatterns []pattern
}
typPatterns := map[string][]arg{
"sync.WaitGroup.Add => WaitGroup.Done": {
{0, "-1"},
},
"bytes.Buffer.Truncate => Buffer.Reset": {
{0, "0"},
},
}
pkgPatterns := map[string][]arg{
"http.HandlerFunc => http.NotFoundHandler": {
{0, "http.NotFound"},
},
"strings.SplitN => strings.Split": {
{2, "-1"},
},
"strings.Replace => strings.ReplaceAll": {
{3, "-1"},
},
"strings.TrimFunc => strings.TrimSpace": {
{1, "unicode.IsSpace"},
},
"strings.Map => strings.ToTitle": {
{0, "unicode.ToTitle"},
},
"bytes.SplitN => bytes.Split": {
{2, "-1"},
},
"bytes.Replace => bytes.ReplaceAll": {
{3, "-1"},
},
"bytes.TrimFunc => bytes.TrimSpace": {
{1, "unicode.IsSpace"},
},
"bytes.Map => bytes.ToUpper": {
{0, "unicode.ToUpper"},
},
"bytes.Map => bytes.ToLower": {
{0, "unicode.ToLower"},
},
"bytes.Map => bytes.ToTitle": {
{0, "unicode.ToTitle"},
},
"draw.DrawMask => draw.Draw": {
{4, "nil"},
{5, "image.Point{}"},
},
}
matchers := make(map[string]*matcher)
type templateKey struct {
from string
to string
}
decodeKey := func(key string) templateKey {
parts := strings.Split(key, " => ")
return templateKey{from: parts[0], to: parts[1]}
}
// Expand pkg patterns.
for key, args := range pkgPatterns {
key := decodeKey(key)
parts := strings.Split(key.from, ".")
fn := parts[1]
m := matchers[fn]
if m == nil {
m = &matcher{}
matchers[fn] = m
}
m.pkgPatterns = append(m.pkgPatterns, pattern{
pkg: parts[0],
args: args,
suggestion: key.to,
})
}
// Expand typ patterns.
for key, args := range typPatterns {
key := decodeKey(key)
parts := strings.Split(key.from, ".")
fn := parts[2]
m := matchers[fn]
if m == nil {
m = &matcher{}
matchers[fn] = m
}
m.typPatterns = append(m.typPatterns, pattern{
pkg: parts[0],
typ: parts[1],
args: args,
suggestion: key.to,
})
}
var valueOf func(x ast.Expr) string
valueOf = func(x ast.Expr) string {
switch x := x.(type) {
case *ast.Ident:
return x.Name
case *ast.SelectorExpr:
id, ok := x.X.(*ast.Ident)
if ok {
return id.Name + "." + x.Sel.Name
}
case *ast.BasicLit:
return x.Value
case *ast.UnaryExpr:
switch x.Op {
case token.SUB:
return "-" + valueOf(x.X)
case token.ADD:
return valueOf(x.X)
}
}
return ""
}
findSuggestion := func(call *ast.CallExpr, pkg, typ string, patterns []pattern) string {
for _, pat := range patterns {
if pat.pkg != pkg || pat.typ != typ {
continue
}
for _, arg := range pat.args {
if arg.value == valueOf(call.Args[arg.index]) {
return pat.suggestion
}
}
}
return ""
}
c := &wrapperFuncChecker{ctx: ctx}
c.findSuggestion = func(call *ast.CallExpr) string {
sel := astcast.ToSelectorExpr(call.Fun).Sel
if sel == nil {
return ""
}
x := astcast.ToSelectorExpr(call.Fun).X
m := matchers[sel.Name]
if m == nil {
return ""
}
if x, ok := x.(*ast.Ident); ok {
obj, ok := c.ctx.TypesInfo.ObjectOf(x).(*types.PkgName)
if ok {
return findSuggestion(call, obj.Name(), "", m.pkgPatterns)
}
}
typ := c.ctx.TypeOf(x)
tn, ok := typ.(*types.Named)
if !ok {
return ""
}
return findSuggestion(
call,
tn.Obj().Pkg().Name(),
tn.Obj().Name(),
m.typPatterns)
}
return astwalk.WalkerForExpr(c), nil
})
}
type wrapperFuncChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
findSuggestion func(*ast.CallExpr) string
}
func (c *wrapperFuncChecker) VisitExpr(expr ast.Expr) {
call := astcast.ToCallExpr(expr)
if len(call.Args) == 0 {
return
}
if suggest := c.findSuggestion(call); suggest != "" {
c.warn(call, suggest)
}
}
func (c *wrapperFuncChecker) warn(cause ast.Node, suggest string) {
c.ctx.Warn(cause, "use %s method in `%s`", suggest, cause)
}

View file

@ -1,66 +0,0 @@
package checkers
import (
"go/ast"
"go/token"
"github.com/go-critic/go-critic/checkers/internal/astwalk"
"github.com/go-critic/go-critic/framework/linter"
"github.com/go-toolsmith/astcopy"
"github.com/go-toolsmith/astp"
)
func init() {
var info linter.CheckerInfo
info.Name = "yodaStyleExpr"
info.Tags = []string{"style", "experimental"}
info.Summary = "Detects Yoda style expressions and suggests to replace them"
info.Before = `return nil != ptr`
info.After = `return ptr != nil`
collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) {
return astwalk.WalkerForLocalExpr(&yodaStyleExprChecker{ctx: ctx}), nil
})
}
type yodaStyleExprChecker struct {
astwalk.WalkHandler
ctx *linter.CheckerContext
}
func (c *yodaStyleExprChecker) VisitLocalExpr(expr ast.Expr) {
binexpr, ok := expr.(*ast.BinaryExpr)
if !ok {
return
}
switch binexpr.Op {
case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GEQ, token.GTR:
if c.isConstExpr(binexpr.X) && !c.isConstExpr(binexpr.Y) {
c.warn(binexpr)
}
}
}
func (c *yodaStyleExprChecker) isConstExpr(expr ast.Expr) bool {
return qualifiedName(expr) == "nil" || astp.IsBasicLit(expr)
}
func (c *yodaStyleExprChecker) invert(expr *ast.BinaryExpr) {
expr.X, expr.Y = expr.Y, expr.X
switch expr.Op {
case token.LSS:
expr.Op = token.GEQ
case token.LEQ:
expr.Op = token.GTR
case token.GEQ:
expr.Op = token.LSS
case token.GTR:
expr.Op = token.LEQ
}
}
func (c *yodaStyleExprChecker) warn(expr *ast.BinaryExpr) {
e := astcopy.BinaryExpr(expr)
c.invert(e)
c.ctx.Warn(expr, "consider to change order in expression to %s", e)
}

View file

@ -0,0 +1,51 @@
package linter
import (
"fmt"
"strconv"
"strings"
)
type GoVersion struct {
Major int
Minor int
}
// GreaterOrEqual performs $v >= $other operation.
//
// In other words, it reports whether $v version constraint can use
// a feature from the $other Go version.
//
// As a special case, Major=0 covers all versions.
func (v GoVersion) GreaterOrEqual(other GoVersion) bool {
if v.Major == 0 {
return true
}
if v.Major == other.Major {
return v.Minor >= other.Minor
}
return v.Major >= other.Major
}
func parseGoVersion(version string) GoVersion {
version = strings.TrimPrefix(version, "go")
if version == "" {
return GoVersion{}
}
parts := strings.Split(version, ".")
if len(parts) != 2 {
panic(fmt.Sprintf("invalid Go version format: %s", version))
}
major, err := strconv.Atoi(parts[0])
if err != nil {
panic(fmt.Sprintf("invalid major version part: %s: %s", parts[0], err))
}
minor, err := strconv.Atoi(parts[1])
if err != nil {
panic(fmt.Sprintf("invalid minor version part: %s: %s", parts[1], err))
}
return GoVersion{
Major: major,
Minor: minor,
}
}

View file

@ -87,6 +87,10 @@ type CheckerInfo struct {
// Note is an optional caution message or advice.
Note string
// EmbeddedRuleguard tells whether this checker is auto-generated
// from the embedded ruleguard rules.
EmbeddedRuleguard bool
// Collection establishes a checker-to-collection relationship.
Collection *CheckerCollection
}
@ -126,6 +130,14 @@ func (c *Checker) Check(f *ast.File) []Warning {
return c.ctx.warnings
}
// QuickFix is our analysis.TextEdit; we're using it here to avoid
// direct analysis package dependency for now.
type QuickFix struct {
From token.Pos
To token.Pos
Replacement []byte
}
// Warning represents issue that is found by checker.
type Warning struct {
// Node is an AST node that caused warning to trigger.
@ -134,6 +146,19 @@ type Warning struct {
// Text is warning message without source location info.
Text string
// Suggestion is a quick fix for a given problem.
// QuickFix is analysis.TextEdit and can be used to
// construct an analysis.SuggestedFix object.
//
// For convenience, there is Warning.HasQuickFix() method
// that reports whether Suggestion has something meaningful.
Suggestion QuickFix
}
// HasQuickFix reports whether this warning has a suggested fix.
func (warn Warning) HasQuickFix() bool {
return warn.Suggestion.Replacement != nil
}
// NewChecker returns initialized checker identified by an info.
@ -153,6 +178,9 @@ type Context struct {
// Arch-dependent.
SizesInfo types.Sizes
// GoVersion is a target Go version.
GoVersion GoVersion
// FileSet is a file set that was used during the program loading.
FileSet *token.FileSet
@ -194,6 +222,19 @@ func NewContext(fset *token.FileSet, sizes types.Sizes) *Context {
}
}
// SetGoVersion adjust the target Go language version.
//
// The format is like "1.5", "1.8", etc.
// It's permitted to have "go" prefix (e.g. "go1.5").
//
// Empty string (the default) means that we make no
// Go version assumptions and (like gocritic does) behave
// like all features are available. To make gocritic
// more conservative, the upper Go version level should be adjusted.
func (c *Context) SetGoVersion(version string) {
c.GoVersion = parseGoVersion(version)
}
// SetPackageInfo sets package-related metadata.
//
// Must be called for every package being checked.
@ -239,6 +280,15 @@ func (ctx *CheckerContext) Warn(node ast.Node, format string, args ...interface{
})
}
// WarnFixable emits a warning with a fix suggestion provided by the caller.
func (ctx *CheckerContext) WarnFixable(node ast.Node, fix QuickFix, format string, args ...interface{}) {
ctx.warnings = append(ctx.warnings, Warning{
Text: ctx.printer.Sprintf(format, args...),
Node: node,
Suggestion: fix,
})
}
// UnknownType is a special sentinel value that is returned from the CheckerContext.TypeOf
// method instead of the nil type.
var UnknownType types.Type = types.Typ[types.Invalid]

View file

@ -60,6 +60,14 @@ func astNodeEq(x, y ast.Node) bool {
case ast.Decl:
y, ok := y.(ast.Decl)
return ok && astDeclEq(x, y)
case *ast.Field:
y, ok := y.(*ast.Field)
return ok && astFieldEq(x, y)
case *ast.FieldList:
y, ok := y.(*ast.FieldList)
return ok && astFieldListEq(x, y)
default:
return false
}

View file

@ -1 +1,3 @@
module github.com/go-toolsmith/astequal
require github.com/go-toolsmith/strparse v1.0.0

2
vendor/github.com/go-toolsmith/astequal/go.sum generated vendored Normal file
View file

@ -0,0 +1,2 @@
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=

View file

@ -8,8 +8,10 @@
# Please keep the list sorted.
Amazon.com, Inc
Damian Gryski <dgryski@gmail.com>
Google Inc.
Jan Mercl <0xjnml@gmail.com>
Klaus Post <klauspost@gmail.com>
Rodolfo Carvalho <rhcarvalho@gmail.com>
Sebastien Binet <seb.binet@gmail.com>

View file

@ -28,7 +28,9 @@
Damian Gryski <dgryski@gmail.com>
Jan Mercl <0xjnml@gmail.com>
Jonathan Swinney <jswinney@amazon.com>
Kai Backman <kaib@golang.org>
Klaus Post <klauspost@gmail.com>
Marc-Antoine Ruel <maruel@chromium.org>
Nigel Tao <nigeltao@golang.org>
Rob Pike <r@golang.org>

View file

@ -52,6 +52,8 @@ const (
// Otherwise, a newly allocated slice will be returned.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// Decode handles the Snappy block format, not the Snappy stream format.
func Decode(dst, src []byte) ([]byte, error) {
dLen, s, err := decodedLen(src)
if err != nil {
@ -83,6 +85,8 @@ func NewReader(r io.Reader) *Reader {
}
// Reader is an io.Reader that can read Snappy-compressed bytes.
//
// Reader handles the Snappy stream format, not the Snappy block format.
type Reader struct {
r io.Reader
err error

494
vendor/github.com/golang/snappy/decode_arm64.s generated vendored Normal file
View file

@ -0,0 +1,494 @@
// Copyright 2020 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.
// +build !appengine
// +build gc
// +build !noasm
#include "textflag.h"
// The asm code generally follows the pure Go code in decode_other.go, except
// where marked with a "!!!".
// func decode(dst, src []byte) int
//
// All local variables fit into registers. The non-zero stack size is only to
// spill registers and push args when issuing a CALL. The register allocation:
// - R2 scratch
// - R3 scratch
// - R4 length or x
// - R5 offset
// - R6 &src[s]
// - R7 &dst[d]
// + R8 dst_base
// + R9 dst_len
// + R10 dst_base + dst_len
// + R11 src_base
// + R12 src_len
// + R13 src_base + src_len
// - R14 used by doCopy
// - R15 used by doCopy
//
// The registers R8-R13 (marked with a "+") are set at the start of the
// function, and after a CALL returns, and are not otherwise modified.
//
// The d variable is implicitly R7 - R8, and len(dst)-d is R10 - R7.
// The s variable is implicitly R6 - R11, and len(src)-s is R13 - R6.
TEXT ·decode(SB), NOSPLIT, $56-56
// Initialize R6, R7 and R8-R13.
MOVD dst_base+0(FP), R8
MOVD dst_len+8(FP), R9
MOVD R8, R7
MOVD R8, R10
ADD R9, R10, R10
MOVD src_base+24(FP), R11
MOVD src_len+32(FP), R12
MOVD R11, R6
MOVD R11, R13
ADD R12, R13, R13
loop:
// for s < len(src)
CMP R13, R6
BEQ end
// R4 = uint32(src[s])
//
// switch src[s] & 0x03
MOVBU (R6), R4
MOVW R4, R3
ANDW $3, R3
MOVW $1, R1
CMPW R1, R3
BGE tagCopy
// ----------------------------------------
// The code below handles literal tags.
// case tagLiteral:
// x := uint32(src[s] >> 2)
// switch
MOVW $60, R1
LSRW $2, R4, R4
CMPW R4, R1
BLS tagLit60Plus
// case x < 60:
// s++
ADD $1, R6, R6
doLit:
// This is the end of the inner "switch", when we have a literal tag.
//
// We assume that R4 == x and x fits in a uint32, where x is the variable
// used in the pure Go decode_other.go code.
// length = int(x) + 1
//
// Unlike the pure Go code, we don't need to check if length <= 0 because
// R4 can hold 64 bits, so the increment cannot overflow.
ADD $1, R4, R4
// Prepare to check if copying length bytes will run past the end of dst or
// src.
//
// R2 = len(dst) - d
// R3 = len(src) - s
MOVD R10, R2
SUB R7, R2, R2
MOVD R13, R3
SUB R6, R3, R3
// !!! Try a faster technique for short (16 or fewer bytes) copies.
//
// if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
// goto callMemmove // Fall back on calling runtime·memmove.
// }
//
// The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
// against 21 instead of 16, because it cannot assume that all of its input
// is contiguous in memory and so it needs to leave enough source bytes to
// read the next tag without refilling buffers, but Go's Decode assumes
// contiguousness (the src argument is a []byte).
CMP $16, R4
BGT callMemmove
CMP $16, R2
BLT callMemmove
CMP $16, R3
BLT callMemmove
// !!! Implement the copy from src to dst as a 16-byte load and store.
// (Decode's documentation says that dst and src must not overlap.)
//
// This always copies 16 bytes, instead of only length bytes, but that's
// OK. If the input is a valid Snappy encoding then subsequent iterations
// will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
// non-nil error), so the overrun will be ignored.
//
// Note that on arm64, it is legal and cheap to issue unaligned 8-byte or
// 16-byte loads and stores. This technique probably wouldn't be as
// effective on architectures that are fussier about alignment.
LDP 0(R6), (R14, R15)
STP (R14, R15), 0(R7)
// d += length
// s += length
ADD R4, R7, R7
ADD R4, R6, R6
B loop
callMemmove:
// if length > len(dst)-d || length > len(src)-s { etc }
CMP R2, R4
BGT errCorrupt
CMP R3, R4
BGT errCorrupt
// copy(dst[d:], src[s:s+length])
//
// This means calling runtime·memmove(&dst[d], &src[s], length), so we push
// R7, R6 and R4 as arguments. Coincidentally, we also need to spill those
// three registers to the stack, to save local variables across the CALL.
MOVD R7, 8(RSP)
MOVD R6, 16(RSP)
MOVD R4, 24(RSP)
MOVD R7, 32(RSP)
MOVD R6, 40(RSP)
MOVD R4, 48(RSP)
CALL runtime·memmove(SB)
// Restore local variables: unspill registers from the stack and
// re-calculate R8-R13.
MOVD 32(RSP), R7
MOVD 40(RSP), R6
MOVD 48(RSP), R4
MOVD dst_base+0(FP), R8
MOVD dst_len+8(FP), R9
MOVD R8, R10
ADD R9, R10, R10
MOVD src_base+24(FP), R11
MOVD src_len+32(FP), R12
MOVD R11, R13
ADD R12, R13, R13
// d += length
// s += length
ADD R4, R7, R7
ADD R4, R6, R6
B loop
tagLit60Plus:
// !!! This fragment does the
//
// s += x - 58; if uint(s) > uint(len(src)) { etc }
//
// checks. In the asm version, we code it once instead of once per switch case.
ADD R4, R6, R6
SUB $58, R6, R6
MOVD R6, R3
SUB R11, R3, R3
CMP R12, R3
BGT errCorrupt
// case x == 60:
MOVW $61, R1
CMPW R1, R4
BEQ tagLit61
BGT tagLit62Plus
// x = uint32(src[s-1])
MOVBU -1(R6), R4
B doLit
tagLit61:
// case x == 61:
// x = uint32(src[s-2]) | uint32(src[s-1])<<8
MOVHU -2(R6), R4
B doLit
tagLit62Plus:
CMPW $62, R4
BHI tagLit63
// case x == 62:
// x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
MOVHU -3(R6), R4
MOVBU -1(R6), R3
ORR R3<<16, R4
B doLit
tagLit63:
// case x == 63:
// x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
MOVWU -4(R6), R4
B doLit
// The code above handles literal tags.
// ----------------------------------------
// The code below handles copy tags.
tagCopy4:
// case tagCopy4:
// s += 5
ADD $5, R6, R6
// if uint(s) > uint(len(src)) { etc }
MOVD R6, R3
SUB R11, R3, R3
CMP R12, R3
BGT errCorrupt
// length = 1 + int(src[s-5])>>2
MOVD $1, R1
ADD R4>>2, R1, R4
// offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
MOVWU -4(R6), R5
B doCopy
tagCopy2:
// case tagCopy2:
// s += 3
ADD $3, R6, R6
// if uint(s) > uint(len(src)) { etc }
MOVD R6, R3
SUB R11, R3, R3
CMP R12, R3
BGT errCorrupt
// length = 1 + int(src[s-3])>>2
MOVD $1, R1
ADD R4>>2, R1, R4
// offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
MOVHU -2(R6), R5
B doCopy
tagCopy:
// We have a copy tag. We assume that:
// - R3 == src[s] & 0x03
// - R4 == src[s]
CMP $2, R3
BEQ tagCopy2
BGT tagCopy4
// case tagCopy1:
// s += 2
ADD $2, R6, R6
// if uint(s) > uint(len(src)) { etc }
MOVD R6, R3
SUB R11, R3, R3
CMP R12, R3
BGT errCorrupt
// offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
MOVD R4, R5
AND $0xe0, R5
MOVBU -1(R6), R3
ORR R5<<3, R3, R5
// length = 4 + int(src[s-2])>>2&0x7
MOVD $7, R1
AND R4>>2, R1, R4
ADD $4, R4, R4
doCopy:
// This is the end of the outer "switch", when we have a copy tag.
//
// We assume that:
// - R4 == length && R4 > 0
// - R5 == offset
// if offset <= 0 { etc }
MOVD $0, R1
CMP R1, R5
BLE errCorrupt
// if d < offset { etc }
MOVD R7, R3
SUB R8, R3, R3
CMP R5, R3
BLT errCorrupt
// if length > len(dst)-d { etc }
MOVD R10, R3
SUB R7, R3, R3
CMP R3, R4
BGT errCorrupt
// forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
//
// Set:
// - R14 = len(dst)-d
// - R15 = &dst[d-offset]
MOVD R10, R14
SUB R7, R14, R14
MOVD R7, R15
SUB R5, R15, R15
// !!! Try a faster technique for short (16 or fewer bytes) forward copies.
//
// First, try using two 8-byte load/stores, similar to the doLit technique
// above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
// still OK if offset >= 8. Note that this has to be two 8-byte load/stores
// and not one 16-byte load/store, and the first store has to be before the
// second load, due to the overlap if offset is in the range [8, 16).
//
// if length > 16 || offset < 8 || len(dst)-d < 16 {
// goto slowForwardCopy
// }
// copy 16 bytes
// d += length
CMP $16, R4
BGT slowForwardCopy
CMP $8, R5
BLT slowForwardCopy
CMP $16, R14
BLT slowForwardCopy
MOVD 0(R15), R2
MOVD R2, 0(R7)
MOVD 8(R15), R3
MOVD R3, 8(R7)
ADD R4, R7, R7
B loop
slowForwardCopy:
// !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
// can still try 8-byte load stores, provided we can overrun up to 10 extra
// bytes. As above, the overrun will be fixed up by subsequent iterations
// of the outermost loop.
//
// The C++ snappy code calls this technique IncrementalCopyFastPath. Its
// commentary says:
//
// ----
//
// The main part of this loop is a simple copy of eight bytes at a time
// until we've copied (at least) the requested amount of bytes. However,
// if d and d-offset are less than eight bytes apart (indicating a
// repeating pattern of length < 8), we first need to expand the pattern in
// order to get the correct results. For instance, if the buffer looks like
// this, with the eight-byte <d-offset> and <d> patterns marked as
// intervals:
//
// abxxxxxxxxxxxx
// [------] d-offset
// [------] d
//
// a single eight-byte copy from <d-offset> to <d> will repeat the pattern
// once, after which we can move <d> two bytes without moving <d-offset>:
//
// ababxxxxxxxxxx
// [------] d-offset
// [------] d
//
// and repeat the exercise until the two no longer overlap.
//
// This allows us to do very well in the special case of one single byte
// repeated many times, without taking a big hit for more general cases.
//
// The worst case of extra writing past the end of the match occurs when
// offset == 1 and length == 1; the last copy will read from byte positions
// [0..7] and write to [4..11], whereas it was only supposed to write to
// position 1. Thus, ten excess bytes.
//
// ----
//
// That "10 byte overrun" worst case is confirmed by Go's
// TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
// and finishSlowForwardCopy algorithm.
//
// if length > len(dst)-d-10 {
// goto verySlowForwardCopy
// }
SUB $10, R14, R14
CMP R14, R4
BGT verySlowForwardCopy
makeOffsetAtLeast8:
// !!! As above, expand the pattern so that offset >= 8 and we can use
// 8-byte load/stores.
//
// for offset < 8 {
// copy 8 bytes from dst[d-offset:] to dst[d:]
// length -= offset
// d += offset
// offset += offset
// // The two previous lines together means that d-offset, and therefore
// // R15, is unchanged.
// }
CMP $8, R5
BGE fixUpSlowForwardCopy
MOVD (R15), R3
MOVD R3, (R7)
SUB R5, R4, R4
ADD R5, R7, R7
ADD R5, R5, R5
B makeOffsetAtLeast8
fixUpSlowForwardCopy:
// !!! Add length (which might be negative now) to d (implied by R7 being
// &dst[d]) so that d ends up at the right place when we jump back to the
// top of the loop. Before we do that, though, we save R7 to R2 so that, if
// length is positive, copying the remaining length bytes will write to the
// right place.
MOVD R7, R2
ADD R4, R7, R7
finishSlowForwardCopy:
// !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
// length means that we overrun, but as above, that will be fixed up by
// subsequent iterations of the outermost loop.
MOVD $0, R1
CMP R1, R4
BLE loop
MOVD (R15), R3
MOVD R3, (R2)
ADD $8, R15, R15
ADD $8, R2, R2
SUB $8, R4, R4
B finishSlowForwardCopy
verySlowForwardCopy:
// verySlowForwardCopy is a simple implementation of forward copy. In C
// parlance, this is a do/while loop instead of a while loop, since we know
// that length > 0. In Go syntax:
//
// for {
// dst[d] = dst[d - offset]
// d++
// length--
// if length == 0 {
// break
// }
// }
MOVB (R15), R3
MOVB R3, (R7)
ADD $1, R15, R15
ADD $1, R7, R7
SUB $1, R4, R4
CBNZ R4, verySlowForwardCopy
B loop
// The code above handles copy tags.
// ----------------------------------------
end:
// This is the end of the "for s < len(src)".
//
// if d != len(dst) { etc }
CMP R10, R7
BNE errCorrupt
// return 0
MOVD $0, ret+48(FP)
RET
errCorrupt:
// return decodeErrCodeCorrupt
MOVD $1, R2
MOVD R2, ret+48(FP)
RET

View file

@ -5,6 +5,7 @@
// +build !appengine
// +build gc
// +build !noasm
// +build amd64 arm64
package snappy

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine !gc noasm
// +build !amd64,!arm64 appengine !gc noasm
package snappy
@ -85,14 +85,28 @@ func decode(dst, src []byte) int {
if offset <= 0 || d < offset || length > len(dst)-d {
return decodeErrCodeCorrupt
}
// Copy from an earlier sub-slice of dst to a later sub-slice. Unlike
// the built-in copy function, this byte-by-byte copy always runs
// Copy from an earlier sub-slice of dst to a later sub-slice.
// If no overlap, use the built-in copy:
if offset >= length {
copy(dst[d:d+length], dst[d-offset:])
d += length
continue
}
// Unlike the built-in copy function, this byte-by-byte copy always runs
// forwards, even if the slices overlap. Conceptually, this is:
//
// d += forwardCopy(dst[d:d+length], dst[d-offset:])
for end := d + length; d != end; d++ {
dst[d] = dst[d-offset]
//
// We align the slices into a and b and show the compiler they are the same size.
// This allows the loop to run without bounds checks.
a := dst[d : d+length]
b := dst[d-offset:]
b = b[:len(a)]
for i := range a {
a[i] = b[i]
}
d += length
}
if d != len(dst) {
return decodeErrCodeCorrupt

View file

@ -15,6 +15,8 @@ import (
// Otherwise, a newly allocated slice will be returned.
//
// The dst and src must not overlap. It is valid to pass a nil dst.
//
// Encode handles the Snappy block format, not the Snappy stream format.
func Encode(dst, src []byte) []byte {
if n := MaxEncodedLen(len(src)); n < 0 {
panic(ErrTooLarge)
@ -139,6 +141,8 @@ func NewBufferedWriter(w io.Writer) *Writer {
}
// Writer is an io.Writer that can write Snappy-compressed bytes.
//
// Writer handles the Snappy stream format, not the Snappy block format.
type Writer struct {
w io.Writer
err error

722
vendor/github.com/golang/snappy/encode_arm64.s generated vendored Normal file
View file

@ -0,0 +1,722 @@
// Copyright 2020 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.
// +build !appengine
// +build gc
// +build !noasm
#include "textflag.h"
// The asm code generally follows the pure Go code in encode_other.go, except
// where marked with a "!!!".
// ----------------------------------------------------------------------------
// func emitLiteral(dst, lit []byte) int
//
// All local variables fit into registers. The register allocation:
// - R3 len(lit)
// - R4 n
// - R6 return value
// - R8 &dst[i]
// - R10 &lit[0]
//
// The 32 bytes of stack space is to call runtime·memmove.
//
// The unusual register allocation of local variables, such as R10 for the
// source pointer, matches the allocation used at the call site in encodeBlock,
// which makes it easier to manually inline this function.
TEXT ·emitLiteral(SB), NOSPLIT, $32-56
MOVD dst_base+0(FP), R8
MOVD lit_base+24(FP), R10
MOVD lit_len+32(FP), R3
MOVD R3, R6
MOVW R3, R4
SUBW $1, R4, R4
CMPW $60, R4
BLT oneByte
CMPW $256, R4
BLT twoBytes
threeBytes:
MOVD $0xf4, R2
MOVB R2, 0(R8)
MOVW R4, 1(R8)
ADD $3, R8, R8
ADD $3, R6, R6
B memmove
twoBytes:
MOVD $0xf0, R2
MOVB R2, 0(R8)
MOVB R4, 1(R8)
ADD $2, R8, R8
ADD $2, R6, R6
B memmove
oneByte:
LSLW $2, R4, R4
MOVB R4, 0(R8)
ADD $1, R8, R8
ADD $1, R6, R6
memmove:
MOVD R6, ret+48(FP)
// copy(dst[i:], lit)
//
// This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
// R8, R10 and R3 as arguments.
MOVD R8, 8(RSP)
MOVD R10, 16(RSP)
MOVD R3, 24(RSP)
CALL runtime·memmove(SB)
RET
// ----------------------------------------------------------------------------
// func emitCopy(dst []byte, offset, length int) int
//
// All local variables fit into registers. The register allocation:
// - R3 length
// - R7 &dst[0]
// - R8 &dst[i]
// - R11 offset
//
// The unusual register allocation of local variables, such as R11 for the
// offset, matches the allocation used at the call site in encodeBlock, which
// makes it easier to manually inline this function.
TEXT ·emitCopy(SB), NOSPLIT, $0-48
MOVD dst_base+0(FP), R8
MOVD R8, R7
MOVD offset+24(FP), R11
MOVD length+32(FP), R3
loop0:
// for length >= 68 { etc }
CMPW $68, R3
BLT step1
// Emit a length 64 copy, encoded as 3 bytes.
MOVD $0xfe, R2
MOVB R2, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
SUB $64, R3, R3
B loop0
step1:
// if length > 64 { etc }
CMP $64, R3
BLE step2
// Emit a length 60 copy, encoded as 3 bytes.
MOVD $0xee, R2
MOVB R2, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
SUB $60, R3, R3
step2:
// if length >= 12 || offset >= 2048 { goto step3 }
CMP $12, R3
BGE step3
CMPW $2048, R11
BGE step3
// Emit the remaining copy, encoded as 2 bytes.
MOVB R11, 1(R8)
LSRW $3, R11, R11
AND $0xe0, R11, R11
SUB $4, R3, R3
LSLW $2, R3
AND $0xff, R3, R3
ORRW R3, R11, R11
ORRW $1, R11, R11
MOVB R11, 0(R8)
ADD $2, R8, R8
// Return the number of bytes written.
SUB R7, R8, R8
MOVD R8, ret+40(FP)
RET
step3:
// Emit the remaining copy, encoded as 3 bytes.
SUB $1, R3, R3
AND $0xff, R3, R3
LSLW $2, R3, R3
ORRW $2, R3, R3
MOVB R3, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
// Return the number of bytes written.
SUB R7, R8, R8
MOVD R8, ret+40(FP)
RET
// ----------------------------------------------------------------------------
// func extendMatch(src []byte, i, j int) int
//
// All local variables fit into registers. The register allocation:
// - R6 &src[0]
// - R7 &src[j]
// - R13 &src[len(src) - 8]
// - R14 &src[len(src)]
// - R15 &src[i]
//
// The unusual register allocation of local variables, such as R15 for a source
// pointer, matches the allocation used at the call site in encodeBlock, which
// makes it easier to manually inline this function.
TEXT ·extendMatch(SB), NOSPLIT, $0-48
MOVD src_base+0(FP), R6
MOVD src_len+8(FP), R14
MOVD i+24(FP), R15
MOVD j+32(FP), R7
ADD R6, R14, R14
ADD R6, R15, R15
ADD R6, R7, R7
MOVD R14, R13
SUB $8, R13, R13
cmp8:
// As long as we are 8 or more bytes before the end of src, we can load and
// compare 8 bytes at a time. If those 8 bytes are equal, repeat.
CMP R13, R7
BHI cmp1
MOVD (R15), R3
MOVD (R7), R4
CMP R4, R3
BNE bsf
ADD $8, R15, R15
ADD $8, R7, R7
B cmp8
bsf:
// If those 8 bytes were not equal, XOR the two 8 byte values, and return
// the index of the first byte that differs.
// RBIT reverses the bit order, then CLZ counts the leading zeros, the
// combination of which finds the least significant bit which is set.
// The arm64 architecture is little-endian, and the shift by 3 converts
// a bit index to a byte index.
EOR R3, R4, R4
RBIT R4, R4
CLZ R4, R4
ADD R4>>3, R7, R7
// Convert from &src[ret] to ret.
SUB R6, R7, R7
MOVD R7, ret+40(FP)
RET
cmp1:
// In src's tail, compare 1 byte at a time.
CMP R7, R14
BLS extendMatchEnd
MOVB (R15), R3
MOVB (R7), R4
CMP R4, R3
BNE extendMatchEnd
ADD $1, R15, R15
ADD $1, R7, R7
B cmp1
extendMatchEnd:
// Convert from &src[ret] to ret.
SUB R6, R7, R7
MOVD R7, ret+40(FP)
RET
// ----------------------------------------------------------------------------
// func encodeBlock(dst, src []byte) (d int)
//
// All local variables fit into registers, other than "var table". The register
// allocation:
// - R3 . .
// - R4 . .
// - R5 64 shift
// - R6 72 &src[0], tableSize
// - R7 80 &src[s]
// - R8 88 &dst[d]
// - R9 96 sLimit
// - R10 . &src[nextEmit]
// - R11 104 prevHash, currHash, nextHash, offset
// - R12 112 &src[base], skip
// - R13 . &src[nextS], &src[len(src) - 8]
// - R14 . len(src), bytesBetweenHashLookups, &src[len(src)], x
// - R15 120 candidate
// - R16 . hash constant, 0x1e35a7bd
// - R17 . &table
// - . 128 table
//
// The second column (64, 72, etc) is the stack offset to spill the registers
// when calling other functions. We could pack this slightly tighter, but it's
// simpler to have a dedicated spill map independent of the function called.
//
// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An
// extra 64 bytes, to call other functions, and an extra 64 bytes, to spill
// local variables (registers) during calls gives 32768 + 64 + 64 = 32896.
TEXT ·encodeBlock(SB), 0, $32896-56
MOVD dst_base+0(FP), R8
MOVD src_base+24(FP), R7
MOVD src_len+32(FP), R14
// shift, tableSize := uint32(32-8), 1<<8
MOVD $24, R5
MOVD $256, R6
MOVW $0xa7bd, R16
MOVKW $(0x1e35<<16), R16
calcShift:
// for ; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
// shift--
// }
MOVD $16384, R2
CMP R2, R6
BGE varTable
CMP R14, R6
BGE varTable
SUB $1, R5, R5
LSL $1, R6, R6
B calcShift
varTable:
// var table [maxTableSize]uint16
//
// In the asm code, unlike the Go code, we can zero-initialize only the
// first tableSize elements. Each uint16 element is 2 bytes and each
// iterations writes 64 bytes, so we can do only tableSize/32 writes
// instead of the 2048 writes that would zero-initialize all of table's
// 32768 bytes. This clear could overrun the first tableSize elements, but
// it won't overrun the allocated stack size.
ADD $128, RSP, R17
MOVD R17, R4
// !!! R6 = &src[tableSize]
ADD R6<<1, R17, R6
memclr:
STP.P (ZR, ZR), 64(R4)
STP (ZR, ZR), -48(R4)
STP (ZR, ZR), -32(R4)
STP (ZR, ZR), -16(R4)
CMP R4, R6
BHI memclr
// !!! R6 = &src[0]
MOVD R7, R6
// sLimit := len(src) - inputMargin
MOVD R14, R9
SUB $15, R9, R9
// !!! Pre-emptively spill R5, R6 and R9 to the stack. Their values don't
// change for the rest of the function.
MOVD R5, 64(RSP)
MOVD R6, 72(RSP)
MOVD R9, 96(RSP)
// nextEmit := 0
MOVD R6, R10
// s := 1
ADD $1, R7, R7
// nextHash := hash(load32(src, s), shift)
MOVW 0(R7), R11
MULW R16, R11, R11
LSRW R5, R11, R11
outer:
// for { etc }
// skip := 32
MOVD $32, R12
// nextS := s
MOVD R7, R13
// candidate := 0
MOVD $0, R15
inner0:
// for { etc }
// s := nextS
MOVD R13, R7
// bytesBetweenHashLookups := skip >> 5
MOVD R12, R14
LSR $5, R14, R14
// nextS = s + bytesBetweenHashLookups
ADD R14, R13, R13
// skip += bytesBetweenHashLookups
ADD R14, R12, R12
// if nextS > sLimit { goto emitRemainder }
MOVD R13, R3
SUB R6, R3, R3
CMP R9, R3
BHI emitRemainder
// candidate = int(table[nextHash])
MOVHU 0(R17)(R11<<1), R15
// table[nextHash] = uint16(s)
MOVD R7, R3
SUB R6, R3, R3
MOVH R3, 0(R17)(R11<<1)
// nextHash = hash(load32(src, nextS), shift)
MOVW 0(R13), R11
MULW R16, R11
LSRW R5, R11, R11
// if load32(src, s) != load32(src, candidate) { continue } break
MOVW 0(R7), R3
MOVW (R6)(R15*1), R4
CMPW R4, R3
BNE inner0
fourByteMatch:
// As per the encode_other.go code:
//
// A 4-byte match has been found. We'll later see etc.
// !!! Jump to a fast path for short (<= 16 byte) literals. See the comment
// on inputMargin in encode.go.
MOVD R7, R3
SUB R10, R3, R3
CMP $16, R3
BLE emitLiteralFastPath
// ----------------------------------------
// Begin inline of the emitLiteral call.
//
// d += emitLiteral(dst[d:], src[nextEmit:s])
MOVW R3, R4
SUBW $1, R4, R4
MOVW $60, R2
CMPW R2, R4
BLT inlineEmitLiteralOneByte
MOVW $256, R2
CMPW R2, R4
BLT inlineEmitLiteralTwoBytes
inlineEmitLiteralThreeBytes:
MOVD $0xf4, R1
MOVB R1, 0(R8)
MOVW R4, 1(R8)
ADD $3, R8, R8
B inlineEmitLiteralMemmove
inlineEmitLiteralTwoBytes:
MOVD $0xf0, R1
MOVB R1, 0(R8)
MOVB R4, 1(R8)
ADD $2, R8, R8
B inlineEmitLiteralMemmove
inlineEmitLiteralOneByte:
LSLW $2, R4, R4
MOVB R4, 0(R8)
ADD $1, R8, R8
inlineEmitLiteralMemmove:
// Spill local variables (registers) onto the stack; call; unspill.
//
// copy(dst[i:], lit)
//
// This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
// R8, R10 and R3 as arguments.
MOVD R8, 8(RSP)
MOVD R10, 16(RSP)
MOVD R3, 24(RSP)
// Finish the "d +=" part of "d += emitLiteral(etc)".
ADD R3, R8, R8
MOVD R7, 80(RSP)
MOVD R8, 88(RSP)
MOVD R15, 120(RSP)
CALL runtime·memmove(SB)
MOVD 64(RSP), R5
MOVD 72(RSP), R6
MOVD 80(RSP), R7
MOVD 88(RSP), R8
MOVD 96(RSP), R9
MOVD 120(RSP), R15
ADD $128, RSP, R17
MOVW $0xa7bd, R16
MOVKW $(0x1e35<<16), R16
B inner1
inlineEmitLiteralEnd:
// End inline of the emitLiteral call.
// ----------------------------------------
emitLiteralFastPath:
// !!! Emit the 1-byte encoding "uint8(len(lit)-1)<<2".
MOVB R3, R4
SUBW $1, R4, R4
AND $0xff, R4, R4
LSLW $2, R4, R4
MOVB R4, (R8)
ADD $1, R8, R8
// !!! Implement the copy from lit to dst as a 16-byte load and store.
// (Encode's documentation says that dst and src must not overlap.)
//
// This always copies 16 bytes, instead of only len(lit) bytes, but that's
// OK. Subsequent iterations will fix up the overrun.
//
// Note that on arm64, it is legal and cheap to issue unaligned 8-byte or
// 16-byte loads and stores. This technique probably wouldn't be as
// effective on architectures that are fussier about alignment.
LDP 0(R10), (R0, R1)
STP (R0, R1), 0(R8)
ADD R3, R8, R8
inner1:
// for { etc }
// base := s
MOVD R7, R12
// !!! offset := base - candidate
MOVD R12, R11
SUB R15, R11, R11
SUB R6, R11, R11
// ----------------------------------------
// Begin inline of the extendMatch call.
//
// s = extendMatch(src, candidate+4, s+4)
// !!! R14 = &src[len(src)]
MOVD src_len+32(FP), R14
ADD R6, R14, R14
// !!! R13 = &src[len(src) - 8]
MOVD R14, R13
SUB $8, R13, R13
// !!! R15 = &src[candidate + 4]
ADD $4, R15, R15
ADD R6, R15, R15
// !!! s += 4
ADD $4, R7, R7
inlineExtendMatchCmp8:
// As long as we are 8 or more bytes before the end of src, we can load and
// compare 8 bytes at a time. If those 8 bytes are equal, repeat.
CMP R13, R7
BHI inlineExtendMatchCmp1
MOVD (R15), R3
MOVD (R7), R4
CMP R4, R3
BNE inlineExtendMatchBSF
ADD $8, R15, R15
ADD $8, R7, R7
B inlineExtendMatchCmp8
inlineExtendMatchBSF:
// If those 8 bytes were not equal, XOR the two 8 byte values, and return
// the index of the first byte that differs.
// RBIT reverses the bit order, then CLZ counts the leading zeros, the
// combination of which finds the least significant bit which is set.
// The arm64 architecture is little-endian, and the shift by 3 converts
// a bit index to a byte index.
EOR R3, R4, R4
RBIT R4, R4
CLZ R4, R4
ADD R4>>3, R7, R7
B inlineExtendMatchEnd
inlineExtendMatchCmp1:
// In src's tail, compare 1 byte at a time.
CMP R7, R14
BLS inlineExtendMatchEnd
MOVB (R15), R3
MOVB (R7), R4
CMP R4, R3
BNE inlineExtendMatchEnd
ADD $1, R15, R15
ADD $1, R7, R7
B inlineExtendMatchCmp1
inlineExtendMatchEnd:
// End inline of the extendMatch call.
// ----------------------------------------
// ----------------------------------------
// Begin inline of the emitCopy call.
//
// d += emitCopy(dst[d:], base-candidate, s-base)
// !!! length := s - base
MOVD R7, R3
SUB R12, R3, R3
inlineEmitCopyLoop0:
// for length >= 68 { etc }
MOVW $68, R2
CMPW R2, R3
BLT inlineEmitCopyStep1
// Emit a length 64 copy, encoded as 3 bytes.
MOVD $0xfe, R1
MOVB R1, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
SUBW $64, R3, R3
B inlineEmitCopyLoop0
inlineEmitCopyStep1:
// if length > 64 { etc }
MOVW $64, R2
CMPW R2, R3
BLE inlineEmitCopyStep2
// Emit a length 60 copy, encoded as 3 bytes.
MOVD $0xee, R1
MOVB R1, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
SUBW $60, R3, R3
inlineEmitCopyStep2:
// if length >= 12 || offset >= 2048 { goto inlineEmitCopyStep3 }
MOVW $12, R2
CMPW R2, R3
BGE inlineEmitCopyStep3
MOVW $2048, R2
CMPW R2, R11
BGE inlineEmitCopyStep3
// Emit the remaining copy, encoded as 2 bytes.
MOVB R11, 1(R8)
LSRW $8, R11, R11
LSLW $5, R11, R11
SUBW $4, R3, R3
AND $0xff, R3, R3
LSLW $2, R3, R3
ORRW R3, R11, R11
ORRW $1, R11, R11
MOVB R11, 0(R8)
ADD $2, R8, R8
B inlineEmitCopyEnd
inlineEmitCopyStep3:
// Emit the remaining copy, encoded as 3 bytes.
SUBW $1, R3, R3
LSLW $2, R3, R3
ORRW $2, R3, R3
MOVB R3, 0(R8)
MOVW R11, 1(R8)
ADD $3, R8, R8
inlineEmitCopyEnd:
// End inline of the emitCopy call.
// ----------------------------------------
// nextEmit = s
MOVD R7, R10
// if s >= sLimit { goto emitRemainder }
MOVD R7, R3
SUB R6, R3, R3
CMP R3, R9
BLS emitRemainder
// As per the encode_other.go code:
//
// We could immediately etc.
// x := load64(src, s-1)
MOVD -1(R7), R14
// prevHash := hash(uint32(x>>0), shift)
MOVW R14, R11
MULW R16, R11, R11
LSRW R5, R11, R11
// table[prevHash] = uint16(s-1)
MOVD R7, R3
SUB R6, R3, R3
SUB $1, R3, R3
MOVHU R3, 0(R17)(R11<<1)
// currHash := hash(uint32(x>>8), shift)
LSR $8, R14, R14
MOVW R14, R11
MULW R16, R11, R11
LSRW R5, R11, R11
// candidate = int(table[currHash])
MOVHU 0(R17)(R11<<1), R15
// table[currHash] = uint16(s)
ADD $1, R3, R3
MOVHU R3, 0(R17)(R11<<1)
// if uint32(x>>8) == load32(src, candidate) { continue }
MOVW (R6)(R15*1), R4
CMPW R4, R14
BEQ inner1
// nextHash = hash(uint32(x>>16), shift)
LSR $8, R14, R14
MOVW R14, R11
MULW R16, R11, R11
LSRW R5, R11, R11
// s++
ADD $1, R7, R7
// break out of the inner1 for loop, i.e. continue the outer loop.
B outer
emitRemainder:
// if nextEmit < len(src) { etc }
MOVD src_len+32(FP), R3
ADD R6, R3, R3
CMP R3, R10
BEQ encodeBlockEnd
// d += emitLiteral(dst[d:], src[nextEmit:])
//
// Push args.
MOVD R8, 8(RSP)
MOVD $0, 16(RSP) // Unnecessary, as the callee ignores it, but conservative.
MOVD $0, 24(RSP) // Unnecessary, as the callee ignores it, but conservative.
MOVD R10, 32(RSP)
SUB R10, R3, R3
MOVD R3, 40(RSP)
MOVD R3, 48(RSP) // Unnecessary, as the callee ignores it, but conservative.
// Spill local variables (registers) onto the stack; call; unspill.
MOVD R8, 88(RSP)
CALL ·emitLiteral(SB)
MOVD 88(RSP), R8
// Finish the "d +=" part of "d += emitLiteral(etc)".
MOVD 56(RSP), R1
ADD R1, R8, R8
encodeBlockEnd:
MOVD dst_base+0(FP), R3
SUB R3, R8, R8
MOVD R8, d+48(FP)
RET

Some files were not shown because too many files have changed in this diff Show more