diff --git a/go.mod b/go.mod
index cdf023fd55..b6d85d7a0d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.20
require (
cloud.google.com/go/compute/metadata v0.2.3
cloud.google.com/go/storage v1.33.0
- github.com/golangci/golangci-lint v1.54.2
+ github.com/golangci/golangci-lint v1.55.0
github.com/google/addlicense v1.1.1
github.com/google/go-cmp v0.6.0
github.com/google/go-containerregistry v0.16.1
@@ -33,7 +33,7 @@ require (
gocloud.dev/docstore/mongodocstore v0.34.0
gocloud.dev/pubsub/kafkapubsub v0.34.0
golang.org/x/crypto v0.14.0
- google.golang.org/grpc v1.58.3
+ google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
k8s.io/api v0.27.3
k8s.io/apimachinery v0.27.3
@@ -55,11 +55,12 @@ require (
contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.0 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
- github.com/4meepo/tagalign v1.3.2 // indirect
- github.com/Abirdcfly/dupword v0.0.12 // indirect
+ github.com/4meepo/tagalign v1.3.3 // indirect
+ github.com/Abirdcfly/dupword v0.0.13 // indirect
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
github.com/Antonboom/errname v0.1.12 // indirect
github.com/Antonboom/nilnil v0.1.7 // indirect
+ github.com/Antonboom/testifylint v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect
@@ -91,6 +92,7 @@ require (
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
github.com/Shopify/sarama v1.38.1 // indirect
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
+ github.com/alecthomas/go-check-sumtype v0.1.3 // indirect
github.com/alexkohler/nakedret/v2 v2.0.2 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
@@ -133,18 +135,19 @@ require (
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.0.2 // indirect
github.com/bombsimon/wsl/v3 v3.4.0 // indirect
- github.com/breml/bidichk v0.2.4 // indirect
- github.com/breml/errchkjson v0.3.1 // indirect
+ github.com/breml/bidichk v0.2.7 // indirect
+ github.com/breml/errchkjson v0.3.6 // indirect
github.com/buildkite/agent/v3 v3.52.1 // indirect
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect
- github.com/butuzov/ireturn v0.2.0 // indirect
+ github.com/butuzov/ireturn v0.2.1 // indirect
github.com/butuzov/mirror v1.1.0 // indirect
+ github.com/catenacyber/perfsprint v0.2.0 // indirect
github.com/ccojocar/zxcvbn-go v1.0.1 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
- github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 // indirect
+ github.com/chavacava/garif v0.1.0 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
github.com/clbanning/mxj/v2 v2.5.6 // indirect
github.com/cloudevents/sdk-go/v2 v2.14.0 // indirect
@@ -154,7 +157,7 @@ require (
github.com/coreos/go-oidc/v3 v3.6.0 // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect
- github.com/daixiang0/gci v0.11.0 // indirect
+ github.com/daixiang0/gci v0.11.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
@@ -182,6 +185,7 @@ require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+ github.com/ghostiam/protogetter v0.2.3 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
github.com/go-critic/go-critic v0.9.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
@@ -222,11 +226,11 @@ require (
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect
- github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect
+ github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect
github.com/golangci/misspell v0.4.1 // indirect
- github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect
+ github.com/golangci/revgrep v0.5.0 // indirect
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
github.com/google/certificate-transparency-go v1.1.6 // indirect
github.com/google/gnostic v0.6.9 // indirect
@@ -269,7 +273,7 @@ require (
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
github.com/jellydator/ttlcache/v3 v3.1.0 // indirect
- github.com/jgautheron/goconst v1.5.1 // indirect
+ github.com/jgautheron/goconst v1.6.0 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -298,6 +302,7 @@ require (
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
github.com/lufeee/execinquery v1.2.1 // indirect
+ github.com/macabu/inamedparam v0.1.2 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
@@ -308,7 +313,7 @@ require (
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
- github.com/mgechev/revive v1.3.2 // indirect
+ github.com/mgechev/revive v1.3.4 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -322,7 +327,7 @@ require (
github.com/nishanths/exhaustive v0.11.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
- github.com/nunnatsa/ginkgolinter v0.13.5 // indirect
+ github.com/nunnatsa/ginkgolinter v0.14.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oleiade/reflections v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
@@ -336,7 +341,7 @@ require (
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/polyfloyd/go-errorlint v1.4.4 // indirect
+ github.com/polyfloyd/go-errorlint v1.4.5 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
github.com/prometheus/common v0.44.0 // indirect
@@ -350,7 +355,7 @@ require (
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/ryancurrah/gomodguard v1.3.0 // indirect
- github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect
+ github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@@ -358,7 +363,7 @@ require (
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.24.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
- github.com/securego/gosec/v2 v2.17.0 // indirect
+ github.com/securego/gosec/v2 v2.18.1 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
@@ -387,7 +392,7 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect
github.com/tdakkota/asciicheck v0.2.0 // indirect
- github.com/tetafro/godot v1.4.14 // indirect
+ github.com/tetafro/godot v1.4.15 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/theupdateframework/go-tuf v0.6.1 // indirect
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect
@@ -400,20 +405,21 @@ require (
github.com/transparency-dev/merkle v0.0.2 // indirect
github.com/ultraware/funlen v0.1.0 // indirect
github.com/ultraware/whitespace v0.0.5 // indirect
- github.com/uudashr/gocognit v1.0.7 // indirect
+ github.com/uudashr/gocognit v1.1.2 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/xanzy/go-gitlab v0.90.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
- github.com/xen0n/gosmopolitan v1.2.1 // indirect
+ github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.2.0 // indirect
github.com/ykadowak/zerologlint v0.1.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
github.com/zeebo/errs v1.3.0 // indirect
- gitlab.com/bosi/decorder v0.4.0 // indirect
+ gitlab.com/bosi/decorder v0.4.1 // indirect
+ go-simpler.org/sloglint v0.1.2 // indirect
go.mongodb.org/mongo-driver v1.12.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.16.0 // indirect
@@ -436,7 +442,7 @@ require (
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.13.0 // indirect
+ golang.org/x/tools v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/api v0.147.0 // indirect
@@ -453,7 +459,7 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- honnef.co/go/tools v0.4.5 // indirect
+ honnef.co/go/tools v0.4.6 // indirect
inet.af/netaddr v0.0.0-20220811202034-502d2d690317 // indirect
k8s.io/apiextensions-apiserver v0.26.5 // indirect
k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 // indirect
diff --git a/go.sum b/go.sum
index 01ee390621..299155304e 100644
--- a/go.sum
+++ b/go.sum
@@ -89,10 +89,10 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-github.com/4meepo/tagalign v1.3.2 h1:1idD3yxlRGV18VjqtDbqYvQ5pXqQS0wO2dn6M3XstvI=
-github.com/4meepo/tagalign v1.3.2/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE=
-github.com/Abirdcfly/dupword v0.0.12 h1:56NnOyrXzChj07BDFjeRA+IUzSz01jmzEq+G4kEgFhc=
-github.com/Abirdcfly/dupword v0.0.12/go.mod h1:+us/TGct/nI9Ndcbcp3rgNcQzctTj68pq7TcgNpLfdI=
+github.com/4meepo/tagalign v1.3.3 h1:ZsOxcwGD/jP4U/aw7qeWu58i7dwYemfy5Y+IF1ACoNw=
+github.com/4meepo/tagalign v1.3.3/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE=
+github.com/Abirdcfly/dupword v0.0.13 h1:SMS17YXypwP000fA7Lr+kfyBQyW14tTT+nRv9ASwUUo=
+github.com/Abirdcfly/dupword v0.0.13/go.mod h1:Ut6Ue2KgF/kCOawpW4LnExT+xZLQviJPE4klBPMK/5Y=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230618160516-e936619f9f18 h1:rd389Q26LMy03gG4anandGFC2LW/xvjga5GezeeaxQk=
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw=
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs=
@@ -100,6 +100,8 @@ github.com/Antonboom/errname v0.1.12 h1:oh9ak2zUtsLp5oaEd/erjB4GPu9w19NyoIskZClD
github.com/Antonboom/errname v0.1.12/go.mod h1:bK7todrzvlaZoQagP1orKzWXv59X/x0W0Io2XT1Ssro=
github.com/Antonboom/nilnil v0.1.7 h1:ofgL+BA7vlA1K2wNQOsHzLJ2Pw5B5DpWRLdDAVvvTow=
github.com/Antonboom/nilnil v0.1.7/go.mod h1:TP+ScQWVEq0eSIxqU8CbdT5DFWoHp0MbP+KMUO1BKYQ=
+github.com/Antonboom/testifylint v0.2.3 h1:MFq9zyL+rIVpsvLX4vDPLojgN7qODzWsrnftNX2Qh60=
+github.com/Antonboom/testifylint v0.2.3/go.mod h1:IYaXaOX9NbfAyO+Y04nfjGI8wDemC1rUyM/cYolz018=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA=
@@ -187,6 +189,10 @@ github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
+github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
+github.com/alecthomas/go-check-sumtype v0.1.3 h1:M+tqMxB68hcgccRXBMVCPI4UJ+QUfdSx0xdbypKCqA8=
+github.com/alecthomas/go-check-sumtype v0.1.3/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
+github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -319,20 +325,22 @@ github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWT
github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU=
github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo=
-github.com/breml/bidichk v0.2.4 h1:i3yedFWWQ7YzjdZJHnPo9d/xURinSq3OM+gyM43K4/8=
-github.com/breml/bidichk v0.2.4/go.mod h1:7Zk0kRFt1LIZxtQdl9W9JwGAcLTTkOs+tN7wuEYGJ3s=
-github.com/breml/errchkjson v0.3.1 h1:hlIeXuspTyt8Y/UmP5qy1JocGNR00KQHgfaNtRAjoxQ=
-github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U=
+github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY=
+github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ=
+github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA=
+github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/buildkite/agent/v3 v3.52.1 h1:s2pxVsYVt/OSMDlOM+ei5ZuE3+X6WptSwSR+OnQ7Gz8=
github.com/buildkite/agent/v3 v3.52.1/go.mod h1:MSIR+qpVb1Z663HlSqKEoIc4kkhmUFf4XazdCkxyE8E=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 h1:k6UDF1uPYOs0iy1HPeotNa155qXRWrzKnqAaGXHLZCE=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gbPR1gPu9dB96mucYIR7T3B7p/78hRVSOuzIWLHK2Y4=
-github.com/butuzov/ireturn v0.2.0 h1:kCHi+YzC150GE98WFuZQu9yrTn6GEydO2AuPLbTgnO4=
-github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
+github.com/butuzov/ireturn v0.2.1 h1:w5Ks4tnfeFDZskGJ2x1GAkx5gaQV+kdU3NKNr3NEBzY=
+github.com/butuzov/ireturn v0.2.1/go.mod h1:RfGHUvvAuFFxoHKf4Z8Yxuh6OjlCw1KvR2zM1NFHeBk=
github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI=
github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/catenacyber/perfsprint v0.2.0 h1:azOocHLscPjqXVJ7Mf14Zjlkn4uNua0+Hcg1wTR6vUo=
+github.com/catenacyber/perfsprint v0.2.0/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4=
github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
@@ -347,8 +355,8 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
-github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 h1:W9o46d2kbNL06lq7UNDPV0zYLzkrde/bjIqO02eoll0=
-github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo=
+github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
+github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4=
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -387,8 +395,8 @@ github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDU
github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
-github.com/daixiang0/gci v0.11.0 h1:XeQbFKkCRxvVyn06EOuNY6LPGBLVuB/W130c8FrnX6A=
-github.com/daixiang0/gci v0.11.0/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI=
+github.com/daixiang0/gci v0.11.2 h1:Oji+oPsp3bQ6bNNgX30NBAVT18P4uBH4sRZnlOlTj7Y=
+github.com/daixiang0/gci v0.11.2/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -485,6 +493,8 @@ github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlya
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghostiam/protogetter v0.2.3 h1:qdv2pzo3BpLqezwqfGDLZ+nHEYmc5bUpIdsMbBVwMjw=
+github.com/ghostiam/protogetter v0.2.3/go.mod h1:KmNLOsy1v04hKbvZs8EfGI1fk39AgTdRDxWNYPfXVc4=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
@@ -669,18 +679,18 @@ github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo=
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ=
-github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY=
-github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs=
-github.com/golangci/golangci-lint v1.54.2 h1:oR9zxfWYxt7hFqk6+fw6Enr+E7F0SN2nqHhJYyIb0yo=
-github.com/golangci/golangci-lint v1.54.2/go.mod h1:vnsaCTPKCI2wreL9tv7RkHDwUrz3htLjed6+6UsvcwU=
+github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g=
+github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM=
+github.com/golangci/golangci-lint v1.55.0 h1:ePpc6YhM1ZV8kHU8dwmHDHAdeedZHdK8cmTXlkkRdi8=
+github.com/golangci/golangci-lint v1.55.0/go.mod h1:Z/OawFQ4yqFo2/plDYlIjoZlJeVYkRcqS9dW55p0FXg=
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.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g=
github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI=
-github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ=
-github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs=
+github.com/golangci/revgrep v0.5.0 h1:GGBqHFtFOeHiSUQtFVZXPJtVZYOGB4iVlAjaoFRBQvY=
+github.com/golangci/revgrep v0.5.0/go.mod h1:bjAMA+Sh/QUfTDcHzxfyHxr4xKvllVr/0sCv2e7jJHA=
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/addlicense v1.1.1 h1:jpVf9qPbU8rz5MxKo7d+RMcNHkqxi4YJi/laauX4aAE=
@@ -881,8 +891,8 @@ github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJ
github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/jenkins-x/go-scm v1.14.14 h1:a4c3z4+FVPMWMl59hgdLZNbnbc0Z0/Ln6fHXS0hLAyY=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-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/jgautheron/goconst v1.6.0 h1:gbMLWKRMkzAc6kYsQL6/TxaoBUg3Jm9LSF/Ih1ADWGA=
+github.com/jgautheron/goconst v1.6.0/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
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=
@@ -972,6 +982,8 @@ github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA=
github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM=
github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM=
+github.com/macabu/inamedparam v0.1.2 h1:RR5cnayM6Q7cDhQol32DE2BGAPGMnffJ31LFE+UklaU=
+github.com/macabu/inamedparam v0.1.2/go.mod h1:Xg25QvY7IBRl1KLPV9Rbml8JOMZtF/iAkNkmV7eQgjw=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -1004,8 +1016,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk
github.com/matttproud/golang_protobuf_extensions v1.0.4/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/revive v1.3.2 h1:Wb8NQKBaALBJ3xrrj4zpwJwqwNA6nDpyJSEQWcCka6U=
-github.com/mgechev/revive v1.3.2/go.mod h1:UCLtc7o5vg5aXCwdUTU1kEBQ1v+YXPAkYDIDXbrs5I0=
+github.com/mgechev/revive v1.3.4 h1:k/tO3XTaWY4DEHal9tWBkkUMJYO/dLDVyMmAQxmIMDc=
+github.com/mgechev/revive v1.3.4/go.mod h1:W+pZCMu9qj8Uhfs1iJMQsEFLRozUfvwFwqVvRbSNLVw=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@@ -1047,8 +1059,8 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=
-github.com/nunnatsa/ginkgolinter v0.13.5 h1:fOsPB4CEZOPkyMqF4B9hoqOpooFWU7vWSVkCSscVpgU=
-github.com/nunnatsa/ginkgolinter v0.13.5/go.mod h1:OBHy4536xtuX3102NM63XRtOyxqZOO02chsaeDWXVO8=
+github.com/nunnatsa/ginkgolinter v0.14.0 h1:XQPNmw+kZz5cC/HbFK3mQutpjzAQv1dHregRA+4CGGg=
+github.com/nunnatsa/ginkgolinter v0.14.0/go.mod h1:cm2xaqCUCRd7qcP4DqbVvpcyEMkuLM9CF0wY6VASohk=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -1066,14 +1078,14 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
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.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
@@ -1083,8 +1095,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
github.com/openzipkin/zipkin-go v0.3.0 h1:XtuXmOLIXLjiU2XduuWREDT0LOKtSgos/g7i7RYyoZQ=
github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
-github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
+github.com/otiai10/copy v1.11.0 h1:OKBD80J/mLBrwnzXqGtFCzprFSGioo30JcmR4APsNwc=
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=
@@ -1114,8 +1126,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/polyfloyd/go-errorlint v1.4.4 h1:A9gytp+p6TYqeALTYRoxJESYP8wJRETRX2xzGWFsEBU=
-github.com/polyfloyd/go-errorlint v1.4.4/go.mod h1:ry5NqF7l9Q77V+XqAfUg1zfryrEtyac3G5+WVpIK0xU=
+github.com/polyfloyd/go-errorlint v1.4.5 h1:70YWmMy4FgRHehGNOUask3HtSFSOLKgmDn7ryNe7LqI=
+github.com/polyfloyd/go-errorlint v1.4.5/go.mod h1:sIZEbFoDOCnTYYZoVkjc4hTnM459tuWA9H/EkdXwsKk=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1172,8 +1184,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw=
github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50=
-github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI=
-github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ=
+github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
+github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
@@ -1193,8 +1205,8 @@ github.com/sassoftware/relic/v7 v7.6.1 h1:O5s8ewCgq5QYNpv45dK4u6IpBmDM9RIcsbf/G1
github.com/secure-systems-lab/go-securesystemslib v0.3.1/go.mod h1:o8hhjkbNl2gOamKUA/eNW3xUrntHT9L4W89W1nfj43U=
github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg=
github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI=
-github.com/securego/gosec/v2 v2.17.0 h1:ZpAStTDKY39insEG9OH6kV3IkhQZPTq9a9eGOLOjcdI=
-github.com/securego/gosec/v2 v2.17.0/go.mod h1:lt+mgC91VSmriVoJLentrMkRCYs+HLTBnUFUBuhV2hc=
+github.com/securego/gosec/v2 v2.18.1 h1:xnnehWg7dIW8qrRPGm8ykY21zp2MueKyC99Vlcuj96I=
+github.com/securego/gosec/v2 v2.18.1/go.mod h1:ZUTcKD9gAFip1lLGHWCjkoBQJyaEzePTNzjwlL2HHoE=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
@@ -1320,8 +1332,8 @@ 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.14 h1:ScO641OHpf9UpHPk8fCknSuXNMpi4iFlwuWoBs3L+1s=
-github.com/tetafro/godot v1.4.14/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
+github.com/tetafro/godot v1.4.15 h1:QzdIs+XB8q+U1WmQEWKHQbKmCw06QuQM7gLx/dky2RM=
+github.com/tetafro/godot v1.4.15/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/theupdateframework/go-tuf v0.6.1 h1:6J89fGjQf7s0mLmTG7p7pO/MbKOg+bIXhaLyQdmbKuE=
@@ -1349,8 +1361,8 @@ github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqz
github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
-github.com/uudashr/gocognit v1.0.7 h1:e9aFXgKgUJrQ5+bs61zBigmj7bFJ/5cC6HmMahVzuDo=
-github.com/uudashr/gocognit v1.0.7/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY=
+github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI=
+github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
@@ -1375,8 +1387,8 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xen0n/gosmopolitan v1.2.1 h1:3pttnTuFumELBRSh+KQs1zcz4fN6Zy7aB0xlnQSn1Iw=
-github.com/xen0n/gosmopolitan v1.2.1/go.mod h1:JsHq/Brs1o050OOdmzHeOr0N7OtlnKRAGAsElF8xBQA=
+github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
+github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o=
@@ -1402,9 +1414,11 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4=
github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs=
github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
-gitlab.com/bosi/decorder v0.4.0 h1:HWuxAhSxIvsITcXeP+iIRg9d1cVfvVkmlF7M68GaoDY=
-gitlab.com/bosi/decorder v0.4.0/go.mod h1:xarnteyUoJiOTEldDysquWKTVDCKo2TOIOIibSuWqOg=
+gitlab.com/bosi/decorder v0.4.1 h1:VdsdfxhstabyhZovHafFw+9eJ6eU0d2CkFNJcZz/NU4=
+gitlab.com/bosi/decorder v0.4.1/go.mod h1:jecSqWUew6Yle1pCr2eLWTensJMmsxHsBwt+PVbkAqA=
go-simpler.org/assert v0.6.0 h1:QxSrXa4oRuo/1eHMXSBFHKvJIpWABayzKldqZyugG7E=
+go-simpler.org/sloglint v0.1.2 h1:IjdhF8NPxyn0Ckn2+fuIof7ntSnVUAqBFcQRrnG9AiM=
+go-simpler.org/sloglint v0.1.2/go.mod h1:2LL+QImPfTslD5muNPydAEYmpXIj6o/WYcqnJjLi4o4=
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
@@ -1867,8 +1881,8 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
-golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2058,8 +2072,8 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
-google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
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=
@@ -2130,8 +2144,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo=
-honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k=
+honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8=
+honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
inet.af/netaddr v0.0.0-20220811202034-502d2d690317 h1:U2fwK6P2EqmopP/hFLTOAjWTki0qgd4GMJn5X8wOleU=
inet.af/netaddr v0.0.0-20220811202034-502d2d690317/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k=
k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y=
diff --git a/vendor/github.com/4meepo/tagalign/README.md b/vendor/github.com/4meepo/tagalign/README.md
index 262a2e429f..9d04dccbf2 100644
--- a/vendor/github.com/4meepo/tagalign/README.md
+++ b/vendor/github.com/4meepo/tagalign/README.md
@@ -48,7 +48,7 @@ By default tagalign will only align tags, but not sort them. But alignment and [
* As a Golangci Linter (Recommended)
Tagalign is a built-in linter in [Golangci Lint](https://golangci-lint.run/usage/linters/#tagalign) since `v1.53`.
- > Note: In order to have the best experience, add the `--fix` flag to `golangci-lint` to enabled the aufofix feature.
+ > Note: In order to have the best experience, add the `--fix` flag to `golangci-lint` to enable the autofix feature.
* Standalone Mode
@@ -117,7 +117,7 @@ type StrictStyleExample struct {
}
```
-> Note: The strict style can't run without the align or sort feature enabled.
+> ⚠️Note: The strict style can't run without the align or sort feature enabled.
## References
diff --git a/vendor/github.com/4meepo/tagalign/tagalign.go b/vendor/github.com/4meepo/tagalign/tagalign.go
index c998510360..4734b56661 100644
--- a/vendor/github.com/4meepo/tagalign/tagalign.go
+++ b/vendor/github.com/4meepo/tagalign/tagalign.go
@@ -29,6 +29,10 @@ const (
StrictStyle
)
+const (
+ errTagValueSyntax = "bad syntax for struct tag value"
+)
+
func NewAnalyzer(options ...Option) *analysis.Analyzer {
return &analysis.Analyzer{
Name: "tagalign",
@@ -208,16 +212,25 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
uniqueKeys = append(uniqueKeys, k)
}
- for i, field := range fields {
- offsets[i] = pass.Fset.Position(field.Tag.Pos()).Column
+ for i := 0; i < len(fields); {
+ field := fields[i]
+ column := pass.Fset.Position(field.Tag.Pos()).Column - 1
+ offsets[i] = column
+
tag, err := strconv.Unquote(field.Tag.Value)
if err != nil {
- break
+ // if tag value is not a valid string, report it directly
+ w.report(pass, field, column, errTagValueSyntax, field.Tag.Value)
+ fields = removeField(fields, i)
+ continue
}
tags, err := structtag.Parse(tag)
if err != nil {
- break
+ // if tag value is not a valid struct tag, report it directly
+ w.report(pass, field, column, err.Error(), field.Tag.Value)
+ fields = removeField(fields, i)
+ continue
}
maxTagNum = max(maxTagNum, tags.Len())
@@ -234,6 +247,8 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
addKey(t.Key)
}
tagsGroup = append(tagsGroup, tags.Tags())
+
+ i++
}
if w.sort && StrictStyle == w.style {
@@ -325,19 +340,22 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
msg := "tag is not aligned, should be: " + unquoteTag
- w.report(pass, field, offsets[i]-1, msg, newTagValue)
+ w.report(pass, field, offsets[i], msg, newTagValue)
}
}
// process single fields
for _, field := range w.singleFields {
+ column := pass.Fset.Position(field.Tag.Pos()).Column - 1
tag, err := strconv.Unquote(field.Tag.Value)
if err != nil {
+ w.report(pass, field, column, errTagValueSyntax, field.Tag.Value)
continue
}
tags, err := structtag.Parse(tag)
if err != nil {
+ w.report(pass, field, column, err.Error(), field.Tag.Value)
continue
}
originalTags := append([]*structtag.Tag(nil), tags.Tags()...)
@@ -353,7 +371,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit
msg := "tag is not aligned , should be: " + tags.String()
- w.report(pass, field, pass.Fset.Position(field.Tag.Pos()).Column-1, msg, newTagValue)
+ w.report(pass, field, column, msg, newTagValue)
}
}
@@ -431,3 +449,11 @@ func max(a, b int) int {
}
return b
}
+
+func removeField(fields []*ast.Field, index int) []*ast.Field {
+ if index < 0 || index >= len(fields) {
+ return fields
+ }
+
+ return append(fields[:index], fields[index+1:]...)
+}
diff --git a/vendor/github.com/Abirdcfly/dupword/README.md b/vendor/github.com/Abirdcfly/dupword/README.md
index 6917acae25..e6c5b919fa 100644
--- a/vendor/github.com/Abirdcfly/dupword/README.md
+++ b/vendor/github.com/Abirdcfly/dupword/README.md
@@ -109,10 +109,12 @@ Flags:
apply all suggested fixes
-flags
print analyzer flags in JSON
+ -ignore value
+ ignore words
-json
emit JSON output
-keyword value
- key words for detecting duplicate words
+ keywords for detecting duplicate words
-memprofile string
write memory profile to this file
-source
@@ -128,7 +130,7 @@ Flags:
### 5. my advice
-use `--keyword=the,and,a` and `-fix` together. I personally think that specifying only common repeated prepositions can effectively avoid false positives.
+use `--keyword=the,and,a` and `-fix` together. I think that specifying only commonly repeated prepositions can effectively avoid false positives.
see [dupword#4](https://github.com/Abirdcfly/dupword/issues/4) for real code example.
diff --git a/vendor/github.com/Abirdcfly/dupword/dupword.go b/vendor/github.com/Abirdcfly/dupword/dupword.go
index 508caca52f..c291eab527 100644
--- a/vendor/github.com/Abirdcfly/dupword/dupword.go
+++ b/vendor/github.com/Abirdcfly/dupword/dupword.go
@@ -52,6 +52,7 @@ This analyzer checks miswritten duplicate words in comments or package doc or st
var (
defaultWord = []string{}
// defaultWord = []string{"the", "and", "a"}
+ ignoreWord = map[string]bool{}
)
type analyzer struct {
@@ -70,7 +71,31 @@ func (a *analyzer) Set(w string) error {
return nil
}
+type ignore struct {
+}
+
+func (a *ignore) String() string {
+ t := make([]string,0, len(ignoreWord))
+ for k := range ignoreWord {
+ t = append(t, k)
+ }
+ return strings.Join(t, ",")
+}
+
+func (a *ignore) Set(w string) error {
+ for _, k := range strings.Split(w, ","){
+ ignoreWord[k] = true
+ }
+ return nil
+}
+
+// for test only
+func ClearIgnoreWord() {
+ ignoreWord = map[string]bool{}
+}
+
func NewAnalyzer() *analysis.Analyzer {
+ ignore := &ignore{}
analyzer := &analyzer{KeyWord: defaultWord}
a := &analysis.Analyzer{
Name: Name,
@@ -80,7 +105,8 @@ func NewAnalyzer() *analysis.Analyzer {
RunDespiteErrors: true,
}
a.Flags.Init(Name, flag.ExitOnError)
- a.Flags.Var(analyzer, "keyword", "key words for detecting duplicate words")
+ a.Flags.Var(analyzer, "keyword", "keywords for detecting duplicate words")
+ a.Flags.Var(ignore, "ignore", "ignore words")
a.Flags.Var(version{}, "V", "print version and exit")
return a
}
@@ -176,7 +202,7 @@ func (a *analyzer) fixDuplicateWordInString(pass *analysis.Pass, lit *ast.BasicL
}
}
-// CheckOneKey use to check there is defined duplicate word in a string.
+// CheckOneKey use to check there is a defined duplicate word in a string.
// raw is checked line. key is the keyword to check. empty means just check duplicate word.
func CheckOneKey(raw, key string) (new string, findWord string, find bool) {
if key == "" {
@@ -298,5 +324,8 @@ func ExcludeWords(word string) (exclude bool) {
if unicode.IsSymbol(firstRune) {
return true
}
+ if _, exist := ignoreWord[word]; exist {
+ return true
+ }
return false
}
diff --git a/vendor/github.com/Antonboom/testifylint/LICENSE b/vendor/github.com/Antonboom/testifylint/LICENSE
new file mode 100644
index 0000000000..9b1cf3a393
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 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.
diff --git a/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go b/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go
new file mode 100644
index 0000000000..c0b98f83c4
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/analyzer/analyzer.go
@@ -0,0 +1,175 @@
+package analyzer
+
+import (
+ "fmt"
+ "go/ast"
+ "go/types"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/ast/inspector"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+ "github.com/Antonboom/testifylint/internal/checkers"
+ "github.com/Antonboom/testifylint/internal/config"
+ "github.com/Antonboom/testifylint/internal/testify"
+)
+
+const (
+ name = "testifylint"
+ doc = "Checks usage of " + testify.ModulePath + "."
+ url = "https://github.com/antonboom/" + name
+)
+
+// New returns new instance of testifylint analyzer.
+func New() *analysis.Analyzer {
+ cfg := config.NewDefault()
+
+ analyzer := &analysis.Analyzer{
+ Name: name,
+ Doc: doc,
+ URL: url,
+ Run: func(pass *analysis.Pass) (any, error) {
+ regularCheckers, advancedCheckers, err := newCheckers(cfg)
+ if err != nil {
+ return nil, fmt.Errorf("build checkers: %v", err)
+ }
+
+ tl := &testifyLint{
+ regularCheckers: regularCheckers,
+ advancedCheckers: advancedCheckers,
+ }
+ return tl.run(pass)
+ },
+ }
+ config.BindToFlags(&cfg, &analyzer.Flags)
+
+ return analyzer
+}
+
+type testifyLint struct {
+ regularCheckers []checkers.RegularChecker
+ advancedCheckers []checkers.AdvancedChecker
+}
+
+func (tl *testifyLint) run(pass *analysis.Pass) (any, error) {
+ filesToAnalysis := make([]*ast.File, 0, len(pass.Files))
+ for _, f := range pass.Files {
+ if !analysisutil.Imports(f, testify.AssertPkgPath, testify.RequirePkgPath, testify.SuitePkgPath) {
+ continue
+ }
+ filesToAnalysis = append(filesToAnalysis, f)
+ }
+
+ insp := inspector.New(filesToAnalysis)
+
+ // Regular checkers.
+ insp.Preorder([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node) {
+ tl.regularCheck(pass, node.(*ast.CallExpr))
+ })
+
+ // Advanced checkers.
+ for _, ch := range tl.advancedCheckers {
+ for _, d := range ch.Check(pass, insp) {
+ pass.Report(d)
+ }
+ }
+
+ return nil, nil
+}
+
+func (tl *testifyLint) regularCheck(pass *analysis.Pass, ce *ast.CallExpr) {
+ se, ok := ce.Fun.(*ast.SelectorExpr)
+ if !ok || se.Sel == nil {
+ return
+ }
+ fnName := se.Sel.Name
+
+ initiatorPkg, isPkgCall := func() (*types.Package, bool) {
+ // Examples:
+ // s.Assert -> method of *suite.Suite -> package suite ("vendor/github.com/stretchr/testify/suite")
+ // s.Assert().Equal -> method of *assert.Assertions -> package assert ("vendor/github.com/stretchr/testify/assert")
+ // s.Equal -> method of *assert.Assertions -> package assert ("vendor/github.com/stretchr/testify/assert")
+ // reqObj.Falsef -> method of *require.Assertions -> package require ("vendor/github.com/stretchr/testify/require")
+ if sel, ok := pass.TypesInfo.Selections[se]; ok {
+ return sel.Obj().Pkg(), false
+ }
+
+ // Examples:
+ // assert.False -> assert -> package assert ("vendor/github.com/stretchr/testify/assert")
+ // require.NotEqualf -> require -> package require ("vendor/github.com/stretchr/testify/require")
+ if id, ok := se.X.(*ast.Ident); ok {
+ if selObj := pass.TypesInfo.ObjectOf(id); selObj != nil {
+ if pkg, ok := selObj.(*types.PkgName); ok {
+ return pkg.Imported(), true
+ }
+ }
+ }
+ return nil, false
+ }()
+ if initiatorPkg == nil {
+ return
+ }
+
+ isAssert := analysisutil.IsPkg(initiatorPkg, testify.AssertPkgName, testify.AssertPkgPath)
+ isRequire := analysisutil.IsPkg(initiatorPkg, testify.RequirePkgName, testify.RequirePkgPath)
+ if !(isAssert || isRequire) {
+ return
+ }
+
+ call := &checkers.CallMeta{
+ Range: ce,
+ IsPkg: isPkgCall,
+ IsAssert: isAssert,
+ Selector: se,
+ SelectorXStr: analysisutil.NodeString(pass.Fset, se.X),
+ Fn: checkers.FnMeta{
+ Range: se.Sel,
+ Name: fnName,
+ IsFmt: strings.HasSuffix(fnName, "f"),
+ },
+ Args: trimTArg(pass, isAssert, ce.Args),
+ ArgsRaw: ce.Args,
+ }
+ for _, ch := range tl.regularCheckers {
+ if d := ch.Check(pass, call); d != nil {
+ pass.Report(*d)
+ // NOTE(a.telyshev): I'm not interested in multiple diagnostics per assertion.
+ // This simplifies the code and also makes the linter more efficient.
+ return
+ }
+ }
+}
+
+func trimTArg(pass *analysis.Pass, isAssert bool, args []ast.Expr) []ast.Expr {
+ if len(args) == 0 {
+ return args
+ }
+
+ if isTestingTPtr(pass, isAssert, args[0]) {
+ return args[1:]
+ }
+ return args
+}
+
+func isTestingTPtr(pass *analysis.Pass, isAssert bool, arg ast.Expr) bool {
+ pkgPath := testify.RequirePkgPath
+ if isAssert {
+ pkgPath = testify.AssertPkgPath
+ }
+
+ testingInterfaceObj := analysisutil.ObjectOf(pass.Pkg, pkgPath, "TestingT")
+ if testingInterfaceObj == nil {
+ return false
+ }
+
+ argType := pass.TypesInfo.TypeOf(arg)
+ if argType == nil {
+ return false
+ }
+
+ return types.Implements(
+ argType,
+ testingInterfaceObj.Type().Underlying().(*types.Interface),
+ )
+}
diff --git a/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go b/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go
new file mode 100644
index 0000000000..e87e35e50d
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/analyzer/checkers_factory.go
@@ -0,0 +1,48 @@
+package analyzer
+
+import (
+ "fmt"
+
+ "github.com/Antonboom/testifylint/internal/checkers"
+ "github.com/Antonboom/testifylint/internal/config"
+)
+
+// newCheckers accepts linter config and returns slices of enabled checkers sorted by priority.
+func newCheckers(cfg config.Config) ([]checkers.RegularChecker, []checkers.AdvancedChecker, error) {
+ enabledCheckers := cfg.EnabledCheckers
+ if len(enabledCheckers) == 0 {
+ enabledCheckers = checkers.EnabledByDefault()
+ }
+ if cfg.EnableAll {
+ enabledCheckers = checkers.All()
+ }
+
+ checkers.SortByPriority(enabledCheckers)
+
+ regularCheckers := make([]checkers.RegularChecker, 0, len(enabledCheckers))
+ advancedCheckers := make([]checkers.AdvancedChecker, 0, len(enabledCheckers)/2)
+
+ for _, name := range enabledCheckers {
+ ch, ok := checkers.Get(name)
+ if !ok {
+ return nil, nil, fmt.Errorf("unknown checker %q", name)
+ }
+
+ switch c := ch.(type) {
+ case *checkers.ExpectedActual:
+ c.SetExpVarPattern(cfg.ExpectedActual.ExpVarPattern.Regexp)
+
+ case *checkers.SuiteExtraAssertCall:
+ c.SetMode(cfg.SuiteExtraAssertCall.Mode)
+ }
+
+ switch casted := ch.(type) {
+ case checkers.RegularChecker:
+ regularCheckers = append(regularCheckers, casted)
+ case checkers.AdvancedChecker:
+ advancedCheckers = append(advancedCheckers, casted)
+ }
+ }
+
+ return regularCheckers, advancedCheckers, nil
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/analysisutil/doc.go b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/doc.go
new file mode 100644
index 0000000000..b57cbd9384
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/doc.go
@@ -0,0 +1,9 @@
+// Package analysisutil contains functions common for `analyzer` and `internal/checkers` packages.
+// In addition, it is intended to "lighten" these packages.
+//
+// If the function is common to several packages, or it makes sense to test it separately without
+// "polluting" the target package with tests of private functionality, then you can put function in this package.
+//
+// It's important to avoid dependency on `golang.org/x/tools/go/analysis` in the helpers API.
+// This makes the API "narrower" and also allows you to test functions without some "abstraction leaks".
+package analysisutil
diff --git a/vendor/github.com/Antonboom/testifylint/internal/analysisutil/file.go b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/file.go
new file mode 100644
index 0000000000..3fc1f42b86
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/file.go
@@ -0,0 +1,28 @@
+package analysisutil
+
+import (
+ "go/ast"
+ "strconv"
+)
+
+// Imports tells if the file imports at least one of the packages.
+// If no packages provided then function returns false.
+func Imports(file *ast.File, pkgs ...string) bool {
+ for _, i := range file.Imports {
+ if i.Path == nil {
+ continue
+ }
+
+ path, err := strconv.Unquote(i.Path.Value)
+ if err != nil {
+ continue
+ }
+ // NOTE(a.telyshev): Don't use `slices.Contains` to keep the minimum module version 1.20.
+ for _, pkg := range pkgs { // Small O(n).
+ if pkg == path {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/analysisutil/format.go b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/format.go
new file mode 100644
index 0000000000..fcb4b847f6
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/format.go
@@ -0,0 +1,34 @@
+package analysisutil
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/token"
+)
+
+// NodeString is a more powerful analogue of types.ExprString.
+// Return empty string if node AST is invalid.
+func NodeString(fset *token.FileSet, node ast.Node) string {
+ if v := formatNode(fset, node); v != nil {
+ return v.String()
+ }
+ return ""
+}
+
+// NodeBytes works as NodeString but returns a byte slice.
+// Return nil if node AST is invalid.
+func NodeBytes(fset *token.FileSet, node ast.Node) []byte {
+ if v := formatNode(fset, node); v != nil {
+ return v.Bytes()
+ }
+ return nil
+}
+
+func formatNode(fset *token.FileSet, node ast.Node) *bytes.Buffer {
+ buf := new(bytes.Buffer)
+ if err := format.Node(buf, fset, node); err != nil {
+ return nil
+ }
+ return buf
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/analysisutil/object.go b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/object.go
new file mode 100644
index 0000000000..e01fba5c13
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/object.go
@@ -0,0 +1,34 @@
+package analysisutil
+
+import (
+ "go/ast"
+ "go/types"
+)
+
+// ObjectOf works in context of Golang package and returns types.Object for the given object's package and name.
+// The search is based on the provided package and its dependencies (imports).
+// Returns nil if the object is not found.
+func ObjectOf(pkg *types.Package, objPkg, objName string) types.Object {
+ if pkg.Path() == objPkg {
+ return pkg.Scope().Lookup(objName)
+ }
+
+ for _, i := range pkg.Imports() {
+ if trimVendor(i.Path()) == objPkg {
+ return i.Scope().Lookup(objName)
+ }
+ }
+ return nil
+}
+
+// IsObj returns true if expression is identifier which notes to given types.Object.
+// Useful in combination with types.Universe objects.
+func IsObj(typesInfo *types.Info, expr ast.Expr, expected types.Object) bool {
+ id, ok := expr.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ obj := typesInfo.ObjectOf(id)
+ return obj.Id() == expected.Id()
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/analysisutil/pkg.go b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/pkg.go
new file mode 100644
index 0000000000..d34be5d341
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/analysisutil/pkg.go
@@ -0,0 +1,19 @@
+package analysisutil
+
+import (
+ "go/types"
+ "strings"
+)
+
+// IsPkg checks that package has corresponding objName and path.
+// Supports vendored packages.
+func IsPkg(pkg *types.Package, name, path string) bool {
+ return pkg.Name() == name && trimVendor(pkg.Path()) == path
+}
+
+func trimVendor(path string) string {
+ if strings.HasPrefix(path, "vendor/") {
+ return path[len("vendor/"):]
+ }
+ return path
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go
new file mode 100644
index 0000000000..8245ab58e6
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/bool_compare.go
@@ -0,0 +1,223 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// BoolCompare detects situations like
+//
+// assert.Equal(t, false, result)
+// assert.NotEqual(t, result, true)
+// assert.False(t, !result)
+// assert.True(t, result == true)
+// ...
+//
+// and requires
+//
+// assert.False(t, result)
+// assert.True(t, result)
+type BoolCompare struct{} //
+
+// NewBoolCompare constructs BoolCompare checker.
+func NewBoolCompare() BoolCompare { return BoolCompare{} }
+func (BoolCompare) Name() string { return "bool-compare" }
+
+func (checker BoolCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ newUseFnDiagnostic := func(proposed string, survivingArg ast.Node, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic {
+ return newUseFunctionDiagnostic(checker.Name(), call, proposed,
+ newSuggestedFuncReplacement(call, proposed, analysis.TextEdit{
+ Pos: replaceStart,
+ End: replaceEnd,
+ NewText: analysisutil.NodeBytes(pass.Fset, survivingArg),
+ }),
+ )
+ }
+
+ newUseTrueDiagnostic := func(survivingArg ast.Node, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic {
+ return newUseFnDiagnostic("True", survivingArg, replaceStart, replaceEnd)
+ }
+
+ newUseFalseDiagnostic := func(survivingArg ast.Node, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic {
+ return newUseFnDiagnostic("False", survivingArg, replaceStart, replaceEnd)
+ }
+
+ newNeedSimplifyDiagnostic := func(survivingArg ast.Node, replaceStart, replaceEnd token.Pos) *analysis.Diagnostic {
+ return newDiagnostic(checker.Name(), call, "need to simplify the assertion",
+ &analysis.SuggestedFix{
+ Message: "Simplify the assertion",
+ TextEdits: []analysis.TextEdit{{
+ Pos: replaceStart,
+ End: replaceEnd,
+ NewText: analysisutil.NodeBytes(pass.Fset, survivingArg),
+ }},
+ },
+ )
+ }
+
+ switch call.Fn.Name {
+ case "Equal", "Equalf":
+ if len(call.Args) < 2 {
+ return nil
+ }
+
+ arg1, arg2 := call.Args[0], call.Args[1]
+ t1, t2 := isUntypedTrue(pass, arg1), isUntypedTrue(pass, arg2)
+ f1, f2 := isUntypedFalse(pass, arg1), isUntypedFalse(pass, arg2)
+
+ switch {
+ case xor(t1, t2):
+ survivingArg, _ := anyVal([]bool{t1, t2}, arg2, arg1)
+ return newUseTrueDiagnostic(survivingArg, arg1.Pos(), arg2.End())
+
+ case xor(f1, f2):
+ survivingArg, _ := anyVal([]bool{f1, f2}, arg2, arg1)
+ return newUseFalseDiagnostic(survivingArg, arg1.Pos(), arg2.End())
+ }
+
+ case "NotEqual", "NotEqualf":
+ if len(call.Args) < 2 {
+ return nil
+ }
+
+ arg1, arg2 := call.Args[0], call.Args[1]
+ t1, t2 := isUntypedTrue(pass, arg1), isUntypedTrue(pass, arg2)
+ f1, f2 := isUntypedFalse(pass, arg1), isUntypedFalse(pass, arg2)
+
+ switch {
+ case xor(t1, t2):
+ survivingArg, _ := anyVal([]bool{t1, t2}, arg2, arg1)
+ return newUseFalseDiagnostic(survivingArg, arg1.Pos(), arg2.End())
+
+ case xor(f1, f2):
+ survivingArg, _ := anyVal([]bool{f1, f2}, arg2, arg1)
+ return newUseTrueDiagnostic(survivingArg, arg1.Pos(), arg2.End())
+ }
+
+ case "True", "Truef":
+ if len(call.Args) < 1 {
+ return nil
+ }
+ expr := call.Args[0]
+
+ {
+ arg1, ok1 := isComparisonWithTrue(pass, expr, token.EQL)
+ arg2, ok2 := isComparisonWithFalse(pass, expr, token.NEQ)
+
+ if survivingArg, ok := anyVal([]bool{ok1, ok2}, arg1, arg2); ok {
+ return newNeedSimplifyDiagnostic(survivingArg, expr.Pos(), expr.End())
+ }
+ }
+
+ {
+ arg1, ok1 := isComparisonWithTrue(pass, expr, token.NEQ)
+ arg2, ok2 := isComparisonWithFalse(pass, expr, token.EQL)
+ arg3, ok3 := isNegation(expr)
+
+ if survivingArg, ok := anyVal([]bool{ok1, ok2, ok3}, arg1, arg2, arg3); ok {
+ return newUseFalseDiagnostic(survivingArg, expr.Pos(), expr.End())
+ }
+ }
+
+ case "False", "Falsef":
+ if len(call.Args) < 1 {
+ return nil
+ }
+ expr := call.Args[0]
+
+ {
+ arg1, ok1 := isComparisonWithTrue(pass, expr, token.EQL)
+ arg2, ok2 := isComparisonWithFalse(pass, expr, token.NEQ)
+
+ if survivingArg, ok := anyVal([]bool{ok1, ok2}, arg1, arg2); ok {
+ return newNeedSimplifyDiagnostic(survivingArg, expr.Pos(), expr.End())
+ }
+ }
+
+ {
+ arg1, ok1 := isComparisonWithTrue(pass, expr, token.NEQ)
+ arg2, ok2 := isComparisonWithFalse(pass, expr, token.EQL)
+ arg3, ok3 := isNegation(expr)
+
+ if survivingArg, ok := anyVal([]bool{ok1, ok2, ok3}, arg1, arg2, arg3); ok {
+ return newUseTrueDiagnostic(survivingArg, expr.Pos(), expr.End())
+ }
+ }
+ }
+ return nil
+}
+
+var (
+ falseObj = types.Universe.Lookup("false")
+ trueObj = types.Universe.Lookup("true")
+)
+
+func isUntypedTrue(pass *analysis.Pass, e ast.Expr) bool {
+ return analysisutil.IsObj(pass.TypesInfo, e, trueObj)
+}
+
+func isUntypedFalse(pass *analysis.Pass, e ast.Expr) bool {
+ return analysisutil.IsObj(pass.TypesInfo, e, falseObj)
+}
+
+func isComparisonWithTrue(pass *analysis.Pass, e ast.Expr, op token.Token) (ast.Expr, bool) {
+ return isComparisonWith(pass, e, isUntypedTrue, op)
+}
+
+func isComparisonWithFalse(pass *analysis.Pass, e ast.Expr, op token.Token) (ast.Expr, bool) {
+ return isComparisonWith(pass, e, isUntypedFalse, op)
+}
+
+type predicate func(pass *analysis.Pass, e ast.Expr) bool
+
+func isComparisonWith(pass *analysis.Pass, e ast.Expr, predicate predicate, op token.Token) (ast.Expr, bool) {
+ be, ok := e.(*ast.BinaryExpr)
+ if !ok {
+ return nil, false
+ }
+ if be.Op != op {
+ return nil, false
+ }
+
+ t1, t2 := predicate(pass, be.X), predicate(pass, be.Y)
+ if xor(t1, t2) {
+ if t1 {
+ return be.Y, true
+ }
+ return be.X, true
+ }
+ return nil, false
+}
+
+func isNegation(e ast.Expr) (ast.Expr, bool) {
+ ue, ok := e.(*ast.UnaryExpr)
+ if !ok {
+ return nil, false
+ }
+ return ue.X, ue.Op == token.NOT
+}
+
+func xor(a, b bool) bool {
+ return a != b
+}
+
+// anyVal returns the first value[i] for which bools[i] is true.
+func anyVal[T any](bools []bool, vals ...T) (T, bool) {
+ if len(bools) != len(vals) {
+ panic("inconsistent usage of valOr") //nolint:forbidigo // Does not depend on the code being analyzed.
+ }
+
+ for i, b := range bools {
+ if b {
+ return vals[i], true
+ }
+ }
+
+ var _default T
+ return _default, false
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go
new file mode 100644
index 0000000000..f3249dc3ce
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/checker.go
@@ -0,0 +1,59 @@
+package checkers
+
+import (
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+// CallMeta stores meta info about assertion function/method call, for example
+//
+// assert.Equal(t, 42, result, "helpful comment")
+type CallMeta struct {
+ // Range contains start and end position of assertion call.
+ analysis.Range
+ // IsPkg true if this is package (not object) call.
+ IsPkg bool
+ // IsAssert true if this is "testify/assert" package (or object) call.
+ IsAssert bool
+ // Selector is the AST expression of "assert.Equal".
+ Selector *ast.SelectorExpr
+ // SelectorXStr is a string representation of Selector's left part – value before point, e.g. "assert".
+ SelectorXStr string
+ // Fn stores meta info about assertion function itself.
+ Fn FnMeta
+ // Args stores assertion call arguments but without `t *testing.T` argument.
+ // E.g [42, result, "helpful comment"].
+ Args []ast.Expr
+ // ArgsRaw stores assertion call initial arguments.
+ // E.g [t, 42, result, "helpful comment"].
+ ArgsRaw []ast.Expr
+}
+
+// FnMeta stores meta info about assertion function itself, for example "Equal".
+type FnMeta struct {
+ // Range contains start and end position of function Name.
+ analysis.Range
+ // Name is a function name.
+ Name string
+ // IsFmt is true if function is formatted, e.g. "Equalf".
+ IsFmt bool
+}
+
+// Checker describes named checker.
+type Checker interface {
+ Name() string
+}
+
+// RegularChecker check assertion call presented in CallMeta form.
+type RegularChecker interface {
+ Checker
+ Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic
+}
+
+// AdvancedChecker implements complex Check logic different from trivial CallMeta check.
+type AdvancedChecker interface {
+ Checker
+ Check(pass *analysis.Pass, inspector *inspector.Inspector) []analysis.Diagnostic
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go
new file mode 100644
index 0000000000..47eaafb760
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/checkers_registry.go
@@ -0,0 +1,101 @@
+package checkers
+
+import (
+ "sort"
+)
+
+// registry stores checkers meta information in checkers' priority order.
+var registry = checkersRegistry{
+ // Regular checkers.
+ {factory: asCheckerFactory(NewFloatCompare), enabledByDefault: true},
+ {factory: asCheckerFactory(NewBoolCompare), enabledByDefault: true},
+ {factory: asCheckerFactory(NewEmpty), enabledByDefault: true},
+ {factory: asCheckerFactory(NewLen), enabledByDefault: true},
+ {factory: asCheckerFactory(NewCompares), enabledByDefault: true},
+ {factory: asCheckerFactory(NewErrorNil), enabledByDefault: true},
+ {factory: asCheckerFactory(NewErrorIsAs), enabledByDefault: true},
+ {factory: asCheckerFactory(NewRequireError), enabledByDefault: true},
+ {factory: asCheckerFactory(NewExpectedActual), enabledByDefault: true},
+ {factory: asCheckerFactory(NewSuiteExtraAssertCall), enabledByDefault: true},
+ {factory: asCheckerFactory(NewSuiteDontUsePkg), enabledByDefault: true},
+ // Advanced checkers.
+ {factory: asCheckerFactory(NewSuiteTHelper), enabledByDefault: false},
+}
+
+type checkersRegistry []checkerMeta
+
+type checkerMeta struct {
+ factory checkerFactory
+ enabledByDefault bool
+}
+
+type checkerFactory func() Checker
+
+func asCheckerFactory[T Checker](fn func() T) checkerFactory {
+ return func() Checker {
+ return fn()
+ }
+}
+
+func (r checkersRegistry) get(name string) (m checkerMeta, priority int, found bool) {
+ for i, meta := range r {
+ if meta.factory().Name() == name {
+ return meta, i, true
+ }
+ }
+ return checkerMeta{}, 0, false
+}
+
+// All returns all checkers names sorted by checker's priority.
+func All() []string {
+ result := make([]string, 0, len(registry))
+ for _, meta := range registry {
+ result = append(result, meta.factory().Name())
+ }
+ return result
+}
+
+// EnabledByDefault returns checkers enabled by default sorted by checker's priority.
+func EnabledByDefault() []string {
+ result := make([]string, 0, len(registry))
+ for _, meta := range registry {
+ if meta.enabledByDefault {
+ result = append(result, meta.factory().Name())
+ }
+ }
+ return result
+}
+
+// Get returns new checker instance by checker's name.
+func Get(name string) (Checker, bool) {
+ meta, _, ok := registry.get(name)
+ if ok {
+ return meta.factory(), true
+ }
+ return nil, false
+}
+
+// IsKnown checks if there is a checker with that name.
+func IsKnown(name string) bool {
+ _, _, ok := registry.get(name)
+ return ok
+}
+
+// IsEnabledByDefault returns true if a checker is enabled by default.
+// Returns false if there is no such checker in the registry.
+// For pre-validation use Get or IsKnown.
+func IsEnabledByDefault(name string) bool {
+ meta, _, ok := registry.get(name)
+ return ok && meta.enabledByDefault
+}
+
+// SortByPriority mutates the input checkers names by sorting them in checker priority order.
+// Ignores unknown checkers. For pre-validation use Get or IsKnown.
+func SortByPriority(checkers []string) {
+ sort.Slice(checkers, func(i, j int) bool {
+ lhs, rhs := checkers[i], checkers[j]
+ _, lhsPriority, _ := registry.get(lhs)
+ _, rhsPriority, _ := registry.get(rhs)
+ return lhsPriority < rhsPriority
+ })
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/compares.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/compares.go
new file mode 100644
index 0000000000..afc829f971
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/compares.go
@@ -0,0 +1,95 @@
+package checkers
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// Compares detects situations like
+//
+// assert.True(t, a == b)
+// assert.True(t, a != b)
+// assert.True(t, a > b)
+// assert.True(t, a >= b)
+// assert.True(t, a < b)
+// assert.True(t, a <= b)
+// ...
+//
+// and requires
+//
+// assert.Equal(t, a, b)
+// assert.NotEqual(t, a, b)
+// assert.Greater(t, a, b)
+// assert.GreaterOrEqual(t, a, b)
+// assert.Less(t, a, b)
+// assert.LessOrEqual(t, a, b)
+type Compares struct{}
+
+// NewCompares constructs Compares checker.
+func NewCompares() Compares { return Compares{} }
+func (Compares) Name() string { return "compares" }
+
+func (checker Compares) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ if len(call.Args) < 1 {
+ return nil
+ }
+
+ be, ok := call.Args[0].(*ast.BinaryExpr)
+ if !ok {
+ return nil
+ }
+
+ var tokenToProposedFn map[token.Token]string
+
+ switch call.Fn.Name {
+ case "True", "Truef":
+ tokenToProposedFn = tokenToProposedFnInsteadOfTrue
+ case "False", "Falsef":
+ tokenToProposedFn = tokenToProposedFnInsteadOfFalse
+ default:
+ return nil
+ }
+
+ if proposedFn, ok := tokenToProposedFn[be.Op]; ok {
+ a, b := be.X, be.Y
+ return newUseFunctionDiagnostic(checker.Name(), call, proposedFn,
+ newSuggestedFuncReplacement(call, proposedFn, analysis.TextEdit{
+ Pos: be.X.Pos(),
+ End: be.Y.End(),
+ NewText: formatAsCallArgs(pass, a, b),
+ }),
+ )
+ }
+ return nil
+}
+
+var tokenToProposedFnInsteadOfTrue = map[token.Token]string{
+ token.EQL: "Equal",
+ token.NEQ: "NotEqual",
+ token.GTR: "Greater",
+ token.GEQ: "GreaterOrEqual",
+ token.LSS: "Less",
+ token.LEQ: "LessOrEqual",
+}
+
+var tokenToProposedFnInsteadOfFalse = map[token.Token]string{
+ token.EQL: "NotEqual",
+ token.NEQ: "Equal",
+ token.GTR: "LessOrEqual",
+ token.GEQ: "Less",
+ token.LSS: "GreaterOrEqual",
+ token.LEQ: "Greater",
+}
+
+// formatAsCallArgs joins a and b and return bytes like `a, b`.
+func formatAsCallArgs(pass *analysis.Pass, a, b ast.Node) []byte {
+ return bytes.Join([][]byte{
+ analysisutil.NodeBytes(pass.Fset, a),
+ analysisutil.NodeBytes(pass.Fset, b),
+ }, []byte(", "))
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/diagnostic.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/diagnostic.go
new file mode 100644
index 0000000000..4ab69c69bb
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/diagnostic.go
@@ -0,0 +1,60 @@
+package checkers
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+func newUseFunctionDiagnostic(
+ checker string,
+ call *CallMeta,
+ proposedFn string,
+ fix *analysis.SuggestedFix,
+) *analysis.Diagnostic {
+ f := proposedFn
+ if call.Fn.IsFmt {
+ f += "f"
+ }
+ msg := fmt.Sprintf("use %s.%s", call.SelectorXStr, f)
+
+ return newDiagnostic(checker, call, msg, fix)
+}
+
+func newDiagnostic(
+ checker string,
+ rng analysis.Range,
+ msg string,
+ fix *analysis.SuggestedFix,
+) *analysis.Diagnostic {
+ d := analysis.Diagnostic{
+ Pos: rng.Pos(),
+ End: rng.End(),
+ Category: checker,
+ Message: checker + ": " + msg,
+ }
+ if fix != nil {
+ d.SuggestedFixes = []analysis.SuggestedFix{*fix}
+ }
+ return &d
+}
+
+func newSuggestedFuncReplacement(
+ call *CallMeta,
+ proposedFn string,
+ additionalEdits ...analysis.TextEdit,
+) *analysis.SuggestedFix {
+ if call.Fn.IsFmt {
+ proposedFn += "f"
+ }
+ return &analysis.SuggestedFix{
+ Message: fmt.Sprintf("Replace `%s` with `%s`", call.Fn.Name, proposedFn),
+ TextEdits: append([]analysis.TextEdit{
+ {
+ Pos: call.Fn.Pos(),
+ End: call.Fn.End(),
+ NewText: []byte(proposedFn),
+ },
+ }, additionalEdits...),
+ }
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go
new file mode 100644
index 0000000000..79c64205f4
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/empty.go
@@ -0,0 +1,172 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// Empty detects situations like
+//
+// assert.Len(t, arr, 0)
+// assert.Equal(t, 0, len(arr))
+// assert.NotEqual(t, 0, len(arr))
+// assert.GreaterOrEqual(t, len(arr), 1)
+// ...
+//
+// and requires
+//
+// assert.Empty(t, arr)
+// assert.NotEmpty(t, arr)
+type Empty struct{}
+
+// NewEmpty constructs Empty checker.
+func NewEmpty() Empty { return Empty{} }
+func (Empty) Name() string { return "empty" }
+
+func (checker Empty) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ if d := checker.checkEmpty(pass, call); d != nil {
+ return d
+ }
+ return checker.checkNotEmpty(pass, call)
+}
+
+func (checker Empty) checkEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit
+ newUseEmptyDiagnostic := func(replaceStart, replaceEnd token.Pos, replaceWith ast.Expr) *analysis.Diagnostic {
+ const proposed = "Empty"
+ return newUseFunctionDiagnostic(checker.Name(), call, proposed,
+ newSuggestedFuncReplacement(call, proposed, analysis.TextEdit{
+ Pos: replaceStart,
+ End: replaceEnd,
+ NewText: analysisutil.NodeBytes(pass.Fset, replaceWith),
+ }),
+ )
+ }
+
+ if len(call.Args) < 2 {
+ return nil
+ }
+ a, b := call.Args[0], call.Args[1]
+
+ switch call.Fn.Name {
+ case "Len", "Lenf":
+ if isZero(b) {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), a)
+ }
+
+ case "Equal", "Equalf":
+ arg1, ok1 := isLenCallAndZero(pass, a, b)
+ arg2, ok2 := isLenCallAndZero(pass, b, a)
+
+ if lenArg, ok := anyVal([]bool{ok1, ok2}, arg1, arg2); ok {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "LessOrEqual", "LessOrEqualf":
+ if lenArg, ok := isBuiltinLenCall(pass, a); ok && isZero(b) {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "GreaterOrEqual", "GreaterOrEqualf":
+ if lenArg, ok := isBuiltinLenCall(pass, b); ok && isZero(a) {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "Less", "Lessf":
+ if lenArg, ok := isBuiltinLenCall(pass, a); ok && isOne(b) {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "Greater", "Greaterf":
+ if lenArg, ok := isBuiltinLenCall(pass, b); ok && isOne(a) {
+ return newUseEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+ }
+ return nil
+}
+
+func (checker Empty) checkNotEmpty(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic { //nolint:gocognit
+ newUseNotEmptyDiagnostic := func(replaceStart, replaceEnd token.Pos, replaceWith ast.Expr) *analysis.Diagnostic {
+ const proposed = "NotEmpty"
+ return newUseFunctionDiagnostic(checker.Name(), call, proposed,
+ newSuggestedFuncReplacement(call, proposed, analysis.TextEdit{
+ Pos: replaceStart,
+ End: replaceEnd,
+ NewText: analysisutil.NodeBytes(pass.Fset, replaceWith),
+ }),
+ )
+ }
+
+ if len(call.Args) < 2 {
+ return nil
+ }
+ a, b := call.Args[0], call.Args[1]
+
+ switch call.Fn.Name {
+ case "NotEqual", "NotEqualf":
+ arg1, ok1 := isLenCallAndZero(pass, a, b)
+ arg2, ok2 := isLenCallAndZero(pass, b, a)
+
+ if lenArg, ok := anyVal([]bool{ok1, ok2}, arg1, arg2); ok {
+ return newUseNotEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "Greater", "Greaterf":
+ if lenArg, ok := isBuiltinLenCall(pass, a); ok && isZero(b) || isOne(b) {
+ return newUseNotEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "Less", "Lessf":
+ if lenArg, ok := isBuiltinLenCall(pass, b); ok && isZero(a) || isOne(a) {
+ return newUseNotEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "GreaterOrEqual", "GreaterOrEqualf":
+ if lenArg, ok := isBuiltinLenCall(pass, a); ok && isOne(b) {
+ return newUseNotEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+
+ case "LessOrEqual", "LessOrEqualf":
+ if lenArg, ok := isBuiltinLenCall(pass, b); ok && isOne(a) {
+ return newUseNotEmptyDiagnostic(a.Pos(), b.End(), lenArg)
+ }
+ }
+ return nil
+}
+
+var lenObj = types.Universe.Lookup("len")
+
+func isLenCallAndZero(pass *analysis.Pass, a, b ast.Expr) (ast.Expr, bool) {
+ lenArg, ok := isBuiltinLenCall(pass, a)
+ return lenArg, ok && isZero(b)
+}
+
+func isBuiltinLenCall(pass *analysis.Pass, e ast.Expr) (ast.Expr, bool) {
+ ce, ok := e.(*ast.CallExpr)
+ if !ok {
+ return nil, false
+ }
+
+ if analysisutil.IsObj(pass.TypesInfo, ce.Fun, lenObj) && len(ce.Args) == 1 {
+ return ce.Args[0], true
+ }
+ return nil, false
+}
+
+func isZero(e ast.Expr) bool {
+ return isIntNumber(e, 0)
+}
+
+func isOne(e ast.Expr) bool {
+ return isIntNumber(e, 1)
+}
+
+func isIntNumber(e ast.Expr, v int) bool {
+ bl, ok := e.(*ast.BasicLit)
+ return ok && bl.Kind == token.INT && bl.Value == fmt.Sprintf("%d", v)
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go
new file mode 100644
index 0000000000..e6abd0ba4f
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_is_as.go
@@ -0,0 +1,124 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// ErrorIsAs detects situations like
+//
+// assert.Error(t, err, errSentinel)
+// assert.NoError(t, err, errSentinel)
+// assert.True(t, errors.Is(err, errSentinel))
+// assert.False(t, errors.Is(err, errSentinel))
+// assert.True(t, errors.As(err, &target))
+//
+// and requires
+//
+// assert.ErrorIs(t, err, errSentinel)
+// assert.NotErrorIs(t, err, errSentinel)
+// assert.ErrorAs(t, err, &target)
+type ErrorIsAs struct{}
+
+// NewErrorIsAs constructs ErrorIsAs checker.
+func NewErrorIsAs() ErrorIsAs { return ErrorIsAs{} }
+func (ErrorIsAs) Name() string { return "error-is-as" }
+
+func (checker ErrorIsAs) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ switch call.Fn.Name {
+ case "Error", "Errorf":
+ if len(call.Args) >= 2 && isError(pass, call.Args[1]) {
+ const proposed = "ErrorIs"
+ msg := fmt.Sprintf("invalid usage of %[1]s.Error, use %[1]s.%[2]s instead", call.SelectorXStr, proposed)
+ return newDiagnostic(checker.Name(), call, msg, newSuggestedFuncReplacement(call, proposed))
+ }
+
+ case "NoError", "NoErrorf":
+ if len(call.Args) >= 2 && isError(pass, call.Args[1]) {
+ const proposed = "NotErrorIs"
+ msg := fmt.Sprintf("invalid usage of %[1]s.NoError, use %[1]s.%[2]s instead", call.SelectorXStr, proposed)
+ return newDiagnostic(checker.Name(), call, msg, newSuggestedFuncReplacement(call, proposed))
+ }
+
+ case "True", "Truef":
+ if len(call.Args) < 1 {
+ return nil
+ }
+
+ ce, ok := call.Args[0].(*ast.CallExpr)
+ if !ok {
+ return nil
+ }
+ if len(ce.Args) != 2 {
+ return nil
+ }
+
+ var proposed string
+ switch {
+ case isErrorsIsCall(pass, ce):
+ proposed = "ErrorIs"
+ case isErrorsAsCall(pass, ce):
+ proposed = "ErrorAs"
+ }
+ if proposed != "" {
+ return newUseFunctionDiagnostic(checker.Name(), call, proposed,
+ newSuggestedFuncReplacement(call, proposed, analysis.TextEdit{
+ Pos: ce.Pos(),
+ End: ce.End(),
+ NewText: formatAsCallArgs(pass, ce.Args[0], ce.Args[1]),
+ }),
+ )
+ }
+
+ case "False", "Falsef":
+ if len(call.Args) < 1 {
+ return nil
+ }
+
+ ce, ok := call.Args[0].(*ast.CallExpr)
+ if !ok {
+ return nil
+ }
+ if len(ce.Args) != 2 {
+ return nil
+ }
+
+ if isErrorsIsCall(pass, ce) {
+ const proposed = "NotErrorIs"
+ return newUseFunctionDiagnostic(checker.Name(), call, proposed,
+ newSuggestedFuncReplacement(call, proposed, analysis.TextEdit{
+ Pos: ce.Pos(),
+ End: ce.End(),
+ NewText: formatAsCallArgs(pass, ce.Args[0], ce.Args[1]),
+ }),
+ )
+ }
+ }
+ return nil
+}
+
+func isErrorsIsCall(pass *analysis.Pass, ce *ast.CallExpr) bool {
+ return isErrorsPkgFnCall(pass, ce, "Is")
+}
+
+func isErrorsAsCall(pass *analysis.Pass, ce *ast.CallExpr) bool {
+ return isErrorsPkgFnCall(pass, ce, "As")
+}
+
+func isErrorsPkgFnCall(pass *analysis.Pass, ce *ast.CallExpr, fn string) bool {
+ se, ok := ce.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+
+ errorsIsObj := analysisutil.ObjectOf(pass.Pkg, "errors", fn)
+ if errorsIsObj == nil {
+ return false
+ }
+
+ return analysisutil.IsObj(pass.TypesInfo, se.Sel, errorsIsObj)
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go
new file mode 100644
index 0000000000..b45629a48f
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/error_nil.go
@@ -0,0 +1,109 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// ErrorNil detects situations like
+//
+// assert.Nil(t, err)
+// assert.NotNil(t, err)
+// assert.Equal(t, err, nil)
+// assert.NotEqual(t, err, nil)
+//
+// and requires
+//
+// assert.NoError(t, err)
+// assert.Error(t, err)
+type ErrorNil struct{}
+
+// NewErrorNil constructs ErrorNil checker.
+func NewErrorNil() ErrorNil { return ErrorNil{} }
+func (ErrorNil) Name() string { return "error-nil" }
+
+func (checker ErrorNil) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ const (
+ errorFn = "Error"
+ noErrorFn = "NoError"
+ )
+
+ proposedFn, survivingArg, replacementEndPos := func() (string, ast.Expr, token.Pos) {
+ switch call.Fn.Name {
+ case "NotNil", "NotNilf":
+ if len(call.Args) >= 1 && isError(pass, call.Args[0]) {
+ return errorFn, call.Args[0], call.Args[0].End()
+ }
+
+ case "Nil", "Nilf":
+ if len(call.Args) >= 1 && isError(pass, call.Args[0]) {
+ return noErrorFn, call.Args[0], call.Args[0].End()
+ }
+
+ case "Equal", "Equalf":
+ if len(call.Args) < 2 {
+ return "", nil, token.NoPos
+ }
+ a, b := call.Args[0], call.Args[1]
+
+ switch {
+ case isError(pass, a) && isNil(pass, b):
+ return noErrorFn, a, b.End()
+ case isNil(pass, a) && isError(pass, b):
+ return noErrorFn, b, b.End()
+ }
+
+ case "NotEqual", "NotEqualf":
+ if len(call.Args) < 2 {
+ return "", nil, token.NoPos
+ }
+ a, b := call.Args[0], call.Args[1]
+
+ switch {
+ case isError(pass, a) && isNil(pass, b):
+ return errorFn, a, b.End()
+ case isNil(pass, a) && isError(pass, b):
+ return errorFn, b, b.End()
+ }
+ }
+ return "", nil, token.NoPos
+ }()
+
+ if proposedFn != "" {
+ return newUseFunctionDiagnostic(checker.Name(), call, proposedFn,
+ newSuggestedFuncReplacement(call, proposedFn, analysis.TextEdit{
+ Pos: call.Args[0].Pos(),
+ End: replacementEndPos,
+ NewText: analysisutil.NodeBytes(pass.Fset, survivingArg),
+ }),
+ )
+ }
+ return nil
+}
+
+var errIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+func isError(pass *analysis.Pass, expr ast.Expr) bool {
+ t := pass.TypesInfo.TypeOf(expr)
+ if t == nil {
+ return false
+ }
+
+ _, ok := t.Underlying().(*types.Interface)
+ return ok && types.Implements(t, errIface)
+}
+
+func isNil(pass *analysis.Pass, expr ast.Expr) bool {
+ t := pass.TypesInfo.TypeOf(expr)
+ if t == nil {
+ return false
+ }
+
+ b, ok := t.(*types.Basic)
+ return ok && b.Kind()&types.UntypedNil > 0
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go
new file mode 100644
index 0000000000..ff8243980b
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/expected_actual.go
@@ -0,0 +1,156 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/types"
+ "regexp"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// DefaultExpectedVarPattern matches variables with "expected" or "wanted" prefix or suffix in the name.
+var DefaultExpectedVarPattern = regexp.MustCompile(
+ `(^(exp(ected)?|want(ed)?)([A-Z]\w*)?$)|(^(\w*[a-z])?(Exp(ected)?|Want(ed)?)$)`)
+
+// ExpectedActual detects situation like
+//
+// assert.NotEqual(t, result, "expected value")
+//
+// and requires
+//
+// assert.NotEqual(t, "expected value", result)
+type ExpectedActual struct {
+ expVarPattern *regexp.Regexp
+}
+
+// NewExpectedActual constructs ExpectedActual checker using DefaultExpectedVarPattern.
+func NewExpectedActual() *ExpectedActual {
+ return &ExpectedActual{expVarPattern: DefaultExpectedVarPattern}
+}
+
+func (ExpectedActual) Name() string { return "expected-actual" }
+
+func (checker *ExpectedActual) SetExpVarPattern(p *regexp.Regexp) *ExpectedActual {
+ if p != nil {
+ checker.expVarPattern = p
+ }
+ return checker
+}
+
+func (checker ExpectedActual) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ switch call.Fn.Name {
+ case "Equal", "Equalf", "NotEqual", "NotEqualf",
+ "JSONEq", "JSONEqf", "YAMLEq", "YAMLEqf":
+ default:
+ return nil
+ }
+
+ if len(call.Args) < 2 {
+ return nil
+ }
+ first, second := call.Args[0], call.Args[1]
+
+ if checker.isWrongExpectedActualOrder(pass, first, second) {
+ return newDiagnostic(checker.Name(), call, "need to reverse actual and expected values", &analysis.SuggestedFix{
+ Message: "Reverse actual and expected values",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: first.Pos(),
+ End: second.End(),
+ NewText: formatAsCallArgs(pass, second, first),
+ },
+ },
+ })
+ }
+ return nil
+}
+
+func (checker ExpectedActual) isWrongExpectedActualOrder(pass *analysis.Pass, first, second ast.Expr) bool {
+ leftIsCandidate := checker.isExpectedValueCandidate(pass, first)
+ rightIsCandidate := checker.isExpectedValueCandidate(pass, second)
+ return rightIsCandidate && !leftIsCandidate
+}
+
+func (checker ExpectedActual) isExpectedValueCandidate(pass *analysis.Pass, expr ast.Expr) bool {
+ switch v := expr.(type) {
+ case *ast.CompositeLit:
+ return true
+
+ case *ast.CallExpr:
+ return isCastedBasicLitOrExpectedValue(v, checker.expVarPattern) ||
+ isExpectedValueFactory(v, checker.expVarPattern)
+ }
+
+ return isBasicLit(expr) ||
+ isUntypedConst(pass, expr) ||
+ isTypedConst(pass, expr) ||
+ isIdentNamedAsExpected(checker.expVarPattern, expr) ||
+ isStructFieldNamedAsExpected(checker.expVarPattern, expr)
+}
+
+func isCastedBasicLitOrExpectedValue(ce *ast.CallExpr, pattern *regexp.Regexp) bool {
+ if len(ce.Args) != 1 {
+ return false
+ }
+
+ fn, ok := ce.Fun.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ switch fn.Name {
+ case "complex64", "complex128":
+ return true
+
+ case "uint", "uint8", "uint16", "uint32", "uint64",
+ "int", "int8", "int16", "int32", "int64",
+ "float32", "float64",
+ "rune", "string":
+ return isBasicLit(ce.Args[0]) || isIdentNamedAsExpected(pattern, ce.Args[0])
+ }
+ return false
+}
+
+func isExpectedValueFactory(ce *ast.CallExpr, pattern *regexp.Regexp) bool {
+ if len(ce.Args) != 0 {
+ return false
+ }
+
+ switch fn := ce.Fun.(type) {
+ case *ast.Ident:
+ return pattern.MatchString(fn.Name)
+ case *ast.SelectorExpr:
+ return pattern.MatchString(fn.Sel.Name)
+ }
+ return false
+}
+
+func isBasicLit(e ast.Expr) bool {
+ _, ok := e.(*ast.BasicLit)
+ return ok
+}
+
+func isUntypedConst(p *analysis.Pass, e ast.Expr) bool {
+ t := p.TypesInfo.TypeOf(e)
+ if t == nil {
+ return false
+ }
+
+ b, ok := t.(*types.Basic)
+ return ok && b.Info()&types.IsUntyped > 0
+}
+
+func isTypedConst(p *analysis.Pass, e ast.Expr) bool {
+ tt, ok := p.TypesInfo.Types[e]
+ return ok && tt.IsValue() && tt.Value != nil
+}
+
+func isIdentNamedAsExpected(pattern *regexp.Regexp, e ast.Expr) bool {
+ id, ok := e.(*ast.Ident)
+ return ok && pattern.MatchString(id.Name)
+}
+
+func isStructFieldNamedAsExpected(pattern *regexp.Regexp, e ast.Expr) bool {
+ s, ok := e.(*ast.SelectorExpr)
+ return ok && isIdentNamedAsExpected(pattern, s.Sel)
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/float_compare.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/float_compare.go
new file mode 100644
index 0000000000..7d5b358b35
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/float_compare.go
@@ -0,0 +1,63 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/token"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// FloatCompare detects situation like
+//
+// assert.Equal(t, 42.42, a)
+// assert.True(t, a == 42.42)
+// assert.False(t, a != 42.42)
+//
+// and requires
+//
+// assert.InEpsilon(t, 42.42, a, 0.0001) // Or assert.InDelta
+type FloatCompare struct{}
+
+// NewFloatCompare constructs FloatCompare checker.
+func NewFloatCompare() FloatCompare { return FloatCompare{} }
+func (FloatCompare) Name() string { return "float-compare" }
+
+func (checker FloatCompare) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ invalid := func() bool {
+ switch call.Fn.Name {
+ case "Equal", "Equalf":
+ return len(call.Args) > 1 && isFloat(pass, call.Args[0]) && isFloat(pass, call.Args[1])
+
+ case "True", "Truef":
+ return len(call.Args) > 0 && isFloatCompare(pass, call.Args[0], token.EQL)
+
+ case "False", "Falsef":
+ return len(call.Args) > 0 && isFloatCompare(pass, call.Args[0], token.NEQ)
+ }
+ return false
+ }()
+
+ if invalid {
+ return newUseFunctionDiagnostic(checker.Name(), call, "InEpsilon (or InDelta)", nil)
+ }
+ return nil
+}
+
+func isFloat(pass *analysis.Pass, expr ast.Expr) bool {
+ t := pass.TypesInfo.TypeOf(expr)
+ if t == nil {
+ return false
+ }
+
+ bt, ok := t.Underlying().(*types.Basic)
+ return ok && (bt.Info()&types.IsFloat > 0)
+}
+
+func isFloatCompare(p *analysis.Pass, e ast.Expr, op token.Token) bool {
+ be, ok := e.(*ast.BinaryExpr)
+ if !ok {
+ return false
+ }
+ return be.Op == op && (isFloat(p, be.X) || isFloat(p, be.Y))
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go
new file mode 100644
index 0000000000..f10412f636
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/len.go
@@ -0,0 +1,86 @@
+package checkers
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// Len detects situations like
+//
+// assert.Equal(t, 3, len(arr))
+// assert.True(t, len(arr) == 3)
+//
+// and requires
+//
+// assert.Len(t, arr, 3)
+type Len struct{}
+
+// NewLen constructs Len checker.
+func NewLen() Len { return Len{} }
+func (Len) Name() string { return "len" }
+
+func (checker Len) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ const proposedFn = "Len"
+
+ switch call.Fn.Name {
+ case "Equal", "Equalf":
+ if len(call.Args) < 2 {
+ return nil
+ }
+ a, b := call.Args[0], call.Args[1]
+
+ if lenArg, expectedLen, ok := xorLenCall(pass, a, b); ok {
+ return newUseFunctionDiagnostic(checker.Name(), call, proposedFn,
+ newSuggestedFuncReplacement(call, proposedFn, analysis.TextEdit{
+ Pos: a.Pos(),
+ End: b.End(),
+ NewText: formatAsCallArgs(pass, lenArg, expectedLen),
+ }),
+ )
+ }
+
+ case "True", "Truef":
+ if len(call.Args) < 1 {
+ return nil
+ }
+ expr := call.Args[0]
+
+ if lenArg, expectedLen, ok := isLenEquality(pass, expr); ok {
+ return newUseFunctionDiagnostic(checker.Name(), call, proposedFn,
+ newSuggestedFuncReplacement(call, proposedFn, analysis.TextEdit{
+ Pos: expr.Pos(),
+ End: expr.End(),
+ NewText: formatAsCallArgs(pass, lenArg, expectedLen),
+ }),
+ )
+ }
+ }
+ return nil
+}
+
+func xorLenCall(pass *analysis.Pass, a, b ast.Expr) (lenArg ast.Expr, expectedLen ast.Expr, ok bool) {
+ arg1, ok1 := isBuiltinLenCall(pass, a)
+ arg2, ok2 := isBuiltinLenCall(pass, b)
+
+ if xor(ok1, ok2) {
+ if ok1 {
+ return arg1, b, true
+ }
+ return arg2, a, true
+ }
+ return nil, nil, false
+}
+
+func isLenEquality(pass *analysis.Pass, e ast.Expr) (ast.Expr, ast.Expr, bool) {
+ be, ok := e.(*ast.BinaryExpr)
+ if !ok {
+ return nil, nil, false
+ }
+
+ if be.Op != token.EQL {
+ return nil, nil, false
+ }
+ return xorLenCall(pass, be.X, be.Y)
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go
new file mode 100644
index 0000000000..2da71ed817
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/require_error.go
@@ -0,0 +1,35 @@
+package checkers
+
+import "golang.org/x/tools/go/analysis"
+
+// RequireError detects situations like
+//
+// assert.NoError(t, err)
+// s.ErrorIs(err, io.EOF)
+// s.Assert().Error(err)
+//
+// and requires
+//
+// require.NoError(t, err)
+// s.Require().ErrorIs(err, io.EOF)
+// s.Require().Error(err)
+type RequireError struct{}
+
+// NewRequireError constructs RequireError checker.
+func NewRequireError() RequireError { return RequireError{} }
+func (RequireError) Name() string { return "require-error" }
+
+func (checker RequireError) Check(_ *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ if !call.IsAssert {
+ return nil
+ }
+
+ const msg = "for error assertions use require"
+
+ switch call.Fn.Name {
+ case "Error", "ErrorIs", "ErrorAs", "EqualError", "ErrorContains", "NoError", "NotErrorIs",
+ "Errorf", "ErrorIsf", "ErrorAsf", "EqualErrorf", "ErrorContainsf", "NoErrorf", "NotErrorIsf":
+ return newDiagnostic(checker.Name(), call, msg, nil)
+ }
+ return nil
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_dont_use_pkg.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_dont_use_pkg.go
new file mode 100644
index 0000000000..bf84f6378e
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_dont_use_pkg.go
@@ -0,0 +1,96 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+ "github.com/Antonboom/testifylint/internal/testify"
+)
+
+// SuiteDontUsePkg detects situation like
+//
+// func (s *MySuite) TestSomething() {
+// assert.Equal(s.T(), 42, value)
+// }
+//
+// and requires
+//
+// func (s *MySuite) TestSomething() {
+// s.Equal(42, value)
+// }
+type SuiteDontUsePkg struct{}
+
+// NewSuiteDontUsePkg constructs SuiteDontUsePkg checker.
+func NewSuiteDontUsePkg() SuiteDontUsePkg { return SuiteDontUsePkg{} }
+func (SuiteDontUsePkg) Name() string { return "suite-dont-use-pkg" }
+
+func (checker SuiteDontUsePkg) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ if !call.IsPkg {
+ return nil
+ }
+
+ args := call.ArgsRaw
+ if len(args) < 2 {
+ return nil
+ }
+ t := args[0]
+
+ ce, ok := t.(*ast.CallExpr)
+ if !ok {
+ return nil
+ }
+ se, ok := ce.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return nil
+ }
+ if se.X == nil || !implementsTestifySuiteIface(pass, se.X) {
+ return nil
+ }
+ if se.Sel == nil || se.Sel.Name != "T" {
+ return nil
+ }
+ rcv, ok := se.X.(*ast.Ident) // At this point we ensure that `s.T()` is used as the first argument of assertion.
+ if !ok {
+ return nil
+ }
+
+ newSelector := rcv.Name
+ if !call.IsAssert {
+ newSelector += "." + "Require()"
+ }
+
+ msg := fmt.Sprintf("use %s.%s", newSelector, call.Fn.Name)
+ return newDiagnostic(checker.Name(), call, msg, &analysis.SuggestedFix{
+ Message: fmt.Sprintf("Replace `%s` with `%s`", call.SelectorXStr, newSelector),
+ TextEdits: []analysis.TextEdit{
+ // Replace package function with suite method.
+ {
+ Pos: call.Selector.X.Pos(),
+ End: call.Selector.X.End(),
+ NewText: []byte(newSelector),
+ },
+ // Remove `s.T()`.
+ {
+ Pos: t.Pos(),
+ End: args[1].Pos(),
+ NewText: []byte(""),
+ },
+ },
+ })
+}
+
+func implementsTestifySuiteIface(pass *analysis.Pass, rcv ast.Expr) bool {
+ suiteIface := analysisutil.ObjectOf(pass.Pkg, testify.SuitePkgPath, "TestingSuite")
+ if suiteIface == nil {
+ return false
+ }
+
+ return types.Implements(
+ pass.TypesInfo.TypeOf(rcv),
+ suiteIface.Type().Underlying().(*types.Interface),
+ )
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_extra_assert_call.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_extra_assert_call.go
new file mode 100644
index 0000000000..791488b651
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_extra_assert_call.go
@@ -0,0 +1,99 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+)
+
+// SuiteExtraAssertCallMode reflects different modes of work of SuiteExtraAssertCall checker.
+type SuiteExtraAssertCallMode int
+
+const (
+ SuiteExtraAssertCallModeRemove SuiteExtraAssertCallMode = iota
+ SuiteExtraAssertCallModeRequire
+)
+
+const DefaultSuiteExtraAssertCallMode = SuiteExtraAssertCallModeRemove
+
+// SuiteExtraAssertCall detects situation like
+//
+// func (s *MySuite) TestSomething() {
+// s.Assert().Equal(42, value)
+// }
+//
+// and requires
+//
+// func (s *MySuite) TestSomething() {
+// s.Equal(42, value)
+// }
+//
+// or vice versa (depending on the configurable mode).
+type SuiteExtraAssertCall struct {
+ mode SuiteExtraAssertCallMode
+}
+
+// NewSuiteExtraAssertCall constructs SuiteExtraAssertCall checker.
+func NewSuiteExtraAssertCall() *SuiteExtraAssertCall {
+ return &SuiteExtraAssertCall{mode: DefaultSuiteExtraAssertCallMode}
+}
+
+func (SuiteExtraAssertCall) Name() string { return "suite-extra-assert-call" }
+
+func (checker *SuiteExtraAssertCall) SetMode(m SuiteExtraAssertCallMode) *SuiteExtraAssertCall {
+ checker.mode = m
+ return checker
+}
+
+func (checker SuiteExtraAssertCall) Check(pass *analysis.Pass, call *CallMeta) *analysis.Diagnostic {
+ if call.IsPkg {
+ return nil
+ }
+
+ switch checker.mode {
+ case SuiteExtraAssertCallModeRequire:
+ x, ok := call.Selector.X.(*ast.Ident) // s.True
+ if !ok || x == nil || !implementsTestifySuiteIface(pass, x) {
+ return nil
+ }
+
+ msg := fmt.Sprintf("use an explicit %s.Assert().%s", analysisutil.NodeString(pass.Fset, x), call.Fn.Name)
+ return newDiagnostic(checker.Name(), call, msg, &analysis.SuggestedFix{
+ Message: "Add `Assert()` call",
+ TextEdits: []analysis.TextEdit{{
+ Pos: x.End(),
+ End: x.End(), // Pure insertion.
+ NewText: []byte(".Assert()"),
+ }},
+ })
+
+ case SuiteExtraAssertCallModeRemove:
+ x, ok := call.Selector.X.(*ast.CallExpr) // s.Assert().True
+ if !ok {
+ return nil
+ }
+
+ se, ok := x.Fun.(*ast.SelectorExpr)
+ if !ok || se == nil || !implementsTestifySuiteIface(pass, se.X) {
+ return nil
+ }
+ if se.Sel == nil || se.Sel.Name != "Assert" {
+ return nil
+ }
+
+ msg := fmt.Sprintf("need to simplify the assertion to %s.%s", analysisutil.NodeString(pass.Fset, se.X), call.Fn.Name)
+ return newDiagnostic(checker.Name(), call, msg, &analysis.SuggestedFix{
+ Message: "Remove `Assert()` call",
+ TextEdits: []analysis.TextEdit{{
+ Pos: se.Sel.Pos(),
+ End: x.End() + 1, // +1 for dot.
+ NewText: []byte(""),
+ }},
+ })
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go
new file mode 100644
index 0000000000..5cadc93ada
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/checkers/suite_thelper.go
@@ -0,0 +1,130 @@
+package checkers
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/ast/inspector"
+
+ "github.com/Antonboom/testifylint/internal/analysisutil"
+ "github.com/Antonboom/testifylint/internal/testify"
+)
+
+// SuiteTHelper requires t.Helper() call in suite helpers:
+//
+// func (s *RoomSuite) assertRoomRound(roundID RoundID) {
+// s.T().Helper()
+// s.Equal(roundID, s.getRoom().CurrentRound.ID)
+// }
+type SuiteTHelper struct{}
+
+// NewSuiteTHelper constructs SuiteTHelper checker.
+func NewSuiteTHelper() SuiteTHelper { return SuiteTHelper{} }
+func (SuiteTHelper) Name() string { return "suite-thelper" }
+
+func (checker SuiteTHelper) Check(pass *analysis.Pass, inspector *inspector.Inspector) (diagnostics []analysis.Diagnostic) {
+ inspector.Preorder([]ast.Node{(*ast.FuncDecl)(nil)}, func(node ast.Node) {
+ fd := node.(*ast.FuncDecl)
+ if !isTestifySuiteMethod(pass, fd) {
+ return
+ }
+
+ if ident := fd.Name; ident == nil || isTestMethod(ident.Name) || isServiceMethod(ident.Name) {
+ return
+ }
+
+ if !containsSuiteAssertions(pass, fd) {
+ return
+ }
+
+ rcv := fd.Recv.List[0]
+ if len(rcv.Names) != 1 || rcv.Names[0] == nil {
+ return
+ }
+ rcvName := rcv.Names[0].Name
+
+ helperCallStr := fmt.Sprintf("%s.T().Helper()", rcvName)
+
+ firstStmt := fd.Body.List[0]
+ if analysisutil.NodeString(pass.Fset, firstStmt) == helperCallStr {
+ return
+ }
+
+ msg := fmt.Sprintf("suite helper method must start with " + helperCallStr)
+ d := newDiagnostic(checker.Name(), fd, msg, &analysis.SuggestedFix{
+ Message: fmt.Sprintf("Insert `%s`", helperCallStr),
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: firstStmt.Pos(),
+ End: firstStmt.Pos(), // Pure insertion.
+ NewText: []byte(helperCallStr + "\n\n"),
+ },
+ },
+ })
+ diagnostics = append(diagnostics, *d)
+ })
+ return diagnostics
+}
+
+func isTestifySuiteMethod(pass *analysis.Pass, fDecl *ast.FuncDecl) bool {
+ if fDecl.Recv == nil || len(fDecl.Recv.List) != 1 {
+ return false
+ }
+
+ rcv := fDecl.Recv.List[0]
+ return implementsTestifySuiteIface(pass, rcv.Type)
+}
+
+func isTestMethod(name string) bool {
+ return strings.HasPrefix(name, "Test")
+}
+
+func isServiceMethod(name string) bool {
+ // https://github.com/stretchr/testify/blob/master/suite/interfaces.go
+ switch name {
+ case "T", "SetT", "SetS", "SetupSuite", "SetupTest", "TearDownSuite", "TearDownTest",
+ "BeforeTest", "AfterTest", "HandleStats", "SetupSubTest", "TearDownSubTest":
+ return true
+ }
+ return false
+}
+
+func containsSuiteAssertions(pass *analysis.Pass, fn *ast.FuncDecl) bool {
+ if fn.Body == nil {
+ return false
+ }
+
+ for _, s := range fn.Body.List {
+ if isSuiteAssertion(pass, s) {
+ return true
+ }
+ }
+ return false
+}
+
+func isSuiteAssertion(pass *analysis.Pass, stmt ast.Stmt) bool {
+ expr, ok := stmt.(*ast.ExprStmt)
+ if !ok {
+ return false
+ }
+
+ ce, ok := expr.X.(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+
+ se, ok := ce.Fun.(*ast.SelectorExpr)
+ if !ok || se.Sel == nil {
+ return false
+ }
+
+ if sel, ok := pass.TypesInfo.Selections[se]; ok {
+ pkg := sel.Obj().Pkg()
+ isAssert := analysisutil.IsPkg(pkg, testify.AssertPkgName, testify.AssertPkgPath)
+ isRequire := analysisutil.IsPkg(pkg, testify.RequirePkgName, testify.RequirePkgPath)
+ return isAssert || isRequire
+ }
+ return false
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/config/config.go b/vendor/github.com/Antonboom/testifylint/internal/config/config.go
new file mode 100644
index 0000000000..51f6270088
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/config/config.go
@@ -0,0 +1,53 @@
+package config
+
+import (
+ "flag"
+
+ "github.com/Antonboom/testifylint/internal/checkers"
+)
+
+// NewDefault builds default testifylint config.
+func NewDefault() Config {
+ return Config{
+ EnableAll: false,
+ EnabledCheckers: checkers.EnabledByDefault(),
+ ExpectedActual: ExpectedActualConfig{
+ ExpVarPattern: RegexpValue{checkers.DefaultExpectedVarPattern},
+ },
+ SuiteExtraAssertCall: SuiteExtraAssertCallConfig{
+ Mode: checkers.DefaultSuiteExtraAssertCallMode,
+ },
+ }
+}
+
+// Config implements testifylint configuration.
+type Config struct {
+ EnableAll bool
+ EnabledCheckers KnownCheckersValue
+ ExpectedActual ExpectedActualConfig
+ SuiteExtraAssertCall SuiteExtraAssertCallConfig
+}
+
+// ExpectedActualConfig implements configuration of checkers.ExpectedActual.
+type ExpectedActualConfig struct {
+ ExpVarPattern RegexpValue
+}
+
+// SuiteExtraAssertCallConfig implements configuration of checkers.SuiteExtraAssertCall.
+type SuiteExtraAssertCallConfig struct {
+ Mode checkers.SuiteExtraAssertCallMode
+}
+
+// BindToFlags binds Config fields to according flags.
+func BindToFlags(cfg *Config, fs *flag.FlagSet) {
+ fs.BoolVar(&cfg.EnableAll, "enable-all", false, "enable all checkers")
+ fs.Var(&cfg.EnabledCheckers, "enable", "comma separated list of enabled checkers")
+ fs.Var(&cfg.ExpectedActual.ExpVarPattern, "expected-actual.pattern", "regexp for expected variable name")
+ fs.Var(NewEnumValue(suiteExtraAssertCallModeAsString, &cfg.SuiteExtraAssertCall.Mode),
+ "suite-extra-assert-call.mode", "to require or remove extra Assert() call")
+}
+
+var suiteExtraAssertCallModeAsString = map[string]checkers.SuiteExtraAssertCallMode{
+ "remove": checkers.SuiteExtraAssertCallModeRemove,
+ "require": checkers.SuiteExtraAssertCallModeRequire,
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/config/flag_value_types.go b/vendor/github.com/Antonboom/testifylint/internal/config/flag_value_types.go
new file mode 100644
index 0000000000..2f0ee978f3
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/config/flag_value_types.go
@@ -0,0 +1,105 @@
+package config
+
+import (
+ "flag"
+ "fmt"
+ "regexp"
+ "sort"
+ "strings"
+
+ "github.com/Antonboom/testifylint/internal/checkers"
+)
+
+var (
+ _ flag.Value = (*KnownCheckersValue)(nil)
+ _ flag.Value = (*RegexpValue)(nil)
+ _ flag.Value = (*EnumValue[checkers.SuiteExtraAssertCallMode])(nil)
+)
+
+// KnownCheckersValue implements comma separated list of testify checkers.
+type KnownCheckersValue []string
+
+func (kcv KnownCheckersValue) String() string {
+ return strings.Join(kcv, ",")
+}
+
+func (kcv *KnownCheckersValue) Set(v string) error {
+ chckrs := strings.Split(v, ",")
+ for _, checkerName := range chckrs {
+ if ok := checkers.IsKnown(checkerName); !ok {
+ return fmt.Errorf("unknown checker %q", checkerName)
+ }
+ }
+
+ *kcv = chckrs
+ return nil
+}
+
+// RegexpValue is a special wrapper for support of flag.FlagSet over regexp.Regexp.
+// Original regexp is available through RegexpValue.Regexp.
+type RegexpValue struct {
+ *regexp.Regexp
+}
+
+func (rv RegexpValue) String() string {
+ if rv.Regexp == nil {
+ return ""
+ }
+ return rv.Regexp.String()
+}
+
+func (rv *RegexpValue) Set(v string) error {
+ compiled, err := regexp.Compile(v)
+ if err != nil {
+ return err
+ }
+
+ rv.Regexp = compiled
+ return nil
+}
+
+// EnumValue is a special type for support of flag.FlagSet over user-defined constants.
+type EnumValue[EnumT comparable] struct {
+ mapping map[string]EnumT
+ keys []string
+ dst *EnumT
+}
+
+// NewEnumValue takes the "enum-value-name to enum-value" mapping and a destination for the value passed through the CLI.
+// Returns an EnumValue instance suitable for flag.FlagSet.Var.
+func NewEnumValue[EnumT comparable](mapping map[string]EnumT, dst *EnumT) *EnumValue[EnumT] {
+ keys := make([]string, 0, len(mapping))
+ for k := range mapping {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ return &EnumValue[EnumT]{
+ mapping: mapping,
+ keys: keys,
+ dst: dst,
+ }
+}
+
+func (e EnumValue[EnumT]) String() string {
+ if e.dst == nil {
+ return ""
+ }
+
+ for k, v := range e.mapping {
+ if v == *e.dst {
+ return k
+ }
+ }
+ return ""
+}
+
+func (e *EnumValue[EnumT]) Set(s string) error {
+ v, ok := e.mapping[s]
+ if !ok {
+ return fmt.Errorf("use one of (%v)", strings.Join(e.keys, " | "))
+ }
+
+ *e.dst = v
+ return nil
+}
diff --git a/vendor/github.com/Antonboom/testifylint/internal/testify/const.go b/vendor/github.com/Antonboom/testifylint/internal/testify/const.go
new file mode 100644
index 0000000000..45731aa97a
--- /dev/null
+++ b/vendor/github.com/Antonboom/testifylint/internal/testify/const.go
@@ -0,0 +1,13 @@
+package testify
+
+const (
+ ModulePath = "github.com/stretchr/testify"
+
+ AssertPkgName = "assert"
+ RequirePkgName = "require"
+ SuitePkgName = "suite"
+
+ AssertPkgPath = ModulePath + "/" + AssertPkgName
+ RequirePkgPath = ModulePath + "/" + RequirePkgName
+ SuitePkgPath = ModulePath + "/" + SuitePkgName
+)
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/.goreleaser.yml b/vendor/github.com/alecthomas/go-check-sumtype/.goreleaser.yml
new file mode 100644
index 0000000000..33bd03d060
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/.goreleaser.yml
@@ -0,0 +1,32 @@
+project_name: go-check-sumtype
+release:
+ github:
+ owner: alecthomas
+ name: go-check-sumtype
+env:
+ - CGO_ENABLED=0
+builds:
+- goos:
+ - linux
+ - darwin
+ - windows
+ goarch:
+ - arm64
+ - amd64
+ - "386"
+ goarm:
+ - "6"
+ main: ./cmd/go-check-sumtype
+ binary: go-check-sumtype
+archives:
+ -
+ format: tar.gz
+ name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{
+ .Arm }}{{ end }}'
+ files:
+ - COPYING
+ - README*
+snapshot:
+ name_template: SNAPSHOT-{{ .Commit }}
+checksum:
+ name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/COPYING b/vendor/github.com/alecthomas/go-check-sumtype/COPYING
new file mode 100644
index 0000000000..bb9c20a094
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/COPYING
@@ -0,0 +1,3 @@
+This project is dual-licensed under the Unlicense and MIT licenses.
+
+You may use this code under the terms of either license.
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/LICENSE-MIT b/vendor/github.com/alecthomas/go-check-sumtype/LICENSE-MIT
new file mode 100644
index 0000000000..3b0a5dc09c
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Andrew Gallant
+
+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.
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/README.md b/vendor/github.com/alecthomas/go-check-sumtype/README.md
new file mode 100644
index 0000000000..36614ef400
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/README.md
@@ -0,0 +1,120 @@
+**Note: This is a fork of the great project [go-sumtype](https://github.com/BurntSushi/go-sumtype) by BurntSushi.**
+**The original seems largely unmaintained, and the changes in this fork are backwards incompatible.**
+
+# go-check-sumtype [![CI](https://github.com/alecthomas/go-check-sumtype/actions/workflows/ci.yml/badge.svg)](https://github.com/alecthomas/go-check-sumtype/actions/workflows/ci.yml)
+A simple utility for running exhaustiveness checks on type switch statements.
+Exhaustiveness checks are only run on interfaces that are declared to be
+"sum types."
+
+Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
+
+This work was inspired by our code at
+[Diffeo](https://diffeo.com).
+
+## Installation
+
+```go
+$ go get github.com/alecthomas/go-check-sumtype
+```
+
+For usage info, just run the command:
+
+```
+$ go-check-sumtype
+```
+
+Typical usage might look like this:
+
+```
+$ go-check-sumtype $(go list ./... | grep -v vendor)
+```
+
+## Usage
+
+`go-check-sumtype` takes a list of Go package paths or files and looks for sum type
+declarations in each package/file provided. Exhaustiveness checks are then
+performed for each use of a declared sum type in a type switch statement.
+Namely, `go-check-sumtype` will report an error for any type switch statement that
+either lacks a `default` clause or does not account for all possible variants.
+
+Declarations are provided in comments like so:
+
+```
+//sumtype:decl
+type MySumType interface { ... }
+```
+
+`MySumType` must be *sealed*. That is, part of its interface definition
+contains an unexported method.
+
+`go-check-sumtype` will produce an error if any of the above is not true.
+
+For valid declarations, `go-check-sumtype` will look for all occurrences in which a
+value of type `MySumType` participates in a type switch statement. In those
+occurrences, it will attempt to detect whether the type switch is exhaustive
+or not. If it's not, `go-check-sumtype` will report an error. For example, running
+`go-check-sumtype` on this source file:
+
+```go
+package main
+
+//sumtype:decl
+type MySumType interface {
+ sealed()
+}
+
+type VariantA struct{}
+
+func (*VariantA) sealed() {}
+
+type VariantB struct{}
+
+func (*VariantB) sealed() {}
+
+func main() {
+ switch MySumType(nil).(type) {
+ case *VariantA:
+ }
+}
+```
+
+produces the following:
+
+```
+$ sumtype mysumtype.go
+mysumtype.go:18:2: exhaustiveness check failed for sum type 'MySumType': missing cases for VariantB
+```
+
+Adding either a `default` clause or a clause to handle `*VariantB` will cause
+exhaustive checks to pass.
+
+As a special case, if the type switch statement contains a `default` clause
+that always panics, then exhaustiveness checks are still performed.
+
+## Details and motivation
+
+Sum types are otherwise known as discriminated unions. That is, a sum type is
+a finite set of disjoint values. In type systems that support sum types, the
+language will guarantee that if one has a sum type `T`, then its value must
+be one of its variants.
+
+Go's type system does not support sum types. A typical proxy for representing
+sum types in Go is to use an interface with an unexported method and define
+each variant of the sum type in the same package to satisfy said interface.
+This guarantees that the set of types that satisfy the interface is closed
+at compile time. Performing case analysis on these types is then done with
+a type switch statement, e.g., `switch x.(type) { ... }`. Each clause of the
+type switch corresponds to a *variant* of the sum type. The downside of this
+approach is that Go's type system is not aware of the set of variants, so it
+cannot tell you whether case analysis over a sum type is complete or not.
+
+The `go-check-sumtype` command recognizes this pattern, but it needs a small amount
+of help to recognize which interfaces should be treated as sum types, which
+is why the `//sumtype:decl` annotation is required. `go-check-sumtype` will
+figure out all of the variants of a sum type by finding the set of types
+defined in the same package that satisfy the interface specified by the
+declaration.
+
+The `go-check-sumtype` command will prove its worth when you need to add a variant
+to an existing sum type. Running `go-check-sumtype` will tell you immediately which
+case analyses need to be updated to account for the new variant.
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/UNLICENSE b/vendor/github.com/alecthomas/go-check-sumtype/UNLICENSE
new file mode 100644
index 0000000000..68a49daad8
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/UNLICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/check.go b/vendor/github.com/alecthomas/go-check-sumtype/check.go
new file mode 100644
index 0000000000..21d751af42
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/check.go
@@ -0,0 +1,184 @@
+package gochecksumtype
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "sort"
+ "strings"
+
+ "golang.org/x/tools/go/packages"
+)
+
+// inexhaustiveError is returned from check for each occurrence of inexhaustive
+// case analysis in a Go type switch statement.
+type inexhaustiveError struct {
+ Position token.Position
+ Def sumTypeDef
+ Missing []types.Object
+}
+
+func (e inexhaustiveError) Pos() token.Position { return e.Position }
+func (e inexhaustiveError) Error() string {
+ return fmt.Sprintf(
+ "%s: exhaustiveness check failed for sum type %q (from %s): missing cases for %s",
+ e.Pos(), e.Def.Decl.TypeName, e.Def.Decl.Pos, strings.Join(e.Names(), ", "))
+}
+
+// Names returns a sorted list of names corresponding to the missing variant
+// cases.
+func (e inexhaustiveError) Names() []string {
+ var list []string
+ for _, o := range e.Missing {
+ list = append(list, o.Name())
+ }
+ sort.Strings(list)
+ return list
+}
+
+// check does exhaustiveness checking for the given sum type definitions in the
+// given package. Every instance of inexhaustive case analysis is returned.
+func check(pkg *packages.Package, defs []sumTypeDef) []error {
+ var errs []error
+ for _, astfile := range pkg.Syntax {
+ ast.Inspect(astfile, func(n ast.Node) bool {
+ swtch, ok := n.(*ast.TypeSwitchStmt)
+ if !ok {
+ return true
+ }
+ if err := checkSwitch(pkg, defs, swtch); err != nil {
+ errs = append(errs, err)
+ }
+ return true
+ })
+ }
+ return errs
+}
+
+// checkSwitch performs an exhaustiveness check on the given type switch
+// statement. If the type switch is used on a sum type and does not cover
+// all variants of that sum type, then an error is returned indicating which
+// variants were missed.
+//
+// Note that if the type switch contains a non-panicing default case, then
+// exhaustiveness checks are disabled.
+func checkSwitch(
+ pkg *packages.Package,
+ defs []sumTypeDef,
+ swtch *ast.TypeSwitchStmt,
+) error {
+ def, missing := missingVariantsInSwitch(pkg, defs, swtch)
+ if len(missing) > 0 {
+ return inexhaustiveError{
+ Position: pkg.Fset.Position(swtch.Pos()),
+ Def: *def,
+ Missing: missing,
+ }
+ }
+ return nil
+}
+
+// missingVariantsInSwitch returns a list of missing variants corresponding to
+// the given switch statement. The corresponding sum type definition is also
+// returned. (If no sum type definition could be found, then no exhaustiveness
+// checks are performed, and therefore, no missing variants are returned.)
+func missingVariantsInSwitch(
+ pkg *packages.Package,
+ defs []sumTypeDef,
+ swtch *ast.TypeSwitchStmt,
+) (*sumTypeDef, []types.Object) {
+ asserted := findTypeAssertExpr(swtch)
+ ty := pkg.TypesInfo.TypeOf(asserted)
+ def := findDef(defs, ty)
+ if def == nil {
+ // We couldn't find a corresponding sum type, so there's
+ // nothing we can do to check it.
+ return nil, nil
+ }
+ variantExprs, hasDefault := switchVariants(swtch)
+ if hasDefault && !defaultClauseAlwaysPanics(swtch) {
+ // A catch-all case defeats all exhaustiveness checks.
+ return def, nil
+ }
+ var variantTypes []types.Type
+ for _, expr := range variantExprs {
+ variantTypes = append(variantTypes, pkg.TypesInfo.TypeOf(expr))
+ }
+ return def, def.missing(variantTypes)
+}
+
+// switchVariants returns all case expressions found in a type switch. This
+// includes expressions from cases that have a list of expressions.
+func switchVariants(swtch *ast.TypeSwitchStmt) (exprs []ast.Expr, hasDefault bool) {
+ for _, stmt := range swtch.Body.List {
+ clause := stmt.(*ast.CaseClause)
+ if clause.List == nil {
+ hasDefault = true
+ } else {
+ exprs = append(exprs, clause.List...)
+ }
+ }
+ return
+}
+
+// defaultClauseAlwaysPanics returns true if the given switch statement has a
+// default clause that always panics. Note that this is done on a best-effort
+// basis. While there will never be any false positives, there may be false
+// negatives.
+//
+// If the given switch statement has no default clause, then this function
+// panics.
+func defaultClauseAlwaysPanics(swtch *ast.TypeSwitchStmt) bool {
+ var clause *ast.CaseClause
+ for _, stmt := range swtch.Body.List {
+ c := stmt.(*ast.CaseClause)
+ if c.List == nil {
+ clause = c
+ break
+ }
+ }
+ if clause == nil {
+ panic("switch statement has no default clause")
+ }
+ if len(clause.Body) != 1 {
+ return false
+ }
+ exprStmt, ok := clause.Body[0].(*ast.ExprStmt)
+ if !ok {
+ return false
+ }
+ callExpr, ok := exprStmt.X.(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+ fun, ok := callExpr.Fun.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ return fun.Name == "panic"
+}
+
+// findTypeAssertExpr extracts the expression that is being type asserted from a
+// type swtich statement.
+func findTypeAssertExpr(swtch *ast.TypeSwitchStmt) ast.Expr {
+ var expr ast.Expr
+ if assign, ok := swtch.Assign.(*ast.AssignStmt); ok {
+ expr = assign.Rhs[0]
+ } else {
+ expr = swtch.Assign.(*ast.ExprStmt).X
+ }
+ return expr.(*ast.TypeAssertExpr).X
+}
+
+// findDef returns the sum type definition corresponding to the given type. If
+// no such sum type definition exists, then nil is returned.
+func findDef(defs []sumTypeDef, needle types.Type) *sumTypeDef {
+ for i := range defs {
+ def := &defs[i]
+ if types.Identical(needle.Underlying(), def.Ty) {
+ return def
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/decl.go b/vendor/github.com/alecthomas/go-check-sumtype/decl.go
new file mode 100644
index 0000000000..ea2cd06dfa
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/decl.go
@@ -0,0 +1,68 @@
+package gochecksumtype
+
+import (
+ "go/ast"
+ "go/token"
+ "strings"
+
+ "golang.org/x/tools/go/packages"
+)
+
+// sumTypeDecl is a declaration of a sum type in a Go source file.
+type sumTypeDecl struct {
+ // The package path that contains this decl.
+ Package *packages.Package
+ // The type named by this decl.
+ TypeName string
+ // Position where the declaration was found.
+ Pos token.Position
+}
+
+// Location returns a short string describing where this declaration was found.
+func (d sumTypeDecl) Location() string {
+ return d.Pos.String()
+}
+
+// findSumTypeDecls searches every package given for sum type declarations of
+// the form `sumtype:decl`.
+func findSumTypeDecls(pkgs []*packages.Package) ([]sumTypeDecl, error) {
+ var decls []sumTypeDecl
+ var retErr error
+ for _, pkg := range pkgs {
+ for _, file := range pkg.Syntax {
+ ast.Inspect(file, func(node ast.Node) bool {
+ if node == nil {
+ return true
+ }
+ decl, ok := node.(*ast.GenDecl)
+ if !ok || decl.Doc == nil {
+ return true
+ }
+ var tspec *ast.TypeSpec
+ for _, spec := range decl.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ tspec = ts
+ }
+ for _, line := range decl.Doc.List {
+ if !strings.HasPrefix(line.Text, "//sumtype:decl") {
+ continue
+ }
+ pos := pkg.Fset.Position(decl.Pos())
+ if tspec == nil {
+ retErr = notFoundError{Decl: sumTypeDecl{Package: pkg, Pos: pos}}
+ return false
+ }
+ pos = pkg.Fset.Position(tspec.Pos())
+ decl := sumTypeDecl{Package: pkg, TypeName: tspec.Name.Name, Pos: pos}
+ decls = append(decls, decl)
+ break
+ }
+ return true
+ })
+ }
+ }
+ return decls, retErr
+}
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/def.go b/vendor/github.com/alecthomas/go-check-sumtype/def.go
new file mode 100644
index 0000000000..811b98f98c
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/def.go
@@ -0,0 +1,157 @@
+package gochecksumtype
+
+import (
+ "fmt"
+ "go/token"
+ "go/types"
+)
+
+// Error as returned by Run()
+type Error interface {
+ error
+ Pos() token.Position
+}
+
+// unsealedError corresponds to a declared sum type whose interface is not
+// sealed. A sealed interface requires at least one unexported method.
+type unsealedError struct {
+ Decl sumTypeDecl
+}
+
+func (e unsealedError) Pos() token.Position { return e.Decl.Pos }
+func (e unsealedError) Error() string {
+ return fmt.Sprintf(
+ "%s: interface '%s' is not sealed "+
+ "(sealing requires at least one unexported method)",
+ e.Decl.Location(), e.Decl.TypeName)
+}
+
+// notFoundError corresponds to a declared sum type whose type definition
+// could not be found in the same Go package.
+type notFoundError struct {
+ Decl sumTypeDecl
+}
+
+func (e notFoundError) Pos() token.Position { return e.Decl.Pos }
+func (e notFoundError) Error() string {
+ return fmt.Sprintf("%s: type '%s' is not defined", e.Decl.Location(), e.Decl.TypeName)
+}
+
+// notInterfaceError corresponds to a declared sum type that does not
+// correspond to an interface.
+type notInterfaceError struct {
+ Decl sumTypeDecl
+}
+
+func (e notInterfaceError) Pos() token.Position { return e.Decl.Pos }
+func (e notInterfaceError) Error() string {
+ return fmt.Sprintf("%s: type '%s' is not an interface", e.Decl.Location(), e.Decl.TypeName)
+}
+
+// sumTypeDef corresponds to the definition of a Go interface that is
+// interpreted as a sum type. Its variants are determined by finding all types
+// that implement said interface in the same package.
+type sumTypeDef struct {
+ Decl sumTypeDecl
+ Ty *types.Interface
+ Variants []types.Object
+}
+
+// findSumTypeDefs attempts to find a Go type definition for each of the given
+// sum type declarations. If no such sum type definition could be found for
+// any of the given declarations, then an error is returned.
+func findSumTypeDefs(decls []sumTypeDecl) ([]sumTypeDef, []error) {
+ var defs []sumTypeDef
+ var errs []error
+ for _, decl := range decls {
+ def, err := newSumTypeDef(decl.Package.Types, decl)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+ if def == nil {
+ errs = append(errs, notFoundError{decl})
+ continue
+ }
+ defs = append(defs, *def)
+ }
+ return defs, errs
+}
+
+// newSumTypeDef attempts to extract a sum type definition from a single
+// package. If no such type corresponds to the given decl, then this function
+// returns a nil def and a nil error.
+//
+// If the decl corresponds to a type that isn't an interface containing at
+// least one unexported method, then this returns an error.
+func newSumTypeDef(pkg *types.Package, decl sumTypeDecl) (*sumTypeDef, error) {
+ obj := pkg.Scope().Lookup(decl.TypeName)
+ if obj == nil {
+ return nil, nil
+ }
+ iface, ok := obj.Type().Underlying().(*types.Interface)
+ if !ok {
+ return nil, notInterfaceError{decl}
+ }
+ hasUnexported := false
+ for i := 0; i < iface.NumMethods(); i++ {
+ if !iface.Method(i).Exported() {
+ hasUnexported = true
+ break
+ }
+ }
+ if !hasUnexported {
+ return nil, unsealedError{decl}
+ }
+ def := &sumTypeDef{
+ Decl: decl,
+ Ty: iface,
+ }
+ for _, name := range pkg.Scope().Names() {
+ obj, ok := pkg.Scope().Lookup(name).(*types.TypeName)
+ if !ok {
+ continue
+ }
+ ty := obj.Type()
+ if types.Identical(ty.Underlying(), iface) {
+ continue
+ }
+ if types.Implements(ty, iface) || types.Implements(types.NewPointer(ty), iface) {
+ def.Variants = append(def.Variants, obj)
+ }
+ }
+ return def, nil
+}
+
+func (def *sumTypeDef) String() string {
+ return def.Decl.TypeName
+}
+
+// missing returns a list of variants in this sum type that are not in the
+// given list of types.
+func (def *sumTypeDef) missing(tys []types.Type) []types.Object {
+ // TODO(ag): This is O(n^2). Fix that. /shrug
+ var missing []types.Object
+ for _, v := range def.Variants {
+ found := false
+ varty := indirect(v.Type())
+ for _, ty := range tys {
+ ty = indirect(ty)
+ if types.Identical(varty, ty) {
+ found = true
+ }
+ }
+ if !found {
+ missing = append(missing, v)
+ }
+ }
+ return missing
+}
+
+// indirect dereferences through an arbitrary number of pointer types.
+func indirect(ty types.Type) types.Type {
+ if ty, ok := ty.(*types.Pointer); ok {
+ return indirect(ty.Elem())
+ }
+ return ty
+}
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/doc.go b/vendor/github.com/alecthomas/go-check-sumtype/doc.go
new file mode 100644
index 0000000000..2b6e86764e
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/doc.go
@@ -0,0 +1,53 @@
+/*
+sumtype takes a list of Go package paths or files and looks for sum type
+declarations in each package/file provided. Exhaustiveness checks are then
+performed for each use of a declared sum type in a type switch statement.
+Namely, sumtype will report an error for any type switch statement that
+either lacks a default clause or does not account for all possible variants.
+
+Declarations are provided in comments like so:
+
+ //sumtype:decl
+ type MySumType interface { ... }
+
+MySumType must be *sealed*. That is, part of its interface definition contains
+an unexported method.
+
+sumtype will produce an error if any of the above is not true.
+
+For valid declarations, sumtype will look for all occurrences in which a
+value of type MySumType participates in a type switch statement. In those
+occurrences, it will attempt to detect whether the type switch is exhaustive
+or not. If it's not, sumtype will report an error. For example:
+
+ $ cat mysumtype.go
+ package gochecksumtype
+
+ //sumtype:decl
+ type MySumType interface {
+ sealed()
+ }
+
+ type VariantA struct{}
+
+ func (a *VariantA) sealed() {}
+
+ type VariantB struct{}
+
+ func (b *VariantB) sealed() {}
+
+ func main() {
+ switch MySumType(nil).(type) {
+ case *VariantA:
+ }
+ }
+ $ sumtype mysumtype.go
+ mysumtype.go:18:2: exhaustiveness check failed for sum type 'MySumType': missing cases for VariantB
+
+Adding either a default clause or a clause to handle *VariantB will cause
+exhaustive checks to pass.
+
+As a special case, if the type switch statement contains a default clause
+that always panics, then exhaustiveness checks are still performed.
+*/
+package gochecksumtype
diff --git a/vendor/github.com/alecthomas/go-check-sumtype/run.go b/vendor/github.com/alecthomas/go-check-sumtype/run.go
new file mode 100644
index 0000000000..fdcb643c5d
--- /dev/null
+++ b/vendor/github.com/alecthomas/go-check-sumtype/run.go
@@ -0,0 +1,26 @@
+package gochecksumtype
+
+import "golang.org/x/tools/go/packages"
+
+// Run sumtype checking on the given packages.
+func Run(pkgs []*packages.Package) []error {
+ var errs []error
+
+ decls, err := findSumTypeDecls(pkgs)
+ if err != nil {
+ return []error{err}
+ }
+
+ defs, defErrs := findSumTypeDefs(decls)
+ errs = append(errs, defErrs...)
+ if len(defs) == 0 {
+ return errs
+ }
+
+ for _, pkg := range pkgs {
+ if pkgErrs := check(pkg, defs); pkgErrs != nil {
+ errs = append(errs, pkgErrs...)
+ }
+ }
+ return errs
+}
diff --git a/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go b/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go
index 2e1e899349..f1bf20faba 100644
--- a/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go
+++ b/vendor/github.com/breml/bidichk/pkg/bidichk/bidichk.go
@@ -15,7 +15,7 @@ import (
const (
doc = "bidichk detects dangerous unicode character sequences"
- disallowedDoc = `coma separated list of disallowed runes (full name or short name)
+ disallowedDoc = `comma separated list of disallowed runes (full name or short name)
Supported runes
diff --git a/vendor/github.com/breml/errchkjson/.goreleaser.yml b/vendor/github.com/breml/errchkjson/.goreleaser.yml
index 5f23690f15..a05c172cb6 100644
--- a/vendor/github.com/breml/errchkjson/.goreleaser.yml
+++ b/vendor/github.com/breml/errchkjson/.goreleaser.yml
@@ -14,13 +14,14 @@ builds:
- windows
- darwin
archives:
- - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
- replacements:
- darwin: Darwin
- linux: Linux
- windows: Windows
- 386: i386
- amd64: x86_64
+ - name_template: >-
+ {{- .Binary }}_
+ {{- .Version }}_
+ {{- title .Os }}_
+ {{- if eq .Arch "amd64" }}x86_64
+ {{- else if eq .Arch "386" }}i386
+ {{- else }}{{ .Arch }}{{ end }}
+ {{- if .Arm }}v{{ .Arm }}{{ end -}}
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
diff --git a/vendor/github.com/breml/errchkjson/errchkjson.go b/vendor/github.com/breml/errchkjson/errchkjson.go
index 746709c763..4a23929cf2 100644
--- a/vendor/github.com/breml/errchkjson/errchkjson.go
+++ b/vendor/github.com/breml/errchkjson/errchkjson.go
@@ -308,14 +308,14 @@ func (e *errchkjson) inspectArgs(pass *analysis.Pass, args []ast.Expr) {
}
// Construct *types.Interface for interface encoding.TextMarshaler
-// type TextMarshaler interface {
-// MarshalText() (text []byte, err error)
-// }
//
+// type TextMarshaler interface {
+// MarshalText() (text []byte, err error)
+// }
func textMarshalerInterface() *types.Interface {
textMarshalerInterface := types.NewInterfaceType([]*types.Func{
- types.NewFunc(token.NoPos, nil, "MarshalText", types.NewSignature(
- nil, nil, types.NewTuple(
+ types.NewFunc(token.NoPos, nil, "MarshalText", types.NewSignatureType(
+ nil, nil, nil, nil, types.NewTuple(
types.NewVar(token.NoPos, nil, "text",
types.NewSlice(
types.Universe.Lookup("byte").Type())),
@@ -328,14 +328,14 @@ func textMarshalerInterface() *types.Interface {
}
// Construct *types.Interface for interface json.Marshaler
-// type Marshaler interface {
-// MarshalJSON() ([]byte, error)
-// }
//
+// type Marshaler interface {
+// MarshalJSON() ([]byte, error)
+// }
func jsonMarshalerInterface() *types.Interface {
textMarshalerInterface := types.NewInterfaceType([]*types.Func{
- types.NewFunc(token.NoPos, nil, "MarshalJSON", types.NewSignature(
- nil, nil, types.NewTuple(
+ types.NewFunc(token.NoPos, nil, "MarshalJSON", types.NewSignatureType(
+ nil, nil, nil, nil, types.NewTuple(
types.NewVar(token.NoPos, nil, "",
types.NewSlice(
types.Universe.Lookup("byte").Type())),
diff --git a/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go b/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go
index 3a0bf7402d..21e5897b26 100644
--- a/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go
+++ b/vendor/github.com/butuzov/ireturn/analyzer/analyzer.go
@@ -23,6 +23,7 @@ type validator interface {
type analyzer struct {
once sync.Once
+ mu sync.RWMutex
handler validator
err error
@@ -83,11 +84,13 @@ func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {
}
seen[key] = true
- a.found = append(a.found, issue.ExportDiagnostic())
+ a.addDiagnostic(issue.ExportDiagnostic())
}
})
// 02. Printing reports.
+ a.mu.RLock()
+ defer a.mu.RUnlock()
for i := range a.found {
pass.Report(a.found[i])
}
@@ -95,6 +98,13 @@ func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
+func (a *analyzer) addDiagnostic(d analysis.Diagnostic) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ a.found = append(a.found, d)
+}
+
func (a *analyzer) readConfiguration(fs *flag.FlagSet) {
cnf, err := config.New(fs)
if err != nil {
diff --git a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/config.go b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/config.go
index e2f1aef6e9..46c73170ae 100644
--- a/vendor/github.com/butuzov/ireturn/analyzer/internal/config/config.go
+++ b/vendor/github.com/butuzov/ireturn/analyzer/internal/config/config.go
@@ -2,6 +2,7 @@ package config
import (
"regexp"
+ "sync"
"github.com/butuzov/ireturn/analyzer/internal/types"
)
@@ -13,16 +14,13 @@ type defaultConfig struct {
List []string
// private fields (for search optimization look ups)
- init bool
+ once sync.Once
quick uint8
list []*regexp.Regexp
}
func (config *defaultConfig) Has(i types.IFace) bool {
- if !config.init {
- config.compileList()
- config.init = true
- }
+ config.once.Do(config.compileList)
if config.quick&uint8(i.Type) > 0 {
return true
diff --git a/vendor/github.com/butuzov/ireturn/analyzer/std.go b/vendor/github.com/butuzov/ireturn/analyzer/std.go
index ec361cd442..4c6c4e4204 100644
--- a/vendor/github.com/butuzov/ireturn/analyzer/std.go
+++ b/vendor/github.com/butuzov/ireturn/analyzer/std.go
@@ -191,4 +191,10 @@ var std = map[string]struct{}{
// added in Go v1.20 in compare to v1.19 (docker image)
"crypto/ecdh": {},
"runtime/coverage": {},
+ // added in Go v1.21 in compare to v1.20 (docker image)
+ "cmp": {},
+ "log/slog": {},
+ "maps": {},
+ "slices": {},
+ "testing/slogtest": {},
}
diff --git a/vendor/github.com/catenacyber/perfsprint/LICENSE b/vendor/github.com/catenacyber/perfsprint/LICENSE
new file mode 100644
index 0000000000..14c2b9e737
--- /dev/null
+++ b/vendor/github.com/catenacyber/perfsprint/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Catena cyber
+
+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.
diff --git a/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go b/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go
new file mode 100644
index 0000000000..69087802a7
--- /dev/null
+++ b/vendor/github.com/catenacyber/perfsprint/analyzer/analyzer.go
@@ -0,0 +1,333 @@
+package analyzer
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/token"
+ "go/types"
+ "strconv"
+
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "perfsprint",
+ Doc: "Checks that fmt.Sprintf can be replaced with a faster alternative.",
+ Run: run,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ var fmtSprintObj, fmtSprintfObj types.Object
+ for _, pkg := range pass.Pkg.Imports() {
+ if pkg.Path() == "fmt" {
+ fmtSprintObj = pkg.Scope().Lookup("Sprint")
+ fmtSprintfObj = pkg.Scope().Lookup("Sprintf")
+ }
+ }
+ if fmtSprintfObj == nil {
+ return nil, nil
+ }
+
+ insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ nodeFilter := []ast.Node{
+ (*ast.CallExpr)(nil),
+ }
+ insp.Preorder(nodeFilter, func(node ast.Node) {
+ call := node.(*ast.CallExpr)
+ called, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ calledObj := pass.TypesInfo.ObjectOf(called.Sel)
+
+ var (
+ fn string
+ verb string
+ value ast.Expr
+ err error
+ )
+ switch {
+ case calledObj == fmtSprintObj && len(call.Args) == 1:
+ fn = "fmt.Sprint"
+ verb = "%v"
+ value = call.Args[0]
+
+ case calledObj == fmtSprintfObj && len(call.Args) == 2:
+ verbLit, ok := call.Args[0].(*ast.BasicLit)
+ if !ok {
+ return
+ }
+ verb, err = strconv.Unquote(verbLit.Value)
+ if err != nil {
+ // Probably unreachable.
+ return
+ }
+
+ fn = "fmt.Sprintf"
+ value = call.Args[1]
+
+ default:
+ return
+ }
+
+ switch verb {
+ default:
+ return
+ case "%d", "%v", "%x", "%t", "%s":
+ }
+
+ valueType := pass.TypesInfo.TypeOf(value)
+ a, isArray := valueType.(*types.Array)
+ s, isSlice := valueType.(*types.Slice)
+
+ var d *analysis.Diagnostic
+ switch {
+ case isBasicType(valueType, types.String) && oneOf(verb, "%v", "%s"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with just using the string",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Just use string value",
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Pos(),
+ End: call.End(),
+ NewText: []byte(formatNode(pass.Fset, value)),
+ }},
+ },
+ },
+ }
+
+ case types.Implements(valueType, errIface) && oneOf(verb, "%v", "%s"):
+ errMethodCall := formatNode(pass.Fset, value) + ".Error()"
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with " + errMethodCall,
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use " + errMethodCall,
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Pos(),
+ End: call.End(),
+ NewText: []byte(errMethodCall),
+ }},
+ },
+ },
+ }
+
+ case isBasicType(valueType, types.Bool) && oneOf(verb, "%v", "%t"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.FormatBool",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.FormatBool",
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.FormatBool("),
+ }},
+ },
+ },
+ }
+
+ case isArray && isBasicType(a.Elem(), types.Uint8) && oneOf(verb, "%x"):
+ if _, ok := value.(*ast.Ident); !ok {
+ // Doesn't support array literals.
+ return
+ }
+
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster hex.EncodeToString",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use hex.EncodeToString",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("hex.EncodeToString("),
+ },
+ {
+ Pos: value.End(),
+ End: value.End(),
+ NewText: []byte("[:]"),
+ },
+ },
+ },
+ },
+ }
+ case isSlice && isBasicType(s.Elem(), types.Uint8) && oneOf(verb, "%x"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster hex.EncodeToString",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use hex.EncodeToString",
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("hex.EncodeToString("),
+ }},
+ },
+ },
+ }
+
+ case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.Itoa",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.Itoa",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.Itoa(int("),
+ },
+ {
+ Pos: value.End(),
+ End: value.End(),
+ NewText: []byte(")"),
+ },
+ },
+ },
+ },
+ }
+ case isBasicType(valueType, types.Int) && oneOf(verb, "%v", "%d"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.Itoa",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.Itoa",
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.Itoa("),
+ }},
+ },
+ },
+ }
+ case isBasicType(valueType, types.Int64) && oneOf(verb, "%v", "%d"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.FormatInt",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.FormatInt",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.FormatInt("),
+ },
+ {
+ Pos: value.End(),
+ End: value.End(),
+ NewText: []byte(", 10"),
+ },
+ },
+ },
+ },
+ }
+
+ case isBasicType(valueType, types.Uint8, types.Uint16, types.Uint32, types.Uint) && oneOf(verb, "%v", "%d"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.FormatUint",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.FormatUint",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.FormatUint(uint64("),
+ },
+ {
+ Pos: value.End(),
+ End: value.End(),
+ NewText: []byte("), 10"),
+ },
+ },
+ },
+ },
+ }
+ case isBasicType(valueType, types.Uint64) && oneOf(verb, "%v", "%d"):
+ d = &analysis.Diagnostic{
+ Pos: call.Pos(),
+ End: call.End(),
+ Message: fn + " can be replaced with faster strconv.FormatUint",
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: "Use strconv.FormatUint",
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: call.Pos(),
+ End: value.Pos(),
+ NewText: []byte("strconv.FormatUint("),
+ },
+ {
+ Pos: value.End(),
+ End: value.End(),
+ NewText: []byte(", 10"),
+ },
+ },
+ },
+ },
+ }
+ }
+
+ if d != nil {
+ // Need to run goimports to fix using of fmt, strconv or encoding/hex afterwards.
+ pass.Report(*d)
+ }
+ })
+
+ return nil, nil
+}
+
+var errIface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+func isBasicType(lhs types.Type, expected ...types.BasicKind) bool {
+ for _, rhs := range expected {
+ if types.Identical(lhs, types.Typ[rhs]) {
+ return true
+ }
+ }
+ return false
+}
+
+func formatNode(fset *token.FileSet, node ast.Node) string {
+ buf := new(bytes.Buffer)
+ if err := format.Node(buf, fset, node); err != nil {
+ return ""
+ }
+ return buf.String()
+}
+
+func oneOf[T comparable](v T, expected ...T) bool {
+ for _, rhs := range expected {
+ if v == rhs {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/chavacava/garif/enums.go b/vendor/github.com/chavacava/garif/enums.go
new file mode 100644
index 0000000000..dea2daf131
--- /dev/null
+++ b/vendor/github.com/chavacava/garif/enums.go
@@ -0,0 +1,41 @@
+package garif
+
+type ResultKind string
+
+// declare JSON values
+const (
+ _pass ResultKind = "pass"
+ _open ResultKind = "open"
+ _informational ResultKind = "informational"
+ _notApplicable ResultKind = "notApplicable"
+ _review ResultKind = "review"
+ _fail ResultKind = "fail"
+)
+
+// create public visible constants with a namespace as enums
+const (
+ ResultKind_Pass ResultKind = _pass
+ ResultKind_Open ResultKind = _open
+ ResultKind_Informational ResultKind = _informational
+ ResultKind_NotApplicable ResultKind = _notApplicable
+ ResultKind_Review ResultKind = _review
+ ResultKind_Fail ResultKind = _fail
+)
+
+type ResultLevel string
+
+// declare JSON values
+const (
+ _warning ResultLevel = "warning"
+ _error ResultLevel = "error"
+ _note ResultLevel = "note"
+ _none ResultLevel = "none"
+)
+
+// create public visible constants with a namespace as enums
+const (
+ ResultLevel_Warning ResultLevel = _warning
+ ResultLevel_Error ResultLevel = _error
+ ResultLevel_Note ResultLevel = _note
+ ResultLevel_None ResultLevel = _none
+)
diff --git a/vendor/github.com/chavacava/garif/models.go b/vendor/github.com/chavacava/garif/models.go
index 3668436a3c..f16a86136e 100644
--- a/vendor/github.com/chavacava/garif/models.go
+++ b/vendor/github.com/chavacava/garif/models.go
@@ -935,10 +935,10 @@ type Result struct {
HostedViewerUri string `json:"hostedViewerUri,omitempty"`
// A value that categorizes results by evaluation state.
- Kind interface{} `json:"kind,omitempty"`
+ Kind ResultKind `json:"kind,omitempty"`
// A value specifying the severity level of the result.
- Level interface{} `json:"level,omitempty"`
+ Level ResultLevel `json:"level,omitempty"`
// The set of locations where the result was detected. Specify only one location unless the problem indicated by the result can only be corrected by making a change at every specified location.
Locations []*Location `json:"locations,omitempty"`
diff --git a/vendor/github.com/daixiang0/gci/pkg/config/config.go b/vendor/github.com/daixiang0/gci/pkg/config/config.go
index 120e787e91..98513c056a 100644
--- a/vendor/github.com/daixiang0/gci/pkg/config/config.go
+++ b/vendor/github.com/daixiang0/gci/pkg/config/config.go
@@ -1,7 +1,6 @@
package config
import (
- "io/ioutil"
"sort"
"strings"
@@ -73,19 +72,18 @@ func (g YamlConfig) Parse() (*Config, error) {
return &Config{g.Cfg, sections, sectionSeparators}, nil
}
-func InitializeGciConfigFromYAML(filePath string) (*Config, error) {
+func ParseConfig(in string) (*Config, error) {
config := YamlConfig{}
- yamlData, err := ioutil.ReadFile(filePath)
- if err != nil {
- return nil, err
- }
- err = yaml.Unmarshal(yamlData, &config)
+
+ err := yaml.Unmarshal([]byte(in), &config)
if err != nil {
return nil, err
}
+
gciCfg, err := config.Parse()
if err != nil {
return nil, err
}
+
return gciCfg, nil
}
diff --git a/vendor/github.com/daixiang0/gci/pkg/gci/gci.go b/vendor/github.com/daixiang0/gci/pkg/gci/gci.go
index e84a166761..163e95a861 100644
--- a/vendor/github.com/daixiang0/gci/pkg/gci/gci.go
+++ b/vendor/github.com/daixiang0/gci/pkg/gci/gci.go
@@ -127,11 +127,17 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err
return nil, nil, err
}
+ return LoadFormat(src, file.Path(), cfg)
+}
+
+func LoadFormat(in []byte, path string, cfg config.Config) (src, dist []byte, err error) {
+ src = in
+
if cfg.SkipGenerated && parse.IsGeneratedFileByComment(string(src)) {
return src, src, nil
}
- imports, headEnd, tailStart, cStart, cEnd, err := parse.ParseFile(src, file.Path())
+ imports, headEnd, tailStart, cStart, cEnd, err := parse.ParseFile(src, path)
if err != nil {
if errors.Is(err, parse.NoImportError{}) {
return src, src, nil
@@ -201,6 +207,10 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err
for _, s := range slices {
i += copy(dist[i:], s)
}
+
+ // remove ^M(\r\n) from Win to Unix
+ dist = bytes.ReplaceAll(dist, []byte{utils.WinLinebreak}, []byte{utils.Linebreak})
+
log.L().Debug(fmt.Sprintf("raw:\n%s", dist))
dist, err = goFormat.Source(dist)
if err != nil {
diff --git a/vendor/github.com/daixiang0/gci/pkg/gci/testdata.go b/vendor/github.com/daixiang0/gci/pkg/gci/testdata.go
new file mode 100644
index 0000000000..a48ce356c8
--- /dev/null
+++ b/vendor/github.com/daixiang0/gci/pkg/gci/testdata.go
@@ -0,0 +1,1245 @@
+package gci
+
+type Cases struct {
+ name, config, in, out string
+}
+
+var commonConfig = `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`
+
+var testCases = []Cases{
+ {
+ "already-good",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "blank-format",
+
+ commonConfig,
+
+ `package main
+import (
+ "fmt"
+
+ // comment
+ g "github.com/golang" // comment
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ // comment
+ g "github.com/golang" // comment
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "cgo-block",
+
+ commonConfig,
+
+ `package main
+
+import (
+ /*
+ #include "types.h"
+ */
+ "C"
+)
+`,
+ `package main
+
+import (
+ /*
+ #include "types.h"
+ */
+ "C"
+)
+`,
+ },
+ {
+ "cgo-block-after-import",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+
+ "github.com/daixiang0/gci"
+ g "github.com/golang"
+)
+
+// #cgo CFLAGS: -DPNG_DEBUG=1
+// #cgo amd64 386 CFLAGS: -DX86=1
+// #cgo LDFLAGS: -lpng
+// #include
+import "C"
+`,
+ `package main
+
+// #cgo CFLAGS: -DPNG_DEBUG=1
+// #cgo amd64 386 CFLAGS: -DX86=1
+// #cgo LDFLAGS: -lpng
+// #include
+import "C"
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "cgo-block-before-import",
+
+ commonConfig,
+
+ `package main
+
+// #cgo CFLAGS: -DPNG_DEBUG=1
+// #cgo amd64 386 CFLAGS: -DX86=1
+// #cgo LDFLAGS: -lpng
+// #include
+import "C"
+
+import (
+ "fmt"
+
+ "github.com/daixiang0/gci"
+
+ g "github.com/golang"
+)
+`,
+ `package main
+
+// #cgo CFLAGS: -DPNG_DEBUG=1
+// #cgo amd64 386 CFLAGS: -DX86=1
+// #cgo LDFLAGS: -lpng
+// #include
+import "C"
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "cgo-block-mixed",
+
+ commonConfig,
+
+ `package main
+
+import (
+ /* #include "types.h"
+ */"C"
+)
+`,
+ `package main
+
+import (
+ /* #include "types.h"
+ */"C"
+)
+`,
+ },
+ {
+ "cgo-block-mixed-with-content",
+
+ commonConfig,
+
+ `package main
+
+import (
+ /* #include "types.h"
+ #include "other.h" */"C"
+)
+`,
+ `package main
+
+import (
+ /* #include "types.h"
+ #include "other.h" */"C"
+)
+`,
+ },
+ {
+ "cgo-block-prefix",
+
+ commonConfig,
+
+ `package main
+
+import (
+ /* #include "types.h" */ "C"
+)
+`,
+ `package main
+
+import (
+ /* #include "types.h" */ "C"
+)
+`,
+ },
+ {
+ "cgo-block-single-line",
+
+ commonConfig,
+
+ `package main
+
+import (
+ /* #include "types.h" */
+ "C"
+)
+`,
+ `package main
+
+import (
+ /* #include "types.h" */
+ "C"
+)
+`,
+ },
+ {
+ "cgo-line",
+
+ commonConfig,
+
+ `package main
+
+import (
+ // #include "types.h"
+ "C"
+)
+`,
+ `package main
+
+import (
+ // #include "types.h"
+ "C"
+)
+`,
+ },
+ {
+ "cgo-multiline",
+
+ commonConfig,
+
+ `package main
+
+import (
+ // #include "types.h"
+ // #include "other.h"
+ "C"
+)
+`,
+ `package main
+
+import (
+ // #include "types.h"
+ // #include "other.h"
+ "C"
+)
+`,
+ },
+ {
+ "cgo-single",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+
+ "github.com/daixiang0/gci"
+)
+
+import "C"
+
+import "github.com/golang"
+
+import (
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import "C"
+
+import (
+ "fmt"
+
+ "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "comment",
+
+ commonConfig,
+
+ `package main
+import (
+ //Do not forget to run Gci
+ "fmt"
+)
+`,
+ `package main
+import (
+ //Do not forget to run Gci
+ "fmt"
+)
+`,
+ },
+ {
+ "comment-before-import",
+
+ commonConfig,
+
+ `package main
+
+// comment
+import (
+ "fmt"
+ "os"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+// comment
+import (
+ "fmt"
+ "os"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "comment-in-the-tail",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+
+type test int
+
+// test
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+
+type test int
+
+// test
+`,
+ },
+ {
+ "comment-top",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "os" // https://pkg.go.dev/os
+ // https://pkg.go.dev/fmt
+ "fmt"
+)
+`,
+ `package main
+
+import (
+ // https://pkg.go.dev/fmt
+ "fmt"
+ "os" // https://pkg.go.dev/os
+)
+`,
+ },
+ {
+ "comment-whithout-whitespace",
+
+ commonConfig,
+
+ `package proc
+
+import (
+ "context"// no separating whitespace here //nolint:confusion
+)
+`,
+ `package proc
+
+import (
+ "context"// no separating whitespace here //nolint:confusion
+)
+`,
+ },
+ {
+ "comment-with-slashslash",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt" // https://pkg.go.dev/fmt
+)
+`,
+ `package main
+
+import (
+ "fmt" // https://pkg.go.dev/fmt
+)
+`,
+ },
+ {
+ "custom-order",
+
+ `customOrder: true
+sections:
+ - Prefix(github.com/daixiang0)
+ - Default
+ - Standard
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+)
+`,
+ `package main
+
+import (
+ "github.com/daixiang0/a"
+
+ g "github.com/golang"
+
+ "fmt"
+)
+`,
+ },
+ {
+ "default-order",
+
+ `sections:
+ - Standard
+ - Prefix(github.com/daixiang0)
+ - Default
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+)
+`,
+ },
+ {
+ "dot-and-blank",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+ - Blank
+ - Dot
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+ . "github.com/golang/dot"
+ _ "github.com/golang/blank"
+
+ "github.com/daixiang0/a"
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+ . "github.com/daixiang0/gci/dot"
+ _ "github.com/daixiang0/gci/blank"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+
+ _ "github.com/daixiang0/gci/blank"
+ _ "github.com/golang/blank"
+
+ . "github.com/daixiang0/gci/dot"
+ . "github.com/golang/dot"
+)
+`,
+ },
+ {
+ "duplicate-imports",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ a "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ a "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "grouped-multiple-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0)
+`,
+ `package main
+
+import (
+ "daixiang0/lib1"
+ "fmt"
+ "github.com/daixiang0/gci"
+ "gitlab.com/daixiang0/gci"
+ g "github.com/golang"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "daixiang0/lib1"
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+ "gitlab.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "leading-comment",
+
+ commonConfig,
+
+ `package main
+
+import (
+ // foo
+ "fmt"
+)
+`,
+ `package main
+
+import (
+ // foo
+ "fmt"
+)
+`,
+ },
+ {
+ "linebreak",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`,
+ `package main
+
+import (
+ g "github.com/golang"
+
+ "fmt"
+
+ "github.com/daixiang0/gci"
+
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "linebreak-no-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`,
+ `package main
+
+import (
+ g "github.com/golang"
+
+ "fmt"
+
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+)
+`,
+ },
+ {
+ "mismatch-section",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+ - Prefix(github.com/daixiang0/gci)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "multiple-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+ - Prefix(github.com/daixiang0/gci)
+ - Prefix(github.com/daixiang0/gci/subtest)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/a"
+
+ "github.com/daixiang0/gci"
+
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ },
+ {
+ "multiple-imports",
+
+ commonConfig,
+
+ `package main
+
+import "fmt"
+
+import "context"
+
+import (
+ "os"
+
+ "github.com/daixiang0/test"
+)
+
+import "math"
+
+
+// main
+func main() {
+}
+`,
+ `package main
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "os"
+
+ "github.com/daixiang0/test"
+)
+
+// main
+func main() {
+}
+`,
+ },
+ {
+ "multiple-line-comment",
+
+ commonConfig,
+
+ `package proc
+
+import (
+ "context" // in-line comment
+ "fmt"
+ "os"
+
+ //nolint:depguard // A multi-line comment explaining why in
+ // this one case it's OK to use os/exec even though depguard
+ // is configured to force us to use dlib/exec instead.
+ "os/exec"
+
+ "golang.org/x/sys/unix"
+ "github.com/local/dlib/dexec"
+)
+`,
+ `package proc
+
+import (
+ "context" // in-line comment
+ "fmt"
+ "os"
+ //nolint:depguard // A multi-line comment explaining why in
+ // this one case it's OK to use os/exec even though depguard
+ // is configured to force us to use dlib/exec instead.
+ "os/exec"
+
+ "github.com/local/dlib/dexec"
+ "golang.org/x/sys/unix"
+)
+`,
+ },
+ {
+ "nochar-after-import",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+)
+`,
+ },
+ {
+ "no-format",
+
+ commonConfig,
+
+ `package main
+
+import(
+"fmt"
+
+g "github.com/golang"
+
+"github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "nolint",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+
+ "github.com/forbidden/pkg" //nolint:depguard
+
+ _ "github.com/daixiang0/gci" //nolint:depguard
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ "github.com/forbidden/pkg" //nolint:depguard
+
+ _ "github.com/daixiang0/gci" //nolint:depguard
+)
+`,
+ },
+ {
+ "number-in-alias",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+
+ go_V1 "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ go_V1 "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "one-import",
+
+ commonConfig,
+
+ `package main
+import (
+ "fmt"
+)
+
+func main() {
+}
+`,
+ `package main
+import (
+ "fmt"
+)
+
+func main() {
+}
+`,
+ },
+ {
+ "one-import-one-line",
+
+ commonConfig,
+
+ `package main
+
+import "fmt"
+
+func main() {
+}
+`,
+ `package main
+
+import "fmt"
+
+func main() {
+}
+`,
+ },
+ {
+ "one-line-import-after-import",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0)
+`,
+ `package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/daixiang0/test"
+)
+
+import "context"
+`,
+ `package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/daixiang0/test"
+)
+`,
+ },
+ {
+ "same-prefix-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0/gci)
+ - Prefix(github.com/daixiang0/gci/subtest)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ },
+ {
+ "simple-case",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "golang.org/x/tools"
+
+ "fmt"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ "golang.org/x/tools"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "whitespace-test",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+ "github.com/golang" // golang
+ alias "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ "github.com/golang" // golang
+
+ alias "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "with-above-comment-and-alias",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+ // golang
+ _ "github.com/golang"
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ // golang
+ _ "github.com/golang"
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "with-comment-and-alias",
+
+ commonConfig,
+
+ `package main
+
+import (
+ "fmt"
+ _ "github.com/golang" // golang
+ "github.com/daixiang0/gci"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ _ "github.com/golang" // golang
+
+ "github.com/daixiang0/gci"
+)
+`,
+ },
+ {
+ "same-prefix-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0/gci)
+ - Prefix(github.com/daixiang0/gci/subtest)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ },
+ {
+ "same-prefix-custom",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix(github.com/daixiang0/gci)
+ - Prefix(github.com/daixiang0/gci/subtest)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ },
+ {
+ "blank-in-config",
+
+ `sections:
+ - Standard
+ - Default
+ - Prefix( github.com/daixiang0/gci, github.com/daixiang0/gci/subtest )
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ `package main
+
+import (
+ "fmt"
+
+ g "github.com/golang"
+
+ "github.com/daixiang0/gci"
+ "github.com/daixiang0/gci/subtest"
+)
+`,
+ },
+}
diff --git a/vendor/github.com/daixiang0/gci/pkg/section/prefix.go b/vendor/github.com/daixiang0/gci/pkg/section/prefix.go
index a274347cdd..30bdd8f4ea 100644
--- a/vendor/github.com/daixiang0/gci/pkg/section/prefix.go
+++ b/vendor/github.com/daixiang0/gci/pkg/section/prefix.go
@@ -20,6 +20,7 @@ const CustomType = "custom"
func (c Custom) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
for _, prefix := range strings.Split(c.Prefix, CustomSeparator) {
+ prefix = strings.TrimSpace(prefix)
if strings.HasPrefix(spec.Path, prefix) {
return specificity.Match{Length: len(prefix)}
}
diff --git a/vendor/github.com/daixiang0/gci/pkg/utils/constants.go b/vendor/github.com/daixiang0/gci/pkg/utils/constants.go
index 0e7cce7576..2fafbc32cc 100644
--- a/vendor/github.com/daixiang0/gci/pkg/utils/constants.go
+++ b/vendor/github.com/daixiang0/gci/pkg/utils/constants.go
@@ -1,8 +1,9 @@
package utils
const (
- Indent = '\t'
- Linebreak = '\n'
+ Indent = '\t'
+ Linebreak = '\n'
+ WinLinebreak = '\r'
Colon = ":"
diff --git a/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml b/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml
new file mode 100644
index 0000000000..a70d0fb006
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/.goreleaser.yaml
@@ -0,0 +1,24 @@
+before:
+ hooks:
+ - go mod tidy
+builds:
+ - id: protogetter
+ main: ./cmd/protogetter
+ binary: protogetter
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - linux
+ - windows
+ - darwin
+checksum:
+ name_template: 'checksums.txt'
+snapshot:
+ name_template: "{{ incpatch .Version }}-next"
+changelog:
+ sort: asc
+ filters:
+ exclude:
+ - '^docs:'
+ - '^test:'
+ - '^ci:'
\ No newline at end of file
diff --git a/vendor/github.com/ghostiam/protogetter/LICENSE b/vendor/github.com/ghostiam/protogetter/LICENSE
new file mode 100644
index 0000000000..b4449661b7
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Vladislav Fursov (GhostIAm)
+
+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.
\ No newline at end of file
diff --git a/vendor/github.com/ghostiam/protogetter/Makefile b/vendor/github.com/ghostiam/protogetter/Makefile
new file mode 100644
index 0000000000..af4b62bdf4
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/Makefile
@@ -0,0 +1,9 @@
+.PHONY: test
+test:
+ cd testdata && make vendor
+ go test -v ./...
+
+.PHONY: install
+install:
+ go install ./cmd/protogetter
+ @echo "Installed in $(shell which protogetter)"
diff --git a/vendor/github.com/ghostiam/protogetter/README.md b/vendor/github.com/ghostiam/protogetter/README.md
new file mode 100644
index 0000000000..c033e9597f
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/README.md
@@ -0,0 +1,73 @@
+# Protogetter
+Welcome to the Protogetter project!
+
+## Overview
+Protogetter is a linter developed specifically for Go programmers working with nested `protobuf` types.\
+It's designed to aid developers in preventing `invalid memory address or nil pointer dereference` errors arising from direct access of nested `protobuf` fields.
+
+When working with `protobuf`, it's quite common to have complex structures where a message field is contained within another message, which itself can be part of another message, and so on.
+If these fields are accessed directly and some field in the call chain will not be initialized, it can result in application panic.
+
+Protogetter addresses this issue by suggesting use of getter methods for field access.
+
+## How does it work?
+Protogetter analyzes your Go code and helps detect direct `protobuf` field accesses that could give rise to panic.\
+The linter suggests using getters:
+```go
+m.GetFoo().GetBar().GetBaz()
+```
+instead of direct field access:
+```go
+m.Foo.Bar.Baz
+```
+
+And you will then only need to perform a nil check after the final call:
+```go
+if m.GetFoo().GetBar().GetBaz() != nil {
+ // Do something with m.GetFoo().GetBar().GetBaz()
+}
+```
+instead of:
+```go
+if m.Foo != nil {
+ if m.Foo.Bar != nil {
+ if m.Foo.Bar.Baz != nil {
+ // Do something with m.Foo.Bar.Baz
+ }
+ }
+}
+```
+
+or use zero values:
+
+```go
+// If one of the methods returns `nil` we will receive 0 instead of panic.
+v := m.GetFoo().GetBar().GetBaz().GetInt()
+```
+
+instead of panic:
+
+```go
+// If at least one structure in the chains is not initialized, we will get a panic.
+v := m.Foo.Bar.Baz.Int
+```
+
+which simplifies the code and makes it more reliable.
+
+## Installation
+
+```bash
+go install github.com/ghostiam/protogetter/cmd/protogetter@latest
+```
+
+## Usage
+
+To run the linter:
+```bash
+protogetter ./...
+```
+
+Or to apply suggested fixes directly:
+```bash
+protogetter --fix ./...
+```
diff --git a/vendor/github.com/ghostiam/protogetter/posfilter.go b/vendor/github.com/ghostiam/protogetter/posfilter.go
new file mode 100644
index 0000000000..82075ccb16
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/posfilter.go
@@ -0,0 +1,65 @@
+package protogetter
+
+import (
+ "go/token"
+)
+
+type PosFilter struct {
+ positions map[token.Pos]struct{}
+ alreadyReplaced map[string]map[int][2]int // map[filename][line][start, end]
+}
+
+func NewPosFilter() *PosFilter {
+ return &PosFilter{
+ positions: make(map[token.Pos]struct{}),
+ alreadyReplaced: make(map[string]map[int][2]int),
+ }
+}
+
+func (f *PosFilter) IsFiltered(pos token.Pos) bool {
+ _, ok := f.positions[pos]
+ return ok
+}
+
+func (f *PosFilter) AddPos(pos token.Pos) {
+ f.positions[pos] = struct{}{}
+}
+
+func (f *PosFilter) IsAlreadyReplaced(fset *token.FileSet, pos, end token.Pos) bool {
+ filePos := fset.Position(pos)
+ fileEnd := fset.Position(end)
+
+ lines, ok := f.alreadyReplaced[filePos.Filename]
+ if !ok {
+ return false
+ }
+
+ lineRange, ok := lines[filePos.Line]
+ if !ok {
+ return false
+ }
+
+ if lineRange[0] <= filePos.Offset && fileEnd.Offset <= lineRange[1] {
+ return true
+ }
+
+ return false
+}
+
+func (f *PosFilter) AddAlreadyReplaced(fset *token.FileSet, pos, end token.Pos) {
+ filePos := fset.Position(pos)
+ fileEnd := fset.Position(end)
+
+ lines, ok := f.alreadyReplaced[filePos.Filename]
+ if !ok {
+ lines = make(map[int][2]int)
+ f.alreadyReplaced[filePos.Filename] = lines
+ }
+
+ lineRange, ok := lines[filePos.Line]
+ if ok && lineRange[0] <= filePos.Offset && fileEnd.Offset <= lineRange[1] {
+ return
+ }
+
+ lines[filePos.Line] = [2]int{filePos.Offset, fileEnd.Offset}
+}
diff --git a/vendor/github.com/ghostiam/protogetter/processor.go b/vendor/github.com/ghostiam/protogetter/processor.go
new file mode 100644
index 0000000000..445f136b85
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/processor.go
@@ -0,0 +1,234 @@
+package protogetter
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "reflect"
+ "strings"
+)
+
+type processor struct {
+ info *types.Info
+ filter *PosFilter
+
+ to strings.Builder
+ from strings.Builder
+ err error
+}
+
+func Process(info *types.Info, filter *PosFilter, n ast.Node) (*Result, error) {
+ p := &processor{
+ info: info,
+ filter: filter,
+ }
+
+ return p.process(n)
+}
+
+func (c *processor) process(n ast.Node) (*Result, error) {
+ switch x := n.(type) {
+ case *ast.AssignStmt:
+ // Skip any assignment to the field.
+ for _, lhs := range x.Lhs {
+ c.filter.AddPos(lhs.Pos())
+ }
+
+ case *ast.IncDecStmt:
+ // Skip any increment/decrement to the field.
+ c.filter.AddPos(x.X.Pos())
+
+ case *ast.UnaryExpr:
+ if x.Op == token.AND {
+ // Skip all expressions when the field is used as a pointer.
+ // Because this is not direct reading, but most likely writing by pointer (for example like sql.Scan).
+ c.filter.AddPos(x.X.Pos())
+ }
+
+ case *ast.CallExpr:
+ f, ok := x.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return &Result{}, nil
+ }
+
+ if !isProtoMessage(c.info, f.X) {
+ return &Result{}, nil
+ }
+
+ c.processInner(x)
+
+ case *ast.SelectorExpr:
+ if !isProtoMessage(c.info, x.X) {
+ // If the selector is not on a proto message, skip it.
+ return &Result{}, nil
+ }
+
+ c.processInner(x)
+
+ default:
+ return nil, fmt.Errorf("not implemented for type: %s (%s)", reflect.TypeOf(x), formatNode(n))
+ }
+
+ if c.err != nil {
+ return nil, c.err
+ }
+
+ return &Result{
+ From: c.from.String(),
+ To: c.to.String(),
+ }, nil
+}
+
+func (c *processor) processInner(expr ast.Expr) {
+ switch x := expr.(type) {
+ case *ast.Ident:
+ c.write(x.Name)
+
+ case *ast.BasicLit:
+ c.write(x.Value)
+
+ case *ast.UnaryExpr:
+ if x.Op == token.AND {
+ c.write(formatNode(x))
+ return
+ }
+
+ c.write(x.Op.String())
+ c.processInner(x.X)
+
+ case *ast.SelectorExpr:
+ c.processInner(x.X)
+ c.write(".")
+
+ // If getter exists, use it.
+ if methodIsExists(c.info, x.X, "Get"+x.Sel.Name) {
+ c.writeFrom(x.Sel.Name)
+ c.writeTo("Get" + x.Sel.Name + "()")
+ return
+ }
+
+ // If the selector is not a proto-message or the method has already been called, we leave it unchanged.
+ // This approach is significantly more efficient than verifying the presence of methods in all cases.
+ c.write(x.Sel.Name)
+
+ case *ast.CallExpr:
+ c.processInner(x.Fun)
+ c.write("(")
+ for i, arg := range x.Args {
+ if i > 0 {
+ c.write(",")
+ }
+ c.processInner(arg)
+ }
+ c.write(")")
+
+ case *ast.IndexExpr:
+ c.processInner(x.X)
+ c.write("[")
+ c.processInner(x.Index)
+ c.write("]")
+
+ case *ast.BinaryExpr:
+ c.processInner(x.X)
+ c.write(x.Op.String())
+ c.processInner(x.Y)
+
+ case *ast.ParenExpr:
+ c.write("(")
+ c.processInner(x.X)
+ c.write(")")
+
+ case *ast.StarExpr:
+ c.write("*")
+ c.processInner(x.X)
+
+ case *ast.CompositeLit:
+ c.write(formatNode(x))
+
+ case *ast.TypeAssertExpr:
+ c.write(formatNode(x))
+
+ default:
+ c.err = fmt.Errorf("processInner: not implemented for type: %s", reflect.TypeOf(x))
+ }
+}
+
+func (c *processor) write(s string) {
+ c.writeTo(s)
+ c.writeFrom(s)
+}
+
+func (c *processor) writeTo(s string) {
+ c.to.WriteString(s)
+}
+
+func (c *processor) writeFrom(s string) {
+ c.from.WriteString(s)
+}
+
+// Result contains source code (from) and suggested change (to)
+type Result struct {
+ From string
+ To string
+}
+
+func (r *Result) Skipped() bool {
+ // If from and to are the same, skip it.
+ return r.From == r.To
+}
+
+func isProtoMessage(info *types.Info, expr ast.Expr) bool {
+ // First, we are checking for the presence of the ProtoReflect method which is currently being generated
+ // and corresponds to v2 version.
+ // https://pkg.go.dev/google.golang.org/protobuf@v1.31.0/proto#Message
+ const protoV2Method = "ProtoReflect"
+ ok := methodIsExists(info, expr, protoV2Method)
+ if ok {
+ return true
+ }
+
+ // Afterwards, we are checking the ProtoMessage method. All the structures that implement the proto.Message interface
+ // have a ProtoMessage method and are proto-structures. This interface has been generated since version 1.0.0 and
+ // continues to exist for compatibility.
+ // https://pkg.go.dev/github.com/golang/protobuf/proto?utm_source=godoc#Message
+ const protoV1Method = "ProtoMessage"
+ ok = methodIsExists(info, expr, protoV1Method)
+ if ok {
+ // Since there is a protoc-gen-gogo generator that implements the proto.Message interface, but may not generate
+ // getters or generate from without checking for nil, so even if getters exist, we skip them.
+ const protocGenGoGoMethod = "MarshalToSizedBuffer"
+ return !methodIsExists(info, expr, protocGenGoGoMethod)
+ }
+
+ return false
+}
+
+func methodIsExists(info *types.Info, x ast.Expr, name string) bool {
+ if info == nil {
+ return false
+ }
+
+ t := info.TypeOf(x)
+ if t == nil {
+ return false
+ }
+
+ ptr, ok := t.Underlying().(*types.Pointer)
+ if ok {
+ t = ptr.Elem()
+ }
+
+ named, ok := t.(*types.Named)
+ if !ok {
+ return false
+ }
+
+ for i := 0; i < named.NumMethods(); i++ {
+ if named.Method(i).Name() == name {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/vendor/github.com/ghostiam/protogetter/protogetter.go b/vendor/github.com/ghostiam/protogetter/protogetter.go
new file mode 100644
index 0000000000..80a8296720
--- /dev/null
+++ b/vendor/github.com/ghostiam/protogetter/protogetter.go
@@ -0,0 +1,183 @@
+package protogetter
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+ "go/token"
+ "log"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+type Mode int
+
+const (
+ StandaloneMode Mode = iota
+ GolangciLintMode
+)
+
+const msgFormat = "avoid direct access to proto field %s, use %s instead"
+
+func NewAnalyzer() *analysis.Analyzer {
+ return &analysis.Analyzer{
+ Name: "protogetter",
+ Doc: "Reports direct reads from proto message fields when getters should be used",
+ Run: func(pass *analysis.Pass) (any, error) {
+ Run(pass, StandaloneMode)
+ return nil, nil
+ },
+ }
+}
+
+func Run(pass *analysis.Pass, mode Mode) []Issue {
+ nodeTypes := []ast.Node{
+ (*ast.AssignStmt)(nil),
+ (*ast.CallExpr)(nil),
+ (*ast.SelectorExpr)(nil),
+ (*ast.IncDecStmt)(nil),
+ (*ast.UnaryExpr)(nil),
+ }
+
+ // Skip protoc-generated files.
+ var files []*ast.File
+ for _, f := range pass.Files {
+ if !isProtocGeneratedFile(f) {
+ files = append(files, f)
+
+ // ast.Print(pass.Fset, f)
+ }
+ }
+
+ ins := inspector.New(files)
+
+ var issues []Issue
+
+ filter := NewPosFilter()
+ ins.Preorder(nodeTypes, func(node ast.Node) {
+ report := analyse(pass, filter, node)
+ if report == nil {
+ return
+ }
+
+ switch mode {
+ case StandaloneMode:
+ pass.Report(report.ToDiagReport())
+ case GolangciLintMode:
+ issues = append(issues, report.ToIssue(pass.Fset))
+ }
+ })
+
+ return issues
+}
+
+func analyse(pass *analysis.Pass, filter *PosFilter, n ast.Node) *Report {
+ // fmt.Printf("\n>>> check: %s\n", formatNode(n))
+ // ast.Print(pass.Fset, n)
+ if filter.IsFiltered(n.Pos()) {
+ // fmt.Printf(">>> filtered\n")
+ return nil
+ }
+
+ result, err := Process(pass.TypesInfo, filter, n)
+ if err != nil {
+ pass.Report(analysis.Diagnostic{
+ Pos: n.Pos(),
+ End: n.End(),
+ Message: fmt.Sprintf("error: %v", err),
+ })
+
+ return nil
+ }
+
+ // If existing in filter, skip it.
+ if filter.IsFiltered(n.Pos()) {
+ return nil
+ }
+
+ if result.Skipped() {
+ return nil
+ }
+
+ // If the expression has already been replaced, skip it.
+ if filter.IsAlreadyReplaced(pass.Fset, n.Pos(), n.End()) {
+ return nil
+ }
+ // Add the expression to the filter.
+ filter.AddAlreadyReplaced(pass.Fset, n.Pos(), n.End())
+
+ return &Report{
+ node: n,
+ result: result,
+ }
+}
+
+// Issue is used to integrate with golangci-lint's inline auto fix.
+type Issue struct {
+ Pos token.Position
+ Message string
+ InlineFix InlineFix
+}
+
+type InlineFix struct {
+ StartCol int // zero-based
+ Length int
+ NewString string
+}
+
+type Report struct {
+ node ast.Node
+ result *Result
+}
+
+func (r *Report) ToDiagReport() analysis.Diagnostic {
+ msg := fmt.Sprintf(msgFormat, r.result.From, r.result.To)
+
+ return analysis.Diagnostic{
+ Pos: r.node.Pos(),
+ End: r.node.End(),
+ Message: msg,
+ SuggestedFixes: []analysis.SuggestedFix{
+ {
+ Message: msg,
+ TextEdits: []analysis.TextEdit{
+ {
+ Pos: r.node.Pos(),
+ End: r.node.End(),
+ NewText: []byte(r.result.To),
+ },
+ },
+ },
+ },
+ }
+}
+
+func (r *Report) ToIssue(fset *token.FileSet) Issue {
+ msg := fmt.Sprintf(msgFormat, r.result.From, r.result.To)
+ return Issue{
+ Pos: fset.Position(r.node.Pos()),
+ Message: msg,
+ InlineFix: InlineFix{
+ StartCol: fset.Position(r.node.Pos()).Column - 1,
+ Length: len(r.result.From),
+ NewString: r.result.To,
+ },
+ }
+}
+
+func isProtocGeneratedFile(f *ast.File) bool {
+ return len(f.Comments) > 0 && strings.HasPrefix(f.Comments[0].Text(), "Code generated by protoc-gen-go")
+}
+
+func formatNode(node ast.Node) string {
+ buf := new(bytes.Buffer)
+ if err := format.Node(buf, token.NewFileSet(), node); err != nil {
+ log.Printf("Error formatting expression: %v", err)
+ return ""
+ }
+
+ return buf.String()
+}
diff --git a/vendor/github.com/golangci/gofmt/gofmt/doc.go b/vendor/github.com/golangci/gofmt/gofmt/doc.go
index da0c8581dd..d0a4580219 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/doc.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/doc.go
@@ -13,9 +13,11 @@ that directory, recursively. (Files starting with a period are ignored.)
By default, gofmt prints the reformatted sources to standard output.
Usage:
+
gofmt [flags] [path ...]
The flags are:
+
-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
@@ -37,10 +39,10 @@ The flags are:
the original file is restored from an automatic backup.
Debugging support:
+
-cpuprofile filename
Write cpu profile to the specified file.
-
The rewrite rule specified with the -r flag must be a string of the form:
pattern -> replacement
@@ -57,7 +59,7 @@ such a fragment, gofmt preserves leading indentation as well as leading
and trailing spaces, so that individual sections of a Go program can be
formatted by piping them through gofmt.
-Examples
+# Examples
To check files for unnecessary parentheses:
@@ -71,7 +73,7 @@ To convert the package tree from explicit slice upper bounds to implicit ones:
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
-The simplify command
+# The simplify command
When invoked with -s gofmt will make the following source transformations where possible.
diff --git a/vendor/github.com/golangci/gofmt/gofmt/gofmt.go b/vendor/github.com/golangci/gofmt/gofmt/gofmt.go
index e7612afae0..be046f34cf 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/gofmt.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/gofmt.go
@@ -76,6 +76,11 @@ func initParserMode() {
if *allErrors {
parserMode |= parser.AllErrors
}
+ // It's only -r that makes use of go/ast's object resolution,
+ // so avoid the unnecessary work if the flag isn't used.
+ if *rewriteRule == "" {
+ parserMode |= parser.SkipObjectResolution
+ }
}
func isGoFile(f fs.DirEntry) bool {
@@ -286,12 +291,9 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e
}
}
if *doDiff {
- data, err := diffWithReplaceTempFile(src, res, filename)
- if err != nil {
- return fmt.Errorf("computing diff: %s", err)
- }
- fmt.Fprintf(r, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename))
- r.Write(data)
+ newName := filepath.ToSlash(filename)
+ oldName := newName + ".orig"
+ r.Write(diff.Diff(oldName, src, newName, res))
}
}
@@ -350,7 +352,12 @@ func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) {
// stop to avoid corrupting it.)
src := make([]byte, size+1)
n, err := io.ReadFull(in, src)
- if err != nil && err != io.ErrUnexpectedEOF {
+ switch err {
+ case nil, io.EOF, io.ErrUnexpectedEOF:
+ // io.ReadFull returns io.EOF (for an empty file) or io.ErrUnexpectedEOF
+ // (for a non-empty file) if the file was changed unexpectedly. Continue
+ // with comparing file sizes in those cases.
+ default:
return nil, err
}
if n < size {
@@ -463,43 +470,6 @@ func fileWeight(path string, info fs.FileInfo) int64 {
return info.Size()
}
-func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) {
- data, err := diff.Diff("gofmt", b1, b2)
- if len(data) > 0 {
- return replaceTempFilename(data, filename)
- }
- return data, err
-}
-
-// replaceTempFilename replaces temporary filenames in diff with actual one.
-//
-// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500
-// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500
-// ...
-// ->
-// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500
-// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500
-// ...
-func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
- bs := bytes.SplitN(diff, []byte{'\n'}, 3)
- if len(bs) < 3 {
- return nil, fmt.Errorf("got unexpected diff for %s", filename)
- }
- // Preserve timestamps.
- var t0, t1 []byte
- if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
- t0 = bs[0][i:]
- }
- if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
- t1 = bs[1][i:]
- }
- // Always print filepath with slash separator.
- f := filepath.ToSlash(filename)
- bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
- bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
- return bytes.Join(bs, []byte{'\n'}), nil
-}
-
const chmodSupported = runtime.GOOS != "windows"
// backupFile writes data to a new file named filename with permissions perm,
diff --git a/vendor/github.com/golangci/gofmt/gofmt/golangci.go b/vendor/github.com/golangci/gofmt/gofmt/golangci.go
index c9c3fe2ae5..a69611e1d3 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/golangci.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/golangci.go
@@ -8,8 +8,14 @@ import (
"go/printer"
"go/token"
"os"
+ "path/filepath"
+ "sync"
+
+ "github.com/golangci/gofmt/gofmt/internal/diff"
)
+var parserModeMu sync.RWMutex
+
type RewriteRule struct {
Pattern string
Replacement string
@@ -31,7 +37,9 @@ func RunRewrite(filename string, needSimplify bool, rewriteRules []RewriteRule)
fset := token.NewFileSet()
+ parserModeMu.Lock()
initParserMode()
+ parserModeMu.Unlock()
file, sourceAdj, indentAdj, err := parse(fset, filename, src, false)
if err != nil {
@@ -59,12 +67,10 @@ func RunRewrite(filename string, needSimplify bool, rewriteRules []RewriteRule)
}
// formatting has changed
- data, err := diffWithReplaceTempFile(src, res, filename)
- if err != nil {
- return nil, fmt.Errorf("error computing diff: %s", err)
- }
+ newName := filepath.ToSlash(filename)
+ oldName := newName + ".orig"
- return data, nil
+ return diff.Diff(oldName, src, newName, res), nil
}
func rewriteFileContent(fset *token.FileSet, file *ast.File, rewriteRules []RewriteRule) (*ast.File, error) {
diff --git a/vendor/github.com/golangci/gofmt/gofmt/internal.go b/vendor/github.com/golangci/gofmt/gofmt/internal.go
index 1abbdd6989..31a825bf83 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/internal.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/internal.go
@@ -26,6 +26,13 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
indentAdj int,
err error,
) {
+
+ // START - Change related to usgae inside golangci-lint
+ parserModeMu.Lock()
+ parserMode := parserMode
+ parserModeMu.Unlock()
+ // END - Change related to usgae inside golangci-lint
+
// Try as whole source file.
file, err = parser.ParseFile(fset, filename, src, parserMode)
// If there's no error, return. If the error is that the source file didn't begin with a
diff --git a/vendor/github.com/golangci/gofmt/gofmt/internal/diff/diff.go b/vendor/github.com/golangci/gofmt/gofmt/internal/diff/diff.go
index cbd0529ec6..47b2856714 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/internal/diff/diff.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/internal/diff/diff.go
@@ -1,79 +1,261 @@
-// Copyright 2019 The Go Authors. All rights reserved.
+// Copyright 2022 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.
-// Package diff implements a Diff function that compare two inputs
-// using the 'diff' tool.
package diff
import (
"bytes"
- "io/ioutil"
- "os"
- "runtime"
-
- exec "github.com/golangci/gofmt/gofmt/internal/execabs"
+ "fmt"
+ "sort"
+ "strings"
)
-// Returns diff of two arrays of bytes in diff tool format.
-func Diff(prefix string, b1, b2 []byte) ([]byte, error) {
- f1, err := writeTempFile(prefix, b1)
- if err != nil {
- return nil, err
+// A pair is a pair of values tracked for both the x and y side of a diff.
+// It is typically a pair of line indexes.
+type pair struct{ x, y int }
+
+// Diff returns an anchored diff of the two texts old and new
+// in the “unified diff” format. If old and new are identical,
+// Diff returns a nil slice (no output).
+//
+// Unix diff implementations typically look for a diff with
+// the smallest number of lines inserted and removed,
+// which can in the worst case take time quadratic in the
+// number of lines in the texts. As a result, many implementations
+// either can be made to run for a long time or cut off the search
+// after a predetermined amount of work.
+//
+// In contrast, this implementation looks for a diff with the
+// smallest number of “unique” lines inserted and removed,
+// where unique means a line that appears just once in both old and new.
+// We call this an “anchored diff” because the unique lines anchor
+// the chosen matching regions. An anchored diff is usually clearer
+// than a standard diff, because the algorithm does not try to
+// reuse unrelated blank lines or closing braces.
+// The algorithm also guarantees to run in O(n log n) time
+// instead of the standard O(n²) time.
+//
+// Some systems call this approach a “patience diff,” named for
+// the “patience sorting” algorithm, itself named for a solitaire card game.
+// We avoid that name for two reasons. First, the name has been used
+// for a few different variants of the algorithm, so it is imprecise.
+// Second, the name is frequently interpreted as meaning that you have
+// to wait longer (to be patient) for the diff, meaning that it is a slower algorithm,
+// when in fact the algorithm is faster than the standard one.
+func Diff(oldName string, old []byte, newName string, new []byte) []byte {
+ if bytes.Equal(old, new) {
+ return nil
}
- defer os.Remove(f1)
+ x := lines(old)
+ y := lines(new)
+
+ // Print diff header.
+ var out bytes.Buffer
+ fmt.Fprintf(&out, "diff %s %s\n", oldName, newName)
+ fmt.Fprintf(&out, "--- %s\n", oldName)
+ fmt.Fprintf(&out, "+++ %s\n", newName)
+
+ // Loop over matches to consider,
+ // expanding each match to include surrounding lines,
+ // and then printing diff chunks.
+ // To avoid setup/teardown cases outside the loop,
+ // tgs returns a leading {0,0} and trailing {len(x), len(y)} pair
+ // in the sequence of matches.
+ var (
+ done pair // printed up to x[:done.x] and y[:done.y]
+ chunk pair // start lines of current chunk
+ count pair // number of lines from each side in current chunk
+ ctext []string // lines for current chunk
+ )
+ for _, m := range tgs(x, y) {
+ if m.x < done.x {
+ // Already handled scanning forward from earlier match.
+ continue
+ }
- f2, err := writeTempFile(prefix, b2)
- if err != nil {
- return nil, err
+ // Expand matching lines as far possible,
+ // establishing that x[start.x:end.x] == y[start.y:end.y].
+ // Note that on the first (or last) iteration we may (or definitey do)
+ // have an empty match: start.x==end.x and start.y==end.y.
+ start := m
+ for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] {
+ start.x--
+ start.y--
+ }
+ end := m
+ for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] {
+ end.x++
+ end.y++
+ }
+
+ // Emit the mismatched lines before start into this chunk.
+ // (No effect on first sentinel iteration, when start = {0,0}.)
+ for _, s := range x[done.x:start.x] {
+ ctext = append(ctext, "-"+s)
+ count.x++
+ }
+ for _, s := range y[done.y:start.y] {
+ ctext = append(ctext, "+"+s)
+ count.y++
+ }
+
+ // If we're not at EOF and have too few common lines,
+ // the chunk includes all the common lines and continues.
+ const C = 3 // number of context lines
+ if (end.x < len(x) || end.y < len(y)) &&
+ (end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) {
+ for _, s := range x[start.x:end.x] {
+ ctext = append(ctext, " "+s)
+ count.x++
+ count.y++
+ }
+ done = end
+ continue
+ }
+
+ // End chunk with common lines for context.
+ if len(ctext) > 0 {
+ n := end.x - start.x
+ if n > C {
+ n = C
+ }
+ for _, s := range x[start.x : start.x+n] {
+ ctext = append(ctext, " "+s)
+ count.x++
+ count.y++
+ }
+ done = pair{start.x + n, start.y + n}
+
+ // Format and emit chunk.
+ // Convert line numbers to 1-indexed.
+ // Special case: empty file shows up as 0,0 not 1,0.
+ if count.x > 0 {
+ chunk.x++
+ }
+ if count.y > 0 {
+ chunk.y++
+ }
+ fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y)
+ for _, s := range ctext {
+ out.WriteString(s)
+ }
+ count.x = 0
+ count.y = 0
+ ctext = ctext[:0]
+ }
+
+ // If we reached EOF, we're done.
+ if end.x >= len(x) && end.y >= len(y) {
+ break
+ }
+
+ // Otherwise start a new chunk.
+ chunk = pair{end.x - C, end.y - C}
+ for _, s := range x[chunk.x:end.x] {
+ ctext = append(ctext, " "+s)
+ count.x++
+ count.y++
+ }
+ done = end
}
- defer os.Remove(f2)
- cmd := "diff"
- if runtime.GOOS == "plan9" {
- cmd = "/bin/ape/diff"
+ return out.Bytes()
+}
+
+// lines returns the lines in the file x, including newlines.
+// If the file does not end in a newline, one is supplied
+// along with a warning about the missing newline.
+func lines(x []byte) []string {
+ l := strings.SplitAfter(string(x), "\n")
+ if l[len(l)-1] == "" {
+ l = l[:len(l)-1]
+ } else {
+ // Treat last line as having a message about the missing newline attached,
+ // using the same text as BSD/GNU diff (including the leading backslash).
+ l[len(l)-1] += "\n\\ No newline at end of file\n"
}
+ return l
+}
- data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput()
- if len(data) > 0 {
- // diff exits with a non-zero status when the files don't match.
- // Ignore that failure as long as we get output.
- err = nil
+// tgs returns the pairs of indexes of the longest common subsequence
+// of unique lines in x and y, where a unique line is one that appears
+// once in x and once in y.
+//
+// The longest common subsequence algorithm is as described in
+// Thomas G. Szymanski, “A Special Case of the Maximal Common
+// Subsequence Problem,” Princeton TR #170 (January 1975),
+// available at https://research.swtch.com/tgs170.pdf.
+func tgs(x, y []string) []pair {
+ // Count the number of times each string appears in a and b.
+ // We only care about 0, 1, many, counted as 0, -1, -2
+ // for the x side and 0, -4, -8 for the y side.
+ // Using negative numbers now lets us distinguish positive line numbers later.
+ m := make(map[string]int)
+ for _, s := range x {
+ if c := m[s]; c > -2 {
+ m[s] = c - 1
+ }
+ }
+ for _, s := range y {
+ if c := m[s]; c > -8 {
+ m[s] = c - 4
+ }
}
- // If we are on Windows and the diff is Cygwin diff,
- // machines can get into a state where every Cygwin
- // command works fine but prints a useless message like:
+ // Now unique strings can be identified by m[s] = -1+-4.
//
- // Cygwin WARNING:
- // Couldn't compute FAST_CWD pointer. This typically occurs if you're using
- // an older Cygwin version on a newer Windows. Please update to the latest
- // available Cygwin version from https://cygwin.com/. If the problem persists,
- // please see https://cygwin.com/problems.html
- //
- // Skip over that message and just return the actual diff.
- if len(data) > 0 && !bytes.HasPrefix(data, []byte("--- ")) {
- i := bytes.Index(data, []byte("\n--- "))
- if i >= 0 && i < 80*10 && bytes.Contains(data[:i], []byte("://cygwin.com/")) {
- data = data[i+1:]
+ // Gather the indexes of those strings in x and y, building:
+ // xi[i] = increasing indexes of unique strings in x.
+ // yi[i] = increasing indexes of unique strings in y.
+ // inv[i] = index j such that x[xi[i]] = y[yi[j]].
+ var xi, yi, inv []int
+ for i, s := range y {
+ if m[s] == -1+-4 {
+ m[s] = len(yi)
+ yi = append(yi, i)
+ }
+ }
+ for i, s := range x {
+ if j, ok := m[s]; ok && j >= 0 {
+ xi = append(xi, i)
+ inv = append(inv, j)
}
}
- return data, err
-}
-
-func writeTempFile(prefix string, data []byte) (string, error) {
- file, err := ioutil.TempFile("", prefix)
- if err != nil {
- return "", err
+ // Apply Algorithm A from Szymanski's paper.
+ // In those terms, A = J = inv and B = [0, n).
+ // We add sentinel pairs {0,0}, and {len(x),len(y)}
+ // to the returned sequence, to help the processing loop.
+ J := inv
+ n := len(xi)
+ T := make([]int, n)
+ L := make([]int, n)
+ for i := range T {
+ T[i] = n + 1
+ }
+ for i := 0; i < n; i++ {
+ k := sort.Search(n, func(k int) bool {
+ return T[k] >= J[i]
+ })
+ T[k] = J[i]
+ L[i] = k + 1
}
- _, err = file.Write(data)
- if err1 := file.Close(); err == nil {
- err = err1
+ k := 0
+ for _, v := range L {
+ if k < v {
+ k = v
+ }
}
- if err != nil {
- os.Remove(file.Name())
- return "", err
+ seq := make([]pair, 2+k)
+ seq[1+k] = pair{len(x), len(y)} // sentinel at end
+ lastj := n
+ for i := n - 1; i >= 0; i-- {
+ if L[i] == k && J[i] < lastj {
+ seq[k] = pair{xi[i], yi[J[i]]}
+ k--
+ }
}
- return file.Name(), nil
+ seq[0] = pair{0, 0} // sentinel at start
+ return seq
}
diff --git a/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go b/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go
deleted file mode 100644
index 9a05d971da..0000000000
--- a/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2021 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.
-
-// Package execabs is a drop-in replacement for os/exec
-// that requires PATH lookups to find absolute paths.
-// That is, execabs.Command("cmd") runs the same PATH lookup
-// as exec.Command("cmd"), but if the result is a path
-// which is relative, the Run and Start methods will report
-// an error instead of running the executable.
-package execabs
-
-import (
- "context"
- "fmt"
- "os/exec"
- "path/filepath"
- "reflect"
- "unsafe"
-)
-
-var ErrNotFound = exec.ErrNotFound
-
-type (
- Cmd = exec.Cmd
- Error = exec.Error
- ExitError = exec.ExitError
-)
-
-func relError(file, path string) error {
- return fmt.Errorf("%s resolves to executable relative to current directory (.%c%s)", file, filepath.Separator, path)
-}
-
-func LookPath(file string) (string, error) {
- path, err := exec.LookPath(file)
- if err != nil {
- return "", err
- }
- if filepath.Base(file) == file && !filepath.IsAbs(path) {
- return "", relError(file, path)
- }
- return path, nil
-}
-
-func fixCmd(name string, cmd *exec.Cmd) {
- if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
- // exec.Command was called with a bare binary name and
- // exec.LookPath returned a path which is not absolute.
- // Set cmd.lookPathErr and clear cmd.Path so that it
- // cannot be run.
- lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
- if *lookPathErr == nil {
- *lookPathErr = relError(name, cmd.Path)
- }
- cmd.Path = ""
- }
-}
-
-func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
- cmd := exec.CommandContext(ctx, name, arg...)
- fixCmd(name, cmd)
- return cmd
-
-}
-
-func Command(name string, arg ...string) *exec.Cmd {
- cmd := exec.Command(name, arg...)
- fixCmd(name, cmd)
- return cmd
-}
diff --git a/vendor/github.com/golangci/gofmt/gofmt/readme.md b/vendor/github.com/golangci/gofmt/gofmt/readme.md
index 36a716d819..c2faaab82d 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/readme.md
+++ b/vendor/github.com/golangci/gofmt/gofmt/readme.md
@@ -1,3 +1,5 @@
# Hard Fork of gofmt
2022-08-31: Sync with go1.18.5
+2023-10-04: Sync with go1.19.13
+2023-10-04: Sync with go1.20.8
diff --git a/vendor/github.com/golangci/gofmt/gofmt/simplify.go b/vendor/github.com/golangci/gofmt/gofmt/simplify.go
index 2c75495a69..3b34d562ba 100644
--- a/vendor/github.com/golangci/gofmt/gofmt/simplify.go
+++ b/vendor/github.com/golangci/gofmt/gofmt/simplify.go
@@ -53,22 +53,26 @@ func (s simplifier) Visit(node ast.Node) ast.Visitor {
// can be simplified to: s[a:]
// if s is "simple enough" (for now we only accept identifiers)
//
- // Note: This may not be correct because len may have been redeclared in another
- // file belonging to the same package. However, this is extremely unlikely
- // and so far (April 2016, after years of supporting this rewrite feature)
+ // Note: This may not be correct because len may have been redeclared in
+ // the same package. However, this is extremely unlikely and so far
+ // (April 2022, after years of supporting this rewrite feature)
// has never come up, so let's keep it working as is (see also #15153).
+ //
+ // Also note that this code used to use go/ast's object tracking,
+ // which was removed in exchange for go/parser.Mode.SkipObjectResolution.
+ // False positives are extremely unlikely as described above,
+ // and go/ast's object tracking is incomplete in any case.
if n.Max != nil {
// - 3-index slices always require the 2nd and 3rd index
break
}
- if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
- // the array/slice object is a single, resolved identifier
+ if s, _ := n.X.(*ast.Ident); s != nil {
+ // the array/slice object is a single identifier
if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
// the high expression is a function call with a single argument
- if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
- // the function called is "len" and it is not locally defined; and
- // because we don't have dot imports, it must be the predefined len()
- if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
+ if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" {
+ // the function called is "len"
+ if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Name == s.Name {
// the len argument is the array/slice object
n.High = nil
}
diff --git a/vendor/github.com/golangci/gofmt/goimports/goimports.go b/vendor/github.com/golangci/gofmt/goimports/goimports.go
index 1fa3328f8a..20d92e119c 100644
--- a/vendor/github.com/golangci/gofmt/goimports/goimports.go
+++ b/vendor/github.com/golangci/gofmt/goimports/goimports.go
@@ -14,7 +14,7 @@ import (
"runtime"
)
-// Extracted from golang.org/x/tools@v0.1.12/cmd/goimports/goimports.go
+// Extracted from golang.org/x/tools@v0.13.0/cmd/goimports/goimports.go
func writeTempFile(dir, prefix string, data []byte) (string, error) {
file, err := ioutil.TempFile(dir, prefix)
diff --git a/vendor/github.com/golangci/gofmt/goimports/golangci.go b/vendor/github.com/golangci/gofmt/goimports/golangci.go
index 7edc37937c..6ff286ae06 100644
--- a/vendor/github.com/golangci/gofmt/goimports/golangci.go
+++ b/vendor/github.com/golangci/gofmt/goimports/golangci.go
@@ -3,7 +3,7 @@ package goimports
import (
"bytes"
"fmt"
- "io/ioutil"
+ "os"
"golang.org/x/tools/imports"
)
@@ -11,7 +11,7 @@ import (
// Run runs goimports.
// The local prefixes (comma separated) must be defined through the global variable imports.LocalPrefix.
func Run(filename string) ([]byte, error) {
- src, err := ioutil.ReadFile(filename)
+ src, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/golangci/gofmt/goimports/readme.md b/vendor/github.com/golangci/gofmt/goimports/readme.md
index 6c793eb7d1..e57ed550b1 100644
--- a/vendor/github.com/golangci/gofmt/goimports/readme.md
+++ b/vendor/github.com/golangci/gofmt/goimports/readme.md
@@ -1,3 +1,4 @@
# Hard Fork of goimports
2022-08-31: Sync with golang.org/x/tools v0.1.12
+2023-10-04: Sync with golang.org/x/tools v0.13.0
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go
index 5fe4c784d6..efe62ced2a 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go
@@ -149,10 +149,10 @@ func (e *Executor) needVersionOption() bool {
}
func initRootFlagSet(fs *pflag.FlagSet, cfg *config.Config, needVersionOption bool) {
- fs.BoolVarP(&cfg.Run.IsVerbose, "verbose", "v", false, wh("verbose output"))
+ fs.BoolVarP(&cfg.Run.IsVerbose, "verbose", "v", false, wh("Verbose output"))
var silent bool
- fs.BoolVarP(&silent, "silent", "s", false, wh("disables congrats outputs"))
+ fs.BoolVarP(&silent, "silent", "s", false, wh("Disables congrats outputs"))
if err := fs.MarkHidden("silent"); err != nil {
panic(err)
}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go b/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go
index 417b28bdbf..5968d83d56 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go
@@ -54,7 +54,7 @@ var DefaultExcludePatterns = []ExcludePattern{
},
{
ID: "EXC0008",
- Pattern: "(G104|G307)",
+ Pattern: "(G104)",
Linter: "gosec",
Why: "Duplicated errcheck checks",
},
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go b/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go
index 805d0ff473..0fee9f81ef 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go
@@ -113,6 +113,12 @@ var defaultLintersSettings = LintersSettings{
Ignore: "",
Qualified: false,
},
+ SlogLint: SlogLintSettings{
+ KVOnly: false,
+ AttrOnly: false,
+ NoRawKeys: false,
+ ArgsOnSepLines: false,
+ },
TagAlign: TagAlignSettings{
Align: true,
Sort: true,
@@ -126,6 +132,15 @@ var defaultLintersSettings = LintersSettings{
Unparam: UnparamSettings{
Algo: "cha",
},
+ Unused: UnusedSettings{
+ FieldWritesAreUses: true,
+ PostStatementsAreReads: false,
+ ExportedIsUsed: true,
+ ExportedFieldsAreUsed: true,
+ ParametersAreUsed: true,
+ LocalVariablesAreUsed: true,
+ GeneratedIsUsed: true,
+ },
UseStdlibVars: UseStdlibVarsSettings{
HTTPMethod: true,
HTTPStatusCode: true,
@@ -213,15 +228,18 @@ type LintersSettings struct {
Reassign ReassignSettings
Revive ReviveSettings
RowsErrCheck RowsErrCheckSettings
+ SlogLint SlogLintSettings
Staticcheck StaticCheckSettings
Structcheck StructCheckSettings
Stylecheck StaticCheckSettings
TagAlign TagAlignSettings
Tagliatelle TagliatelleSettings
+ Testifylint TestifylintSettings
Tenv TenvSettings
Testpackage TestpackageSettings
Thelper ThelperSettings
Unparam UnparamSettings
+ Unused UnusedSettings
UseStdlibVars UseStdlibVarsSettings
Varcheck VarCheckSettings
Varnamelen VarnamelenSettings
@@ -292,6 +310,7 @@ type DuplSettings struct {
type DupWordSettings struct {
Keywords []string `mapstructure:"keywords"`
+ Ignore []string `mapstructure:"ignore"`
}
type ErrcheckSettings struct {
@@ -393,13 +412,14 @@ type GciSettings struct {
}
type GinkgoLinterSettings struct {
- SuppressLenAssertion bool `mapstructure:"suppress-len-assertion"`
- SuppressNilAssertion bool `mapstructure:"suppress-nil-assertion"`
- SuppressErrAssertion bool `mapstructure:"suppress-err-assertion"`
- SuppressCompareAssertion bool `mapstructure:"suppress-compare-assertion"`
- SuppressAsyncAssertion bool `mapstructure:"suppress-async-assertion"`
- ForbidFocusContainer bool `mapstructure:"forbid-focus-container"`
- AllowHaveLenZero bool `mapstructure:"allow-havelen-zero"`
+ SuppressLenAssertion bool `mapstructure:"suppress-len-assertion"`
+ SuppressNilAssertion bool `mapstructure:"suppress-nil-assertion"`
+ SuppressErrAssertion bool `mapstructure:"suppress-err-assertion"`
+ SuppressCompareAssertion bool `mapstructure:"suppress-compare-assertion"`
+ SuppressAsyncAssertion bool `mapstructure:"suppress-async-assertion"`
+ SuppressTypeCompareWarning bool `mapstructure:"suppress-type-compare-assertion"`
+ ForbidFocusContainer bool `mapstructure:"forbid-focus-container"`
+ AllowHaveLenZero bool `mapstructure:"allow-havelen-zero"`
}
type GocognitSettings struct {
@@ -704,6 +724,13 @@ type RowsErrCheckSettings struct {
Packages []string
}
+type SlogLintSettings struct {
+ KVOnly bool `mapstructure:"kv-only"`
+ AttrOnly bool `mapstructure:"attr-only"`
+ NoRawKeys bool `mapstructure:"no-raw-keys"`
+ ArgsOnSepLines bool `mapstructure:"args-on-sep-lines"`
+}
+
type StaticCheckSettings struct {
// Deprecated: use the global `run.go` instead.
GoVersion string `mapstructure:"go"`
@@ -736,6 +763,19 @@ type TagliatelleSettings struct {
}
}
+type TestifylintSettings struct {
+ EnableAll bool `mapstructure:"enable-all"`
+ EnabledCheckers []string `mapstructure:"enable"`
+
+ ExpectedActual struct {
+ ExpVarPattern string `mapstructure:"pattern"`
+ } `mapstructure:"expected-actual"`
+
+ SuiteExtraAssertCall struct {
+ Mode string `mapstructure:"mode"`
+ } `mapstructure:"suite-extra-assert-call"`
+}
+
type TestpackageSettings struct {
SkipRegexp string `mapstructure:"skip-regexp"`
AllowPackages []string `mapstructure:"allow-packages"`
@@ -778,6 +818,16 @@ type UnparamSettings struct {
Algo string
}
+type UnusedSettings struct {
+ FieldWritesAreUses bool `mapstructure:"field-writes-are-uses"`
+ PostStatementsAreReads bool `mapstructure:"post-statements-are-reads"`
+ ExportedIsUsed bool `mapstructure:"exported-is-used"`
+ ExportedFieldsAreUsed bool `mapstructure:"exported-fields-are-used"`
+ ParametersAreUsed bool `mapstructure:"parameters-are-used"`
+ LocalVariablesAreUsed bool `mapstructure:"local-variables-are-used"`
+ GeneratedIsUsed bool `mapstructure:"generated-is-used"`
+}
+
type VarCheckSettings struct {
CheckExportedFields bool `mapstructure:"exported-fields"`
}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go
index f5a99bc0df..6f079ffc89 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go
@@ -17,6 +17,7 @@ func NewDupWord(setting *config.DupWordSettings) *goanalysis.Linter {
if setting != nil {
cfgMap[a.Name] = map[string]any{
"keyword": strings.Join(setting.Keywords, ","),
+ "ignore": strings.Join(setting.Ignore, ","),
}
}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go
index 7b8102b631..8919de15bf 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go
@@ -14,13 +14,14 @@ func NewGinkgoLinter(cfg *config.GinkgoLinterSettings) *goanalysis.Linter {
cfgMap := make(map[string]map[string]any)
if cfg != nil {
cfgMap[a.Name] = map[string]any{
- "suppress-len-assertion": cfg.SuppressLenAssertion,
- "suppress-nil-assertion": cfg.SuppressNilAssertion,
- "suppress-err-assertion": cfg.SuppressErrAssertion,
- "suppress-compare-assertion": cfg.SuppressCompareAssertion,
- "suppress-async-assertion": cfg.SuppressAsyncAssertion,
- "forbid-focus-container": cfg.ForbidFocusContainer,
- "allow-havelen-0": cfg.AllowHaveLenZero,
+ "suppress-len-assertion": cfg.SuppressLenAssertion,
+ "suppress-nil-assertion": cfg.SuppressNilAssertion,
+ "suppress-err-assertion": cfg.SuppressErrAssertion,
+ "suppress-compare-assertion": cfg.SuppressCompareAssertion,
+ "suppress-async-assertion": cfg.SuppressAsyncAssertion,
+ "suppress-type-compare-assertion": cfg.SuppressTypeCompareWarning,
+ "forbid-focus-container": cfg.ForbidFocusContainer,
+ "allow-havelen-0": cfg.AllowHaveLenZero,
}
}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype.go
new file mode 100644
index 0000000000..fcc0cad588
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecksumtype.go
@@ -0,0 +1,80 @@
+package golinters
+
+import (
+ "strings"
+ "sync"
+
+ gochecksumtype "github.com/alecthomas/go-check-sumtype"
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/packages"
+
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+ "github.com/golangci/golangci-lint/pkg/lint/linter"
+ "github.com/golangci/golangci-lint/pkg/result"
+)
+
+const goCheckSumTypeName = "gochecksumtype"
+
+func NewGoCheckSumType() *goanalysis.Linter {
+ var mu sync.Mutex
+ var resIssues []goanalysis.Issue
+
+ analyzer := &analysis.Analyzer{
+ Name: goCheckSumTypeName,
+ Doc: goanalysis.TheOnlyanalyzerDoc,
+ Run: func(pass *analysis.Pass) (any, error) {
+ issues, err := runGoCheckSumType(pass)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(issues) == 0 {
+ return nil, nil
+ }
+
+ mu.Lock()
+ resIssues = append(resIssues, issues...)
+ mu.Unlock()
+
+ return nil, nil
+ },
+ }
+
+ return goanalysis.NewLinter(
+ goCheckSumTypeName,
+ `Run exhaustiveness checks on Go "sum types"`,
+ []*analysis.Analyzer{analyzer},
+ nil,
+ ).WithIssuesReporter(func(ctx *linter.Context) []goanalysis.Issue {
+ return resIssues
+ }).WithLoadMode(goanalysis.LoadModeTypesInfo)
+}
+
+func runGoCheckSumType(pass *analysis.Pass) ([]goanalysis.Issue, error) {
+ var resIssues []goanalysis.Issue
+
+ pkg := &packages.Package{
+ Fset: pass.Fset,
+ Syntax: pass.Files,
+ Types: pass.Pkg,
+ TypesInfo: pass.TypesInfo,
+ }
+
+ var unknownError error
+ errors := gochecksumtype.Run([]*packages.Package{pkg})
+ for _, err := range errors {
+ err, ok := err.(gochecksumtype.Error)
+ if !ok {
+ unknownError = err
+ continue
+ }
+
+ resIssues = append(resIssues, goanalysis.NewIssue(&result.Issue{
+ FromLinter: goCheckSumTypeName,
+ Text: strings.TrimPrefix(err.Error(), err.Pos().String()+": "),
+ Pos: err.Pos(),
+ }, pass))
+ }
+
+ return resIssues, unknownError
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go
index 5a1309cd01..4e16fb1429 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go
@@ -2,6 +2,7 @@ package golinters
import (
"golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/appends"
"golang.org/x/tools/go/analysis/passes/asmdecl"
"golang.org/x/tools/go/analysis/passes/assign"
"golang.org/x/tools/go/analysis/passes/atomic"
@@ -53,6 +54,7 @@ import (
var (
allAnalyzers = []*analysis.Analyzer{
+ appends.Analyzer,
asmdecl.Analyzer,
assign.Analyzer,
atomic.Analyzer,
@@ -95,8 +97,9 @@ var (
unusedwrite.Analyzer,
}
- // https://github.com/golang/go/blob/c19c4c566c63818dfd059b352e52c4710eecf14d/src/cmd/vet/main.go#L47-L78
+ // https://github.com/golang/go/blob/b56645a87b28840a180d64077877cb46570b4176/src/cmd/vet/main.go#L49-L81
defaultAnalyzers = []*analysis.Analyzer{
+ appends.Analyzer,
asmdecl.Analyzer,
assign.Analyzer,
atomic.Analyzer,
@@ -105,6 +108,7 @@ var (
cgocall.Analyzer,
composite.Analyzer,
copylock.Analyzer,
+ defers.Analyzer,
directive.Analyzer,
errorsas.Analyzer,
framepointer.Analyzer,
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam.go
new file mode 100644
index 0000000000..2906307552
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/inamedparam.go
@@ -0,0 +1,19 @@
+package golinters
+
+import (
+ "github.com/macabu/inamedparam"
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+)
+
+func NewINamedParam() *goanalysis.Linter {
+ a := inamedparam.Analyzer
+
+ return goanalysis.NewLinter(
+ a.Name,
+ a.Doc,
+ []*analysis.Analyzer{a},
+ nil,
+ ).WithLoadMode(goanalysis.LoadModeSyntax)
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint.go
new file mode 100644
index 0000000000..fb248a85dc
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/perfsprint.go
@@ -0,0 +1,19 @@
+package golinters
+
+import (
+ "github.com/catenacyber/perfsprint/analyzer"
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+)
+
+func NewPerfSprint() *goanalysis.Linter {
+ a := analyzer.Analyzer
+
+ return goanalysis.NewLinter(
+ a.Name,
+ a.Doc,
+ []*analysis.Analyzer{a},
+ nil,
+ ).WithLoadMode(goanalysis.LoadModeTypesInfo)
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter.go
new file mode 100644
index 0000000000..23325ad55e
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/protogetter.go
@@ -0,0 +1,59 @@
+package golinters
+
+import (
+ "sync"
+
+ "github.com/ghostiam/protogetter"
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+ "github.com/golangci/golangci-lint/pkg/lint/linter"
+ "github.com/golangci/golangci-lint/pkg/result"
+)
+
+func NewProtoGetter() *goanalysis.Linter {
+ var mu sync.Mutex
+ var resIssues []goanalysis.Issue
+
+ a := protogetter.NewAnalyzer()
+ a.Run = func(pass *analysis.Pass) (any, error) {
+ pgIssues := protogetter.Run(pass, protogetter.GolangciLintMode)
+
+ issues := make([]goanalysis.Issue, len(pgIssues))
+ for i, issue := range pgIssues {
+ report := &result.Issue{
+ FromLinter: a.Name,
+ Pos: issue.Pos,
+ Text: issue.Message,
+ Replacement: &result.Replacement{
+ Inline: &result.InlineFix{
+ StartCol: issue.InlineFix.StartCol,
+ Length: issue.InlineFix.Length,
+ NewString: issue.InlineFix.NewString,
+ },
+ },
+ }
+
+ issues[i] = goanalysis.NewIssue(report, pass)
+ }
+
+ if len(issues) == 0 {
+ return nil, nil
+ }
+
+ mu.Lock()
+ resIssues = append(resIssues, issues...)
+ mu.Unlock()
+
+ return nil, nil
+ }
+
+ return goanalysis.NewLinter(
+ a.Name,
+ a.Doc,
+ []*analysis.Analyzer{a},
+ nil,
+ ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
+ return resIssues
+ }).WithLoadMode(goanalysis.LoadModeTypesInfo)
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go
index b57566e7af..28231957c4 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go
@@ -247,7 +247,7 @@ func safeTomlSlice(r []any) []any {
}
// This element is not exported by revive, so we need copy the code.
-// Extracted from https://github.com/mgechev/revive/blob/v1.3.0/config/config.go#L15
+// Extracted from https://github.com/mgechev/revive/blob/v1.3.4/config/config.go#L15
var defaultRules = []lint.Rule{
&rule.VarDeclarationsRule{},
&rule.PackageCommentsRule{},
@@ -267,7 +267,6 @@ var defaultRules = []lint.Rule{
&rule.TimeNamingRule{},
&rule.ContextKeysType{},
&rule.ContextAsArgumentRule{},
- &rule.IfReturnRule{},
&rule.EmptyBlockRule{},
&rule.SuperfluousElseRule{},
&rule.UnusedParamRule{},
@@ -317,12 +316,17 @@ var allRules = append([]lint.Rule{
&rule.FunctionLength{},
&rule.NestedStructs{},
&rule.UselessBreak{},
+ &rule.UncheckedTypeAssertionRule{},
&rule.TimeEqualRule{},
&rule.BannedCharsRule{},
&rule.OptimizeOperandsOrderRule{},
&rule.UseAnyRule{},
&rule.DataRaceRule{},
&rule.CommentSpacingsRule{},
+ &rule.IfReturnRule{},
+ &rule.RedundantImportAlias{},
+ &rule.ImportAliasNamingRule{},
+ &rule.EnforceMapStyleRule{},
}, defaultRules...)
const defaultConfidence = 0.8
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint.go
new file mode 100644
index 0000000000..b506d187fd
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/sloglint.go
@@ -0,0 +1,27 @@
+package golinters
+
+import (
+ "go-simpler.org/sloglint"
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/golangci/golangci-lint/pkg/config"
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+)
+
+func NewSlogLint(settings *config.SlogLintSettings) *goanalysis.Linter {
+ var opts *sloglint.Options
+ if settings != nil {
+ opts = &sloglint.Options{
+ KVOnly: settings.KVOnly,
+ AttrOnly: settings.AttrOnly,
+ NoRawKeys: settings.NoRawKeys,
+ ArgsOnSepLines: settings.ArgsOnSepLines,
+ }
+ }
+
+ a := sloglint.New(opts)
+
+ return goanalysis.
+ NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil).
+ WithLoadMode(goanalysis.LoadModeTypesInfo)
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint.go
new file mode 100644
index 0000000000..83bae2868a
--- /dev/null
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testifylint.go
@@ -0,0 +1,36 @@
+package golinters
+
+import (
+ "github.com/Antonboom/testifylint/analyzer"
+ "golang.org/x/tools/go/analysis"
+
+ "github.com/golangci/golangci-lint/pkg/config"
+ "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+)
+
+func NewTestifylint(settings *config.TestifylintSettings) *goanalysis.Linter {
+ a := analyzer.New()
+
+ cfg := make(map[string]map[string]any)
+ if settings != nil {
+ cfg[a.Name] = map[string]any{
+ "enable-all": settings.EnableAll,
+ }
+ if len(settings.EnabledCheckers) > 0 {
+ cfg[a.Name]["enable"] = settings.EnabledCheckers
+ }
+ if p := settings.ExpectedActual.ExpVarPattern; p != "" {
+ cfg[a.Name]["expected-actual.pattern"] = p
+ }
+ if m := settings.SuiteExtraAssertCall.Mode; m != "" {
+ cfg[a.Name]["suite-extra-assert-call.mode"] = m
+ }
+ }
+
+ return goanalysis.NewLinter(
+ a.Name,
+ a.Doc,
+ []*analysis.Analyzer{a},
+ cfg,
+ ).WithLoadMode(goanalysis.LoadModeTypesInfo)
+}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go
index aa9374d343..89ae7e98a2 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go
@@ -5,6 +5,9 @@ import (
"sync"
"golang.org/x/tools/go/analysis"
+ "honnef.co/go/tools/analysis/facts/directives"
+ "honnef.co/go/tools/analysis/facts/generated"
+ "honnef.co/go/tools/analysis/lint"
"honnef.co/go/tools/unused"
"github.com/golangci/golangci-lint/pkg/config"
@@ -15,11 +18,7 @@ import (
const unusedName = "unused"
-type UnusedSettings struct {
- GoVersion string
-}
-
-func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
+func NewUnused(settings *config.UnusedSettings, scSettings *config.StaticCheckSettings) *goanalysis.Linter {
var mu sync.Mutex
var resIssues []goanalysis.Issue
@@ -28,11 +27,7 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
Doc: unused.Analyzer.Analyzer.Doc,
Requires: unused.Analyzer.Analyzer.Requires,
Run: func(pass *analysis.Pass) (any, error) {
- issues, err := runUnused(pass)
- if err != nil {
- return nil, err
- }
-
+ issues := runUnused(pass, settings)
if len(issues) == 0 {
return nil, nil
}
@@ -45,7 +40,7 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
},
}
- setAnalyzerGoVersion(analyzer, getGoVersion(settings))
+ setAnalyzerGoVersion(analyzer, getGoVersion(scSettings))
return goanalysis.NewLinter(
unusedName,
@@ -57,21 +52,18 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
}
-func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) {
- res, err := unused.Analyzer.Analyzer.Run(pass)
- if err != nil {
- return nil, err
- }
+func runUnused(pass *analysis.Pass, cfg *config.UnusedSettings) []goanalysis.Issue {
+ res := getUnusedResults(pass, cfg)
used := make(map[string]bool)
- for _, obj := range res.(unused.Result).Used {
+ for _, obj := range res.Used {
used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true
}
var issues []goanalysis.Issue
// Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197
- for _, object := range res.(unused.Result).Unused {
+ for _, object := range res.Unused {
if object.Kind == "type param" {
continue
}
@@ -90,5 +82,31 @@ func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) {
issues = append(issues, issue)
}
- return issues, nil
+ return issues
+}
+
+func getUnusedResults(pass *analysis.Pass, settings *config.UnusedSettings) unused.Result {
+ opts := unused.Options{
+ FieldWritesAreUses: settings.FieldWritesAreUses,
+ PostStatementsAreReads: settings.PostStatementsAreReads,
+ ExportedIsUsed: settings.ExportedIsUsed,
+ ExportedFieldsAreUsed: settings.ExportedFieldsAreUsed,
+ ParametersAreUsed: settings.ParametersAreUsed,
+ LocalVariablesAreUsed: settings.LocalVariablesAreUsed,
+ GeneratedIsUsed: settings.GeneratedIsUsed,
+ }
+
+ // ref: https://github.com/dominikh/go-tools/blob/4ec1f474ca6c0feb8e10a8fcca4ab95f5b5b9881/internal/cmd/unused/unused.go#L68
+ nodes := unused.Graph(pass.Fset,
+ pass.Files,
+ pass.Pkg,
+ pass.TypesInfo,
+ pass.ResultOf[directives.Analyzer].([]lint.Directive),
+ pass.ResultOf[generated.Analyzer].(map[string]generated.Generator),
+ opts,
+ )
+
+ sg := unused.SerializedGraph{}
+ sg.Merge(nodes)
+ return sg.Results()
}
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go
index 4de3a1116f..fd329ce57f 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go
@@ -127,16 +127,18 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
reassignCfg *config.ReassignSettings
reviveCfg *config.ReviveSettings
rowserrcheckCfg *config.RowsErrCheckSettings
+ sloglintCfg *config.SlogLintSettings
staticcheckCfg *config.StaticCheckSettings
structcheckCfg *config.StructCheckSettings
stylecheckCfg *config.StaticCheckSettings
tagalignCfg *config.TagAlignSettings
tagliatelleCfg *config.TagliatelleSettings
tenvCfg *config.TenvSettings
+ testifylintCfg *config.TestifylintSettings
testpackageCfg *config.TestpackageSettings
thelperCfg *config.ThelperSettings
unparamCfg *config.UnparamSettings
- unusedCfg *config.StaticCheckSettings
+ unusedCfg *config.UnusedSettings
usestdlibvars *config.UseStdlibVarsSettings
varcheckCfg *config.VarCheckSettings
varnamelenCfg *config.VarnamelenSettings
@@ -207,16 +209,18 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
reassignCfg = &m.cfg.LintersSettings.Reassign
reviveCfg = &m.cfg.LintersSettings.Revive
rowserrcheckCfg = &m.cfg.LintersSettings.RowsErrCheck
+ sloglintCfg = &m.cfg.LintersSettings.SlogLint
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
structcheckCfg = &m.cfg.LintersSettings.Structcheck
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
tagalignCfg = &m.cfg.LintersSettings.TagAlign
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
tenvCfg = &m.cfg.LintersSettings.Tenv
+ testifylintCfg = &m.cfg.LintersSettings.Testifylint
testpackageCfg = &m.cfg.LintersSettings.Testpackage
thelperCfg = &m.cfg.LintersSettings.Thelper
unparamCfg = &m.cfg.LintersSettings.Unparam
- unusedCfg = new(config.StaticCheckSettings)
+ unusedCfg = &m.cfg.LintersSettings.Unused
usestdlibvars = &m.cfg.LintersSettings.UseStdlibVars
varcheckCfg = &m.cfg.LintersSettings.Varcheck
varnamelenCfg = &m.cfg.LintersSettings.Varnamelen
@@ -245,9 +249,6 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
if stylecheckCfg != nil && stylecheckCfg.GoVersion != "" {
stylecheckCfg.GoVersion = trimGoVersion(m.cfg.Run.Go)
}
- if unusedCfg != nil && unusedCfg.GoVersion == "" {
- unusedCfg.GoVersion = trimGoVersion(m.cfg.Run.Go)
- }
}
const megacheckName = "megacheck"
@@ -439,6 +440,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("v1.12.0").
WithPresets(linter.PresetStyle),
+ linter.NewConfig(golinters.NewGoCheckSumType()).
+ WithSince("v1.55.0").
+ WithPresets(linter.PresetBugs).
+ WithLoadForGoAnalysis().
+ WithURL("https://github.com/alecthomas/go-check-sumtype"),
+
linter.NewConfig(golinters.NewGocognit(gocognitCfg)).
WithSince("v1.20.0").
WithPresets(linter.PresetComplexity).
@@ -573,6 +580,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/julz/importas"),
+ linter.NewConfig(golinters.NewINamedParam()).
+ WithSince("v1.55.0").
+ WithPresets(linter.PresetStyle).
+ WithURL("https://github.com/macabu/inamedparam"),
+
linter.NewConfig(golinters.NewIneffassign()).
WithEnabledByDefault().
WithSince("v1.0.0").
@@ -700,6 +712,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetStyle, linter.PresetTest).
WithURL("https://github.com/kunwardeep/paralleltest"),
+ linter.NewConfig(golinters.NewPerfSprint()).
+ WithSince("v1.55.0").
+ WithLoadForGoAnalysis().
+ WithPresets(linter.PresetPerformance).
+ WithURL("https://github.com/catenacyber/perfsprint"),
+
linter.NewConfig(golinters.NewPreAlloc(preallocCfg)).
WithSince("v1.19.0").
WithPresets(linter.PresetPerformance).
@@ -715,6 +733,13 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetStyle).
WithURL("https://github.com/yeya24/promlinter"),
+ linter.NewConfig(golinters.NewProtoGetter()).
+ WithSince("v1.55.0").
+ WithPresets(linter.PresetBugs).
+ WithLoadForGoAnalysis().
+ WithAutoFix().
+ WithURL("https://github.com/ghostiam/protogetter"),
+
linter.NewConfig(golinters.NewReassign(reassignCfg)).
WithSince("1.49.0").
WithPresets(linter.PresetBugs).
@@ -733,6 +758,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetBugs, linter.PresetSQL).
WithURL("https://github.com/jingyugao/rowserrcheck"),
+ linter.NewConfig(golinters.NewSlogLint(sloglintCfg)).
+ WithSince("v1.55.0").
+ WithLoadForGoAnalysis().
+ WithPresets(linter.PresetStyle, linter.PresetFormatting).
+ WithURL("https://github.com/go-simpler/sloglint"),
+
linter.NewConfig(golinters.NewScopelint()).
WithSince("v1.12.0").
WithPresets(linter.PresetBugs).
@@ -788,6 +819,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetTest).
WithURL("https://github.com/maratori/testableexamples"),
+ linter.NewConfig(golinters.NewTestifylint(testifylintCfg)).
+ WithSince("v1.55.0").
+ WithPresets(linter.PresetTest, linter.PresetBugs).
+ WithLoadForGoAnalysis().
+ WithURL("https://github.com/Antonboom/testifylint"),
+
linter.NewConfig(golinters.NewTestpackage(testpackageCfg)).
WithSince("v1.25.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
@@ -825,7 +862,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithLoadForGoAnalysis().
WithURL("https://github.com/mvdan/unparam"),
- linter.NewConfig(golinters.NewUnused(unusedCfg)).
+ linter.NewConfig(golinters.NewUnused(unusedCfg, staticcheckCfg)).
WithEnabledByDefault().
WithSince("v1.20.0").
WithLoadForGoAnalysis().
diff --git a/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go b/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go
index 80c9fed7a9..94479bc7b9 100644
--- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go
+++ b/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go
@@ -59,7 +59,7 @@ const (
DebugKeyGoCritic = "gocritic" // Debugs `go-critic` linter.
DebugKeyMegacheck = "megacheck" // Debugs `staticcheck` related linters.
DebugKeyNolint = "nolint" // Debugs a filter excluding issues by `//nolint` comments.
- DebugKeyRevive = "revive" // Debugs `revice` linter.
+ DebugKeyRevive = "revive" // Debugs `revive` linter.
)
func getEnabledDebugs() map[string]bool {
diff --git a/vendor/github.com/golangci/revgrep/.golangci.yml b/vendor/github.com/golangci/revgrep/.golangci.yml
index b8ed6204fe..02ed5ec849 100644
--- a/vendor/github.com/golangci/revgrep/.golangci.yml
+++ b/vendor/github.com/golangci/revgrep/.golangci.yml
@@ -28,12 +28,20 @@ linters-settings:
linters:
enable-all: true
disable:
- - maligned # Deprecated
- - scopelint # Deprecated
- - golint # Deprecated
- - interfacer # Deprecated
- - exhaustivestruct # Deprecated
+ - deadcode # deprecated
+ - exhaustivestruct # deprecated
+ - golint # deprecated
+ - ifshort # deprecated
+ - interfacer # deprecated
+ - maligned # deprecated
+ - nosnakecase # deprecated
+ - scopelint # deprecated
+ - structcheck # deprecated
+ - varcheck # deprecated
- cyclop # duplicate of gocyclo
+ - sqlclosecheck # not relevant (SQL)
+ - rowserrcheck # not relevant (SQL)
+ - execinquery # not relevant (SQL)
- dupl
- lll
- nestif
@@ -54,6 +62,7 @@ linters:
- nosnakecase
- nonamedreturns
- nilerr
+ - depguard
issues:
exclude-use-default: false
diff --git a/vendor/github.com/golangci/revgrep/revgrep.go b/vendor/github.com/golangci/revgrep/revgrep.go
index 4b990fa048..d7af69231b 100644
--- a/vendor/github.com/golangci/revgrep/revgrep.go
+++ b/vendor/github.com/golangci/revgrep/revgrep.go
@@ -1,3 +1,4 @@
+// Package revgrep filter static analysis tools to only lines changed based on a commit reference.
package revgrep
import (
@@ -17,31 +18,26 @@ import (
// Checker provides APIs to filter static analysis tools to specific commits,
// such as showing only issues since last commit.
type Checker struct {
- // Patch file (unified) to read to detect lines being changed, if nil revgrep
- // will attempt to detect the VCS and generate an appropriate patch. Auto
- // detection will search for uncommitted changes first, if none found, will
- // generate a patch from last committed change. File paths within patches
- // must be relative to current working directory.
+ // Patch file (unified) to read to detect lines being changed,
+ // if nil revgrep will attempt to detect the VCS and generate an appropriate patch.
+ // Auto-detection will search for uncommitted changes first,
+ // if none found, will generate a patch from last committed change.
+ // File paths within patches must be relative to current working directory.
Patch io.Reader
- // NewFiles is a list of file names (with absolute paths) where the entire
- // contents of the file is new.
+ // NewFiles is a list of file names (with absolute paths) where the entire contents of the file is new.
NewFiles []string
// Debug sets the debug writer for additional output.
Debug io.Writer
- // RevisionFrom check revision starting at, leave blank for auto detection
- // ignored if patch is set.
+ // RevisionFrom check revision starting at, leave blank for auto-detection ignored if patch is set.
RevisionFrom string
- // WholeFiles indicates that the user wishes to see all issues that comes up
- // anywhere in any file that has been changed in this revision or patch.
+ // WholeFiles indicates that the user wishes to see all issues that comes up anywhere in any file that has been changed in this revision or patch.
WholeFiles bool
- // RevisionTo checks revision finishing at, leave blank for auto detection
- // ignored if patch is set.
+ // RevisionTo checks revision finishing at, leave blank for auto-detection ignored if patch is set.
RevisionTo string
// Regexp to match path, line number, optional column number, and message.
Regexp string
- // AbsPath is used to make an absolute path of an issue's filename to be
- // relative in order to match patch file. If not set, current working
- // directory is used.
+ // AbsPath is used to make an absolute path of an issue's filename to be relative in order to match patch file.
+ // If not set, current working directory is used.
AbsPath string
// Calculated changes for next calls to IsNewIssue
@@ -56,9 +52,7 @@ type Issue struct {
LineNo int
// ColNo is the column number or 0 if none could be parsed.
ColNo int
- // HunkPos is position from file's first @@, for new files this will be the
- // line number.
- //
+ // HunkPos is position from file's first @@, for new files this will be the line number.
// See also: https://developer.github.com/v3/pulls/comments/#create-a-comment
HunkPos int
// Issue text as it appeared from the tool.
@@ -135,16 +129,14 @@ func (c *Checker) IsNewIssue(i InputIssue) (hunkPos int, isNew bool) {
return 0, false
}
-// Check scans reader and writes any lines to writer that have been added in
-// Checker.Patch.
+// Check scans reader and writes any lines to writer that have been added in Checker.Patch.
//
// Returns the issues written to writer when no error occurs.
//
-// If no VCS could be found or other VCS errors occur, all issues are written
-// to writer and an error is returned.
+// If no VCS could be found or other VCS errors occur,
+// all issues are written to writer and an error is returned.
//
-// File paths in reader must be relative to current working directory or
-// absolute.
+// File paths in reader must be relative to current working directory or absolute.
func (c *Checker) Check(reader io.Reader, writer io.Writer) (issues []Issue, err error) {
returnErr := c.Prepare()
writeAll := returnErr != nil
@@ -265,8 +257,7 @@ func (c *Checker) preparePatch() error {
}
// linesChanges returns a map of file names to line numbers being changed.
-// If key is nil, the file has been recently added, else it contains a slice
-// of positions that have been added.
+// If key is nil, the file has been recently added, else it contains a slice of positions that have been added.
func (c *Checker) linesChanged() map[string][]pos {
type state struct {
file string
@@ -343,14 +334,11 @@ func (c *Checker) linesChanged() map[string][]pos {
return changes
}
-// GitPatch returns a patch from a git repository, if no git repository was
-// was found and no errors occurred, nil is returned, else an error is returned
-// revisionFrom and revisionTo defines the git diff parameters, if left blank
-// and there are unstaged changes or untracked files, only those will be returned
-// else only check changes since HEAD~. If revisionFrom is set but revisionTo
-// is not, untracked files will be included, to exclude untracked files set
-// revisionTo to HEAD~. It's incorrect to specify revisionTo without a
-// revisionFrom.
+// GitPatch returns a patch from a git repository,
+// if no git repository was found and no errors occurred, nil is returned, else an error is returned revisionFrom and revisionTo defines the git diff parameters,
+// if left blank and there are unstaged changes or untracked files, only those will be returned else only check changes since HEAD~.
+// If revisionFrom is set but revisionTo is not, untracked files will be included, to exclude untracked files set revisionTo to HEAD~.
+// It's incorrect to specify revisionTo without a revisionFrom.
func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
var patch bytes.Buffer
@@ -378,7 +366,7 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
}
if revisionFrom != "" {
- cmd := exec.Command("git", "diff", "--color=never", "--relative", revisionFrom)
+ cmd := exec.Command("git", "diff", "--color=never", "--no-ext-diff", "--default-prefix", "--relative", revisionFrom)
if revisionTo != "" {
cmd.Args = append(cmd.Args, revisionTo)
}
@@ -396,8 +384,7 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
}
// make a patch for unstaged changes
- // use --no-prefix to remove b/ given: +++ b/main.go
- cmd := exec.Command("git", "diff", "--color=never", "--relative", "--")
+ cmd := exec.Command("git", "diff", "--color=never", "--no-ext-diff", "--default-prefix", "--relative", "--")
cmd.Stdout = &patch
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("error executing git diff: %w", err)
@@ -412,7 +399,7 @@ func GitPatch(revisionFrom, revisionTo string) (io.Reader, []string, error) {
// check for changes in recent commit
- cmd = exec.Command("git", "diff", "--color=never", "--relative", "HEAD~", "--")
+ cmd = exec.Command("git", "diff", "--color=never", "--no-ext-diff", "--default-prefix", "--relative", "HEAD~", "--")
cmd.Stdout = &patch
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("error executing git diff HEAD~: %w", err)
diff --git a/vendor/github.com/jgautheron/goconst/.gitignore b/vendor/github.com/jgautheron/goconst/.gitignore
new file mode 100644
index 0000000000..a9d34d9c41
--- /dev/null
+++ b/vendor/github.com/jgautheron/goconst/.gitignore
@@ -0,0 +1,2 @@
+.idea
+goconst
\ No newline at end of file
diff --git a/vendor/github.com/jgautheron/goconst/parser.go b/vendor/github.com/jgautheron/goconst/parser.go
index 2ed7a9a909..c1edd4c780 100644
--- a/vendor/github.com/jgautheron/goconst/parser.go
+++ b/vendor/github.com/jgautheron/goconst/parser.go
@@ -99,11 +99,11 @@ func (p *Parser) ProcessResults() {
}
// If the value is a number
- if i, err := strconv.Atoi(str); err == nil {
- if p.numberMin != 0 && i < p.numberMin {
+ if i, err := strconv.ParseInt(str, 0, 0); err == nil {
+ if p.numberMin != 0 && i < int64(p.numberMin) {
delete(p.strs, str)
}
- if p.numberMax != 0 && i > p.numberMax {
+ if p.numberMax != 0 && i > int64(p.numberMax) {
delete(p.strs, str)
}
}
diff --git a/vendor/github.com/jgautheron/goconst/visitor.go b/vendor/github.com/jgautheron/goconst/visitor.go
index c0974da8fd..a553814f5c 100644
--- a/vendor/github.com/jgautheron/goconst/visitor.go
+++ b/vendor/github.com/jgautheron/goconst/visitor.go
@@ -62,10 +62,6 @@ func (v *treeVisitor) Visit(node ast.Node) ast.Visitor {
// if foo == "moo"
case *ast.BinaryExpr:
- if t.Op != token.EQL && t.Op != token.NEQ {
- return v
- }
-
var lit *ast.BasicLit
var ok bool
diff --git a/vendor/github.com/macabu/inamedparam/.gitignore b/vendor/github.com/macabu/inamedparam/.gitignore
new file mode 100644
index 0000000000..3b735ec4a8
--- /dev/null
+++ b/vendor/github.com/macabu/inamedparam/.gitignore
@@ -0,0 +1,21 @@
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
diff --git a/vendor/github.com/macabu/inamedparam/LICENSE-MIT b/vendor/github.com/macabu/inamedparam/LICENSE-MIT
new file mode 100644
index 0000000000..b95f480ee5
--- /dev/null
+++ b/vendor/github.com/macabu/inamedparam/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Matheus Macabu
+
+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.
diff --git a/vendor/github.com/macabu/inamedparam/README.md b/vendor/github.com/macabu/inamedparam/README.md
new file mode 100644
index 0000000000..80911c9d7a
--- /dev/null
+++ b/vendor/github.com/macabu/inamedparam/README.md
@@ -0,0 +1,18 @@
+# inamedparam
+
+A linter that reports interfaces with unnamed method parameters.
+
+## Usage
+
+### Standalone
+You can also run it standalone through `go vet`.
+
+You must install the binary to your `$GOBIN` folder like so:
+```sh
+$ go install github.com/macabu/inamedparam/cmd/inamedparam
+```
+
+And then navigate to your Go project's root folder, where can run `go vet` in the following way:
+```sh
+$ go vet -vettool=$(which inamedparam) ./...
+```
diff --git a/vendor/github.com/macabu/inamedparam/inamedparam.go b/vendor/github.com/macabu/inamedparam/inamedparam.go
new file mode 100644
index 0000000000..433e04e5bf
--- /dev/null
+++ b/vendor/github.com/macabu/inamedparam/inamedparam.go
@@ -0,0 +1,67 @@
+package inamedparam
+
+import (
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "inamedparam",
+ Doc: "reports interfaces with unnamed method parameters",
+ Run: run,
+ Requires: []*analysis.Analyzer{
+ inspect.Analyzer,
+ },
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ types := []ast.Node{
+ &ast.InterfaceType{},
+ }
+
+ inspect.Preorder(types, func(n ast.Node) {
+ interfaceType, ok := n.(*ast.InterfaceType)
+ if !ok || interfaceType == nil || interfaceType.Methods == nil {
+ return
+ }
+
+ for _, method := range interfaceType.Methods.List {
+ interfaceFunc, ok := method.Type.(*ast.FuncType)
+ if !ok || interfaceFunc == nil || interfaceFunc.Params == nil {
+ continue
+ }
+
+ methodName := method.Names[0].Name
+
+ for _, param := range interfaceFunc.Params.List {
+ if param.Names == nil {
+ var builtParamType string
+
+ switch paramType := param.Type.(type) {
+ case *ast.SelectorExpr:
+ if ident := paramType.X.(*ast.Ident); ident != nil {
+ builtParamType += ident.Name + "."
+ }
+
+ builtParamType += paramType.Sel.Name
+ case *ast.Ident:
+ builtParamType = paramType.Name
+ }
+
+ if builtParamType != "" {
+ pass.Reportf(param.Pos(), "interface method %v must have named param for type %v", methodName, builtParamType)
+ } else {
+ pass.Reportf(param.Pos(), "interface method %v must have all named params", methodName)
+ }
+ }
+ }
+ }
+ })
+
+ return nil, nil
+}
diff --git a/vendor/github.com/mgechev/revive/config/config.go b/vendor/github.com/mgechev/revive/config/config.go
index 04cd214042..abd554a9f8 100644
--- a/vendor/github.com/mgechev/revive/config/config.go
+++ b/vendor/github.com/mgechev/revive/config/config.go
@@ -31,7 +31,6 @@ var defaultRules = []lint.Rule{
&rule.TimeNamingRule{},
&rule.ContextKeysType{},
&rule.ContextAsArgumentRule{},
- &rule.IfReturnRule{},
&rule.EmptyBlockRule{},
&rule.SuperfluousElseRule{},
&rule.UnusedParamRule{},
@@ -81,12 +80,17 @@ var allRules = append([]lint.Rule{
&rule.FunctionLength{},
&rule.NestedStructs{},
&rule.UselessBreak{},
+ &rule.UncheckedTypeAssertionRule{},
&rule.TimeEqualRule{},
&rule.BannedCharsRule{},
&rule.OptimizeOperandsOrderRule{},
&rule.UseAnyRule{},
&rule.DataRaceRule{},
&rule.CommentSpacingsRule{},
+ &rule.IfReturnRule{},
+ &rule.RedundantImportAlias{},
+ &rule.ImportAliasNamingRule{},
+ &rule.EnforceMapStyleRule{},
}, defaultRules...)
var allFormatters = []lint.Formatter{
@@ -148,6 +152,14 @@ func parseConfig(path string, config *lint.Config) error {
if err != nil {
return fmt.Errorf("cannot parse the config file: %v", err)
}
+ for k, r := range config.Rules {
+ err := r.Initialize()
+ if err != nil {
+ return fmt.Errorf("error in config of rule [%s] : [%v]", k, err)
+ }
+ config.Rules[k] = r
+ }
+
return nil
}
diff --git a/vendor/github.com/mgechev/revive/formatter/sarif.go b/vendor/github.com/mgechev/revive/formatter/sarif.go
index c6288db76f..c42da73eb0 100644
--- a/vendor/github.com/mgechev/revive/formatter/sarif.go
+++ b/vendor/github.com/mgechev/revive/formatter/sarif.go
@@ -88,7 +88,7 @@ func (l *reviveRunLog) AddResult(failure lint.Failure) {
location := garif.NewLocation().WithURI(filename).WithLineColumn(line, column)
result.Locations = append(result.Locations, location)
result.RuleId = failure.RuleName
- result.Level = l.rules[failure.RuleName].Severity
+ result.Level = garif.ResultLevel(l.rules[failure.RuleName].Severity)
l.run.Results = append(l.run.Results, result)
}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/args.go b/vendor/github.com/mgechev/revive/internal/ifelse/args.go
new file mode 100644
index 0000000000..c6e647e697
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/args.go
@@ -0,0 +1,11 @@
+package ifelse
+
+// PreserveScope is a configuration argument that prevents suggestions
+// that would enlarge variable scope
+const PreserveScope = "preserveScope"
+
+// Args contains arguments common to the early-return, indent-error-flow
+// and superfluous-else rules (currently just preserveScope)
+type Args struct {
+ PreserveScope bool
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go
new file mode 100644
index 0000000000..6e6036b899
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch.go
@@ -0,0 +1,93 @@
+package ifelse
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+// Branch contains information about a branch within an if-else chain.
+type Branch struct {
+ BranchKind
+ Call // The function called at the end for kind Panic or Exit.
+ HasDecls bool // The branch has one or more declarations (at the top level block)
+}
+
+// BlockBranch gets the Branch of an ast.BlockStmt.
+func BlockBranch(block *ast.BlockStmt) Branch {
+ blockLen := len(block.List)
+ if blockLen == 0 {
+ return Empty.Branch()
+ }
+
+ branch := StmtBranch(block.List[blockLen-1])
+ branch.HasDecls = hasDecls(block)
+ return branch
+}
+
+// StmtBranch gets the Branch of an ast.Stmt.
+func StmtBranch(stmt ast.Stmt) Branch {
+ switch stmt := stmt.(type) {
+ case *ast.ReturnStmt:
+ return Return.Branch()
+ case *ast.BlockStmt:
+ return BlockBranch(stmt)
+ case *ast.BranchStmt:
+ switch stmt.Tok {
+ case token.BREAK:
+ return Break.Branch()
+ case token.CONTINUE:
+ return Continue.Branch()
+ case token.GOTO:
+ return Goto.Branch()
+ }
+ case *ast.ExprStmt:
+ fn, ok := ExprCall(stmt)
+ if !ok {
+ break
+ }
+ kind, ok := DeviatingFuncs[fn]
+ if ok {
+ return Branch{BranchKind: kind, Call: fn}
+ }
+ case *ast.EmptyStmt:
+ return Empty.Branch()
+ case *ast.LabeledStmt:
+ return StmtBranch(stmt.Stmt)
+ }
+ return Regular.Branch()
+}
+
+// String returns a brief string representation
+func (b Branch) String() string {
+ switch b.BranchKind {
+ case Panic, Exit:
+ return fmt.Sprintf("... %v()", b.Call)
+ default:
+ return b.BranchKind.String()
+ }
+}
+
+// LongString returns a longer form string representation
+func (b Branch) LongString() string {
+ switch b.BranchKind {
+ case Panic, Exit:
+ return fmt.Sprintf("call to %v function", b.Call)
+ default:
+ return b.BranchKind.LongString()
+ }
+}
+
+func hasDecls(block *ast.BlockStmt) bool {
+ for _, stmt := range block.List {
+ switch stmt := stmt.(type) {
+ case *ast.DeclStmt:
+ return true
+ case *ast.AssignStmt:
+ if stmt.Tok == token.DEFINE {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go
new file mode 100644
index 0000000000..41601d1e1d
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/branch_kind.go
@@ -0,0 +1,101 @@
+package ifelse
+
+// BranchKind is a classifier for if-else branches. It says whether the branch is empty,
+// and whether the branch ends with a statement that deviates control flow.
+type BranchKind int
+
+const (
+ // Empty branches do nothing
+ Empty BranchKind = iota
+
+ // Return branches return from the current function
+ Return
+
+ // Continue branches continue a surrounding "for" loop
+ Continue
+
+ // Break branches break a surrounding "for" loop
+ Break
+
+ // Goto branches conclude with a "goto" statement
+ Goto
+
+ // Panic branches panic the current function
+ Panic
+
+ // Exit branches end the program
+ Exit
+
+ // Regular branches do not fit any category above
+ Regular
+)
+
+// IsEmpty tests if the branch is empty
+func (k BranchKind) IsEmpty() bool { return k == Empty }
+
+// Returns tests if the branch returns from the current function
+func (k BranchKind) Returns() bool { return k == Return }
+
+// Deviates tests if the control does not flow to the first
+// statement following the if-else chain.
+func (k BranchKind) Deviates() bool {
+ switch k {
+ case Empty, Regular:
+ return false
+ case Return, Continue, Break, Goto, Panic, Exit:
+ return true
+ default:
+ panic("invalid kind")
+ }
+}
+
+// Branch returns a Branch with the given kind
+func (k BranchKind) Branch() Branch { return Branch{BranchKind: k} }
+
+// String returns a brief string representation
+func (k BranchKind) String() string {
+ switch k {
+ case Empty:
+ return ""
+ case Regular:
+ return "..."
+ case Return:
+ return "... return"
+ case Continue:
+ return "... continue"
+ case Break:
+ return "... break"
+ case Goto:
+ return "... goto"
+ case Panic:
+ return "... panic()"
+ case Exit:
+ return "... os.Exit()"
+ default:
+ panic("invalid kind")
+ }
+}
+
+// LongString returns a longer form string representation
+func (k BranchKind) LongString() string {
+ switch k {
+ case Empty:
+ return "an empty block"
+ case Regular:
+ return "a regular statement"
+ case Return:
+ return "a return statement"
+ case Continue:
+ return "a continue statement"
+ case Break:
+ return "a break statement"
+ case Goto:
+ return "a goto statement"
+ case Panic:
+ return "a function call that panics"
+ case Exit:
+ return "a function call that exits the program"
+ default:
+ panic("invalid kind")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/chain.go b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go
new file mode 100644
index 0000000000..9891635ee1
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/chain.go
@@ -0,0 +1,10 @@
+package ifelse
+
+// Chain contains information about an if-else chain.
+type Chain struct {
+ If Branch // what happens at the end of the "if" block
+ Else Branch // what happens at the end of the "else" block
+ HasInitializer bool // is there an "if"-initializer somewhere in the chain?
+ HasPriorNonDeviating bool // is there a prior "if" block that does NOT deviate control flow?
+ AtBlockEnd bool // whether the chain is placed at the end of the surrounding block
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/doc.go b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go
new file mode 100644
index 0000000000..0aa2c98175
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/doc.go
@@ -0,0 +1,6 @@
+// Package ifelse provides helpers for analysing the control flow in if-else chains,
+// presently used by the following rules:
+// - early-return
+// - indent-error-flow
+// - superfluous-else
+package ifelse
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/func.go b/vendor/github.com/mgechev/revive/internal/ifelse/func.go
new file mode 100644
index 0000000000..7ba3519184
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/func.go
@@ -0,0 +1,51 @@
+package ifelse
+
+import (
+ "fmt"
+ "go/ast"
+)
+
+// Call contains the name of a function that deviates control flow.
+type Call struct {
+ Pkg string // The package qualifier of the function, if not built-in.
+ Name string // The function name.
+}
+
+// DeviatingFuncs lists known control flow deviating function calls.
+var DeviatingFuncs = map[Call]BranchKind{
+ {"os", "Exit"}: Exit,
+ {"log", "Fatal"}: Exit,
+ {"log", "Fatalf"}: Exit,
+ {"log", "Fatalln"}: Exit,
+ {"", "panic"}: Panic,
+ {"log", "Panic"}: Panic,
+ {"log", "Panicf"}: Panic,
+ {"log", "Panicln"}: Panic,
+}
+
+// ExprCall gets the Call of an ExprStmt, if any.
+func ExprCall(expr *ast.ExprStmt) (Call, bool) {
+ call, ok := expr.X.(*ast.CallExpr)
+ if !ok {
+ return Call{}, false
+ }
+ switch v := call.Fun.(type) {
+ case *ast.Ident:
+ return Call{Name: v.Name}, true
+ case *ast.SelectorExpr:
+ if ident, ok := v.X.(*ast.Ident); ok {
+ return Call{Name: v.Sel.Name, Pkg: ident.Name}, true
+ }
+ }
+ return Call{}, false
+}
+
+// String returns the function name with package qualifier (if any)
+func (f Call) String() string {
+ switch {
+ case f.Pkg != "":
+ return fmt.Sprintf("%s.%s", f.Pkg, f.Name)
+ default:
+ return f.Name
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/rule.go b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go
new file mode 100644
index 0000000000..07ad456b65
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/rule.go
@@ -0,0 +1,105 @@
+package ifelse
+
+import (
+ "go/ast"
+ "go/token"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// Rule is an interface for linters operating on if-else chains
+type Rule interface {
+ CheckIfElse(chain Chain, args Args) (failMsg string)
+}
+
+// Apply evaluates the given Rule on if-else chains found within the given AST,
+// and returns the failures.
+//
+// Note that in if-else chain with multiple "if" blocks, only the *last* one is checked,
+// that is to say, given:
+//
+// if foo {
+// ...
+// } else if bar {
+// ...
+// } else {
+// ...
+// }
+//
+// Only the block following "bar" is linted. This is because the rules that use this function
+// do not presently have anything to say about earlier blocks in the chain.
+func Apply(rule Rule, node ast.Node, target Target, args lint.Arguments) []lint.Failure {
+ v := &visitor{rule: rule, target: target}
+ for _, arg := range args {
+ if arg == PreserveScope {
+ v.args.PreserveScope = true
+ }
+ }
+ ast.Walk(v, node)
+ return v.failures
+}
+
+type visitor struct {
+ failures []lint.Failure
+ target Target
+ rule Rule
+ args Args
+}
+
+func (v *visitor) Visit(node ast.Node) ast.Visitor {
+ block, ok := node.(*ast.BlockStmt)
+ if !ok {
+ return v
+ }
+
+ for i, stmt := range block.List {
+ if ifStmt, ok := stmt.(*ast.IfStmt); ok {
+ v.visitChain(ifStmt, Chain{AtBlockEnd: i == len(block.List)-1})
+ continue
+ }
+ ast.Walk(v, stmt)
+ }
+ return nil
+}
+
+func (v *visitor) visitChain(ifStmt *ast.IfStmt, chain Chain) {
+ // look for other if-else chains nested inside this if { } block
+ ast.Walk(v, ifStmt.Body)
+
+ if ifStmt.Else == nil {
+ // no else branch
+ return
+ }
+
+ if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
+ chain.HasInitializer = true
+ }
+ chain.If = BlockBranch(ifStmt.Body)
+
+ switch elseBlock := ifStmt.Else.(type) {
+ case *ast.IfStmt:
+ if !chain.If.Deviates() {
+ chain.HasPriorNonDeviating = true
+ }
+ v.visitChain(elseBlock, chain)
+ case *ast.BlockStmt:
+ // look for other if-else chains nested inside this else { } block
+ ast.Walk(v, elseBlock)
+
+ chain.Else = BlockBranch(elseBlock)
+ if failMsg := v.rule.CheckIfElse(chain, v.args); failMsg != "" {
+ if chain.HasInitializer {
+ // if statement has a := initializer, so we might need to move the assignment
+ // onto its own line in case the body references it
+ failMsg += " (move short variable declaration to its own line if necessary)"
+ }
+ v.failures = append(v.failures, lint.Failure{
+ Confidence: 1,
+ Node: v.target.node(ifStmt),
+ Failure: failMsg,
+ })
+ }
+ default:
+ panic("invalid node type for else")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/internal/ifelse/target.go b/vendor/github.com/mgechev/revive/internal/ifelse/target.go
new file mode 100644
index 0000000000..81ff1c3037
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/internal/ifelse/target.go
@@ -0,0 +1,25 @@
+package ifelse
+
+import "go/ast"
+
+// Target decides what line/column should be indicated by the rule in question.
+type Target int
+
+const (
+ // TargetIf means the text refers to the "if"
+ TargetIf Target = iota
+
+ // TargetElse means the text refers to the "else"
+ TargetElse
+)
+
+func (t Target) node(ifStmt *ast.IfStmt) ast.Node {
+ switch t {
+ case TargetIf:
+ return ifStmt
+ case TargetElse:
+ return ifStmt.Else
+ default:
+ panic("bad target")
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/lint/config.go b/vendor/github.com/mgechev/revive/lint/config.go
index 2763058046..9b26d58417 100644
--- a/vendor/github.com/mgechev/revive/lint/config.go
+++ b/vendor/github.com/mgechev/revive/lint/config.go
@@ -3,16 +3,44 @@ package lint
// Arguments is type used for the arguments of a rule.
type Arguments = []interface{}
+type FileFilters = []*FileFilter
+
// RuleConfig is type used for the rule configuration.
type RuleConfig struct {
Arguments Arguments
Severity Severity
Disabled bool
+ // Exclude - rule-level file excludes, TOML related (strings)
+ Exclude []string
+ // excludeFilters - regex-based file filters, initialized from Exclude
+ excludeFilters []*FileFilter
+}
+
+// Initialize - should be called after reading from TOML file
+func (rc *RuleConfig) Initialize() error {
+ for _, f := range rc.Exclude {
+ ff, err := ParseFileFilter(f)
+ if err != nil {
+ return err
+ }
+ rc.excludeFilters = append(rc.excludeFilters, ff)
+ }
+ return nil
}
// RulesConfig defines the config for all rules.
type RulesConfig = map[string]RuleConfig
+// MustExclude - checks if given filename `name` must be excluded
+func (rcfg *RuleConfig) MustExclude(name string) bool {
+ for _, exclude := range rcfg.excludeFilters {
+ if exclude.MatchFileName(name) {
+ return true
+ }
+ }
+ return false
+}
+
// DirectiveConfig is type used for the linter directive configuration.
type DirectiveConfig struct {
Severity Severity
diff --git a/vendor/github.com/mgechev/revive/lint/file.go b/vendor/github.com/mgechev/revive/lint/file.go
index dcf0e608f6..23255304c5 100644
--- a/vendor/github.com/mgechev/revive/lint/file.go
+++ b/vendor/github.com/mgechev/revive/lint/file.go
@@ -102,6 +102,9 @@ func (f *File) lint(rules []Rule, config Config, failures chan Failure) {
disabledIntervals := f.disabledIntervals(rules, mustSpecifyDisableReason, failures)
for _, currentRule := range rules {
ruleConfig := rulesConfig[currentRule.Name()]
+ if ruleConfig.MustExclude(f.Name) {
+ continue
+ }
currentFailures := currentRule.Apply(f, ruleConfig.Arguments)
for idx, failure := range currentFailures {
if failure.RuleName == "" {
diff --git a/vendor/github.com/mgechev/revive/lint/filefilter.go b/vendor/github.com/mgechev/revive/lint/filefilter.go
new file mode 100644
index 0000000000..8da090b9cc
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/lint/filefilter.go
@@ -0,0 +1,128 @@
+package lint
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// FileFilter - file filter to exclude some files for rule
+// supports whole
+// 1. file/dir names : pkg/mypkg/my.go,
+// 2. globs: **/*.pb.go,
+// 3. regexes (~ prefix) ~-tmp\.\d+\.go
+// 4. special test marker `TEST` - treats as `~_test\.go`
+type FileFilter struct {
+ // raw definition of filter inside config
+ raw string
+ // don't care what was at start, will use regexes inside
+ rx *regexp.Regexp
+ // marks filter as matching everything
+ matchesAll bool
+ // marks filter as matching nothing
+ matchesNothing bool
+}
+
+// ParseFileFilter - creates [FileFilter] for given raw filter
+// if empty string, it matches nothing
+// if `*`, or `~`, it matches everything
+// while regexp could be invalid, it could return it's compilation error
+func ParseFileFilter(rawFilter string) (*FileFilter, error) {
+ rawFilter = strings.TrimSpace(rawFilter)
+ result := new(FileFilter)
+ result.raw = rawFilter
+ result.matchesNothing = len(result.raw) == 0
+ result.matchesAll = result.raw == "*" || result.raw == "~"
+ if !result.matchesAll && !result.matchesNothing {
+ if err := result.prepareRegexp(); err != nil {
+ return nil, err
+ }
+ }
+ return result, nil
+}
+
+func (ff *FileFilter) String() string { return ff.raw }
+
+// MatchFileName - checks if file name matches filter
+func (ff *FileFilter) MatchFileName(name string) bool {
+ if ff.matchesAll {
+ return true
+ }
+ if ff.matchesNothing {
+ return false
+ }
+ name = strings.ReplaceAll(name, "\\", "/")
+ return ff.rx.MatchString(name)
+}
+
+var fileFilterInvalidGlobRegexp = regexp.MustCompile(`[^/]\*\*[^/]`)
+var escapeRegexSymbols = ".+{}()[]^$"
+
+func (ff *FileFilter) prepareRegexp() error {
+ var err error
+ var src = ff.raw
+ if src == "TEST" {
+ src = "~_test\\.go"
+ }
+ if strings.HasPrefix(src, "~") {
+ ff.rx, err = regexp.Compile(src[1:])
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile error: [%v]", ff.raw, err)
+ }
+ return nil
+ }
+ /* globs */
+ if strings.Contains(src, "*") {
+ if fileFilterInvalidGlobRegexp.MatchString(src) {
+ return fmt.Errorf("invalid file filter [%s], invalid glob pattern", ff.raw)
+ }
+ var rxBuild strings.Builder
+ rxBuild.WriteByte('^')
+ wasStar := false
+ justDirGlob := false
+ for _, c := range src {
+ if c == '*' {
+ if wasStar {
+ rxBuild.WriteString(`[\s\S]*`)
+ wasStar = false
+ justDirGlob = true
+ continue
+ }
+ wasStar = true
+ continue
+ }
+ if wasStar {
+ rxBuild.WriteString("[^/]*")
+ wasStar = false
+ }
+ if strings.ContainsRune(escapeRegexSymbols, c) {
+ rxBuild.WriteByte('\\')
+ }
+ rxBuild.WriteRune(c)
+ if c == '/' && justDirGlob {
+ rxBuild.WriteRune('?')
+ }
+ justDirGlob = false
+ }
+ if wasStar {
+ rxBuild.WriteString("[^/]*")
+ }
+ rxBuild.WriteByte('$')
+ ff.rx, err = regexp.Compile(rxBuild.String())
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile error after glob expand: [%v]", ff.raw, err)
+ }
+ return nil
+ }
+
+ // it's whole file mask, just escape dots and normilze separators
+ fillRx := src
+ fillRx = strings.ReplaceAll(fillRx, "\\", "/")
+ fillRx = strings.ReplaceAll(fillRx, ".", `\.`)
+ fillRx = "^" + fillRx + "$"
+ ff.rx, err = regexp.Compile(fillRx)
+ if err != nil {
+ return fmt.Errorf("invalid file filter [%s], regexp compile full path: [%v]", ff.raw, err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/mgechev/revive/rule/argument-limit.go b/vendor/github.com/mgechev/revive/rule/argument-limit.go
index 8042da15e3..8120288fd5 100644
--- a/vendor/github.com/mgechev/revive/rule/argument-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/argument-limit.go
@@ -14,10 +14,16 @@ type ArgumentsLimitRule struct {
sync.Mutex
}
+const defaultArgumentsLimit = 8
+
func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.total == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.total = defaultArgumentsLimit
+ return
+ }
total, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
@@ -25,7 +31,6 @@ func (r *ArgumentsLimitRule) configure(arguments lint.Arguments) {
}
r.total = int(total)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/banned-characters.go b/vendor/github.com/mgechev/revive/rule/banned-characters.go
index 76fa2235a9..12997bae11 100644
--- a/vendor/github.com/mgechev/revive/rule/banned-characters.go
+++ b/vendor/github.com/mgechev/revive/rule/banned-characters.go
@@ -19,11 +19,11 @@ const bannedCharsRuleName = "banned-characters"
func (r *BannedCharsRule) configure(arguments lint.Arguments) {
r.Lock()
- if r.bannedCharList == nil {
+ defer r.Unlock()
+ if r.bannedCharList == nil && len(arguments) > 0 {
checkNumberOfArguments(1, arguments, bannedCharsRuleName)
r.bannedCharList = r.getBannedCharsList(arguments)
}
- r.Unlock()
}
// Apply applied the rule to the given file.
diff --git a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
index a9c11a7d0b..1973faef87 100644
--- a/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
+++ b/vendor/github.com/mgechev/revive/rule/cognitive-complexity.go
@@ -16,10 +16,17 @@ type CognitiveComplexityRule struct {
sync.Mutex
}
+const defaultMaxCognitiveComplexity = 7
+
func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.maxComplexity == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+
+ if len(arguments) < 1 {
+ r.maxComplexity = defaultMaxCognitiveComplexity
+ return
+ }
complexity, ok := arguments[0].(int64)
if !ok {
@@ -27,7 +34,6 @@ func (r *CognitiveComplexityRule) configure(arguments lint.Arguments) {
}
r.maxComplexity = int(complexity)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/confusing-naming.go b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
index 34cdb907a8..8b1c3eac4b 100644
--- a/vendor/github.com/mgechev/revive/rule/confusing-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/confusing-naming.go
@@ -27,10 +27,10 @@ type packages struct {
func (ps *packages) methodNames(lp *lint.Package) pkgMethods {
ps.mu.Lock()
+ defer ps.mu.Unlock()
for _, pkg := range ps.pkgs {
if pkg.pkg == lp {
- ps.mu.Unlock()
return pkg
}
}
@@ -38,7 +38,6 @@ func (ps *packages) methodNames(lp *lint.Package) pkgMethods {
pkgm := pkgMethods{pkg: lp, methods: make(map[string]map[string]*referenceMethod), mu: &sync.Mutex{}}
ps.pkgs = append(ps.pkgs, pkgm)
- ps.mu.Unlock()
return pkgm
}
@@ -72,6 +71,7 @@ func (*ConfusingNamingRule) Name() string {
// checkMethodName checks if a given method/function name is similar (just case differences) to other method/function of the same struct/file.
func checkMethodName(holder string, id *ast.Ident, w *lintConfusingNames) {
+
if id.Name == "init" && holder == defaultStructName {
// ignore init functions
return
@@ -137,8 +137,11 @@ func getStructName(r *ast.FieldList) string {
t := r.List[0].Type
- if p, _ := t.(*ast.StarExpr); p != nil { // if a pointer receiver => dereference pointer receiver types
- t = p.X
+ switch v := t.(type) {
+ case *ast.StarExpr:
+ t = v.X
+ case *ast.IndexExpr:
+ t = v.X
}
if p, _ := t.(*ast.Ident); p != nil {
diff --git a/vendor/github.com/mgechev/revive/rule/cyclomatic.go b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
index afd41818b8..9f6d50043d 100644
--- a/vendor/github.com/mgechev/revive/rule/cyclomatic.go
+++ b/vendor/github.com/mgechev/revive/rule/cyclomatic.go
@@ -17,10 +17,16 @@ type CyclomaticRule struct {
sync.Mutex
}
+const defaultMaxCyclomaticComplexity = 10
+
func (r *CyclomaticRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.maxComplexity == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.maxComplexity = defaultMaxCyclomaticComplexity
+ return
+ }
complexity, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
@@ -28,7 +34,6 @@ func (r *CyclomaticRule) configure(arguments lint.Arguments) {
}
r.maxComplexity = int(complexity)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/defer.go b/vendor/github.com/mgechev/revive/rule/defer.go
index f8224fd4d1..f3ea17920e 100644
--- a/vendor/github.com/mgechev/revive/rule/defer.go
+++ b/vendor/github.com/mgechev/revive/rule/defer.go
@@ -97,18 +97,21 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
w.newFailure("return in a defer function has no effect", n, 1.0, "logic", "return")
}
case *ast.CallExpr:
- if !w.inADefer && isIdent(n.Fun, "recover") {
+ isCallToRecover := isIdent(n.Fun, "recover")
+ switch {
+ case !w.inADefer && isCallToRecover:
// func fn() { recover() }
//
// confidence is not 1 because recover can be in a function that is deferred elsewhere
w.newFailure("recover must be called inside a deferred function", n, 0.8, "logic", "recover")
- } else if w.inADefer && !w.inAFuncLit && isIdent(n.Fun, "recover") {
+ case w.inADefer && !w.inAFuncLit && isCallToRecover:
// defer helper(recover())
//
// confidence is not truly 1 because this could be in a correctly-deferred func,
// but it is very likely to be a misunderstanding of defer's behavior around arguments.
w.newFailure("recover must be called inside a deferred function, this is executing recover immediately", n, 1, "logic", "immediate-recover")
}
+
case *ast.DeferStmt:
if isIdent(n.Call.Fun, "recover") {
// defer recover()
@@ -119,7 +122,12 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
}
w.visitSubtree(n.Call.Fun, true, false, false)
for _, a := range n.Call.Args {
- w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
+ switch a.(type) {
+ case *ast.FuncLit:
+ continue // too hard to analyze deferred calls with func literals args
+ default:
+ w.visitSubtree(a, true, false, false) // check arguments, they should not contain recover()
+ }
}
if w.inALoop {
@@ -136,6 +144,7 @@ func (w lintDeferRule) Visit(node ast.Node) ast.Visitor {
w.newFailure("be careful when deferring calls to methods without pointer receiver", fn, 0.8, "bad practice", "method-call")
}
}
+
}
return nil
}
diff --git a/vendor/github.com/mgechev/revive/rule/dot-imports.go b/vendor/github.com/mgechev/revive/rule/dot-imports.go
index 25ff526cb5..db78f1957b 100644
--- a/vendor/github.com/mgechev/revive/rule/dot-imports.go
+++ b/vendor/github.com/mgechev/revive/rule/dot-imports.go
@@ -39,9 +39,8 @@ type lintImports struct {
}
func (w lintImports) Visit(_ ast.Node) ast.Visitor {
- for i, is := range w.fileAst.Imports {
- _ = i
- if is.Name != nil && is.Name.Name == "." && !w.file.IsTest() {
+ for _, is := range w.fileAst.Imports {
+ if is.Name != nil && is.Name.Name == "." {
w.onFailure(lint.Failure{
Confidence: 1,
Failure: "should not use dot imports",
diff --git a/vendor/github.com/mgechev/revive/rule/early-return.go b/vendor/github.com/mgechev/revive/rule/early-return.go
index ed0fcfae43..90a0acc558 100644
--- a/vendor/github.com/mgechev/revive/rule/early-return.go
+++ b/vendor/github.com/mgechev/revive/rule/early-return.go
@@ -2,9 +2,8 @@ package rule
import (
"fmt"
- "go/ast"
- "go/token"
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -13,16 +12,8 @@ import (
type EarlyReturnRule struct{}
// Apply applies the rule to given file.
-func (*EarlyReturnRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- w := lintEarlyReturnRule{onFailure: onFailure}
- ast.Walk(w, file.AST)
- return failures
+func (e *EarlyReturnRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetIf, args)
}
// Name returns the rule name.
@@ -30,147 +21,31 @@ func (*EarlyReturnRule) Name() string {
return "early-return"
}
-type lintEarlyReturnRule struct {
- onFailure func(lint.Failure)
-}
-
-func (w lintEarlyReturnRule) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok {
- return w
- }
-
- w.visitIf(ifStmt, false, false)
- return nil
-}
-
-func (w lintEarlyReturnRule) visitIf(ifStmt *ast.IfStmt, hasNonReturnBranch, hasIfInitializer bool) {
- // look for other if-else chains nested inside this if { } block
- ast.Walk(w, ifStmt.Body)
-
- if ifStmt.Else == nil {
- // no else branch
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *EarlyReturnRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.Else.Deviates() {
+ // this rule only applies if the else-block deviates control flow
return
}
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- hasIfInitializer = true
- }
- bodyFlow := w.branchFlow(ifStmt.Body)
-
- switch elseBlock := ifStmt.Else.(type) {
- case *ast.IfStmt:
- if bodyFlow.canFlowIntoNext() {
- hasNonReturnBranch = true
- }
- w.visitIf(elseBlock, hasNonReturnBranch, hasIfInitializer)
-
- case *ast.BlockStmt:
- // look for other if-else chains nested inside this else { } block
- ast.Walk(w, elseBlock)
-
- if hasNonReturnBranch && bodyFlow != branchFlowEmpty {
- // if we de-indent this block then a previous branch
- // might flow into it, affecting program behaviour
- return
- }
-
- if !bodyFlow.canFlowIntoNext() {
- // avoid overlapping with superfluous-else
- return
- }
-
- elseFlow := w.branchFlow(elseBlock)
- if !elseFlow.canFlowIntoNext() {
- failMsg := fmt.Sprintf("if c {%[1]s } else {%[2]s } can be simplified to if !c {%[2]s }%[1]s",
- bodyFlow, elseFlow)
-
- if hasIfInitializer {
- // if statement has a := initializer, so we might need to move the assignment
- // onto its own line in case the body references it
- failMsg += " (move short variable declaration to its own line if necessary)"
- }
-
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: ifStmt,
- Failure: failMsg,
- })
- }
-
- default:
- panic("invalid node type for else")
- }
-}
-
-type branchFlowKind int
-
-const (
- branchFlowEmpty branchFlowKind = iota
- branchFlowReturn
- branchFlowPanic
- branchFlowContinue
- branchFlowBreak
- branchFlowGoto
- branchFlowRegular
-)
-
-func (w lintEarlyReturnRule) branchFlow(block *ast.BlockStmt) branchFlowKind {
- blockLen := len(block.List)
- if blockLen == 0 {
- return branchFlowEmpty
+ if chain.HasPriorNonDeviating && !chain.If.IsEmpty() {
+ // if we de-indent this block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- switch stmt := block.List[blockLen-1].(type) {
- case *ast.ReturnStmt:
- return branchFlowReturn
- case *ast.BlockStmt:
- return w.branchFlow(stmt)
- case *ast.BranchStmt:
- switch stmt.Tok {
- case token.BREAK:
- return branchFlowBreak
- case token.CONTINUE:
- return branchFlowContinue
- case token.GOTO:
- return branchFlowGoto
- }
- case *ast.ExprStmt:
- if call, ok := stmt.X.(*ast.CallExpr); ok && isIdent(call.Fun, "panic") {
- return branchFlowPanic
- }
+ if chain.If.Deviates() {
+ // avoid overlapping with superfluous-else
+ return
}
- return branchFlowRegular
-}
-
-// Whether this branch's control can flow into the next statement following the if-else chain
-func (k branchFlowKind) canFlowIntoNext() bool {
- switch k {
- case branchFlowReturn, branchFlowPanic, branchFlowContinue, branchFlowBreak, branchFlowGoto:
- return false
- default:
- return true
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.If.HasDecls) {
+ // avoid increasing variable scope
+ return
}
-}
-func (k branchFlowKind) String() string {
- switch k {
- case branchFlowEmpty:
- return ""
- case branchFlowReturn:
- return " ... return"
- case branchFlowPanic:
- return " ... panic()"
- case branchFlowContinue:
- return " ... continue"
- case branchFlowBreak:
- return " ... break"
- case branchFlowGoto:
- return " ... goto"
- case branchFlowRegular:
- return " ..."
- default:
- panic("invalid kind")
+ if chain.If.IsEmpty() {
+ return fmt.Sprintf("if c { } else { %[1]v } can be simplified to if !c { %[1]v }", chain.Else)
}
+ return fmt.Sprintf("if c { ... } else { %[1]v } can be simplified to if !c { %[1]v } ...", chain.Else)
}
diff --git a/vendor/github.com/mgechev/revive/rule/enforce-map-style.go b/vendor/github.com/mgechev/revive/rule/enforce-map-style.go
new file mode 100644
index 0000000000..ae27b654f2
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/enforce-map-style.go
@@ -0,0 +1,164 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+type enforceMapStyleType string
+
+const (
+ enforceMapStyleTypeAny enforceMapStyleType = "any"
+ enforceMapStyleTypeMake enforceMapStyleType = "make"
+ enforceMapStyleTypeLiteral enforceMapStyleType = "literal"
+)
+
+func mapStyleFromString(s string) (enforceMapStyleType, error) {
+ switch s {
+ case string(enforceMapStyleTypeAny), "":
+ return enforceMapStyleTypeAny, nil
+ case string(enforceMapStyleTypeMake):
+ return enforceMapStyleTypeMake, nil
+ case string(enforceMapStyleTypeLiteral):
+ return enforceMapStyleTypeLiteral, nil
+ default:
+ return enforceMapStyleTypeAny, fmt.Errorf(
+ "invalid map style: %s (expecting one of %v)",
+ s,
+ []enforceMapStyleType{
+ enforceMapStyleTypeAny,
+ enforceMapStyleTypeMake,
+ enforceMapStyleTypeLiteral,
+ },
+ )
+ }
+}
+
+// EnforceMapStyleRule implements a rule to enforce `make(map[type]type)` over `map[type]type{}`.
+type EnforceMapStyleRule struct {
+ configured bool
+ enforceMapStyle enforceMapStyleType
+ sync.Mutex
+}
+
+func (r *EnforceMapStyleRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ if len(arguments) < 1 {
+ r.enforceMapStyle = enforceMapStyleTypeAny
+ return
+ }
+
+ enforceMapStyle, ok := arguments[0].(string)
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument '%v' for 'enforce-map-style' rule. Expecting string, got %T", arguments[0], arguments[0]))
+ }
+
+ var err error
+ r.enforceMapStyle, err = mapStyleFromString(enforceMapStyle)
+
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the enforce-map-style rule: %v", err))
+ }
+}
+
+// Apply applies the rule to given file.
+func (r *EnforceMapStyleRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ if r.enforceMapStyle == enforceMapStyleTypeAny {
+ // this linter is not configured
+ return nil
+ }
+
+ var failures []lint.Failure
+
+ astFile := file.AST
+ ast.Inspect(astFile, func(n ast.Node) bool {
+ switch v := n.(type) {
+ case *ast.CompositeLit:
+ if r.enforceMapStyle != enforceMapStyleTypeMake {
+ return true
+ }
+
+ if !r.isMapType(v.Type) {
+ return true
+ }
+
+ if len(v.Elts) > 0 {
+ // not an empty map
+ return true
+ }
+
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Node: v,
+ Category: "style",
+ Failure: "use make(map[type]type) instead of map[type]type{}",
+ })
+ case *ast.CallExpr:
+ if r.enforceMapStyle != enforceMapStyleTypeLiteral {
+ // skip any function calls, even if it's make(map[type]type)
+ // we don't want to report it if literals are not enforced
+ return true
+ }
+
+ ident, ok := v.Fun.(*ast.Ident)
+ if !ok || ident.Name != "make" {
+ return true
+ }
+
+ if len(v.Args) != 1 {
+ // skip make(map[type]type, size) and invalid empty declarations
+ return true
+ }
+
+ if !r.isMapType(v.Args[0]) {
+ // not a map type
+ return true
+ }
+
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Node: v.Args[0],
+ Category: "style",
+ Failure: "use map[type]type{} instead of make(map[type]type)",
+ })
+ }
+ return true
+ })
+
+ return failures
+}
+
+// Name returns the rule name.
+func (r *EnforceMapStyleRule) Name() string {
+ return "enforce-map-style"
+}
+
+func (r *EnforceMapStyleRule) isMapType(v ast.Expr) bool {
+ switch t := v.(type) {
+ case *ast.MapType:
+ return true
+ case *ast.Ident:
+ if t.Obj == nil {
+ return false
+ }
+ typeSpec, ok := t.Obj.Decl.(*ast.TypeSpec)
+ if !ok {
+ return false
+ }
+ return r.isMapType(typeSpec.Type)
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/mgechev/revive/rule/file-header.go b/vendor/github.com/mgechev/revive/rule/file-header.go
index 76f548f51f..a7d69ff2b1 100644
--- a/vendor/github.com/mgechev/revive/rule/file-header.go
+++ b/vendor/github.com/mgechev/revive/rule/file-header.go
@@ -21,21 +21,28 @@ var (
func (r *FileHeaderRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.header == "" {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ return
+ }
+
var ok bool
r.header, ok = arguments[0].(string)
if !ok {
- panic(fmt.Sprintf("invalid argument for \"file-header\" rule: first argument should be a string, got %T", arguments[0]))
+ panic(fmt.Sprintf("invalid argument for \"file-header\" rule: argument should be a string, got %T", arguments[0]))
}
}
- r.Unlock()
}
// Apply applies the rule to given file.
func (r *FileHeaderRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
r.configure(arguments)
+ if r.header == "" {
+ return nil
+ }
+
failure := []lint.Failure{
{
Node: file.AST,
diff --git a/vendor/github.com/mgechev/revive/rule/function-length.go b/vendor/github.com/mgechev/revive/rule/function-length.go
index d600d7a2a1..f7ab8b98e6 100644
--- a/vendor/github.com/mgechev/revive/rule/function-length.go
+++ b/vendor/github.com/mgechev/revive/rule/function-length.go
@@ -19,13 +19,13 @@ type FunctionLength struct {
func (r *FunctionLength) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if !r.configured {
maxStmt, maxLines := r.parseArguments(arguments)
r.maxStmt = int(maxStmt)
r.maxLines = int(maxLines)
r.configured = true
}
- r.Unlock()
}
// Apply applies the rule to given file.
@@ -53,7 +53,14 @@ func (*FunctionLength) Name() string {
return "function-length"
}
+const defaultFuncStmtsLimit = 50
+const defaultFuncLinesLimit = 75
+
func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLines int64) {
+ if len(arguments) == 0 {
+ return defaultFuncStmtsLimit, defaultFuncLinesLimit
+ }
+
if len(arguments) != 2 {
panic(fmt.Sprintf(`invalid configuration for "function-length" rule, expected 2 arguments but got %d`, len(arguments)))
}
diff --git a/vendor/github.com/mgechev/revive/rule/function-result-limit.go b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
index 5d2b87316a..6a0748011d 100644
--- a/vendor/github.com/mgechev/revive/rule/function-result-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/function-result-limit.go
@@ -14,11 +14,16 @@ type FunctionResultsLimitRule struct {
sync.Mutex
}
+const defaultResultsLimit = 3
+
func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
-
+ if len(arguments) < 1 {
+ r.max = defaultResultsLimit
+ return
+ }
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok {
panic(fmt.Sprintf(`invalid value passed as return results number to the "function-result-limit" rule; need int64 but got %T`, arguments[0]))
@@ -28,7 +33,6 @@ func (r *FunctionResultsLimitRule) configure(arguments lint.Arguments) {
}
r.max = int(max)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/import-alias-naming.go b/vendor/github.com/mgechev/revive/rule/import-alias-naming.go
new file mode 100644
index 0000000000..292392b5de
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/import-alias-naming.go
@@ -0,0 +1,79 @@
+package rule
+
+import (
+ "fmt"
+ "regexp"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// ImportAliasNamingRule lints import alias naming.
+type ImportAliasNamingRule struct {
+ configured bool
+ namingRuleRegexp *regexp.Regexp
+ sync.Mutex
+}
+
+const defaultNamingRule = "^[a-z][a-z0-9]{0,}$"
+
+var defaultNamingRuleRegexp = regexp.MustCompile(defaultNamingRule)
+
+func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+ if r.configured {
+ return
+ }
+
+ if len(arguments) < 1 {
+ r.namingRuleRegexp = defaultNamingRuleRegexp
+ return
+ }
+
+ namingRule, ok := arguments[0].(string) // Alt. non panicking version
+ if !ok {
+ panic(fmt.Sprintf("Invalid argument '%v' for 'import-alias-naming' rule. Expecting string, got %T", arguments[0], arguments[0]))
+ }
+
+ var err error
+ r.namingRuleRegexp, err = regexp.Compile(namingRule)
+ if err != nil {
+ panic(fmt.Sprintf("Invalid argument to the import-alias-naming rule. Expecting %q to be a valid regular expression, got: %v", namingRule, err))
+ }
+}
+
+// Apply applies the rule to given file.
+func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
+ r.configure(arguments)
+
+ var failures []lint.Failure
+
+ for _, is := range file.AST.Imports {
+ path := is.Path
+ if path == nil {
+ continue
+ }
+
+ alias := is.Name
+ if alias == nil || alias.Name == "_" {
+ continue
+ }
+
+ if !r.namingRuleRegexp.MatchString(alias.Name) {
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("import name (%s) must match the regular expression: %s", alias.Name, r.namingRuleRegexp.String()),
+ Node: alias,
+ Category: "imports",
+ })
+ }
+ }
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*ImportAliasNamingRule) Name() string {
+ return "import-alias-naming"
+}
diff --git a/vendor/github.com/mgechev/revive/rule/import-shadowing.go b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
index 2bab704d02..046aeb688e 100644
--- a/vendor/github.com/mgechev/revive/rule/import-shadowing.go
+++ b/vendor/github.com/mgechev/revive/rule/import-shadowing.go
@@ -29,6 +29,7 @@ func (*ImportShadowingRule) Apply(file *lint.File, _ lint.Arguments) []lint.Fail
failures = append(failures, failure)
},
alreadySeen: map[*ast.Object]struct{}{},
+ skipIdents: map[*ast.Ident]struct{}{},
}
ast.Walk(walker, fileAst)
@@ -62,6 +63,7 @@ type importShadowing struct {
importNames map[string]struct{}
onFailure func(lint.Failure)
alreadySeen map[*ast.Object]struct{}
+ skipIdents map[*ast.Ident]struct{}
}
// Visit visits AST nodes and checks if id nodes (ast.Ident) shadow an import name
@@ -80,6 +82,10 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
*ast.SelectorExpr, // skip analysis of selector expressions (anId.otherId): because if anId shadows an import name, it was already detected, and otherId does not shadows the import name
*ast.StructType: // skip analysis of struct type because struct fields can not shadow an import name
return nil
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ w.skipIdents[n.Name] = struct{}{}
+ }
case *ast.Ident:
if n == w.packageNameIdent {
return nil // skip the ident corresponding to the package name of this file
@@ -92,11 +98,12 @@ func (w importShadowing) Visit(n ast.Node) ast.Visitor {
_, isImportName := w.importNames[id]
_, alreadySeen := w.alreadySeen[n.Obj]
- if isImportName && !alreadySeen {
+ _, skipIdent := w.skipIdents[n]
+ if isImportName && !alreadySeen && !skipIdent {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
- Category: "namming",
+ Category: "naming",
Failure: fmt.Sprintf("The name '%s' shadows an import name", id),
})
diff --git a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
index 7106628155..bb8262cae8 100644
--- a/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
+++ b/vendor/github.com/mgechev/revive/rule/imports-blacklist.go
@@ -52,10 +52,6 @@ func (r *ImportsBlacklistRule) Apply(file *lint.File, arguments lint.Arguments)
var failures []lint.Failure
- if file.IsTest() {
- return failures // skip, test file
- }
-
for _, is := range file.AST.Imports {
path := is.Path
if path != nil && r.isBlacklisted(path.Value) {
diff --git a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
index e455801c47..b80e6486c9 100644
--- a/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
+++ b/vendor/github.com/mgechev/revive/rule/indent-error-flow.go
@@ -1,9 +1,7 @@
package rule
import (
- "go/ast"
- "go/token"
-
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -11,16 +9,8 @@ import (
type IndentErrorFlowRule struct{}
// Apply applies the rule to given file.
-func (*IndentErrorFlowRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
-
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- w := lintElse{make(map[*ast.IfStmt]bool), onFailure}
- ast.Walk(w, file.AST)
- return failures
+func (e *IndentErrorFlowRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetElse, args)
}
// Name returns the rule name.
@@ -28,51 +18,28 @@ func (*IndentErrorFlowRule) Name() string {
return "indent-error-flow"
}
-type lintElse struct {
- ignore map[*ast.IfStmt]bool
- onFailure func(lint.Failure)
-}
-
-func (w lintElse) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok || ifStmt.Else == nil {
- return w
- }
- if w.ignore[ifStmt] {
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- }
- return w
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *IndentErrorFlowRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.If.Deviates() {
+ // this rule only applies if the if-block deviates control flow
+ return
}
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- return w
- }
- if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
- // only care about elses without conditions
- return w
- }
- if len(ifStmt.Body.List) == 0 {
- return w
+
+ if chain.HasPriorNonDeviating {
+ // if we de-indent the "else" block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- shortDecl := false // does the if statement have a ":=" initialization statement?
- if ifStmt.Init != nil {
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- shortDecl = true
- }
+
+ if !chain.If.Returns() {
+ // avoid overlapping with superfluous-else
+ return
}
- lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
- if _, ok := lastStmt.(*ast.ReturnStmt); ok {
- extra := ""
- if shortDecl {
- extra = " (move short variable declaration to its own line if necessary)"
- }
- w.onFailure(lint.Failure{
- Confidence: 1,
- Node: ifStmt.Else,
- Category: "indent",
- Failure: "if block ends with a return statement, so drop this else and outdent its block" + extra,
- })
+
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls) {
+ // avoid increasing variable scope
+ return
}
- return w
+
+ return "if block ends with a return statement, so drop this else and outdent its block"
}
diff --git a/vendor/github.com/mgechev/revive/rule/line-length-limit.go b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
index 9e512c1c2c..1a414f6914 100644
--- a/vendor/github.com/mgechev/revive/rule/line-length-limit.go
+++ b/vendor/github.com/mgechev/revive/rule/line-length-limit.go
@@ -18,10 +18,16 @@ type LineLengthLimitRule struct {
sync.Mutex
}
+const defaultLineLengthLimit = 80
+
func (r *LineLengthLimitRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max == 0 {
- checkNumberOfArguments(1, arguments, r.Name())
+ if len(arguments) < 1 {
+ r.max = defaultLineLengthLimit
+ return
+ }
max, ok := arguments[0].(int64) // Alt. non panicking version
if !ok || max < 0 {
@@ -30,7 +36,6 @@ func (r *LineLengthLimitRule) configure(arguments lint.Arguments) {
r.max = int(max)
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/max-public-structs.go b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
index e39f49c698..25be3e676f 100644
--- a/vendor/github.com/mgechev/revive/rule/max-public-structs.go
+++ b/vendor/github.com/mgechev/revive/rule/max-public-structs.go
@@ -14,9 +14,17 @@ type MaxPublicStructsRule struct {
sync.Mutex
}
+const defaultMaxPublicStructs = 5
+
func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) {
r.Lock()
+ defer r.Unlock()
if r.max < 1 {
+ if len(arguments) < 1 {
+ r.max = defaultMaxPublicStructs
+ return
+ }
+
checkNumberOfArguments(1, arguments, r.Name())
max, ok := arguments[0].(int64) // Alt. non panicking version
@@ -25,7 +33,6 @@ func (r *MaxPublicStructsRule) configure(arguments lint.Arguments) {
}
r.max = max
}
- r.Unlock()
}
// Apply applies the rule to given file.
diff --git a/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go b/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go
new file mode 100644
index 0000000000..fa5281f24b
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/redundant-import-alias.go
@@ -0,0 +1,52 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// RedundantImportAlias lints given else constructs.
+type RedundantImportAlias struct{}
+
+// Apply applies the rule to given file.
+func (*RedundantImportAlias) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ for _, imp := range file.AST.Imports {
+ if imp.Name == nil {
+ continue
+ }
+
+ if getImportPackageName(imp) == imp.Name.Name {
+ failures = append(failures, lint.Failure{
+ Confidence: 1,
+ Failure: fmt.Sprintf("Import alias \"%s\" is redundant", imp.Name.Name),
+ Node: imp,
+ Category: "imports",
+ })
+ }
+ }
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*RedundantImportAlias) Name() string {
+ return "redundant-import-alias"
+}
+
+func getImportPackageName(imp *ast.ImportSpec) string {
+ const pathSep = "/"
+ const strDelim = `"`
+
+ path := imp.Path.Value
+ i := strings.LastIndex(path, pathSep)
+ if i == -1 {
+ return strings.Trim(path, strDelim)
+ }
+
+ return strings.Trim(path[i+1:], strDelim)
+}
diff --git a/vendor/github.com/mgechev/revive/rule/string-format.go b/vendor/github.com/mgechev/revive/rule/string-format.go
index 0e30ebf8b3..3edd62477d 100644
--- a/vendor/github.com/mgechev/revive/rule/string-format.go
+++ b/vendor/github.com/mgechev/revive/rule/string-format.go
@@ -211,10 +211,14 @@ func (lintStringFormatRule) getCallName(call *ast.CallExpr) (callName string, ok
if selector, ok := call.Fun.(*ast.SelectorExpr); ok {
// Scoped function call
scope, ok := selector.X.(*ast.Ident)
- if !ok {
- return "", false
+ if ok {
+ return scope.Name + "." + selector.Sel.Name, true
+ }
+ // Scoped function call inside structure
+ recv, ok := selector.X.(*ast.SelectorExpr)
+ if ok {
+ return recv.Sel.Name + "." + selector.Sel.Name, true
}
- return scope.Name + "." + selector.Sel.Name, true
}
return "", false
diff --git a/vendor/github.com/mgechev/revive/rule/superfluous-else.go b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
index a9e4380c90..1ef67bf1a4 100644
--- a/vendor/github.com/mgechev/revive/rule/superfluous-else.go
+++ b/vendor/github.com/mgechev/revive/rule/superfluous-else.go
@@ -2,9 +2,7 @@ package rule
import (
"fmt"
- "go/ast"
- "go/token"
-
+ "github.com/mgechev/revive/internal/ifelse"
"github.com/mgechev/revive/lint"
)
@@ -12,27 +10,8 @@ import (
type SuperfluousElseRule struct{}
// Apply applies the rule to given file.
-func (*SuperfluousElseRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
- var failures []lint.Failure
- onFailure := func(failure lint.Failure) {
- failures = append(failures, failure)
- }
-
- branchingFunctions := map[string]map[string]bool{
- "os": {"Exit": true},
- "log": {
- "Fatal": true,
- "Fatalf": true,
- "Fatalln": true,
- "Panic": true,
- "Panicf": true,
- "Panicln": true,
- },
- }
-
- w := lintSuperfluousElse{make(map[*ast.IfStmt]bool), onFailure, branchingFunctions}
- ast.Walk(w, file.AST)
- return failures
+func (e *SuperfluousElseRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ return ifelse.Apply(e, file.AST, ifelse.TargetElse, args)
}
// Name returns the rule name.
@@ -40,75 +19,28 @@ func (*SuperfluousElseRule) Name() string {
return "superfluous-else"
}
-type lintSuperfluousElse struct {
- ignore map[*ast.IfStmt]bool
- onFailure func(lint.Failure)
- branchingFunctions map[string]map[string]bool
-}
-
-func (w lintSuperfluousElse) Visit(node ast.Node) ast.Visitor {
- ifStmt, ok := node.(*ast.IfStmt)
- if !ok || ifStmt.Else == nil {
- return w
- }
- if w.ignore[ifStmt] {
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- }
- return w
- }
- if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
- w.ignore[elseif] = true
- return w
- }
- if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
- // only care about elses without conditions
- return w
- }
- if len(ifStmt.Body.List) == 0 {
- return w
- }
- shortDecl := false // does the if statement have a ":=" initialization statement?
- if ifStmt.Init != nil {
- if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
- shortDecl = true
- }
- }
- extra := ""
- if shortDecl {
- extra = " (move short variable declaration to its own line if necessary)"
+// CheckIfElse evaluates the rule against an ifelse.Chain.
+func (e *SuperfluousElseRule) CheckIfElse(chain ifelse.Chain, args ifelse.Args) (failMsg string) {
+ if !chain.If.Deviates() {
+ // this rule only applies if the if-block deviates control flow
+ return
}
- lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
- switch stmt := lastStmt.(type) {
- case *ast.BranchStmt:
- tok := stmt.Tok.String()
- if tok != "fallthrough" {
- w.onFailure(newFailure(ifStmt.Else, "if block ends with a "+tok+" statement, so drop this else and outdent its block"+extra))
- }
- case *ast.ExprStmt:
- if ce, ok := stmt.X.(*ast.CallExpr); ok { // it's a function call
- if fc, ok := ce.Fun.(*ast.SelectorExpr); ok {
- if id, ok := fc.X.(*ast.Ident); ok {
- fn := fc.Sel.Name
- pkg := id.Name
- if w.branchingFunctions[pkg][fn] { // it's a call to a branching function
- w.onFailure(
- newFailure(ifStmt.Else, fmt.Sprintf("if block ends with call to %s.%s function, so drop this else and outdent its block%s", pkg, fn, extra)))
- }
- }
- }
- }
+ if chain.HasPriorNonDeviating {
+ // if we de-indent the "else" block then a previous branch
+ // might flow into it, affecting program behaviour
+ return
}
- return w
-}
+ if chain.If.Returns() {
+ // avoid overlapping with indent-error-flow
+ return
+ }
-func newFailure(node ast.Node, msg string) lint.Failure {
- return lint.Failure{
- Confidence: 1,
- Node: node,
- Category: "indent",
- Failure: msg,
+ if args.PreserveScope && !chain.AtBlockEnd && (chain.HasInitializer || chain.Else.HasDecls) {
+ // avoid increasing variable scope
+ return
}
+
+ return fmt.Sprintf("if block ends with %v, so drop this else and outdent its block", chain.If.LongString())
}
diff --git a/vendor/github.com/mgechev/revive/rule/time-equal.go b/vendor/github.com/mgechev/revive/rule/time-equal.go
index 72ecf26fe4..3b85e18a8e 100644
--- a/vendor/github.com/mgechev/revive/rule/time-equal.go
+++ b/vendor/github.com/mgechev/revive/rule/time-equal.go
@@ -60,9 +60,9 @@ func (l *lintTimeEqual) Visit(node ast.Node) ast.Visitor {
var failure string
switch expr.Op {
case token.EQL:
- failure = fmt.Sprintf("use %s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ failure = fmt.Sprintf("use %s.Equal(%s) instead of %q operator", gofmt(expr.X), gofmt(expr.Y), expr.Op)
case token.NEQ:
- failure = fmt.Sprintf("use !%s.Equal(%s) instead of %q operator", expr.X, expr.Y, expr.Op)
+ failure = fmt.Sprintf("use !%s.Equal(%s) instead of %q operator", gofmt(expr.X), gofmt(expr.Y), expr.Op)
}
l.onFailure(lint.Failure{
diff --git a/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go b/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go
new file mode 100644
index 0000000000..df27743cbd
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/unchecked-type-assertion.go
@@ -0,0 +1,194 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "sync"
+
+ "github.com/mgechev/revive/lint"
+)
+
+const (
+ ruleUTAMessagePanic = "type assertion will panic if not matched"
+ ruleUTAMessageIgnored = "type assertion result ignored"
+)
+
+// UncheckedTypeAssertionRule lints missing or ignored `ok`-value in danymic type casts.
+type UncheckedTypeAssertionRule struct {
+ sync.Mutex
+ acceptIgnoredAssertionResult bool
+ configured bool
+}
+
+func (u *UncheckedTypeAssertionRule) configure(arguments lint.Arguments) {
+ u.Lock()
+ defer u.Unlock()
+
+ if len(arguments) == 0 || u.configured {
+ return
+ }
+
+ u.configured = true
+
+ args, ok := arguments[0].(map[string]any)
+ if !ok {
+ panic("Unable to get arguments. Expected object of key-value-pairs.")
+ }
+
+ for k, v := range args {
+ switch k {
+ case "acceptIgnoredAssertionResult":
+ u.acceptIgnoredAssertionResult, ok = v.(bool)
+ if !ok {
+ panic(fmt.Sprintf("Unable to parse argument '%s'. Expected boolean.", k))
+ }
+ default:
+ panic(fmt.Sprintf("Unknown argument: %s", k))
+ }
+ }
+}
+
+// Apply applies the rule to given file.
+func (u *UncheckedTypeAssertionRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ u.configure(args)
+
+ var failures []lint.Failure
+
+ walker := &lintUnchekedTypeAssertion{
+ onFailure: func(failure lint.Failure) {
+ failures = append(failures, failure)
+ },
+ acceptIgnoredTypeAssertionResult: u.acceptIgnoredAssertionResult,
+ }
+
+ ast.Walk(walker, file.AST)
+
+ return failures
+}
+
+// Name returns the rule name.
+func (*UncheckedTypeAssertionRule) Name() string {
+ return "unchecked-type-assertion"
+}
+
+type lintUnchekedTypeAssertion struct {
+ onFailure func(lint.Failure)
+ acceptIgnoredTypeAssertionResult bool
+}
+
+func isIgnored(e ast.Expr) bool {
+ ident, ok := e.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ return ident.Name == "_"
+}
+
+func isTypeSwitch(e *ast.TypeAssertExpr) bool {
+ return e.Type == nil
+}
+
+func (w *lintUnchekedTypeAssertion) requireNoTypeAssert(expr ast.Expr) {
+ e, ok := expr.(*ast.TypeAssertExpr)
+ if ok && !isTypeSwitch(e) {
+ w.addFailure(e, ruleUTAMessagePanic)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleIfStmt(n *ast.IfStmt) {
+ ifCondition, ok := n.Cond.(*ast.BinaryExpr)
+ if ok {
+ w.requireNoTypeAssert(ifCondition.X)
+ w.requireNoTypeAssert(ifCondition.Y)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) requireBinaryExpressionWithoutTypeAssertion(expr ast.Expr) {
+ binaryExpr, ok := expr.(*ast.BinaryExpr)
+ if ok {
+ w.requireNoTypeAssert(binaryExpr.X)
+ w.requireNoTypeAssert(binaryExpr.Y)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleCaseClause(n *ast.CaseClause) {
+ for _, expr := range n.List {
+ w.requireNoTypeAssert(expr)
+ w.requireBinaryExpressionWithoutTypeAssertion(expr)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleSwitch(n *ast.SwitchStmt) {
+ w.requireNoTypeAssert(n.Tag)
+ w.requireBinaryExpressionWithoutTypeAssertion(n.Tag)
+}
+
+func (w *lintUnchekedTypeAssertion) handleAssignment(n *ast.AssignStmt) {
+ if len(n.Rhs) == 0 {
+ return
+ }
+
+ e, ok := n.Rhs[0].(*ast.TypeAssertExpr)
+ if !ok || e == nil {
+ return
+ }
+
+ if isTypeSwitch(e) {
+ return
+ }
+
+ if len(n.Lhs) == 1 {
+ w.addFailure(e, ruleUTAMessagePanic)
+ }
+
+ if !w.acceptIgnoredTypeAssertionResult && len(n.Lhs) == 2 && isIgnored(n.Lhs[1]) {
+ w.addFailure(e, ruleUTAMessageIgnored)
+ }
+}
+
+// handles "return foo(.*bar)" - one of them is enough to fail as golang does not forward the type cast tuples in return statements
+func (w *lintUnchekedTypeAssertion) handleReturn(n *ast.ReturnStmt) {
+ for _, r := range n.Results {
+ w.requireNoTypeAssert(r)
+ }
+}
+
+func (w *lintUnchekedTypeAssertion) handleRange(n *ast.RangeStmt) {
+ w.requireNoTypeAssert(n.X)
+}
+
+func (w *lintUnchekedTypeAssertion) handleChannelSend(n *ast.SendStmt) {
+ w.requireNoTypeAssert(n.Value)
+}
+
+func (w *lintUnchekedTypeAssertion) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.RangeStmt:
+ w.handleRange(n)
+ case *ast.SwitchStmt:
+ w.handleSwitch(n)
+ case *ast.ReturnStmt:
+ w.handleReturn(n)
+ case *ast.AssignStmt:
+ w.handleAssignment(n)
+ case *ast.IfStmt:
+ w.handleIfStmt(n)
+ case *ast.CaseClause:
+ w.handleCaseClause(n)
+ case *ast.SendStmt:
+ w.handleChannelSend(n)
+ }
+
+ return w
+}
+
+func (w *lintUnchekedTypeAssertion) addFailure(n *ast.TypeAssertExpr, why string) {
+ s := fmt.Sprintf("type cast result is unchecked in %v - %s", gofmt(n), why)
+ w.onFailure(lint.Failure{
+ Category: "bad practice",
+ Confidence: 1,
+ Node: n,
+ Failure: s,
+ })
+}
diff --git a/vendor/github.com/mgechev/revive/rule/unused-param.go b/vendor/github.com/mgechev/revive/rule/unused-param.go
index ab3da453ee..df6cd9af0e 100644
--- a/vendor/github.com/mgechev/revive/rule/unused-param.go
+++ b/vendor/github.com/mgechev/revive/rule/unused-param.go
@@ -3,22 +3,72 @@ package rule
import (
"fmt"
"go/ast"
+ "regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// UnusedParamRule lints unused params in functions.
-type UnusedParamRule struct{}
+type UnusedParamRule struct {
+ configured bool
+ // regex to check if some name is valid for unused parameter, "^_$" by default
+ allowRegex *regexp.Regexp
+ failureMsg string
+ sync.Mutex
+}
+
+func (r *UnusedParamRule) configure(args lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ // while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives
+ // it's more compatible to JSON nature of configurations
+ var allowedRegexStr string
+ if len(args) == 0 {
+ allowedRegexStr = "^_$"
+ r.failureMsg = "parameter '%s' seems to be unused, consider removing or renaming it as _"
+ } else {
+ // Arguments = [{}]
+ options := args[0].(map[string]interface{})
+ // Arguments = [{allowedRegex="^_"}]
+
+ if allowedRegexParam, ok := options["allowRegex"]; ok {
+ allowedRegexStr, ok = allowedRegexParam.(string)
+ if !ok {
+ panic(fmt.Errorf("error configuring %s rule: allowedRegex is not string but [%T]", r.Name(), allowedRegexParam))
+ }
+ }
+ }
+ var err error
+ r.allowRegex, err = regexp.Compile(allowedRegexStr)
+ if err != nil {
+ panic(fmt.Errorf("error configuring %s rule: allowedRegex is not valid regex [%s]: %v", r.Name(), allowedRegexStr, err))
+ }
+
+ if r.failureMsg == "" {
+ r.failureMsg = "parameter '%s' seems to be unused, consider removing or renaming it to match " + r.allowRegex.String()
+ }
+}
// Apply applies the rule to given file.
-func (*UnusedParamRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (r *UnusedParamRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
-
- w := lintUnusedParamRule{onFailure: onFailure}
+ w := lintUnusedParamRule{
+ onFailure: onFailure,
+ allowRegex: r.allowRegex,
+ failureMsg: r.failureMsg,
+ }
ast.Walk(w, file.AST)
@@ -31,7 +81,9 @@ func (*UnusedParamRule) Name() string {
}
type lintUnusedParamRule struct {
- onFailure func(lint.Failure)
+ onFailure func(lint.Failure)
+ allowRegex *regexp.Regexp
+ failureMsg string
}
func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
@@ -65,12 +117,15 @@ func (w lintUnusedParamRule) Visit(node ast.Node) ast.Visitor {
for _, p := range n.Type.Params.List {
for _, n := range p.Names {
+ if w.allowRegex.FindStringIndex(n.Name) != nil {
+ continue
+ }
if params[n.Obj] {
w.onFailure(lint.Failure{
Confidence: 1,
Node: n,
Category: "bad practice",
- Failure: fmt.Sprintf("parameter '%s' seems to be unused, consider removing or renaming it as _", n.Name),
+ Failure: fmt.Sprintf(w.failureMsg, n.Name),
})
}
}
diff --git a/vendor/github.com/mgechev/revive/rule/unused-receiver.go b/vendor/github.com/mgechev/revive/rule/unused-receiver.go
index 2289a517e5..488572b7bd 100644
--- a/vendor/github.com/mgechev/revive/rule/unused-receiver.go
+++ b/vendor/github.com/mgechev/revive/rule/unused-receiver.go
@@ -3,22 +3,72 @@ package rule
import (
"fmt"
"go/ast"
+ "regexp"
+ "sync"
"github.com/mgechev/revive/lint"
)
// UnusedReceiverRule lints unused params in functions.
-type UnusedReceiverRule struct{}
+type UnusedReceiverRule struct {
+ configured bool
+ // regex to check if some name is valid for unused parameter, "^_$" by default
+ allowRegex *regexp.Regexp
+ failureMsg string
+ sync.Mutex
+}
+
+func (r *UnusedReceiverRule) configure(args lint.Arguments) {
+ r.Lock()
+ defer r.Unlock()
+
+ if r.configured {
+ return
+ }
+ r.configured = true
+
+ // while by default args is an array, i think it's good to provide structures inside it by default, not arrays or primitives
+ // it's more compatible to JSON nature of configurations
+ var allowedRegexStr string
+ if len(args) == 0 {
+ allowedRegexStr = "^_$"
+ r.failureMsg = "method receiver '%s' is not referenced in method's body, consider removing or renaming it as _"
+ } else {
+ // Arguments = [{}]
+ options := args[0].(map[string]interface{})
+ // Arguments = [{allowedRegex="^_"}]
+
+ if allowedRegexParam, ok := options["allowRegex"]; ok {
+ allowedRegexStr, ok = allowedRegexParam.(string)
+ if !ok {
+ panic(fmt.Errorf("error configuring [unused-receiver] rule: allowedRegex is not string but [%T]", allowedRegexParam))
+ }
+ }
+ }
+ var err error
+ r.allowRegex, err = regexp.Compile(allowedRegexStr)
+ if err != nil {
+ panic(fmt.Errorf("error configuring [unused-receiver] rule: allowedRegex is not valid regex [%s]: %v", allowedRegexStr, err))
+ }
+ if r.failureMsg == "" {
+ r.failureMsg = "method receiver '%s' is not referenced in method's body, consider removing or renaming it to match " + r.allowRegex.String()
+ }
+}
// Apply applies the rule to given file.
-func (*UnusedReceiverRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+func (r *UnusedReceiverRule) Apply(file *lint.File, args lint.Arguments) []lint.Failure {
+ r.configure(args)
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
- w := lintUnusedReceiverRule{onFailure: onFailure}
+ w := lintUnusedReceiverRule{
+ onFailure: onFailure,
+ allowRegex: r.allowRegex,
+ failureMsg: r.failureMsg,
+ }
ast.Walk(w, file.AST)
@@ -31,7 +81,9 @@ func (*UnusedReceiverRule) Name() string {
}
type lintUnusedReceiverRule struct {
- onFailure func(lint.Failure)
+ onFailure func(lint.Failure)
+ allowRegex *regexp.Regexp
+ failureMsg string
}
func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
@@ -51,6 +103,10 @@ func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
return nil // the receiver is already named _
}
+ if w.allowRegex != nil && w.allowRegex.FindStringIndex(recID.Name) != nil {
+ return nil
+ }
+
// inspect the func body looking for references to the receiver id
fselect := func(n ast.Node) bool {
ident, isAnID := n.(*ast.Ident)
@@ -67,7 +123,7 @@ func (w lintUnusedReceiverRule) Visit(node ast.Node) ast.Visitor {
Confidence: 1,
Node: recID,
Category: "bad practice",
- Failure: fmt.Sprintf("method receiver '%s' is not referenced in method's body, consider removing or renaming it as _", recID.Name),
+ Failure: fmt.Sprintf(w.failureMsg, recID.Name),
})
return nil // full method body already inspected
diff --git a/vendor/github.com/mgechev/revive/rule/var-naming.go b/vendor/github.com/mgechev/revive/rule/var-naming.go
index fa4a188642..286ff9d75d 100644
--- a/vendor/github.com/mgechev/revive/rule/var-naming.go
+++ b/vendor/github.com/mgechev/revive/rule/var-naming.go
@@ -13,27 +13,50 @@ import (
var anyCapsRE = regexp.MustCompile(`[A-Z]`)
+// regexp for constant names like `SOME_CONST`, `SOME_CONST_2`, `X123_3`, `_SOME_PRIVATE_CONST` (#851, #865)
+var upperCaseConstRE = regexp.MustCompile(`^_?[A-Z][A-Z\d]*(_[A-Z\d]+)*$`)
+
// VarNamingRule lints given else constructs.
type VarNamingRule struct {
- configured bool
- whitelist []string
- blacklist []string
+ configured bool
+ whitelist []string
+ blacklist []string
+ upperCaseConst bool // if true - allows to use UPPER_SOME_NAMES for constants
sync.Mutex
}
func (r *VarNamingRule) configure(arguments lint.Arguments) {
r.Lock()
- if !r.configured {
- if len(arguments) >= 1 {
- r.whitelist = getList(arguments[0], "whitelist")
- }
+ defer r.Unlock()
+ if r.configured {
+ return
+ }
+
+ r.configured = true
+ if len(arguments) >= 1 {
+ r.whitelist = getList(arguments[0], "whitelist")
+ }
- if len(arguments) >= 2 {
- r.blacklist = getList(arguments[1], "blacklist")
+ if len(arguments) >= 2 {
+ r.blacklist = getList(arguments[1], "blacklist")
+ }
+
+ if len(arguments) >= 3 {
+ // not pretty code because should keep compatibility with TOML (no mixed array types) and new map parameters
+ thirdArgument := arguments[2]
+ asSlice, ok := thirdArgument.([]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, got %T", "options", arguments[2]))
+ }
+ if len(asSlice) != 1 {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, of len==1, but %d", "options", len(asSlice)))
}
- r.configured = true
+ args, ok := asSlice[0].(map[string]interface{})
+ if !ok {
+ panic(fmt.Sprintf("Invalid third argument to the var-naming rule. Expecting a %s of type slice, of len==1, with map, but %T", "options", asSlice[0]))
+ }
+ r.upperCaseConst = fmt.Sprint(args["upperCaseConst"]) == "true"
}
- r.Unlock()
}
// Apply applies the rule to given file.
@@ -52,6 +75,7 @@ func (r *VarNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)
},
+ upperCaseConst: r.upperCaseConst,
}
// Package names need slightly different handling than other names.
@@ -82,18 +106,18 @@ func (*VarNamingRule) Name() string {
return "var-naming"
}
-func checkList(fl *ast.FieldList, thing string, w *lintNames) {
+func (w *lintNames) checkList(fl *ast.FieldList, thing string) {
if fl == nil {
return
}
for _, f := range fl.List {
for _, id := range f.Names {
- check(id, thing, w)
+ w.check(id, thing)
}
}
}
-func check(id *ast.Ident, thing string, w *lintNames) {
+func (w *lintNames) check(id *ast.Ident, thing string) {
if id.Name == "_" {
return
}
@@ -101,6 +125,12 @@ func check(id *ast.Ident, thing string, w *lintNames) {
return
}
+ // #851 upperCaseConst support
+ // if it's const
+ if thing == token.CONST.String() && w.upperCaseConst && upperCaseConstRE.Match([]byte(id.Name)) {
+ return
+ }
+
// Handle two common styles from other languages that don't belong in Go.
if len(id.Name) >= 5 && allCapsRE.MatchString(id.Name) && strings.Contains(id.Name, "_") {
w.onFailure(lint.Failure{
@@ -111,15 +141,6 @@ func check(id *ast.Ident, thing string, w *lintNames) {
})
return
}
- if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' {
- should := string(id.Name[1]+'a'-'A') + id.Name[2:]
- w.onFailure(lint.Failure{
- Failure: fmt.Sprintf("don't use leading k in Go names; %s %s should be %s", thing, id.Name, should),
- Confidence: 0.8,
- Node: id,
- Category: "naming",
- })
- }
should := lint.Name(id.Name, w.whitelist, w.blacklist)
if id.Name == should {
@@ -144,11 +165,12 @@ func check(id *ast.Ident, thing string, w *lintNames) {
}
type lintNames struct {
- file *lint.File
- fileAst *ast.File
- onFailure func(lint.Failure)
- whitelist []string
- blacklist []string
+ file *lint.File
+ fileAst *ast.File
+ onFailure func(lint.Failure)
+ whitelist []string
+ blacklist []string
+ upperCaseConst bool
}
func (w *lintNames) Visit(n ast.Node) ast.Visitor {
@@ -159,7 +181,7 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
}
for _, exp := range v.Lhs {
if id, ok := exp.(*ast.Ident); ok {
- check(id, "var", w)
+ w.check(id, "var")
}
}
case *ast.FuncDecl:
@@ -181,31 +203,24 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
// not exported in the Go API.
// See https://github.com/golang/lint/issues/144.
if ast.IsExported(v.Name.Name) || !isCgoExported(v) {
- check(v.Name, thing, w)
+ w.check(v.Name, thing)
}
- checkList(v.Type.Params, thing+" parameter", w)
- checkList(v.Type.Results, thing+" result", w)
+ w.checkList(v.Type.Params, thing+" parameter")
+ w.checkList(v.Type.Results, thing+" result")
case *ast.GenDecl:
if v.Tok == token.IMPORT {
return w
}
- var thing string
- switch v.Tok {
- case token.CONST:
- thing = "const"
- case token.TYPE:
- thing = "type"
- case token.VAR:
- thing = "var"
- }
+
+ thing := v.Tok.String()
for _, spec := range v.Specs {
switch s := spec.(type) {
case *ast.TypeSpec:
- check(s.Name, thing, w)
+ w.check(s.Name, thing)
case *ast.ValueSpec:
for _, id := range s.Names {
- check(id, thing, w)
+ w.check(id, thing)
}
}
}
@@ -217,23 +232,23 @@ func (w *lintNames) Visit(n ast.Node) ast.Visitor {
if !ok { // might be an embedded interface name
continue
}
- checkList(ft.Params, "interface method parameter", w)
- checkList(ft.Results, "interface method result", w)
+ w.checkList(ft.Params, "interface method parameter")
+ w.checkList(ft.Results, "interface method result")
}
case *ast.RangeStmt:
if v.Tok == token.ASSIGN {
return w
}
if id, ok := v.Key.(*ast.Ident); ok {
- check(id, "range var", w)
+ w.check(id, "range var")
}
if id, ok := v.Value.(*ast.Ident); ok {
- check(id, "range var", w)
+ w.check(id, "range var")
}
case *ast.StructType:
for _, f := range v.Fields.List {
for _, id := range f.Names {
- check(id, "struct field", w)
+ w.check(id, "struct field")
}
}
}
diff --git a/vendor/github.com/nunnatsa/ginkgolinter/README.md b/vendor/github.com/nunnatsa/ginkgolinter/README.md
index 4193be63dc..6c95917d26 100644
--- a/vendor/github.com/nunnatsa/ginkgolinter/README.md
+++ b/vendor/github.com/nunnatsa/ginkgolinter/README.md
@@ -181,7 +181,29 @@ These container, or the `Focus` spec, must not be part of the final source code,
***This rule is disabled by default***. Use the `--forbid-focus-container=true` command line flag to enable it.
+### Comparing values from different types [BUG]
+The `Equal` and the `BeIdentical` matchers also check the type, not only the value.
+
+The following code will fail in runtime:
+```go
+x := 5 // x is int
+Expect(x).Should(Eqaul(uint(5)) // x and uint(5) are with different
+```
+When using negative checks, it's even worse, because we get a false positive:
+```
+x := 5
+Expect(x).ShouldNot(Equal(uint(5))
+```
+
+The linter suggests two options to solve this warning: either compare with the same type, e.g.
+using casting, or use the `BeEquivalentTo` matcher.
+
+The linter can't guess what is the best solution in each case, and so it won't auto-fix this warning.
+
+To suppress this warning entirely, use the `--suppress-type-compare-assertion=true` command line parameter.
+
+To suppress a specific file or line, use the `// ginkgo-linter:ignore-type-compare-warning` comment (see [below](#suppress-warning-from-the-code))
### Wrong Length Assertion [STYLE]
The linter finds assertion of the golang built-in `len` function, with all kind of matchers, while there are already gomega matchers for these usecases; We want to assert the item, rather than its length.
@@ -317,6 +339,8 @@ Expect(c1 == x1).Should(BeTrue()) // ==> Expect(x1).Should(Equal(c1))
* Use the `--suppress-err-assertion=true` flag to suppress the wrong error assertion warning
* Use the `--suppress-compare-assertion=true` flag to suppress the wrong comparison assertion warning
* Use the `--suppress-async-assertion=true` flag to suppress the function call in async assertion warning
+* Use the `--forbid-focus-container=true` flag to activate the focused container assertion (deactivated by default)
+* Use the `--suppress-type-compare-assertion=true` to suppress the type compare assertion warning
* Use the `--allow-havelen-0=true` flag to avoid warnings about `HaveLen(0)`; Note: this parameter is only supported from
command line, and not from a comment.
@@ -345,6 +369,10 @@ To supress the focus container warning, add a comment with (only)
`ginkgo-linter:ignore-focus-container-warning`
+To suppress the different type comparison, add a comment with (only)
+
+`ginkgo-linter:ignore-type-compare-warning`
+
Notice that this comment will not work for an anonymous variable container like
```go
// ginkgo-linter:ignore-focus-container-warning (not working!!)
diff --git a/vendor/github.com/nunnatsa/ginkgolinter/ginkgo_linter.go b/vendor/github.com/nunnatsa/ginkgolinter/ginkgo_linter.go
index 11cffaca52..a9d3489e1c 100644
--- a/vendor/github.com/nunnatsa/ginkgolinter/ginkgo_linter.go
+++ b/vendor/github.com/nunnatsa/ginkgolinter/ginkgo_linter.go
@@ -9,6 +9,7 @@ import (
"go/printer"
"go/token"
gotypes "go/types"
+ "reflect"
"github.com/go-toolsmith/astcopy"
"golang.org/x/tools/go/analysis"
@@ -38,6 +39,8 @@ const (
missingAsyncAssertionMessage = linterName + `: %q: missing assertion method. Expected "Should()" or "ShouldNot()"`
focusContainerFound = linterName + ": Focus container found. This is used only for local debug and should not be part of the actual source code, consider to replace with %q"
focusSpecFound = linterName + ": Focus spec found. This is used only for local debug and should not be part of the actual source code, consider to remove it"
+ compareDifferentTypes = linterName + ": use %[1]s with different types: Comparing %[2]s with %[3]s; either change the expected value type if possible, or use the BeEquivalentTo() matcher, instead of %[1]s()"
+ compareInterfaces = linterName + ": be careful comparing interfaces. This can fail in runtime, if the actual implementing types are different"
)
const ( // gomega matchers
beEmpty = "BeEmpty"
@@ -55,6 +58,9 @@ const ( // gomega matchers
not = "Not"
omega = "Ω"
succeed = "Succeed"
+ and = "And"
+ or = "Or"
+ withTransform = "WithTransform"
)
const ( // gomega actuals
@@ -99,6 +105,7 @@ func NewAnalyzer() *analysis.Analyzer {
a.Flags.Var(&linter.config.SuppressErr, "suppress-err-assertion", "Suppress warning for wrong error assertions")
a.Flags.Var(&linter.config.SuppressCompare, "suppress-compare-assertion", "Suppress warning for wrong comparison assertions")
a.Flags.Var(&linter.config.SuppressAsync, "suppress-async-assertion", "Suppress warning for function call in async assertion, like Eventually")
+ a.Flags.Var(&linter.config.SuppressTypeCompare, "suppress-type-compare-assertion", "Suppress warning for comparing values from different types, like int32 and uint32")
a.Flags.Var(&linter.config.AllowHaveLen0, "allow-havelen-0", "Do not warn for HaveLen(0); default = false")
a.Flags.BoolVar(&ignored, "suppress-focus-container", true, "Suppress warning for ginkgo focus containers like FDescribe, FContext, FWhen or FIt. Deprecated and ignored: use --forbid-focus-container instead")
@@ -126,6 +133,9 @@ currently, the linter searches for following:
* trigger a warning when a ginkgo focus container (FDescribe, FContext, FWhen or FIt) is found. [Bug]
+* trigger a warning when using the Equal or the BeIdentical matcher with two different types, as these matchers will
+ fail in runtime.
+
* wrong length assertions. We want to assert the item rather than its length. [Style]
For example:
Expect(len(x)).Should(Equal(1))
@@ -299,9 +309,144 @@ func checkExpression(pass *analysis.Pass, config types.Config, assertionExp *ast
} else if checkPointerComparison(pass, config, assertionExp, expr, actualArg, handler, oldExpr) {
return false
- } else {
- return handleAssertionOnly(pass, config, expr, handler, actualArg, oldExpr, true)
+ } else if !handleAssertionOnly(pass, config, expr, handler, actualArg, oldExpr, true) {
+ return false
+ } else if !config.SuppressTypeCompare {
+ return !checkEqualWrongType(pass, assertionExp, actualArg, handler, oldExpr)
+ }
+
+ return true
+}
+
+func checkEqualWrongType(pass *analysis.Pass, origExp *ast.CallExpr, actualArg ast.Expr, handler gomegahandler.Handler, old string) bool {
+ matcher, ok := origExp.Args[0].(*ast.CallExpr)
+ if !ok {
+ return false
}
+
+ return checkEqualDifferentTypes(pass, matcher, actualArg, handler, old, false)
+}
+
+func checkEqualDifferentTypes(pass *analysis.Pass, matcher *ast.CallExpr, actualArg ast.Expr, handler gomegahandler.Handler, old string, parentPointer bool) bool {
+ matcherFuncName, ok := handler.GetActualFuncName(matcher)
+ if !ok {
+ return false
+ }
+
+ actualType := pass.TypesInfo.TypeOf(actualArg)
+
+ switch matcherFuncName {
+ case equal, beIdenticalTo: // continue
+ case and, or:
+ foundIssue := false
+ for _, nestedExp := range matcher.Args {
+ nested, ok := nestedExp.(*ast.CallExpr)
+ if !ok {
+ continue
+ }
+ if checkEqualDifferentTypes(pass, nested, actualArg, handler, old, parentPointer) {
+ foundIssue = true
+ }
+ }
+
+ return foundIssue
+ case withTransform:
+ nested, ok := matcher.Args[1].(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+
+ if t := getFuncType(pass, matcher.Args[0]); t != nil {
+ actualType = t
+ matcher = nested
+ matcherFuncName, ok = handler.GetActualFuncName(nested)
+ if !ok {
+ return false
+ }
+ } else {
+ return checkEqualDifferentTypes(pass, nested, actualArg, handler, old, parentPointer)
+ }
+
+ case not:
+ nested, ok := matcher.Args[0].(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+
+ return checkEqualDifferentTypes(pass, nested, actualArg, handler, old, parentPointer)
+
+ case haveValue:
+ nested, ok := matcher.Args[0].(*ast.CallExpr)
+ if !ok {
+ return false
+ }
+
+ return checkEqualDifferentTypes(pass, nested, actualArg, handler, old, true)
+ default:
+ return false
+ }
+
+ matcherValue := matcher.Args[0]
+
+ switch act := actualType.(type) {
+ case *gotypes.Tuple:
+ actualType = act.At(0).Type()
+ case *gotypes.Pointer:
+ if parentPointer {
+ actualType = act.Elem()
+ }
+ }
+
+ matcherType := pass.TypesInfo.TypeOf(matcherValue)
+
+ if !reflect.DeepEqual(matcherType, actualType) {
+ // Equal can handle comparison of interface and a value that implements it
+ if isImplementing(matcherType, actualType) || isImplementing(actualType, matcherType) {
+ return false
+ }
+
+ reportNoFix(pass, matcher.Pos(), compareDifferentTypes, matcherFuncName, actualType, matcherType)
+ return true
+ }
+
+ return false
+}
+
+func getFuncType(pass *analysis.Pass, expr ast.Expr) gotypes.Type {
+ switch f := expr.(type) {
+ case *ast.FuncLit:
+ if f.Type != nil && f.Type.Results != nil && len(f.Type.Results.List) > 0 {
+ return pass.TypesInfo.TypeOf(f.Type.Results.List[0].Type)
+ }
+ case *ast.Ident:
+ a := pass.TypesInfo.TypeOf(f)
+ if sig, ok := a.(*gotypes.Signature); ok && sig.Results().Len() > 0 {
+ return sig.Results().At(0).Type()
+ }
+ }
+
+ return nil
+}
+
+func isImplementing(ifs, impl gotypes.Type) bool {
+ if gotypes.IsInterface(ifs) {
+
+ var (
+ theIfs *gotypes.Interface
+ ok bool
+ )
+
+ for {
+ theIfs, ok = ifs.(*gotypes.Interface)
+ if ok {
+ break
+ }
+ ifs = ifs.Underlying()
+ }
+
+ return gotypes.Implements(impl, theIfs)
+ }
+ return false
}
// be careful - never change origExp!!! only modify its clone, expr!!!
@@ -1181,8 +1326,7 @@ func isPointer(pass *analysis.Pass, expr ast.Expr) bool {
func isInterface(pass *analysis.Pass, expr ast.Expr) bool {
t := pass.TypesInfo.TypeOf(expr)
- _, ok := t.(*gotypes.Named)
- return ok
+ return gotypes.IsInterface(t)
}
func isNumeric(pass *analysis.Pass, node ast.Expr) bool {
diff --git a/vendor/github.com/nunnatsa/ginkgolinter/types/config.go b/vendor/github.com/nunnatsa/ginkgolinter/types/config.go
index 6d7a099142..6de22738dd 100644
--- a/vendor/github.com/nunnatsa/ginkgolinter/types/config.go
+++ b/vendor/github.com/nunnatsa/ginkgolinter/types/config.go
@@ -14,16 +14,18 @@ const (
suppressCompareAssertionWarning = suppressPrefix + "ignore-compare-assert-warning"
suppressAsyncAsertWarning = suppressPrefix + "ignore-async-assert-warning"
suppressFocusContainerWarning = suppressPrefix + "ignore-focus-container-warning"
+ suppressTypeCompareWarning = suppressPrefix + "ignore-type-compare-warning"
)
type Config struct {
- SuppressLen Boolean
- SuppressNil Boolean
- SuppressErr Boolean
- SuppressCompare Boolean
- SuppressAsync Boolean
- ForbidFocus Boolean
- AllowHaveLen0 Boolean
+ SuppressLen Boolean
+ SuppressNil Boolean
+ SuppressErr Boolean
+ SuppressCompare Boolean
+ SuppressAsync Boolean
+ ForbidFocus Boolean
+ SuppressTypeCompare Boolean
+ AllowHaveLen0 Boolean
}
func (s *Config) AllTrue() bool {
@@ -32,13 +34,14 @@ func (s *Config) AllTrue() bool {
func (s *Config) Clone() Config {
return Config{
- SuppressLen: s.SuppressLen,
- SuppressNil: s.SuppressNil,
- SuppressErr: s.SuppressErr,
- SuppressCompare: s.SuppressCompare,
- SuppressAsync: s.SuppressAsync,
- ForbidFocus: s.ForbidFocus,
- AllowHaveLen0: s.AllowHaveLen0,
+ SuppressLen: s.SuppressLen,
+ SuppressNil: s.SuppressNil,
+ SuppressErr: s.SuppressErr,
+ SuppressCompare: s.SuppressCompare,
+ SuppressAsync: s.SuppressAsync,
+ ForbidFocus: s.ForbidFocus,
+ SuppressTypeCompare: s.SuppressTypeCompare,
+ AllowHaveLen0: s.AllowHaveLen0,
}
}
@@ -69,6 +72,8 @@ func (s *Config) UpdateFromComment(commentGroup []*ast.CommentGroup) {
s.SuppressAsync = true
case suppressFocusContainerWarning:
s.ForbidFocus = false
+ case suppressTypeCompareWarning:
+ s.SuppressTypeCompare = true
}
}
}
diff --git a/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go b/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go
index be4debf9b3..df8d5f7138 100644
--- a/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go
+++ b/vendor/github.com/polyfloyd/go-errorlint/errorlint/allowed.go
@@ -3,6 +3,7 @@ package errorlint
import (
"fmt"
"go/ast"
+ "go/types"
"strings"
)
@@ -110,7 +111,7 @@ func isAllowedErrorComparison(pass *TypesInfoExt, binExpr *ast.BinaryExpr) bool
case *ast.Ident:
// Identifier, most likely to be the `err` variable or whatever
// produces it.
- callExprs = assigningCallExprs(pass, t)
+ callExprs = assigningCallExprs(pass, t, map[types.Object]bool{})
case *ast.CallExpr:
callExprs = append(callExprs, t)
}
@@ -149,15 +150,21 @@ func isAllowedErrorComparison(pass *TypesInfoExt, binExpr *ast.BinaryExpr) bool
// assigningCallExprs finds all *ast.CallExpr nodes that are part of an
// *ast.AssignStmt that assign to the subject identifier.
-func assigningCallExprs(pass *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr {
+func assigningCallExprs(pass *TypesInfoExt, subject *ast.Ident, visitedObjects map[types.Object]bool) []*ast.CallExpr {
if subject.Obj == nil {
return nil
}
- // Find other identifiers that reference this same object. Make sure to
- // exclude the subject identifier as it will cause an infinite recursion
- // and is being used in a read operation anyway.
+ // Find other identifiers that reference this same object.
sobj := pass.TypesInfo.ObjectOf(subject)
+
+ if visitedObjects[sobj] {
+ return nil
+ }
+ visitedObjects[sobj] = true
+
+ // Make sure to exclude the subject identifier as it will cause an infinite recursion and is
+ // being used in a read operation anyway.
identifiers := []*ast.Ident{}
for _, ident := range pass.IdentifiersForObject[sobj] {
if subject.Pos() != ident.Pos() {
@@ -196,7 +203,7 @@ func assigningCallExprs(pass *TypesInfoExt, subject *ast.Ident) []*ast.CallExpr
continue
}
// The subject was the result of assigning from another identifier.
- callExprs = append(callExprs, assigningCallExprs(pass, assignT)...)
+ callExprs = append(callExprs, assigningCallExprs(pass, assignT, visitedObjects)...)
default:
// TODO: inconclusive?
}
diff --git a/vendor/github.com/ryanrolds/sqlclosecheck/pkg/analyzer/analyzer.go b/vendor/github.com/ryanrolds/sqlclosecheck/pkg/analyzer/analyzer.go
index c22817cafc..55e931a898 100644
--- a/vendor/github.com/ryanrolds/sqlclosecheck/pkg/analyzer/analyzer.go
+++ b/vendor/github.com/ryanrolds/sqlclosecheck/pkg/analyzer/analyzer.go
@@ -9,9 +9,10 @@ import (
)
const (
- rowsName = "Rows"
- stmtName = "Stmt"
- closeMethod = "Close"
+ rowsName = "Rows"
+ stmtName = "Stmt"
+ namedStmtName = "NamedStmt"
+ closeMethod = "Close"
)
type action uint8
@@ -31,13 +32,15 @@ var (
sqlPackages = []string{
"database/sql",
"github.com/jmoiron/sqlx",
+ "github.com/jackc/pgx/v5",
+ "github.com/jackc/pgx/v5/pgxpool",
}
)
func NewAnalyzer() *analysis.Analyzer {
return &analysis.Analyzer{
Name: "sqlclosecheck",
- Doc: "Checks that sql.Rows and sql.Stmt are closed.",
+ Doc: "Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed.",
Run: run,
Requires: []*analysis.Analyzer{
buildssa.Analyzer,
@@ -63,20 +66,18 @@ func run(pass *analysis.Pass) (interface{}, error) {
for _, f := range funcs {
for _, b := range f.Blocks {
for i := range b.Instrs {
- // Check if instruction is call that returns a target type
+ // Check if instruction is call that returns a target pointer type
targetValues := getTargetTypesValues(b, i, targetTypes)
if len(targetValues) == 0 {
continue
}
- // log.Printf("%s", f.Name())
-
// For each found target check if they are closed and deferred
for _, targetValue := range targetValues {
refs := (*targetValue.value).Referrers()
isClosed := checkClosed(refs, targetTypes)
if !isClosed {
- pass.Reportf((targetValue.instr).Pos(), "Rows/Stmt was not closed")
+ pass.Reportf((targetValue.instr).Pos(), "Rows/Stmt/NamedStmt was not closed")
}
checkDeferred(pass, refs, targetTypes, false)
@@ -88,17 +89,22 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
-func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []*types.Pointer {
- targets := []*types.Pointer{}
+func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []any {
+ targets := []any{}
for _, sqlPkg := range targetPackages {
pkg := pssa.Pkg.Prog.ImportedPackage(sqlPkg)
if pkg == nil {
// the SQL package being checked isn't imported
- return targets
+ continue
+ }
+
+ rowsPtrType := getTypePointerFromName(pkg, rowsName)
+ if rowsPtrType != nil {
+ targets = append(targets, rowsPtrType)
}
- rowsType := getTypePointerFromName(pkg, rowsName)
+ rowsType := getTypeFromName(pkg, rowsName)
if rowsType != nil {
targets = append(targets, rowsType)
}
@@ -107,6 +113,11 @@ func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []*types.Pointe
if stmtType != nil {
targets = append(targets, stmtType)
}
+
+ namedStmtType := getTypePointerFromName(pkg, namedStmtName)
+ if namedStmtType != nil {
+ targets = append(targets, namedStmtType)
+ }
}
return targets
@@ -115,7 +126,7 @@ func getTargetTypes(pssa *buildssa.SSA, targetPackages []string) []*types.Pointe
func getTypePointerFromName(pkg *ssa.Package, name string) *types.Pointer {
pkgType := pkg.Type(name)
if pkgType == nil {
- // this package does not use Rows/Stmt
+ // this package does not use Rows/Stmt/NamedStmt
return nil
}
@@ -128,12 +139,28 @@ func getTypePointerFromName(pkg *ssa.Package, name string) *types.Pointer {
return types.NewPointer(named)
}
+func getTypeFromName(pkg *ssa.Package, name string) *types.Named {
+ pkgType := pkg.Type(name)
+ if pkgType == nil {
+ // this package does not use Rows/Stmt
+ return nil
+ }
+
+ obj := pkgType.Object()
+ named, ok := obj.Type().(*types.Named)
+ if !ok {
+ return nil
+ }
+
+ return named
+}
+
type targetValue struct {
value *ssa.Value
instr ssa.Instruction
}
-func getTargetTypesValues(b *ssa.BasicBlock, i int, targetTypes []*types.Pointer) []targetValue {
+func getTargetTypesValues(b *ssa.BasicBlock, i int, targetTypes []any) []targetValue {
targetValues := []targetValue{}
instr := b.Instrs[i]
@@ -149,21 +176,32 @@ func getTargetTypesValues(b *ssa.BasicBlock, i int, targetTypes []*types.Pointer
varType := v.Type()
for _, targetType := range targetTypes {
- if !types.Identical(varType, targetType) {
+ var tt types.Type
+
+ switch t := targetType.(type) {
+ case *types.Pointer:
+ tt = t
+ case *types.Named:
+ tt = t
+ default:
+ continue
+ }
+
+ if !types.Identical(varType, tt) {
continue
}
for _, cRef := range *call.Referrers() {
switch instr := cRef.(type) {
case *ssa.Call:
- if len(instr.Call.Args) >= 1 && types.Identical(instr.Call.Args[0].Type(), targetType) {
+ if len(instr.Call.Args) >= 1 && types.Identical(instr.Call.Args[0].Type(), tt) {
targetValues = append(targetValues, targetValue{
value: &instr.Call.Args[0],
instr: call,
})
}
case ssa.Value:
- if types.Identical(instr.Type(), targetType) {
+ if types.Identical(instr.Type(), tt) {
targetValues = append(targetValues, targetValue{
value: &instr,
instr: call,
@@ -177,43 +215,42 @@ func getTargetTypesValues(b *ssa.BasicBlock, i int, targetTypes []*types.Pointer
return targetValues
}
-func checkClosed(refs *[]ssa.Instruction, targetTypes []*types.Pointer) bool {
+func checkClosed(refs *[]ssa.Instruction, targetTypes []any) bool {
numInstrs := len(*refs)
for idx, ref := range *refs {
- // log.Printf("%T - %s", ref, ref)
-
action := getAction(ref, targetTypes)
switch action {
- case actionClosed:
+ case actionClosed, actionReturned, actionHandled:
return true
case actionPassed:
// Passed and not used after
if numInstrs == idx+1 {
return true
}
- case actionReturned:
- return true
- case actionHandled:
- return true
- default:
- // log.Printf(action)
}
}
return false
}
-func getAction(instr ssa.Instruction, targetTypes []*types.Pointer) action {
+func getAction(instr ssa.Instruction, targetTypes []any) action {
switch instr := instr.(type) {
case *ssa.Defer:
- if instr.Call.Value == nil {
- return actionUnvaluedDefer
+ if instr.Call.Value != nil {
+ name := instr.Call.Value.Name()
+ if name == closeMethod {
+ return actionClosed
+ }
}
- name := instr.Call.Value.Name()
- if name == closeMethod {
- return actionClosed
+ if instr.Call.Method != nil {
+ name := instr.Call.Method.Name()
+ if name == closeMethod {
+ return actionClosed
+ }
}
+
+ return actionUnvaluedDefer
case *ssa.Call:
if instr.Call.Value == nil {
return actionUnvaluedCall
@@ -265,7 +302,18 @@ func getAction(instr ssa.Instruction, targetTypes []*types.Pointer) action {
case *ssa.UnOp:
instrType := instr.Type()
for _, targetType := range targetTypes {
- if types.Identical(instrType, targetType) {
+ var tt types.Type
+
+ switch t := targetType.(type) {
+ case *types.Pointer:
+ tt = t
+ case *types.Named:
+ tt = t
+ default:
+ continue
+ }
+
+ if types.Identical(instrType, tt) {
if checkClosed(instr.Referrers(), targetTypes) {
return actionHandled
}
@@ -277,20 +325,22 @@ func getAction(instr ssa.Instruction, targetTypes []*types.Pointer) action {
}
case *ssa.Return:
return actionReturned
- default:
- // log.Printf("%s", instr)
}
return actionUnhandled
}
-func checkDeferred(pass *analysis.Pass, instrs *[]ssa.Instruction, targetTypes []*types.Pointer, inDefer bool) {
+func checkDeferred(pass *analysis.Pass, instrs *[]ssa.Instruction, targetTypes []any, inDefer bool) {
for _, instr := range *instrs {
switch instr := instr.(type) {
case *ssa.Defer:
if instr.Call.Value != nil && instr.Call.Value.Name() == closeMethod {
return
}
+
+ if instr.Call.Method != nil && instr.Call.Method.Name() == closeMethod {
+ return
+ }
case *ssa.Call:
if instr.Call.Value != nil && instr.Call.Value.Name() == closeMethod {
if !inDefer {
@@ -316,7 +366,18 @@ func checkDeferred(pass *analysis.Pass, instrs *[]ssa.Instruction, targetTypes [
case *ssa.UnOp:
instrType := instr.Type()
for _, targetType := range targetTypes {
- if types.Identical(instrType, targetType) {
+ var tt types.Type
+
+ switch t := targetType.(type) {
+ case *types.Pointer:
+ tt = t
+ case *types.Named:
+ tt = t
+ default:
+ continue
+ }
+
+ if types.Identical(instrType, tt) {
checkDeferred(pass, instr.Referrers(), targetTypes, inDefer)
}
}
@@ -326,10 +387,17 @@ func checkDeferred(pass *analysis.Pass, instrs *[]ssa.Instruction, targetTypes [
}
}
-func isTargetType(t types.Type, targetTypes []*types.Pointer) bool {
+func isTargetType(t types.Type, targetTypes []any) bool {
for _, targetType := range targetTypes {
- if types.Identical(t, targetType) {
- return true
+ switch tt := targetType.(type) {
+ case *types.Pointer:
+ if types.Identical(t, tt) {
+ return true
+ }
+ case *types.Named:
+ if types.Identical(t, tt) {
+ return true
+ }
}
}
diff --git a/vendor/github.com/securego/gosec/v2/.golangci.yml b/vendor/github.com/securego/gosec/v2/.golangci.yml
index d6c5de7ba2..caa81b968a 100644
--- a/vendor/github.com/securego/gosec/v2/.golangci.yml
+++ b/vendor/github.com/securego/gosec/v2/.golangci.yml
@@ -9,6 +9,7 @@ linters:
- exportloopref
- gci
- ginkgolinter
+ - gochecknoinits
- gofmt
- gofumpt
- goimports
diff --git a/vendor/github.com/securego/gosec/v2/Makefile b/vendor/github.com/securego/gosec/v2/Makefile
index 09303d11a0..61dad2118d 100644
--- a/vendor/github.com/securego/gosec/v2/Makefile
+++ b/vendor/github.com/securego/gosec/v2/Makefile
@@ -11,7 +11,6 @@ endif
BUILDFLAGS := "-w -s -X 'main.Version=$(GIT_TAG)' -X 'main.GitTag=$(GIT_TAG)' -X 'main.BuildDate=$(BUILD_DATE)'"
CGO_ENABLED = 0
GO := GO111MODULE=on go
-GO_NOMOD :=GO111MODULE=off go
GOPATH ?= $(shell $(GO) env GOPATH)
GOBIN ?= $(GOPATH)/bin
GOSEC ?= $(GOBIN)/gosec
@@ -25,8 +24,8 @@ default:
install-test-deps:
go install github.com/onsi/ginkgo/v2/ginkgo@latest
- $(GO_NOMOD) get -u golang.org/x/crypto/ssh
- $(GO_NOMOD) get -u github.com/lib/pq
+ go install golang.org/x/crypto/...@latest
+ go install github.com/lib/pq/...@latest
install-govulncheck:
@if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \
@@ -89,5 +88,5 @@ image-push: image
tlsconfig:
go generate ./...
-
+
.PHONY: test build clean release image image-push tlsconfig
diff --git a/vendor/github.com/securego/gosec/v2/README.md b/vendor/github.com/securego/gosec/v2/README.md
index 6c6d2982c8..27478bfdc2 100644
--- a/vendor/github.com/securego/gosec/v2/README.md
+++ b/vendor/github.com/securego/gosec/v2/README.md
@@ -1,7 +1,7 @@
# gosec - Golang Security Checker
-Inspects source code for security problems by scanning the Go AST.
+Inspects source code for security problems by scanning the Go AST and SSA code representation.
@@ -157,6 +157,7 @@ directory you can supply `./...` as the input argument.
- G304: File path provided as taint input
- G305: File traversal when extracting zip/tar archive
- G306: Poor file permissions used when writing to a new file
+- G307: Poor file permissions used when creating a file with os.Create
- G401: Detect the usage of DES, RC4, MD5 or SHA1
- G402: Look for bad TLS connection settings
- G403: Ensure minimum RSA key length of 2048 bits
diff --git a/vendor/github.com/securego/gosec/v2/USERS.md b/vendor/github.com/securego/gosec/v2/USERS.md
index ffc0560814..9b6e4eeee4 100644
--- a/vendor/github.com/securego/gosec/v2/USERS.md
+++ b/vendor/github.com/securego/gosec/v2/USERS.md
@@ -15,6 +15,7 @@ This is a list of gosec's users. Please send a pull request with your organisati
9. [PingCAP/tidb](https://github.com/pingcap/tidb)
10. [Checkmarx](https://www.checkmarx.com/)
11. [SeatGeek](https://www.seatgeek.com/)
+12. [reMarkable](https://remarkable.com)
## Projects
diff --git a/vendor/github.com/securego/gosec/v2/action.yml b/vendor/github.com/securego/gosec/v2/action.yml
index 8e28c346d3..86dbb32506 100644
--- a/vendor/github.com/securego/gosec/v2/action.yml
+++ b/vendor/github.com/securego/gosec/v2/action.yml
@@ -10,7 +10,7 @@ inputs:
runs:
using: 'docker'
- image: 'docker://securego/gosec:2.16.0'
+ image: 'docker://securego/gosec:2.18.0'
args:
- ${{ inputs.args }}
diff --git a/vendor/github.com/securego/gosec/v2/analyzer.go b/vendor/github.com/securego/gosec/v2/analyzer.go
index 023514b8aa..5981c9a860 100644
--- a/vendor/github.com/securego/gosec/v2/analyzer.go
+++ b/vendor/github.com/securego/gosec/v2/analyzer.go
@@ -57,6 +57,12 @@ const aliasOfAllRules = "*"
var generatedCodePattern = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`)
+// ignoreLocation keeps the location of an ignored rule
+type ignoreLocation struct {
+ file string
+ line string
+}
+
// The Context is populated with data parsed from the source code as it is scanned.
// It is passed through to all rule functions as they are called. Rules may use
// this data in conjunction with the encountered AST node.
@@ -69,7 +75,7 @@ type Context struct {
Root *ast.File
Imports *ImportTracker
Config Config
- Ignores []map[string][]issue.SuppressionInfo
+ Ignores map[ignoreLocation]map[string][]issue.SuppressionInfo
PassedValues map[string]interface{}
}
@@ -231,9 +237,7 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
return fmt.Errorf("parsing errors in pkg %q: %w", pkg.Name, err)
}
gosec.CheckRules(pkg)
- if on, err := gosec.config.IsGlobalEnabled(SSA); err == nil && on {
- gosec.CheckAnalyzers(pkg)
- }
+ gosec.CheckAnalyzers(pkg)
}
}
}
@@ -284,7 +288,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
return pkgs, nil
}
-// CheckRules runs analysis on the given package
+// CheckRules runs analysis on the given package.
func (gosec *Analyzer) CheckRules(pkg *packages.Package) {
gosec.logger.Println("Checking package:", pkg.Name)
for _, file := range pkg.Syntax {
@@ -320,31 +324,14 @@ func (gosec *Analyzer) CheckRules(pkg *packages.Package) {
}
}
-// CheckAnalyzers runs analyzers on a given package
+// CheckAnalyzers runs analyzers on a given package.
func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
- ssaPass := &analysis.Pass{
- Analyzer: buildssa.Analyzer,
- Fset: pkg.Fset,
- Files: pkg.Syntax,
- OtherFiles: pkg.OtherFiles,
- IgnoredFiles: pkg.IgnoredFiles,
- Pkg: pkg.Types,
- TypesInfo: pkg.TypesInfo,
- TypesSizes: pkg.TypesSizes,
- ResultOf: nil,
- Report: nil,
- ImportObjectFact: nil,
- ExportObjectFact: nil,
- ImportPackageFact: nil,
- ExportPackageFact: nil,
- AllObjectFacts: nil,
- AllPackageFacts: nil,
- }
- ssaResult, err := ssaPass.Analyzer.Run(ssaPass)
- if err != nil {
- gosec.logger.Printf("Error running SSA analyser on package %q: %s", pkg.Name, err)
+ ssaResult, err := gosec.buildSSA(pkg)
+ if err != nil || ssaResult == nil {
+ gosec.logger.Printf("Error building the SSA representation of the package %q: %s", pkg.Name, err)
return
}
+
resultMap := map[*analysis.Analyzer]interface{}{
buildssa.Analyzer: &analyzers.SSAAnalyzerResult{
Config: gosec.Config(),
@@ -377,13 +364,44 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
continue
}
if result != nil {
- if aissue, ok := result.(*issue.Issue); ok {
- gosec.updateIssues(aissue, false, []issue.SuppressionInfo{})
+ if passIssues, ok := result.([]*issue.Issue); ok {
+ for _, iss := range passIssues {
+ gosec.updateIssues(iss)
+ }
}
}
}
}
+// buildSSA runs the SSA pass which builds the SSA representation of the package. It handles gracefully any panic.
+func (gosec *Analyzer) buildSSA(pkg *packages.Package) (interface{}, error) {
+ defer func() {
+ if r := recover(); r != nil {
+ gosec.logger.Printf("Panic when running SSA analyser on package: %s", pkg.Name)
+ }
+ }()
+ ssaPass := &analysis.Pass{
+ Analyzer: buildssa.Analyzer,
+ Fset: pkg.Fset,
+ Files: pkg.Syntax,
+ OtherFiles: pkg.OtherFiles,
+ IgnoredFiles: pkg.IgnoredFiles,
+ Pkg: pkg.Types,
+ TypesInfo: pkg.TypesInfo,
+ TypesSizes: pkg.TypesSizes,
+ ResultOf: nil,
+ Report: nil,
+ ImportObjectFact: nil,
+ ExportObjectFact: nil,
+ ImportPackageFact: nil,
+ ExportPackageFact: nil,
+ AllObjectFacts: nil,
+ AllPackageFacts: nil,
+ }
+
+ return ssaPass.Analyzer.Run(ssaPass)
+}
+
func isGeneratedFile(file *ast.File) bool {
for _, comment := range file.Comments {
for _, row := range comment.List {
@@ -509,10 +527,8 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
// Visit runs the gosec visitor logic over an AST created by parsing go code.
// Rule methods added with AddRule will be invoked as necessary.
func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
- ignores, ok := gosec.updateIgnoredRules(n)
- if !ok {
- return gosec
- }
+ // Update any potentially ignored rules at the node location
+ gosec.updateIgnoredRules(n)
// Using ast.File instead of ast.ImportSpec, so that we can track all imports at once.
switch i := n.(type) {
@@ -521,56 +537,55 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
}
for _, rule := range gosec.ruleset.RegisteredFor(n) {
- suppressions, ignored := gosec.updateSuppressions(rule.ID(), ignores)
issue, err := rule.Match(n, gosec.context)
if err != nil {
file, line := GetLocation(n, gosec.context)
file = path.Base(file)
gosec.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
}
- gosec.updateIssues(issue, ignored, suppressions)
+ gosec.updateIssues(issue)
}
return gosec
}
-func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
- if n == nil {
- if len(gosec.context.Ignores) > 0 {
- gosec.context.Ignores = gosec.context.Ignores[1:]
- }
- return nil, false
- }
- // Get any new rule exclusions.
+func (gosec *Analyzer) updateIgnoredRules(n ast.Node) {
ignoredRules := gosec.ignore(n)
-
- // Now create the union of exclusions.
- ignores := map[string][]issue.SuppressionInfo{}
- if len(gosec.context.Ignores) > 0 {
- for k, v := range gosec.context.Ignores[0] {
- ignores[k] = v
+ if len(ignoredRules) > 0 {
+ if gosec.context.Ignores == nil {
+ gosec.context.Ignores = make(map[ignoreLocation]map[string][]issue.SuppressionInfo)
+ }
+ line := issue.GetLine(gosec.context.FileSet.File(n.Pos()), n)
+ ignoreLocation := ignoreLocation{
+ file: gosec.context.FileSet.File(n.Pos()).Name(),
+ line: line,
}
+ current, ok := gosec.context.Ignores[ignoreLocation]
+ if !ok {
+ current = map[string][]issue.SuppressionInfo{}
+ }
+ for r, s := range ignoredRules {
+ if current[r] == nil {
+ current[r] = []issue.SuppressionInfo{}
+ }
+ current[r] = append(current[r], s)
+ }
+ gosec.context.Ignores[ignoreLocation] = current
}
+}
- for ruleID, suppression := range ignoredRules {
- ignores[ruleID] = append(ignores[ruleID], suppression)
+func (gosec *Analyzer) getSuppressionsAtLineInFile(file string, line string, id string) ([]issue.SuppressionInfo, bool) {
+ ignores, ok := gosec.context.Ignores[ignoreLocation{file: file, line: line}]
+ if !ok {
+ ignores = make(map[string][]issue.SuppressionInfo)
}
- // Push the new set onto the stack.
- gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
-
- return ignores, true
-}
-
-func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
- // Check if all rules are ignored.
+ // Check if the rule was specifically suppressed at this location.
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
- // Check if the specific rule is ignored
ruleSuppressions, ruleIgnored := ignores[id]
-
ignored := generalIgnored || ruleIgnored
suppressions := append(generalSuppressions, ruleSuppressions...)
- // Track external suppressions.
+ // Track external suppressions of this rule.
if gosec.ruleset.IsRuleSuppressed(id) {
ignored = true
suppressions = append(suppressions, issue.SuppressionInfo{
@@ -581,8 +596,9 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.
return suppressions, ignored
}
-func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
+func (gosec *Analyzer) updateIssues(issue *issue.Issue) {
if issue != nil {
+ suppressions, ignored := gosec.getSuppressionsAtLineInFile(issue.File, issue.Line, issue.RuleID)
if gosec.showIgnored {
issue.NoSec = ignored
}
diff --git a/vendor/github.com/securego/gosec/v2/analyzers/slice_bounds.go b/vendor/github.com/securego/gosec/v2/analyzers/slice_bounds.go
new file mode 100644
index 0000000000..08a55eb429
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/analyzers/slice_bounds.go
@@ -0,0 +1,386 @@
+// (c) Copyright gosec's authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package analyzers
+
+import (
+ "errors"
+ "fmt"
+ "go/token"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/buildssa"
+ "golang.org/x/tools/go/ssa"
+
+ "github.com/securego/gosec/v2/issue"
+)
+
+type bound int
+
+const (
+ lowerUnbounded bound = iota
+ upperUnbounded
+ unbounded
+ upperBounded
+)
+
+const maxDepth = 20
+
+func newSliceBoundsAnalyzer(id string, description string) *analysis.Analyzer {
+ return &analysis.Analyzer{
+ Name: id,
+ Doc: description,
+ Run: runSliceBounds,
+ Requires: []*analysis.Analyzer{buildssa.Analyzer},
+ }
+}
+
+func runSliceBounds(pass *analysis.Pass) (interface{}, error) {
+ ssaResult, err := getSSAResult(pass)
+ if err != nil {
+ return nil, err
+ }
+
+ issues := map[ssa.Instruction]*issue.Issue{}
+ ifs := map[ssa.If]*ssa.BinOp{}
+ for _, mcall := range ssaResult.SSA.SrcFuncs {
+ for _, block := range mcall.DomPreorder() {
+ for _, instr := range block.Instrs {
+ switch instr := instr.(type) {
+ case *ssa.Alloc:
+ sliceCap, err := extractSliceCapFromAlloc(instr.String())
+ if err != nil {
+ break
+ }
+ allocRefs := instr.Referrers()
+ if allocRefs == nil {
+ break
+ }
+ for _, instr := range *allocRefs {
+ if slice, ok := instr.(*ssa.Slice); ok {
+ if _, ok := slice.X.(*ssa.Alloc); ok {
+ if slice.Parent() != nil {
+ l, h := extractSliceBounds(slice)
+ newCap := computeSliceNewCap(l, h, sliceCap)
+ violations := []ssa.Instruction{}
+ trackSliceBounds(0, newCap, slice, &violations, ifs)
+ for _, s := range violations {
+ switch s := s.(type) {
+ case *ssa.Slice:
+ issue := newIssue(
+ pass.Analyzer.Name,
+ "slice bounds out of range",
+ pass.Fset,
+ s.Pos(),
+ issue.Low,
+ issue.High)
+ issues[s] = issue
+ case *ssa.IndexAddr:
+ issue := newIssue(
+ pass.Analyzer.Name,
+ "slice index out of range",
+ pass.Fset,
+ s.Pos(),
+ issue.Low,
+ issue.High)
+ issues[s] = issue
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for ifref, binop := range ifs {
+ bound, value, err := extractBinOpBound(binop)
+ if err != nil {
+ continue
+ }
+ for i, block := range ifref.Block().Succs {
+ if i == 1 {
+ bound = invBound(bound)
+ }
+ for _, instr := range block.Instrs {
+ if _, ok := issues[instr]; ok {
+ switch bound {
+ case lowerUnbounded:
+ break
+ case upperUnbounded, unbounded:
+ delete(issues, instr)
+ case upperBounded:
+ switch tinstr := instr.(type) {
+ case *ssa.Slice:
+ lower, upper := extractSliceBounds(tinstr)
+ if isSliceInsideBounds(0, value, lower, upper) {
+ delete(issues, instr)
+ }
+ case *ssa.IndexAddr:
+ indexValue, err := extractIntValue(tinstr.Index.String())
+ if err != nil {
+ break
+ }
+ if isSliceIndexInsideBounds(0, value, indexValue) {
+ delete(issues, instr)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ foundIssues := []*issue.Issue{}
+ for _, issue := range issues {
+ foundIssues = append(foundIssues, issue)
+ }
+ if len(foundIssues) > 0 {
+ return foundIssues, nil
+ }
+ return nil, nil
+}
+
+func trackSliceBounds(depth int, sliceCap int, slice ssa.Node, violations *[]ssa.Instruction, ifs map[ssa.If]*ssa.BinOp) {
+ if depth == maxDepth {
+ return
+ }
+ depth++
+ if violations == nil {
+ violations = &[]ssa.Instruction{}
+ }
+ referrers := slice.Referrers()
+ if referrers != nil {
+ for _, refinstr := range *referrers {
+ switch refinstr := refinstr.(type) {
+ case *ssa.Slice:
+ checkAllSlicesBounds(depth, sliceCap, refinstr, violations, ifs)
+ switch refinstr.X.(type) {
+ case *ssa.Alloc, *ssa.Parameter:
+ l, h := extractSliceBounds(refinstr)
+ newCap := computeSliceNewCap(l, h, sliceCap)
+ trackSliceBounds(depth, newCap, refinstr, violations, ifs)
+ }
+ case *ssa.IndexAddr:
+ indexValue, err := extractIntValue(refinstr.Index.String())
+ if err == nil && !isSliceIndexInsideBounds(0, sliceCap, indexValue) {
+ *violations = append(*violations, refinstr)
+ }
+ case *ssa.Call:
+ if ifref, cond := extractSliceIfLenCondition(refinstr); ifref != nil && cond != nil {
+ ifs[*ifref] = cond
+ } else {
+ parPos := -1
+ for pos, arg := range refinstr.Call.Args {
+ if a, ok := arg.(*ssa.Slice); ok && a == slice {
+ parPos = pos
+ }
+ }
+ if fn, ok := refinstr.Call.Value.(*ssa.Function); ok {
+ if len(fn.Params) > parPos && parPos > -1 {
+ param := fn.Params[parPos]
+ trackSliceBounds(depth, sliceCap, param, violations, ifs)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func checkAllSlicesBounds(depth int, sliceCap int, slice *ssa.Slice, violations *[]ssa.Instruction, ifs map[ssa.If]*ssa.BinOp) {
+ if depth == maxDepth {
+ return
+ }
+ depth++
+ if violations == nil {
+ violations = &[]ssa.Instruction{}
+ }
+ sliceLow, sliceHigh := extractSliceBounds(slice)
+ if !isSliceInsideBounds(0, sliceCap, sliceLow, sliceHigh) {
+ *violations = append(*violations, slice)
+ }
+ switch slice.X.(type) {
+ case *ssa.Alloc, *ssa.Parameter, *ssa.Slice:
+ l, h := extractSliceBounds(slice)
+ newCap := computeSliceNewCap(l, h, sliceCap)
+ trackSliceBounds(depth, newCap, slice, violations, ifs)
+ }
+
+ references := slice.Referrers()
+ if references == nil {
+ return
+ }
+ for _, ref := range *references {
+ switch s := ref.(type) {
+ case *ssa.Slice:
+ checkAllSlicesBounds(depth, sliceCap, s, violations, ifs)
+ switch s.X.(type) {
+ case *ssa.Alloc, *ssa.Parameter:
+ l, h := extractSliceBounds(s)
+ newCap := computeSliceNewCap(l, h, sliceCap)
+ trackSliceBounds(depth, newCap, s, violations, ifs)
+ }
+ }
+ }
+}
+
+func extractSliceIfLenCondition(call *ssa.Call) (*ssa.If, *ssa.BinOp) {
+ if builtInLen, ok := call.Call.Value.(*ssa.Builtin); ok {
+ if builtInLen.Name() == "len" {
+ refs := call.Referrers()
+ if refs != nil {
+ for _, ref := range *refs {
+ if binop, ok := ref.(*ssa.BinOp); ok {
+ binoprefs := binop.Referrers()
+ for _, ref := range *binoprefs {
+ if ifref, ok := ref.(*ssa.If); ok {
+ return ifref, binop
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+
+func computeSliceNewCap(l, h, oldCap int) int {
+ if l == 0 && h == 0 {
+ return oldCap
+ }
+ if l > 0 && h == 0 {
+ return oldCap - l
+ }
+ if l == 0 && h > 0 {
+ return h
+ }
+ return h - l
+}
+
+func invBound(bound bound) bound {
+ switch bound {
+ case lowerUnbounded:
+ return upperUnbounded
+ case upperUnbounded:
+ return lowerUnbounded
+ case upperBounded:
+ return unbounded
+ case unbounded:
+ return upperBounded
+ default:
+ return unbounded
+ }
+}
+
+func extractBinOpBound(binop *ssa.BinOp) (bound, int, error) {
+ if binop.X != nil {
+ if x, ok := binop.X.(*ssa.Const); ok {
+ value, err := strconv.Atoi(x.Value.String())
+ if err != nil {
+ return lowerUnbounded, value, err
+ }
+ switch binop.Op {
+ case token.LSS, token.LEQ:
+ return upperUnbounded, value, nil
+ case token.GTR, token.GEQ:
+ return lowerUnbounded, value, nil
+ case token.EQL:
+ return upperBounded, value, nil
+ case token.NEQ:
+ return unbounded, value, nil
+ }
+ }
+ }
+ if binop.Y != nil {
+ if y, ok := binop.Y.(*ssa.Const); ok {
+ value, err := strconv.Atoi(y.Value.String())
+ if err != nil {
+ return lowerUnbounded, value, err
+ }
+ switch binop.Op {
+ case token.LSS, token.LEQ:
+ return lowerUnbounded, value, nil
+ case token.GTR, token.GEQ:
+ return upperUnbounded, value, nil
+ case token.EQL:
+ return upperBounded, value, nil
+ case token.NEQ:
+ return unbounded, value, nil
+ }
+ }
+ }
+ return lowerUnbounded, 0, fmt.Errorf("unable to extract constant from binop")
+}
+
+func isSliceIndexInsideBounds(l, h int, index int) bool {
+ return (l <= index && index < h)
+}
+
+func isSliceInsideBounds(l, h int, cl, ch int) bool {
+ return (l <= cl && h >= ch) && (l <= ch && h >= cl)
+}
+
+func extractSliceBounds(slice *ssa.Slice) (int, int) {
+ var low int
+ if slice.Low != nil {
+ l, err := extractIntValue(slice.Low.String())
+ if err == nil {
+ low = l
+ }
+ }
+ var high int
+ if slice.High != nil {
+ h, err := extractIntValue(slice.High.String())
+ if err == nil {
+ high = h
+ }
+ }
+ return low, high
+}
+
+func extractIntValue(value string) (int, error) {
+ parts := strings.Split(value, ":")
+ if len(parts) != 2 {
+ return 0, fmt.Errorf("invalid value: %s", value)
+ }
+ if parts[1] != "int" {
+ return 0, fmt.Errorf("invalid value: %s", value)
+ }
+ return strconv.Atoi(parts[0])
+}
+
+func extractSliceCapFromAlloc(instr string) (int, error) {
+ re := regexp.MustCompile(`new \[(\d+)\]*`)
+ var sliceCap int
+ matches := re.FindAllStringSubmatch(instr, -1)
+ if matches == nil {
+ return sliceCap, errors.New("no slice cap found")
+ }
+
+ if len(matches) > 0 {
+ m := matches[0]
+ if len(m) > 1 {
+ return strconv.Atoi(m[1])
+ }
+ }
+
+ return 0, errors.New("no slice cap found")
+}
diff --git a/vendor/github.com/securego/gosec/v2/analyzers/ssrf.go b/vendor/github.com/securego/gosec/v2/analyzers/ssrf.go
deleted file mode 100644
index 70e0211f10..0000000000
--- a/vendor/github.com/securego/gosec/v2/analyzers/ssrf.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// (c) Copyright gosec's authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package analyzers
-
-import (
- "golang.org/x/tools/go/analysis"
- "golang.org/x/tools/go/analysis/passes/buildssa"
- "golang.org/x/tools/go/ssa"
-
- "github.com/securego/gosec/v2/issue"
-)
-
-func newSSRFAnalyzer(id string, description string) *analysis.Analyzer {
- return &analysis.Analyzer{
- Name: id,
- Doc: description,
- Run: runSSRF,
- Requires: []*analysis.Analyzer{buildssa.Analyzer},
- }
-}
-
-func runSSRF(pass *analysis.Pass) (interface{}, error) {
- ssaResult, err := getSSAResult(pass)
- if err != nil {
- return nil, err
- }
- // TODO: implement the analysis
- for _, fn := range ssaResult.SSA.SrcFuncs {
- for _, block := range fn.DomPreorder() {
- for _, instr := range block.Instrs {
- switch instr := instr.(type) {
- case *ssa.Call:
- callee := instr.Call.StaticCallee()
- if callee != nil {
- ssaResult.Logger.Printf("callee: %s\n", callee)
- return newIssue(pass.Analyzer.Name,
- "not implemented",
- pass.Fset, instr.Call.Pos(), issue.Low, issue.High), nil
- }
- }
- }
- }
- }
- return nil, nil
-}
diff --git a/vendor/github.com/securego/gosec/v2/analyzers/util.go b/vendor/github.com/securego/gosec/v2/analyzers/util.go
index f1bd867ae5..5941184aa2 100644
--- a/vendor/github.com/securego/gosec/v2/analyzers/util.go
+++ b/vendor/github.com/securego/gosec/v2/analyzers/util.go
@@ -38,7 +38,7 @@ type SSAAnalyzerResult struct {
// BuildDefaultAnalyzers returns the default list of analyzers
func BuildDefaultAnalyzers() []*analysis.Analyzer {
return []*analysis.Analyzer{
- newSSRFAnalyzer("G107", "URL provided to HTTP request as taint input"),
+ newSliceBoundsAnalyzer("G602", "Possible slice bounds out of range"),
}
}
diff --git a/vendor/github.com/securego/gosec/v2/cwe/data.go b/vendor/github.com/securego/gosec/v2/cwe/data.go
index ff1ad3c7d8..79a6b9d231 100644
--- a/vendor/github.com/securego/gosec/v2/cwe/data.go
+++ b/vendor/github.com/securego/gosec/v2/cwe/data.go
@@ -1,7 +1,5 @@
package cwe
-import "fmt"
-
const (
// Acronym is the acronym of CWE
Acronym = "CWE"
@@ -13,139 +11,128 @@ const (
Organization = "MITRE"
// Description the description of CWE
Description = "The MITRE Common Weakness Enumeration"
-)
-
-var (
// InformationURI link to the published CWE PDF
- InformationURI = fmt.Sprintf("https://cwe.mitre.org/data/published/cwe_v%s.pdf/", Version)
+ InformationURI = "https://cwe.mitre.org/data/published/cwe_v" + Version + ".pdf/"
// DownloadURI link to the zipped XML of the CWE list
- DownloadURI = fmt.Sprintf("https://cwe.mitre.org/data/xml/cwec_v%s.xml.zip", Version)
-
- data = map[string]*Weakness{}
-
- weaknesses = []*Weakness{
- {
- ID: "118",
- Description: "The software does not restrict or incorrectly restricts operations within the boundaries of a resource that is accessed using an index or pointer, such as memory or files.",
- Name: "Incorrect Access of Indexable Resource ('Range Error')",
- },
- {
- ID: "190",
- Description: "The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.",
- Name: "Integer Overflow or Wraparound",
- },
- {
- ID: "200",
- Description: "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.",
- Name: "Exposure of Sensitive Information to an Unauthorized Actor",
- },
- {
- ID: "22",
- Description: "The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.",
- Name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
- },
- {
- ID: "242",
- Description: "The program calls a function that can never be guaranteed to work safely.",
- Name: "Use of Inherently Dangerous Function",
- },
- {
- ID: "276",
- Description: "During installation, installed file permissions are set to allow anyone to modify those files.",
- Name: "Incorrect Default Permissions",
- },
- {
- ID: "295",
- Description: "The software does not validate, or incorrectly validates, a certificate.",
- Name: "Improper Certificate Validation",
- },
- {
- ID: "310",
- Description: "Weaknesses in this category are related to the design and implementation of data confidentiality and integrity. Frequently these deal with the use of encoding techniques, encryption libraries, and hashing algorithms. The weaknesses in this category could lead to a degradation of the quality data if they are not addressed.",
- Name: "Cryptographic Issues",
- },
- {
- ID: "322",
- Description: "The software performs a key exchange with an actor without verifying the identity of that actor.",
- Name: "Key Exchange without Entity Authentication",
- },
- {
- ID: "326",
- Description: "The software stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.",
- Name: "Inadequate Encryption Strength",
- },
- {
- ID: "327",
- Description: "The use of a broken or risky cryptographic algorithm is an unnecessary risk that may result in the exposure of sensitive information.",
- Name: "Use of a Broken or Risky Cryptographic Algorithm",
- },
- {
- ID: "338",
- Description: "The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.",
- Name: "Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)",
- },
- {
- ID: "377",
- Description: "Creating and using insecure temporary files can leave application and system data vulnerable to attack.",
- Name: "Insecure Temporary File",
- },
- {
- ID: "400",
- Description: "The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.",
- Name: "Uncontrolled Resource Consumption",
- },
- {
- ID: "409",
- Description: "The software does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.",
- Name: "Improper Handling of Highly Compressed Data (Data Amplification)",
- },
- {
- ID: "703",
- Description: "The software does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the software.",
- Name: "Improper Check or Handling of Exceptional Conditions",
- },
- {
- ID: "78",
- Description: "The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.",
- Name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')",
- },
- {
- ID: "79",
- Description: "The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.",
- Name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
- },
- {
- ID: "798",
- Description: "The software contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data.",
- Name: "Use of Hard-coded Credentials",
- },
- {
- ID: "88",
- Description: "The software constructs a string for a command to executed by a separate component\nin another control sphere, but it does not properly delimit the\nintended arguments, options, or switches within that command string.",
- Name: "Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')",
- },
- {
- ID: "89",
- Description: "The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.",
- Name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')",
- },
- {
- ID: "676",
- Description: "The program invokes a potentially dangerous function that could introduce a vulnerability if it is used incorrectly, but the function can also be used safely.",
- Name: "Use of Potentially Dangerous Function",
- },
- }
+ DownloadURI = "https://cwe.mitre.org/data/xml/cwec_v" + Version + ".xml.zip"
)
-func init() {
- for _, weakness := range weaknesses {
- data[weakness.ID] = weakness
- }
+var idWeaknesses = map[string]*Weakness{
+ "118": {
+ ID: "118",
+ Description: "The software does not restrict or incorrectly restricts operations within the boundaries of a resource that is accessed using an index or pointer, such as memory or files.",
+ Name: "Incorrect Access of Indexable Resource ('Range Error')",
+ },
+ "190": {
+ ID: "190",
+ Description: "The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.",
+ Name: "Integer Overflow or Wraparound",
+ },
+ "200": {
+ ID: "200",
+ Description: "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.",
+ Name: "Exposure of Sensitive Information to an Unauthorized Actor",
+ },
+ "22": {
+ ID: "22",
+ Description: "The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.",
+ Name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
+ },
+ "242": {
+ ID: "242",
+ Description: "The program calls a function that can never be guaranteed to work safely.",
+ Name: "Use of Inherently Dangerous Function",
+ },
+ "276": {
+ ID: "276",
+ Description: "During installation, installed file permissions are set to allow anyone to modify those files.",
+ Name: "Incorrect Default Permissions",
+ },
+ "295": {
+ ID: "295",
+ Description: "The software does not validate, or incorrectly validates, a certificate.",
+ Name: "Improper Certificate Validation",
+ },
+ "310": {
+ ID: "310",
+ Description: "Weaknesses in this category are related to the design and implementation of data confidentiality and integrity. Frequently these deal with the use of encoding techniques, encryption libraries, and hashing algorithms. The weaknesses in this category could lead to a degradation of the quality data if they are not addressed.",
+ Name: "Cryptographic Issues",
+ },
+ "322": {
+ ID: "322",
+ Description: "The software performs a key exchange with an actor without verifying the identity of that actor.",
+ Name: "Key Exchange without Entity Authentication",
+ },
+ "326": {
+ ID: "326",
+ Description: "The software stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.",
+ Name: "Inadequate Encryption Strength",
+ },
+ "327": {
+ ID: "327",
+ Description: "The use of a broken or risky cryptographic algorithm is an unnecessary risk that may result in the exposure of sensitive information.",
+ Name: "Use of a Broken or Risky Cryptographic Algorithm",
+ },
+ "338": {
+ ID: "338",
+ Description: "The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.",
+ Name: "Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)",
+ },
+ "377": {
+ ID: "377",
+ Description: "Creating and using insecure temporary files can leave application and system data vulnerable to attack.",
+ Name: "Insecure Temporary File",
+ },
+ "400": {
+ ID: "400",
+ Description: "The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.",
+ Name: "Uncontrolled Resource Consumption",
+ },
+ "409": {
+ ID: "409",
+ Description: "The software does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.",
+ Name: "Improper Handling of Highly Compressed Data (Data Amplification)",
+ },
+ "703": {
+ ID: "703",
+ Description: "The software does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the software.",
+ Name: "Improper Check or Handling of Exceptional Conditions",
+ },
+ "78": {
+ ID: "78",
+ Description: "The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.",
+ Name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')",
+ },
+ "79": {
+ ID: "79",
+ Description: "The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.",
+ Name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
+ },
+ "798": {
+ ID: "798",
+ Description: "The software contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data.",
+ Name: "Use of Hard-coded Credentials",
+ },
+ "88": {
+ ID: "88",
+ Description: "The software constructs a string for a command to executed by a separate component\nin another control sphere, but it does not properly delimit the\nintended arguments, options, or switches within that command string.",
+ Name: "Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')",
+ },
+ "89": {
+ ID: "89",
+ Description: "The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.",
+ Name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')",
+ },
+ "676": {
+ ID: "676",
+ Description: "The program invokes a potentially dangerous function that could introduce a vulnerability if it is used incorrectly, but the function can also be used safely.",
+ Name: "Use of Potentially Dangerous Function",
+ },
}
// Get Retrieves a CWE weakness by it's id
func Get(id string) *Weakness {
- weakness, ok := data[id]
+ weakness, ok := idWeaknesses[id]
if ok && weakness != nil {
return weakness
}
diff --git a/vendor/github.com/securego/gosec/v2/helpers.go b/vendor/github.com/securego/gosec/v2/helpers.go
index b4c23e5bba..15b2b5f3a3 100644
--- a/vendor/github.com/securego/gosec/v2/helpers.go
+++ b/vendor/github.com/securego/gosec/v2/helpers.go
@@ -100,7 +100,7 @@ func GetChar(n ast.Node) (byte, error) {
// Unlike the other getters, it does _not_ raise an error for unknown ast.Node types. At the base, the recursion will hit a non-BinaryExpr type,
// either BasicLit or other, so it's not an error case. It will only error if `strconv.Unquote` errors. This matters, because there's
// currently functionality that relies on error values being returned by GetString if and when it hits a non-basiclit string node type,
-// hence for cases where recursion is needed, we use this separate function, so that we can still be backwards compatbile.
+// hence for cases where recursion is needed, we use this separate function, so that we can still be backwards compatible.
//
// This was added to handle a SQL injection concatenation case where the injected value is infixed between two strings, not at the start or end. See example below
//
@@ -183,7 +183,7 @@ func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
case *ast.CallExpr:
switch call := expr.Fun.(type) {
case *ast.Ident:
- if call.Name == "new" {
+ if call.Name == "new" && len(expr.Args) > 0 {
t := ctx.Info.TypeOf(expr.Args[0])
if t != nil {
return t.String(), fn.Sel.Name, nil
diff --git a/vendor/github.com/securego/gosec/v2/issue/issue.go b/vendor/github.com/securego/gosec/v2/issue/issue.go
index db4d630fab..1000b20423 100644
--- a/vendor/github.com/securego/gosec/v2/issue/issue.go
+++ b/vendor/github.com/securego/gosec/v2/issue/issue.go
@@ -178,11 +178,7 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
// New creates a new Issue
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
name := fobj.Name()
- start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
- line := strconv.Itoa(start)
- if start != end {
- line = fmt.Sprintf("%d-%d", start, end)
- }
+ line := GetLine(fobj, node)
col := strconv.Itoa(fobj.Position(node.Pos()).Column)
var code string
@@ -217,3 +213,13 @@ func (i *Issue) WithSuppressions(suppressions []SuppressionInfo) *Issue {
i.Suppressions = suppressions
return i
}
+
+// GetLine returns the line number of a given ast.Node
+func GetLine(fobj *token.File, node ast.Node) string {
+ start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
+ line := strconv.Itoa(start)
+ if start != end {
+ line = fmt.Sprintf("%d-%d", start, end)
+ }
+ return line
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/fileperms.go b/vendor/github.com/securego/gosec/v2/rules/fileperms.go
index 0376b6a03c..5311f74c6c 100644
--- a/vendor/github.com/securego/gosec/v2/rules/fileperms.go
+++ b/vendor/github.com/securego/gosec/v2/rules/fileperms.go
@@ -30,6 +30,7 @@ type filePermissions struct {
calls []string
}
+// ID returns the ID of the rule.
func (r *filePermissions) ID() string {
return r.MetaData.ID
}
@@ -55,6 +56,7 @@ func modeIsSubset(subset int64, superset int64) bool {
return (subset | superset) == superset
}
+// Match checks if the rule is matched.
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, pkg := range r.pkgs {
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
@@ -116,3 +118,47 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}
+
+type osCreatePermissions struct {
+ issue.MetaData
+ mode int64
+ pkgs []string
+ calls []string
+}
+
+const defaultOsCreateMode = 0o666
+
+// ID returns the ID of the rule.
+func (r *osCreatePermissions) ID() string {
+ return r.MetaData.ID
+}
+
+// Match checks if the rule is matched.
+func (r *osCreatePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
+ for _, pkg := range r.pkgs {
+ if _, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
+ if !modeIsSubset(defaultOsCreateMode, r.mode) {
+ return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewOsCreatePerms reates a rule to detect file creation with a more permissive than configured
+// permission mask.
+func NewOsCreatePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ mode := getConfiguredMode(conf, id, 0o666)
+ return &osCreatePermissions{
+ mode: mode,
+ pkgs: []string{"os"},
+ calls: []string{"Create"},
+ MetaData: issue.MetaData{
+ ID: id,
+ Severity: issue.Medium,
+ Confidence: issue.High,
+ What: fmt.Sprintf("Expect file permissions to be %#o or less but os.Create used with default permissions %#o",
+ mode, defaultOsCreateMode),
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go b/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
index ea83860845..ed1fb947d1 100644
--- a/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
+++ b/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
@@ -15,6 +15,7 @@
package rules
import (
+ "fmt"
"go/ast"
"go/token"
"regexp"
@@ -26,10 +27,169 @@ import (
"github.com/securego/gosec/v2/issue"
)
+type secretPattern struct {
+ name string
+ regexp *regexp.Regexp
+}
+
+var secretsPatterns = [...]secretPattern{
+ {
+ name: "RSA private key",
+ regexp: regexp.MustCompile(`-----BEGIN RSA PRIVATE KEY-----`),
+ },
+ {
+ name: "SSH (DSA) private key",
+ regexp: regexp.MustCompile(`-----BEGIN DSA PRIVATE KEY-----`),
+ },
+ {
+ name: "SSH (EC) private key",
+ regexp: regexp.MustCompile(`-----BEGIN EC PRIVATE KEY-----`),
+ },
+ {
+ name: "PGP private key block",
+ regexp: regexp.MustCompile(`-----BEGIN PGP PRIVATE KEY BLOCK-----`),
+ },
+ {
+ name: "Slack Token",
+ regexp: regexp.MustCompile(`xox[pborsa]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32}`),
+ },
+ {
+ name: "AWS API Key",
+ regexp: regexp.MustCompile(`AKIA[0-9A-Z]{16}`),
+ },
+ {
+ name: "Amazon MWS Auth Token",
+ regexp: regexp.MustCompile(`amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`),
+ },
+ {
+ name: "AWS AppSync GraphQL Key",
+ regexp: regexp.MustCompile(`da2-[a-z0-9]{26}`),
+ },
+ {
+ name: "GitHub personal access token",
+ regexp: regexp.MustCompile(`ghp_[a-zA-Z0-9]{36}`),
+ },
+ {
+ name: "GitHub fine-grained access token",
+ regexp: regexp.MustCompile(`github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}`),
+ },
+ {
+ name: "GitHub action temporary token",
+ regexp: regexp.MustCompile(`ghs_[a-zA-Z0-9]{36}`),
+ },
+ {
+ name: "Google API Key",
+ regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
+ },
+ {
+ name: "Google Cloud Platform API Key",
+ regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
+ },
+ {
+ name: "Google Cloud Platform OAuth",
+ regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
+ },
+ {
+ name: "Google Drive API Key",
+ regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
+ },
+ {
+ name: "Google Drive OAuth",
+ regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
+ },
+ {
+ name: "Google (GCP) Service-account",
+ regexp: regexp.MustCompile(`"type": "service_account"`),
+ },
+ {
+ name: "Google Gmail API Key",
+ regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
+ },
+ {
+ name: "Google Gmail OAuth",
+ regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
+ },
+ {
+ name: "Google OAuth Access Token",
+ regexp: regexp.MustCompile(`ya29\.[0-9A-Za-z\-_]+`),
+ },
+ {
+ name: "Google YouTube API Key",
+ regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
+ },
+ {
+ name: "Google YouTube OAuth",
+ regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
+ },
+ {
+ name: "Generic API Key",
+ regexp: regexp.MustCompile(`[aA][pP][iI]_?[kK][eE][yY].*[''|"][0-9a-zA-Z]{32,45}[''|"]`),
+ },
+ {
+ name: "Generic Secret",
+ regexp: regexp.MustCompile(`[sS][eE][cC][rR][eE][tT].*[''|"][0-9a-zA-Z]{32,45}[''|"]`),
+ },
+ {
+ name: "Heroku API Key",
+ regexp: regexp.MustCompile(`[hH][eE][rR][oO][kK][uU].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}`),
+ },
+ {
+ name: "MailChimp API Key",
+ regexp: regexp.MustCompile(`[0-9a-f]{32}-us[0-9]{1,2}`),
+ },
+ {
+ name: "Mailgun API Key",
+ regexp: regexp.MustCompile(`key-[0-9a-zA-Z]{32}`),
+ },
+ {
+ name: "Password in URL",
+ regexp: regexp.MustCompile(`[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}["'\\s]`),
+ },
+ {
+ name: "Slack Webhook",
+ regexp: regexp.MustCompile(`https://hooks\.slack\.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}`),
+ },
+ {
+ name: "Stripe API Key",
+ regexp: regexp.MustCompile(`sk_live_[0-9a-zA-Z]{24}`),
+ },
+ {
+ name: "Stripe API Key",
+ regexp: regexp.MustCompile(`sk_live_[0-9a-zA-Z]{24}`),
+ },
+ {
+ name: "Stripe Restricted API Key",
+ regexp: regexp.MustCompile(`rk_live_[0-9a-zA-Z]{24}`),
+ },
+ {
+ name: "Square Access Token",
+ regexp: regexp.MustCompile(`sq0atp-[0-9A-Za-z\-_]{22}`),
+ },
+ {
+ name: "Square OAuth Secret",
+ regexp: regexp.MustCompile(`sq0csp-[0-9A-Za-z\-_]{43}`),
+ },
+ {
+ name: "Telegram Bot API Key",
+ regexp: regexp.MustCompile(`[0-9]+:AA[0-9A-Za-z\-_]{33}`),
+ },
+ {
+ name: "Twilio API Key",
+ regexp: regexp.MustCompile(`SK[0-9a-fA-F]{32}`),
+ },
+ {
+ name: "Twitter Access Token",
+ regexp: regexp.MustCompile(`[tT][wW][iI][tT][tT][eE][rR].*[1-9][0-9]+-[0-9a-zA-Z]{40}`),
+ },
+ {
+ name: "Twitter OAuth",
+ regexp: regexp.MustCompile(`[tT][wW][iI][tT][tT][eE][rR].*[''|"][0-9a-zA-Z]{35,44}[''|"]`),
+ },
+}
+
type credentials struct {
issue.MetaData
pattern *regexp.Regexp
- patternValue *regexp.Regexp // Pattern for matching string values (LHS on assign statements)
entropyThreshold float64
perCharThreshold float64
truncate int
@@ -56,6 +216,15 @@ func (r *credentials) isHighEntropyString(str string) bool {
entropyPerChar >= r.perCharThreshold))
}
+func (r *credentials) isSecretPattern(str string) (bool, string) {
+ for _, pattern := range secretsPatterns {
+ if pattern.regexp.MatchString(str) {
+ return true, pattern.name
+ }
+ }
+ return false, ""
+}
+
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) {
case *ast.AssignStmt:
@@ -89,9 +258,9 @@ func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*
continue
}
- if r.patternValue.MatchString(val) {
- if r.ignoreEntropy || r.isHighEntropyString(val) {
- return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
+ if r.ignoreEntropy || r.isHighEntropyString(val) {
+ if ok, patternName := r.isSecretPattern(val); ok {
+ return ctx.NewIssue(assign, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
}
}
}
@@ -120,9 +289,9 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
// Now that no variable names have been matched, match the actual values to find any creds
for _, ident := range valueSpec.Values {
if val, err := gosec.GetString(ident); err == nil {
- if r.patternValue.MatchString(val) {
- if r.ignoreEntropy || r.isHighEntropyString(val) {
- return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
+ if r.ignoreEntropy || r.isHighEntropyString(val) {
+ if ok, patternName := r.isSecretPattern(val); ok {
+ return ctx.NewIssue(valueSpec, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
}
}
}
@@ -159,9 +328,9 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
if ok && identStrConst.Kind == token.STRING {
s, _ := gosec.GetString(identStrConst)
- if r.patternValue.MatchString(s) {
- if r.ignoreEntropy || r.isHighEntropyString(s) {
- return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
+ if r.ignoreEntropy || r.isHighEntropyString(s) {
+ if ok, patternName := r.isSecretPattern(s); ok {
+ return ctx.NewIssue(binaryExpr, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
}
}
}
@@ -173,7 +342,6 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
// assigned to variables that appear to be related to credentials.
func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
pattern := `(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred`
- patternValue := "(?i)(^(.*[:;,](\\s)*)?[a-f0-9]{64}$)|(AIza[0-9A-Za-z-_]{35})|(^(.*[:;,](\\s)*)?github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}$)|(^(.*[:;,](\\s)*)?[0-9a-zA-Z-_]{24}$)"
entropyThreshold := 80.0
perCharThreshold := 3.0
ignoreEntropy := false
@@ -186,12 +354,6 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
}
}
- if configPatternValue, ok := conf["patternValue"]; ok {
- if cfgPatternValue, ok := configPatternValue.(string); ok {
- patternValue = cfgPatternValue
- }
- }
-
if configIgnoreEntropy, ok := conf["ignore_entropy"]; ok {
if cfgIgnoreEntropy, ok := configIgnoreEntropy.(bool); ok {
ignoreEntropy = cfgIgnoreEntropy
@@ -222,7 +384,6 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
return &credentials{
pattern: regexp.MustCompile(pattern),
- patternValue: regexp.MustCompile(patternValue),
entropyThreshold: entropyThreshold,
perCharThreshold: perCharThreshold,
ignoreEntropy: ignoreEntropy,
diff --git a/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go b/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
index 32e2fd205f..a7eabb20b4 100644
--- a/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
+++ b/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
@@ -3,6 +3,7 @@ package rules
import (
"go/ast"
"go/token"
+ "go/types"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
@@ -28,23 +29,20 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
return false
}
-func getIdentExpr(expr ast.Expr) *ast.Ident {
+func getIdentExpr(expr ast.Expr) (*ast.Ident, bool) {
+ return doGetIdentExpr(expr, false)
+}
+
+func doGetIdentExpr(expr ast.Expr, hasSelector bool) (*ast.Ident, bool) {
switch node := expr.(type) {
case *ast.Ident:
- return node
+ return node, hasSelector
case *ast.SelectorExpr:
- return getIdentExpr(node.X)
+ return doGetIdentExpr(node.X, true)
case *ast.UnaryExpr:
- switch e := node.X.(type) {
- case *ast.Ident:
- return e
- case *ast.SelectorExpr:
- return getIdentExpr(e.X)
- default:
- return nil
- }
+ return doGetIdentExpr(node.X, hasSelector)
default:
- return nil
+ return nil, false
}
}
@@ -92,9 +90,13 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, er
}
// If we find a unary op of & (reference) of an object within r.aliases, complain.
- if identExpr := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
+ if identExpr, hasSelector := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
if _, contains := r.aliases[identExpr.Obj]; contains {
- return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ _, isPointer := c.Info.TypeOf(identExpr).(*types.Pointer)
+
+ if !hasSelector || !isPointer {
+ return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
}
}
case *ast.ReturnStmt:
diff --git a/vendor/github.com/securego/gosec/v2/rules/rulelist.go b/vendor/github.com/securego/gosec/v2/rules/rulelist.go
index 316691f614..f9ca4f52c4 100644
--- a/vendor/github.com/securego/gosec/v2/rules/rulelist.go
+++ b/vendor/github.com/securego/gosec/v2/rules/rulelist.go
@@ -91,6 +91,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G304", "File path provided as taint input", NewReadFile},
{"G305", "File path traversal when extracting zip archive", NewArchive},
{"G306", "Poor file permissions used when writing to a file", NewWritePerms},
+ {"G307", "Poor file permissions used when creating a file with os.Create", NewOsCreatePerms},
// crypto
{"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography},
@@ -107,7 +108,6 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
// memory safety
{"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},
- {"G602", "Slice access out of bounds", NewSliceBoundCheck},
}
ruleMap := make(map[string]RuleDefinition)
diff --git a/vendor/github.com/securego/gosec/v2/rules/slice_bounds.go b/vendor/github.com/securego/gosec/v2/rules/slice_bounds.go
deleted file mode 100644
index 04811bb50f..0000000000
--- a/vendor/github.com/securego/gosec/v2/rules/slice_bounds.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package rules
-
-import (
- "fmt"
- "go/ast"
- "go/types"
-
- "github.com/securego/gosec/v2"
- "github.com/securego/gosec/v2/issue"
-)
-
-// sliceOutOfBounds is a rule which checks for slices which are accessed outside their capacity,
-// either through indexing it out of bounds or through slice expressions whose low or high index
-// are out of bounds.
-type sliceOutOfBounds struct {
- sliceCaps map[*ast.CallExpr]map[string]*int64 // Capacities of slices. Maps function call -> var name -> value.
- currentScope *types.Scope // Current scope. Map is cleared when scope changes.
- currentFuncName string // Current function.
- funcCallArgs map[string][]*int64 // Caps to load once a func declaration is scanned.
- issue.MetaData // Metadata for this rule.
-}
-
-// ID returns the rule ID for sliceOutOfBounds: G602.
-func (s *sliceOutOfBounds) ID() string {
- return s.MetaData.ID
-}
-
-func (s *sliceOutOfBounds) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
- if s.currentScope == nil {
- s.currentScope = ctx.Pkg.Scope()
- } else if s.currentScope != ctx.Pkg.Scope() {
- s.currentScope = ctx.Pkg.Scope()
-
- // Clear slice map, since we are in a new scope
- sliceMapNil := make(map[string]*int64)
- sliceCaps := make(map[*ast.CallExpr]map[string]*int64)
- sliceCaps[nil] = sliceMapNil
- s.sliceCaps = sliceCaps
- }
-
- switch node := node.(type) {
- case *ast.AssignStmt:
- return s.matchAssign(node, ctx)
- case *ast.SliceExpr:
- return s.matchSliceExpr(node, ctx)
- case *ast.IndexExpr:
- return s.matchIndexExpr(node, ctx)
- case *ast.FuncDecl:
- s.currentFuncName = node.Name.Name
- s.loadArgCaps(node)
- case *ast.CallExpr:
- if _, ok := node.Fun.(*ast.FuncLit); ok {
- // Do nothing with func literals for now.
- break
- }
-
- sliceMap := make(map[string]*int64)
- s.sliceCaps[node] = sliceMap
- s.setupCallArgCaps(node, ctx)
- }
- return nil, nil
-}
-
-// updateSliceCaps takes in a variable name and a map of calls we are updating the variables for to the updated values
-// and will add it to the sliceCaps map.
-func (s *sliceOutOfBounds) updateSliceCaps(varName string, caps map[*ast.CallExpr]*int64) {
- for callExpr, cap := range caps {
- s.sliceCaps[callExpr][varName] = cap
- }
-}
-
-// getAllCalls returns all CallExprs that are calls to the given function.
-func (s *sliceOutOfBounds) getAllCalls(funcName string, ctx *gosec.Context) []*ast.CallExpr {
- calls := []*ast.CallExpr{}
-
- for callExpr := range s.sliceCaps {
- if callExpr != nil {
- // Compare the names of the function the code is scanning with the current call we are iterating over
- _, callFuncName, err := gosec.GetCallInfo(callExpr, ctx)
- if err != nil {
- continue
- }
-
- if callFuncName == funcName {
- calls = append(calls, callExpr)
- }
- }
- }
- return calls
-}
-
-// getSliceCapsForFunc gets all the capacities for slice with given name that are stored for each call to the passed function.
-func (s *sliceOutOfBounds) getSliceCapsForFunc(funcName string, varName string, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
- caps := make(map[*ast.CallExpr]*int64)
-
- calls := s.getAllCalls(funcName, ctx)
- for _, call := range calls {
- if callCaps, ok := s.sliceCaps[call]; ok {
- caps[call] = callCaps[varName]
- }
- }
-
- return caps
-}
-
-// setupCallArgCaps evaluates and saves the caps for any slices in the args so they can be validated when the function is scanned.
-func (s *sliceOutOfBounds) setupCallArgCaps(callExpr *ast.CallExpr, ctx *gosec.Context) {
- // Array of caps to be loaded once the function declaration is scanned
- funcCallArgs := []*int64{}
-
- // Get function name
- _, funcName, err := gosec.GetCallInfo(callExpr, ctx)
- if err != nil {
- return
- }
-
- for _, arg := range callExpr.Args {
- switch node := arg.(type) {
- case *ast.SliceExpr:
- caps := s.evaluateSliceExpr(node, ctx)
-
- // Simplifying assumption: use the lowest capacity. Storing all possible capacities for slices passed
- // to a function call would catch the most issues, but would require a data structure like a stack and a
- // reworking of the code for scanning itself. Use the lowest capacity, as this would be more likely to
- // raise an issue for being out of bounds.
- var lowestCap *int64
- for _, cap := range caps {
- if cap == nil {
- continue
- }
-
- if lowestCap == nil {
- lowestCap = cap
- } else if *lowestCap > *cap {
- lowestCap = cap
- }
- }
-
- if lowestCap == nil {
- funcCallArgs = append(funcCallArgs, nil)
- continue
- }
-
- // Now create a map of just this value to add it to the sliceCaps
- funcCallArgs = append(funcCallArgs, lowestCap)
- case *ast.Ident:
- ident := arg.(*ast.Ident)
- caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
-
- var lowestCap *int64
- for _, cap := range caps {
- if cap == nil {
- continue
- }
-
- if lowestCap == nil {
- lowestCap = cap
- } else if *lowestCap > *cap {
- lowestCap = cap
- }
- }
-
- if lowestCap == nil {
- funcCallArgs = append(funcCallArgs, nil)
- continue
- }
-
- // Now create a map of just this value to add it to the sliceCaps
- funcCallArgs = append(funcCallArgs, lowestCap)
- default:
- funcCallArgs = append(funcCallArgs, nil)
- }
- }
- s.funcCallArgs[funcName] = funcCallArgs
-}
-
-// loadArgCaps loads caps that were saved for a call to this function.
-func (s *sliceOutOfBounds) loadArgCaps(funcDecl *ast.FuncDecl) {
- sliceMap := make(map[string]*int64)
- funcName := funcDecl.Name.Name
-
- // Create a dummmy call expr for the new function. This is so we can still store args for
- // functions which are not explicitly called in the code by other functions (specifically, main).
- ident := ast.NewIdent(funcName)
- dummyCallExpr := ast.CallExpr{
- Fun: ident,
- }
-
- argCaps, ok := s.funcCallArgs[funcName]
- if !ok || len(argCaps) == 0 {
- s.sliceCaps[&dummyCallExpr] = sliceMap
- return
- }
-
- params := funcDecl.Type.Params.List
- if len(params) > len(argCaps) {
- return // Length of params and args doesn't match, so don't do anything with this.
- }
-
- for it := range params {
- capacity := argCaps[it]
- if capacity == nil {
- continue
- }
-
- if len(params[it].Names) == 0 {
- continue
- }
-
- if paramName := params[it].Names[0]; paramName != nil {
- sliceMap[paramName.Name] = capacity
- }
- }
-
- s.sliceCaps[&dummyCallExpr] = sliceMap
-}
-
-// matchSliceMake matches calls to make() and stores the capacity of the new slice in the map to compare against future slice usage.
-func (s *sliceOutOfBounds) matchSliceMake(funcCall *ast.CallExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
- _, funcName, err := gosec.GetCallInfo(funcCall, ctx)
- if err != nil || funcName != "make" {
- return nil, nil
- }
-
- var capacityArg int
- if len(funcCall.Args) < 2 {
- return nil, nil // No size passed
- } else if len(funcCall.Args) == 2 {
- capacityArg = 1
- } else if len(funcCall.Args) == 3 {
- capacityArg = 2
- } else {
- return nil, nil // Unexpected, args should always be 2 or 3
- }
-
- // Check and get the capacity of the slice passed to make. It must be a literal value, since we aren't evaluating the expression.
- sliceCapLit, ok := funcCall.Args[capacityArg].(*ast.BasicLit)
- if !ok {
- return nil, nil
- }
-
- capacity, err := gosec.GetInt(sliceCapLit)
- if err != nil {
- return nil, nil
- }
-
- caps := s.getSliceCapsForFunc(s.currentFuncName, sliceName, ctx)
- for callExpr := range caps {
- caps[callExpr] = &capacity
- }
-
- s.updateSliceCaps(sliceName, caps)
- return nil, nil
-}
-
-// evaluateSliceExpr takes a slice expression and evaluates what the capacity of said slice is for each of the
-// calls to the current function. Returns map of the call expressions of each call to the current function to
-// the evaluated capacities.
-func (s *sliceOutOfBounds) evaluateSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
- // Get ident to get name
- ident, ok := node.X.(*ast.Ident)
- if !ok {
- return nil
- }
-
- // Get cap of old slice to calculate this new slice's cap
- caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
- for callExpr, oldCap := range caps {
- if oldCap == nil {
- continue
- }
-
- // Get and check low value
- lowIdent, ok := node.Low.(*ast.BasicLit)
- if ok && lowIdent != nil {
- low, _ := gosec.GetInt(lowIdent)
-
- newCap := *oldCap - low
- caps[callExpr] = &newCap
- } else if lowIdent == nil { // If no lower bound, capacity will be same
- continue
- }
- }
-
- return caps
-}
-
-// matchSliceAssignment matches slice assignments, calculates capacity of slice if possible to store it in map.
-func (s *sliceOutOfBounds) matchSliceAssignment(node *ast.SliceExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
- // First do the normal match that verifies the slice expr is not out of bounds
- if i, err := s.matchSliceExpr(node, ctx); err != nil {
- return i, fmt.Errorf("There was an error while matching a slice expression to check slice bounds for %s: %w", sliceName, err)
- }
-
- // Now that the assignment is (presumably) successfully, we can calculate the capacity and add this new slice to the map
- caps := s.evaluateSliceExpr(node, ctx)
- s.updateSliceCaps(sliceName, caps)
-
- return nil, nil
-}
-
-// matchAssign matches checks if an assignment statement is making a slice, or if it is assigning a slice.
-func (s *sliceOutOfBounds) matchAssign(node *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
- // Check RHS for calls to make() so we can get the actual size of the slice
- for it, i := range node.Rhs {
- // Get the slice name so we can associate the cap with the slice in the map
- sliceIdent, ok := node.Lhs[it].(*ast.Ident)
- if !ok {
- return nil, nil
- }
- sliceName := sliceIdent.Name
-
- switch expr := i.(type) {
- case *ast.CallExpr: // Check for and handle call to make()
- return s.matchSliceMake(expr, sliceName, ctx)
- case *ast.SliceExpr: // Handle assignments to a slice
- return s.matchSliceAssignment(expr, sliceName, ctx)
- }
- }
- return nil, nil
-}
-
-// matchSliceExpr validates that a given slice expression (eg, slice[10:30]) is not out of bounds.
-func (s *sliceOutOfBounds) matchSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) (*issue.Issue, error) {
- // First get the slice name so we can check the size in our map
- ident, ok := node.X.(*ast.Ident)
- if !ok {
- return nil, nil
- }
-
- // Get slice cap from the map to compare it against high and low
- caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
-
- for _, cap := range caps {
- if cap == nil {
- continue
- }
-
- // Get and check high value
- highIdent, ok := node.High.(*ast.BasicLit)
- if ok && highIdent != nil {
- high, _ := gosec.GetInt(highIdent)
- if high > *cap {
- return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
- }
- }
-
- // Get and check low value
- lowIdent, ok := node.Low.(*ast.BasicLit)
- if ok && lowIdent != nil {
- low, _ := gosec.GetInt(lowIdent)
- if low > *cap {
- return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
- }
- }
- }
-
- return nil, nil
-}
-
-// matchIndexExpr validates that an index into a slice is not out of bounds.
-func (s *sliceOutOfBounds) matchIndexExpr(node *ast.IndexExpr, ctx *gosec.Context) (*issue.Issue, error) {
- // First get the slice name so we can check the size in our map
- ident, ok := node.X.(*ast.Ident)
- if !ok {
- return nil, nil
- }
-
- // Get slice cap from the map to compare it against high and low
- caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
-
- for _, cap := range caps {
- if cap == nil {
- continue
- }
- // Get the index literal
- indexIdent, ok := node.Index.(*ast.BasicLit)
- if ok && indexIdent != nil {
- index, _ := gosec.GetInt(indexIdent)
- if index >= *cap {
- return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
- }
- }
- }
-
- return nil, nil
-}
-
-// NewSliceBoundCheck attempts to find any slices being accessed out of bounds
-// by reslicing or by being indexed.
-func NewSliceBoundCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
- sliceMap := make(map[*ast.CallExpr]map[string]*int64)
-
- return &sliceOutOfBounds{
- sliceCaps: sliceMap,
- currentFuncName: "",
- funcCallArgs: make(map[string][]*int64),
- MetaData: issue.MetaData{
- ID: id,
- Severity: issue.Medium,
- Confidence: issue.Medium,
- What: "Potentially accessing slice out of bounds",
- },
- }, []ast.Node{(*ast.CallExpr)(nil), (*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.SliceExpr)(nil), (*ast.IndexExpr)(nil)}
-}
diff --git a/vendor/github.com/securego/gosec/v2/rules/unsafe.go b/vendor/github.com/securego/gosec/v2/rules/unsafe.go
index e1e8d02310..2e2adca7c7 100644
--- a/vendor/github.com/securego/gosec/v2/rules/unsafe.go
+++ b/vendor/github.com/securego/gosec/v2/rules/unsafe.go
@@ -43,7 +43,7 @@ func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err
func NewUsingUnsafe(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
return &usingUnsafe{
pkg: "unsafe",
- calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
+ calls: []string{"Pointer", "String", "StringData", "Slice", "SliceData"},
MetaData: issue.MetaData{
ID: id,
What: "Use of unsafe calls should be audited",
diff --git a/vendor/github.com/tetafro/godot/README.md b/vendor/github.com/tetafro/godot/README.md
index e8d85fb0a7..6b2e530b93 100644
--- a/vendor/github.com/tetafro/godot/README.md
+++ b/vendor/github.com/tetafro/godot/README.md
@@ -21,7 +21,7 @@ end of the last sentence if needed.
Build from source
```sh
-go get -u github.com/tetafro/godot/cmd/godot
+go install github.com/tetafro/godot/cmd/godot@latest
```
or download binary from [releases page](https://github.com/tetafro/godot/releases).
diff --git a/vendor/github.com/tetafro/godot/checks.go b/vendor/github.com/tetafro/godot/checks.go
index cba54f310c..f5471cdf79 100644
--- a/vendor/github.com/tetafro/godot/checks.go
+++ b/vendor/github.com/tetafro/godot/checks.go
@@ -240,6 +240,9 @@ func isSpecialBlock(comment string) bool {
strings.Contains(comment, "#define")) {
return true
}
+ if strings.HasPrefix(comment, "// Output: ") {
+ return true
+ }
return false
}
diff --git a/vendor/github.com/tetafro/godot/getters.go b/vendor/github.com/tetafro/godot/getters.go
index 8adcc46ae8..1a47c824ff 100644
--- a/vendor/github.com/tetafro/godot/getters.go
+++ b/vendor/github.com/tetafro/godot/getters.go
@@ -200,10 +200,10 @@ func (pf *parsedFile) getAllComments(exclude []*regexp.Regexp) []comment {
return comments
}
-// getText extracts text from comment. If comment is a special block
+// getText extracts text from comment. If the comment is a special block
// (e.g., CGO code), a block of empty lines is returned. If comment contains
// special lines (e.g., tags or indented code examples), they are replaced
-// with `specialReplacer` to skip checks for it.
+// with `specialReplacer` to skip checks for them.
// The result can be multiline.
func getText(comment *ast.CommentGroup, exclude []*regexp.Regexp) (s string) {
if len(comment.List) == 1 &&
@@ -241,7 +241,7 @@ func getText(comment *ast.CommentGroup, exclude []*regexp.Regexp) (s string) {
return s[:len(s)-1] // trim last "\n"
}
-// readFile reads file and returns it's lines as strings.
+// readFile reads file and returns its lines as strings.
func readFile(file *ast.File, fset *token.FileSet) ([]string, error) {
fname := fset.File(file.Package)
f, err := os.ReadFile(fname.Name())
diff --git a/vendor/github.com/tetafro/godot/godot.go b/vendor/github.com/tetafro/godot/godot.go
index 19a652fba4..df9271296a 100644
--- a/vendor/github.com/tetafro/godot/godot.go
+++ b/vendor/github.com/tetafro/godot/godot.go
@@ -101,7 +101,7 @@ func Fix(path string, file *ast.File, fset *token.FileSet, settings Settings) ([
return fixed, nil
}
-// Replace rewrites original file with it's fixed version.
+// Replace rewrites original file with its fixed version.
func Replace(path string, file *ast.File, fset *token.FileSet, settings Settings) error {
info, err := os.Stat(path)
if err != nil {
diff --git a/vendor/github.com/uudashr/gocognit/README.md b/vendor/github.com/uudashr/gocognit/README.md
index 1e028c7897..57f31cf740 100644
--- a/vendor/github.com/uudashr/gocognit/README.md
+++ b/vendor/github.com/uudashr/gocognit/README.md
@@ -1,6 +1,6 @@
[![GoDoc](https://godoc.org/github.com/uudashr/gocognit?status.svg)](https://godoc.org/github.com/uudashr/gocognit)
# Gocognit
-Gocognit calculates cognitive complexities of functions in Go source code. A measurement of how hard does the code is intuitively to understand.
+Gocognit calculates cognitive complexities of functions (and methods) in Go source code. A measurement of how hard does the code is intuitively to understand.
## Understanding the complexity
@@ -37,10 +37,10 @@ func GetWords(number int) string {
As you see above codes are the same, but the second code are easier to understand, that is why the cognitive complexity score are lower compare to the first one.
-## Comparison with cyclometic complexity
+## Comparison with cyclomatic complexity
### Example 1
-#### Cyclometic complexity
+#### Cyclomatic complexity
```go
func GetWords(number int) string { // +1
switch number {
@@ -160,16 +160,40 @@ $ go get github.com/uudashr/gocognit/cmd/gocognit
```
$ gocognit
Calculate cognitive complexities of Go functions.
+
Usage:
- gocognit [flags] ...
+
+ gocognit [ ...] ...
+
Flags:
- -over N show functions with complexity > N only and
- return exit code 1 if the set is non-empty
- -top N show the top N most complex functions only
- -avg show the average complexity over all functions,
- not depending on whether -over or -top are set
-The output fields for each line are:
-
+
+ -over N show functions with complexity > N only
+ and return exit code 1 if the output is non-empty
+ -top N show the top N most complex functions only
+ -avg show the average complexity over all functions,
+ not depending on whether -over or -top are set
+ -json encode the output as JSON
+ -f format string the format to use
+ (default "{{.PkgName}}.{{.FuncName}}:{{.Complexity}}:{{.Pos}}")
+
+The (default) output fields for each line are:
+
+
+
+The (default) output fields for each line are:
+
+ {{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}}
+
+or equal to
+
+The struct being passed to the template is:
+
+ type Stat struct {
+ PkgName string
+ FuncName string
+ Complexity int
+ Pos token.Position
+ }
```
Examples:
@@ -180,6 +204,7 @@ $ gocognit main.go
$ gocognit -top 10 src/
$ gocognit -over 25 docker
$ gocognit -avg .
+$ gocognit -ignore "_test|testdata" .
```
The output fields for each line are:
@@ -187,6 +212,15 @@ The output fields for each line are:
```
+## Ignore individual functions
+Ignore individual functions by specifying `gocognit:ignore` directive.
+```go
+//gocognit:ignore
+func IgnoreMe() {
+ // ...
+}
+```
+
## Related project
- [Gocyclo](https://github.com/fzipp/gocyclo) where the code are based on.
- [Cognitive Complexity: A new way of measuring understandability](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) white paper by G. Ann Campbell.
\ No newline at end of file
diff --git a/vendor/github.com/uudashr/gocognit/gocognit.go b/vendor/github.com/uudashr/gocognit/gocognit.go
index 2fe22abc4b..2bba2eb4f0 100644
--- a/vendor/github.com/uudashr/gocognit/gocognit.go
+++ b/vendor/github.com/uudashr/gocognit/gocognit.go
@@ -26,6 +26,11 @@ func (s Stat) String() string {
func ComplexityStats(f *ast.File, fset *token.FileSet, stats []Stat) []Stat {
for _, decl := range f.Decls {
if fn, ok := decl.(*ast.FuncDecl); ok {
+ d := parseDirective(fn.Doc)
+ if d.Ignore {
+ continue
+ }
+
stats = append(stats, Stat{
PkgName: f.Name.Name,
FuncName: funcName(fn),
@@ -37,6 +42,24 @@ func ComplexityStats(f *ast.File, fset *token.FileSet, stats []Stat) []Stat {
return stats
}
+type directive struct {
+ Ignore bool
+}
+
+func parseDirective(doc *ast.CommentGroup) directive {
+ if doc == nil {
+ return directive{}
+ }
+
+ for _, c := range doc.List {
+ if c.Text == "//gocognit:ignore" {
+ return directive{Ignore: true}
+ }
+ }
+
+ return directive{}
+}
+
// funcName returns the name representation of a function or method:
// "(Type).Name" for methods or simply "Name" for functions.
func funcName(fn *ast.FuncDecl) string {
@@ -356,13 +379,19 @@ func run(pass *analysis.Pass) (interface{}, error) {
(*ast.FuncDecl)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
- fnDecl := n.(*ast.FuncDecl)
+ funcDecl := n.(*ast.FuncDecl)
+
+ d := parseDirective(funcDecl.Doc)
+ if d.Ignore {
+ return
+ }
+
+ fnName := funcName(funcDecl)
- fnName := funcName(fnDecl)
- fnComplexity := Complexity(fnDecl)
+ fnComplexity := Complexity(funcDecl)
if fnComplexity > over {
- pass.Reportf(fnDecl.Pos(), "cognitive complexity %d of func %s is high (> %d)", fnComplexity, fnName, over)
+ pass.Reportf(funcDecl.Pos(), "cognitive complexity %d of func %s is high (> %d)", fnComplexity, fnName, over)
}
})
diff --git a/vendor/github.com/xen0n/gosmopolitan/README.md b/vendor/github.com/xen0n/gosmopolitan/README.md
index 93e3701e5d..86a5e64e00 100644
--- a/vendor/github.com/xen0n/gosmopolitan/README.md
+++ b/vendor/github.com/xen0n/gosmopolitan/README.md
@@ -54,7 +54,9 @@ following characteristics, and may not suit your particular project's needs:
* Originally developed for an audience using non-Latin writing system(s),
* Returns bare strings intended for humans containing such non-Latin characters, and
-* May occasionally (or frequently) refer to the local timezone.
+* May occasionally (or frequently) refer to the system timezone, but is
+ architecturally forbidden/discouraged to just treat the system timezone as
+ the reference timezone.
For example, the lints may prove valuable if you're revamping a web service
originally targetting the Chinese market (hence producing strings with Chinese
@@ -64,71 +66,18 @@ will output nothing.
## golangci-lint integration
-`gosmopolitan` is not integrated into [`golangci-lint`][gcl-home] yet, but
-you can nevertheless run it [as a custom plugin][gcl-plugin].
+`gosmopolitan` support [has been merged][gcl-pr] into [`golangci-lint`][gcl-home],
+and will be usable out-of-the-box in golangci-lint v1.53.0 or later.
+Due to the opinionated coding style this linter advocates and checks for, if
+you have `enable-all: true` in your `golangci.yml` and your project deals a
+lot with Chinese text and/or `time.Local`, then you'll get flooded with lints
+when you upgrade to golangci-lint v1.53.0. Just disable this linter (and
+better yet, move away from `enable-all: true`) if the style does not suit your
+specific use case.
+
+[gcl-pr]: https://github.com/golangci/golangci-lint/pull/3458
[gcl-home]: https://golangci-lint.run
-[gcl-plugin]: https://golangci-lint.run/contributing/new-linters/#how-to-add-a-private-linter-to-golangci-lint
-
-First make yourself a plugin `.so` file like this:
-
-```go
-// compile this with something like `go build -buildmode=plugin`
-
-package main
-
-import (
- "github.com/xen0n/gosmopolitan"
- "golang.org/x/tools/go/analysis"
-)
-
-type analyzerPlugin struct{}
-
-func (analyzerPlugin) GetAnalyzers() []*analysis.Analyzer {
- // You can customize the options via gosmopolitan.NewAnalyzerWithConfig
- // instead.
- return []*analysis.Analyzer{
- gosmopolitan.DefaultAnalyzer,
- }
-}
-
-var AnalyzerPlugin analyzerPlugin
-```
-
-You just need to make sure the `golang.org/x/tools` version used to build the
-plugin is consistent with that of your `golangci-lint` binary. (Of course the
-`golangci-lint` binary should be built with plugin support enabled too;
-notably, [the Homebrew `golangci-lint` is built without plugin support][hb-issue],
-so beware of this.)
-
-[hb-issue]: https://github.com/golangci/golangci-lint/issues/1182
-
-|`golangci-lint` version|`gosmopolitan` tag to use|
-|-----------------------|-------------------------|
-|1.50.x|v1.0.0|
-
-Then reference it in your `.golangci.yml`, and enable it in the `linters`
-section:
-
-```yaml
-linters:
- # ...
- enable:
- # ...
- - gosmopolitan
- # ...
-
-linters-settings:
- custom:
- gosmopolitan:
- path: 'path/to/your/plugin.so'
- description: 'Report certain i18n/l10n anti-patterns in your Go codebase'
- original-url: 'https://github.com/xen0n/gosmopolitan'
- # ...
-```
-
-Then you can `golangci-lint run` and `//nolint:gosmopolitan` as you would
-with any other supported linter.
## License
diff --git a/vendor/github.com/xen0n/gosmopolitan/README.zh-Hans.md b/vendor/github.com/xen0n/gosmopolitan/README.zh-Hans.md
index 7f1b7b7adf..682d10880e 100644
--- a/vendor/github.com/xen0n/gosmopolitan/README.zh-Hans.md
+++ b/vendor/github.com/xen0n/gosmopolitan/README.zh-Hans.md
@@ -46,7 +46,7 @@
* 项目原先是为使用非拉丁字母书写系统的受众群体开发的,
* 项目会返回包含这些非拉丁字母字符的裸的字符串(即,未经处理或变换的),
-* 项目可能偶尔(或者经常)引用程序当前运行环境的本地时区。
+* 项目可能偶尔(或者经常)引用程序当前运行环境的系统时区,但项目架构上禁止或不建议把系统时区直接作为业务参考时区使用。
举个例子:如果您在翻新一个本来面向中国用户群体(因此到处都在产生含有汉字的字符串)的
web 服务,以使其更加国际化,这里的 lints 可能会很有价值。
@@ -55,66 +55,14 @@ linter 则什么都不会输出。
## 与 golangci-lint 集成
-`gosmopolitan` 目前没有集成进上游 [`golangci-lint`][gcl-home],但您仍然可以[以自定义插件的方式][gcl-plugin]使用本项目。
+`gosmopolitan` 支持[已经被合并][gcl-pr]入 [`golangci-lint`][gcl-home] 上游,在 golangci-lint v1.53.0 及以后的版本可以开箱即用。
+[gcl-pr]: https://github.com/golangci/golangci-lint/pull/3458
[gcl-home]: https://golangci-lint.run
-[gcl-plugin]: https://golangci-lint.run/contributing/new-linters/#how-to-add-a-private-linter-to-golangci-lint
-首先像这样做一个插件 `.so` 文件:
-
-```go
-// 用类似 `go build -buildmode=plugin` 的方式编译
-
-package main
-
-import (
- "github.com/xen0n/gosmopolitan"
- "golang.org/x/tools/go/analysis"
-)
-
-type analyzerPlugin struct{}
-
-func (analyzerPlugin) GetAnalyzers() []*analysis.Analyzer {
- // 你可以用 gosmopolitan.NewAnalyzer 来自定义配置。
- return []*analysis.Analyzer{
- gosmopolitan.DefaultAnalyzer,
- }
-}
-
-var AnalyzerPlugin analyzerPlugin
-```
-
-您只需要保证构建时使用的 `golang.org/x/tools` 模块版本和您的 `golangci-lint`
-二进制的相应模块版本一致。(当然,`golangci-lint` 二进制也应该包含插件支持;
-[Homebrew 的 `golangci-lint` 没有插件支持][hb-issue],尤其需要注意。)
-
-[hb-issue]: https://github.com/golangci/golangci-lint/issues/1182
-
-|`golangci-lint` 版本|对应可用的 `gosmopolitan` tag|
-|--------------------|-----------------------------|
-|1.50.x|v1.0.0|
-
-然后在您的 `.golangci.yml` 中引用它,在 `linters` 一节中启用它:
-
-```yaml
-linters:
- # ...
- enable:
- # ...
- - gosmopolitan
- # ...
-
-linters-settings:
- custom:
- gosmopolitan:
- path: 'path/to/your/plugin.so'
- description: 'Report certain i18n/l10n anti-patterns in your Go codebase'
- original-url: 'https://github.com/xen0n/gosmopolitan'
- # ...
-```
-
-这样您就可以像使用其他 linters 一样 `golangci-lint run` 和
-`//nolint:gosmopolitan` 了。
+由于本 linter 倡导和检查的代码风格带有鲜明立场,如果您在 `golangci.yml` 开了
+`enable-all: true` 并且您的项目处理很多中文文本或者 `time.Local`,那么您一旦升级到
+golangci-lint v1.53.0 就将被 lints 淹没。如果这种代码风格不适合您的具体使用场景,直接禁用本 linter(或者更彻底一些,不要 `enable-all: true` 了)就好。
## 许可证
diff --git a/vendor/gitlab.com/bosi/decorder/.gitlab-ci.yml b/vendor/gitlab.com/bosi/decorder/.gitlab-ci.yml
index f3ec4f21a2..73e1273b34 100644
--- a/vendor/gitlab.com/bosi/decorder/.gitlab-ci.yml
+++ b/vendor/gitlab.com/bosi/decorder/.gitlab-ci.yml
@@ -12,7 +12,7 @@ stages:
test:
stage: test
- image: golang:1.20.6@sha256:cfc9d1b07b1ef4f7a4571f0b60a99646a92ef76adb7d9943f4cb7b606c6554e2
+ image: golang:1.21.0@sha256:b490ae1f0ece153648dd3c5d25be59a63f966b5f9e1311245c947de4506981aa
before_script:
- set -eu
- if [[ -f .env.pipeline ]];then cp .env.pipeline .env;fi
@@ -27,7 +27,7 @@ test:
lint:source-code:
stage: test
- image: golangci/golangci-lint:v1.53.3-alpine@sha256:b61d8503f0ad16499c023772301ec8c0f2559bf76c28d228c390446c5e647f55
+ image: golangci/golangci-lint:v1.54.2-alpine@sha256:e950721f6ae622dcc041f57cc0b61c3a78d4bbfc588facfc8b0166901a9f4848
script:
- apk add make bash
- make settings
@@ -36,7 +36,7 @@ lint:source-code:
license-check:
stage: test
- image: golang:1.20.6@sha256:cfc9d1b07b1ef4f7a4571f0b60a99646a92ef76adb7d9943f4cb7b606c6554e2
+ image: golang:1.21.0@sha256:b490ae1f0ece153648dd3c5d25be59a63f966b5f9e1311245c947de4506981aa
before_script:
- set -eu
- if [[ -f .env.pipeline ]];then cp .env.pipeline .env;fi
@@ -53,7 +53,7 @@ license-check:
pages:
stage: release
- image: golang:1.20.6@sha256:cfc9d1b07b1ef4f7a4571f0b60a99646a92ef76adb7d9943f4cb7b606c6554e2
+ image: golang:1.21.0@sha256:b490ae1f0ece153648dd3c5d25be59a63f966b5f9e1311245c947de4506981aa
only:
- tags
script:
diff --git a/vendor/gitlab.com/bosi/decorder/analyzer.go b/vendor/gitlab.com/bosi/decorder/analyzer.go
index f486129447..08f82ccc11 100644
--- a/vendor/gitlab.com/bosi/decorder/analyzer.go
+++ b/vendor/gitlab.com/bosi/decorder/analyzer.go
@@ -5,6 +5,7 @@ import (
"go/ast"
"go/token"
"strings"
+ "sync"
"golang.org/x/tools/go/analysis"
)
@@ -65,6 +66,7 @@ var (
token.CONST: false,
token.VAR: false,
}
+ decLock sync.Mutex
)
//nolint:lll
@@ -79,10 +81,16 @@ func init() {
Analyzer.Flags.BoolVar(&opts.disableInitFuncFirstCheck, FlagDiffc, false, "option to disable check that init function is always first function in file")
}
-func run(pass *analysis.Pass) (interface{}, error) {
+func initDec() {
+ decLock.Lock()
decNumConf[token.TYPE] = opts.disableTypeDecNumCheck
decNumConf[token.CONST] = opts.disableConstDecNumCheck
decNumConf[token.VAR] = opts.disableVarDecNumCheck
+ decLock.Unlock()
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ initDec()
for _, f := range pass.Files {
ast.Inspect(f, runDeclNumAndDecOrderCheck(pass))
diff --git a/vendor/go-simpler.org/sloglint/.golangci.yml b/vendor/go-simpler.org/sloglint/.golangci.yml
new file mode 100644
index 0000000000..ef926a0562
--- /dev/null
+++ b/vendor/go-simpler.org/sloglint/.golangci.yml
@@ -0,0 +1,22 @@
+linters:
+ disable-all: true
+ enable:
+ # enabled by default:
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - unused
+ # disabled by default:
+ - gocritic
+ - gofumpt
+
+linters-settings:
+ gocritic:
+ enabled-tags:
+ - diagnostic
+ - style
+ - performance
+ - experimental
+ - opinionated
diff --git a/vendor/go-simpler.org/sloglint/.goreleaser.yml b/vendor/go-simpler.org/sloglint/.goreleaser.yml
new file mode 100644
index 0000000000..d31ea11d39
--- /dev/null
+++ b/vendor/go-simpler.org/sloglint/.goreleaser.yml
@@ -0,0 +1,18 @@
+builds:
+ - main: ./cmd/sloglint
+ env:
+ - CGO_ENABLED=0
+ flags:
+ - -trimpath
+ ldflags:
+ - -s -w -X main.version={{.Version}}
+ targets:
+ - darwin_amd64
+ - darwin_arm64
+ - linux_amd64
+ - windows_amd64
+
+archives:
+ - format_overrides:
+ - goos: windows
+ format: zip
diff --git a/vendor/go-simpler.org/sloglint/LICENSE b/vendor/go-simpler.org/sloglint/LICENSE
new file mode 100644
index 0000000000..a612ad9813
--- /dev/null
+++ b/vendor/go-simpler.org/sloglint/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/vendor/go-simpler.org/sloglint/README.md b/vendor/go-simpler.org/sloglint/README.md
new file mode 100644
index 0000000000..8f26f3aa74
--- /dev/null
+++ b/vendor/go-simpler.org/sloglint/README.md
@@ -0,0 +1,102 @@
+# sloglint
+
+[![checks](https://github.com/go-simpler/sloglint/actions/workflows/checks.yml/badge.svg)](https://github.com/go-simpler/sloglint/actions/workflows/checks.yml)
+[![pkg.go.dev](https://pkg.go.dev/badge/go-simpler.org/sloglint.svg)](https://pkg.go.dev/go-simpler.org/sloglint)
+[![goreportcard](https://goreportcard.com/badge/go-simpler.org/sloglint)](https://goreportcard.com/report/go-simpler.org/sloglint)
+[![codecov](https://codecov.io/gh/go-simpler/sloglint/branch/main/graph/badge.svg)](https://codecov.io/gh/go-simpler/sloglint)
+
+A Go linter that ensures consistent code style when using `log/slog`.
+
+## 📌 About
+
+The `log/slog` API allows two different types of arguments: key-value pairs and attributes.
+People may have different opinions about which one is better,
+but nobody probably wants to mix them up because it makes the code harder to read.
+
+```go
+slog.Info("a user has logged in", "user_id", 42, slog.String("ip_address", "192.0.2.0")) // ugh
+```
+
+`sloglint` finds such function calls and checks that all the arguments are either key-value pairs or attributes.
+The linter has several options, so you can adjust it to your own code style.
+
+## 🚀 Features
+
+* Forbid mixing key-value pairs and attributes within a single function call (default)
+* Enforce using either key-value pairs or attributes for the entire project (optional)
+* Enforce using constants instead of raw keys (optional)
+* Enforce putting arguments on separate lines (optional)
+
+## 📦 Install
+
+Download a prebuilt binary from the [Releases][1] page.
+
+## 📋 Usage
+
+```shell
+sloglint [flags] ./...
+```
+
+### Key-value pairs only
+
+The `-kv-only` flag causes `sloglint` to report any use of attributes.
+
+```go
+slog.Info("a user has logged in", slog.Int("user_id", 42)) // sloglint: attributes should not be used
+```
+
+### Attributes only
+
+In contrast, the `-attr-only` flag causes `sloglint` to report any use of key-value pairs.
+
+```go
+slog.Info("a user has logged in", "user_id", 42) // sloglint: key-value pairs should not be used
+```
+
+### No raw keys
+
+To prevent typos, you may want to forbid the use of raw keys altogether.
+The `-no-raw-keys` flag causes `sloglint` to report the use of strings as keys (including `slog.Attr` calls, e.g. `slog.Int("user_id", 42)`).
+
+```go
+slog.Info("a user has logged in", "user_id", 42) // sloglint: raw keys should not be used
+```
+
+This report can be fixed by using either constants...
+
+```go
+const UserId = "user_id"
+
+slog.Info("a user has logged in", UserId, 42)
+```
+
+...or custom `slog.Attr` constructors.
+
+```go
+func UserId(value int) slog.Attr { return slog.Int("user_id", value) }
+
+slog.Info("a user has logged in", UserId(42))
+```
+
+> 💡 Such helpers can be automatically generated for you by the [`sloggen`][2] tool. Give it a try too!
+
+### Arguments on separate lines
+
+To improve code readability, you may want to put arguments on separate lines, especially when using key-value pairs.
+The `-args-on-sep-lines` flag causes `sloglint` to report 2+ arguments on the same line.
+
+```go
+slog.Info("a user has logged in", "user_id", 42, "ip_address", "192.0.2.0") // sloglint: arguments should be put on separate lines
+```
+
+This report can be fixed by reformatting the code.
+
+```go
+slog.Info("a user has logged in",
+ "user_id", 42,
+ "ip_address", "192.0.2.0",
+)
+```
+
+[1]: https://github.com/go-simpler/sloglint/releases
+[2]: https://github.com/go-simpler/sloggen
diff --git a/vendor/go-simpler.org/sloglint/sloglint.go b/vendor/go-simpler.org/sloglint/sloglint.go
new file mode 100644
index 0000000000..4e45206985
--- /dev/null
+++ b/vendor/go-simpler.org/sloglint/sloglint.go
@@ -0,0 +1,226 @@
+// Package sloglint implements the sloglint analyzer.
+package sloglint
+
+import (
+ "errors"
+ "flag"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "strconv"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// Options are options for the sloglint analyzer.
+type Options struct {
+ KVOnly bool // Enforce using key-value pairs only (incompatible with AttrOnly).
+ AttrOnly bool // Enforce using attributes only (incompatible with KVOnly).
+ NoRawKeys bool // Enforce using constants instead of raw keys.
+ ArgsOnSepLines bool // Enforce putting arguments on separate lines.
+}
+
+// New creates a new sloglint analyzer.
+func New(opts *Options) *analysis.Analyzer {
+ if opts == nil {
+ opts = new(Options)
+ }
+ return &analysis.Analyzer{
+ Name: "sloglint",
+ Doc: "ensure consistent code style when using log/slog",
+ Flags: flags(opts),
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: func(pass *analysis.Pass) (any, error) {
+ if opts.KVOnly && opts.AttrOnly {
+ return nil, errors.New("sloglint: incompatible options provided")
+ }
+ run(pass, opts)
+ return nil, nil
+ },
+ }
+}
+
+func flags(opts *Options) flag.FlagSet {
+ fs := flag.NewFlagSet("sloglint", flag.ContinueOnError)
+
+ boolVar := func(value *bool, name, usage string) {
+ fs.Func(name, usage, func(s string) error {
+ v, err := strconv.ParseBool(s)
+ *value = v
+ return err
+ })
+ }
+
+ boolVar(&opts.KVOnly, "kv-only", "enforce using key-value pairs only (incompatible with -attr-only)")
+ boolVar(&opts.AttrOnly, "attr-only", "enforce using attributes only (incompatible with -kv-only)")
+ boolVar(&opts.NoRawKeys, "no-raw-keys", "enforce using constants instead of raw keys")
+ boolVar(&opts.ArgsOnSepLines, "args-on-sep-lines", "enforce putting arguments on separate lines")
+
+ return *fs
+}
+
+var slogFuncs = map[string]int{ // funcName:argsPos
+ "log/slog.Log": 3,
+ "log/slog.Debug": 1,
+ "log/slog.Info": 1,
+ "log/slog.Warn": 1,
+ "log/slog.Error": 1,
+ "log/slog.DebugContext": 2,
+ "log/slog.InfoContext": 2,
+ "log/slog.WarnContext": 2,
+ "log/slog.ErrorContext": 2,
+ "(*log/slog.Logger).Log": 3,
+ "(*log/slog.Logger).Debug": 1,
+ "(*log/slog.Logger).Info": 1,
+ "(*log/slog.Logger).Warn": 1,
+ "(*log/slog.Logger).Error": 1,
+ "(*log/slog.Logger).DebugContext": 2,
+ "(*log/slog.Logger).InfoContext": 2,
+ "(*log/slog.Logger).WarnContext": 2,
+ "(*log/slog.Logger).ErrorContext": 2,
+}
+
+var attrFuncs = map[string]struct{}{
+ "log/slog.String": {},
+ "log/slog.Int64": {},
+ "log/slog.Int": {},
+ "log/slog.Uint64": {},
+ "log/slog.Float64": {},
+ "log/slog.Bool": {},
+ "log/slog.Time": {},
+ "log/slog.Duration": {},
+ "log/slog.Group": {},
+ "log/slog.Any": {},
+}
+
+func run(pass *analysis.Pass, opts *Options) {
+ visit := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ filter := []ast.Node{(*ast.CallExpr)(nil)}
+
+ visit.Preorder(filter, func(node ast.Node) {
+ call := node.(*ast.CallExpr)
+
+ fn := typeutil.StaticCallee(pass.TypesInfo, call)
+ if fn == nil {
+ return
+ }
+
+ argsPos, ok := slogFuncs[fn.FullName()]
+ if !ok {
+ return
+ }
+
+ // NOTE: we assume that the arguments have already been validated by govet.
+ args := call.Args[argsPos:]
+ if len(args) == 0 {
+ return
+ }
+
+ var keys []ast.Expr
+ var attrs []ast.Expr
+
+ for i := 0; i < len(args); i++ {
+ typ := pass.TypesInfo.TypeOf(args[i])
+ if typ == nil {
+ continue
+ }
+ switch typ.String() {
+ case "string":
+ keys = append(keys, args[i])
+ i++ // skip the value.
+ case "log/slog.Attr":
+ attrs = append(attrs, args[i])
+ }
+ }
+
+ switch {
+ case opts.KVOnly && len(attrs) > 0:
+ pass.Reportf(call.Pos(), "attributes should not be used")
+ case opts.AttrOnly && len(attrs) < len(args):
+ pass.Reportf(call.Pos(), "key-value pairs should not be used")
+ case 0 < len(attrs) && len(attrs) < len(args):
+ pass.Reportf(call.Pos(), "key-value pairs and attributes should not be mixed")
+ }
+
+ if opts.NoRawKeys && rawKeysUsed(pass.TypesInfo, keys, attrs) {
+ pass.Reportf(call.Pos(), "raw keys should not be used")
+ }
+ if opts.ArgsOnSepLines && argsOnSameLine(pass.Fset, call, keys, attrs) {
+ pass.Reportf(call.Pos(), "arguments should be put on separate lines")
+ }
+ })
+}
+
+func rawKeysUsed(info *types.Info, keys, attrs []ast.Expr) bool {
+ isConst := func(expr ast.Expr) bool {
+ ident, ok := expr.(*ast.Ident)
+ return ok && ident.Obj != nil && ident.Obj.Kind == ast.Con
+ }
+
+ for _, key := range keys {
+ if !isConst(key) {
+ return true
+ }
+ }
+
+ for _, attr := range attrs {
+ switch attr := attr.(type) {
+ case *ast.CallExpr: // e.g. slog.Int()
+ fn := typeutil.StaticCallee(info, attr)
+ if _, ok := attrFuncs[fn.FullName()]; ok && !isConst(attr.Args[0]) {
+ return true
+ }
+
+ case *ast.CompositeLit: // slog.Attr{}
+ isRawKey := func(kv *ast.KeyValueExpr) bool {
+ return kv.Key.(*ast.Ident).Name == "Key" && !isConst(kv.Value)
+ }
+
+ switch len(attr.Elts) {
+ case 1: // slog.Attr{Key: ...} | slog.Attr{Value: ...}
+ kv := attr.Elts[0].(*ast.KeyValueExpr)
+ if isRawKey(kv) {
+ return true
+ }
+ case 2: // slog.Attr{..., ...} | slog.Attr{Key: ..., Value: ...}
+ kv1, ok := attr.Elts[0].(*ast.KeyValueExpr)
+ if ok {
+ kv2 := attr.Elts[1].(*ast.KeyValueExpr)
+ if isRawKey(kv1) || isRawKey(kv2) {
+ return true
+ }
+ } else if !isConst(attr.Elts[0]) {
+ return true
+ }
+ }
+ }
+ }
+
+ return false
+}
+
+func argsOnSameLine(fset *token.FileSet, call ast.Expr, keys, attrs []ast.Expr) bool {
+ if len(keys)+len(attrs) <= 1 {
+ return false // special case: slog.Info("msg", "key", "value") is ok.
+ }
+
+ l := len(keys) + len(attrs) + 1
+ args := make([]ast.Expr, 0, l)
+ args = append(args, call)
+ args = append(args, keys...)
+ args = append(args, attrs...)
+
+ lines := make(map[int]struct{}, l)
+ for _, arg := range args {
+ line := fset.Position(arg.Pos()).Line
+ if _, ok := lines[line]; ok {
+ return true
+ }
+ lines[line] = struct{}{}
+ }
+
+ return false
+}
diff --git a/vendor/golang.org/x/tools/cmd/stringer/stringer.go b/vendor/golang.org/x/tools/cmd/stringer/stringer.go
index 998d1a51bf..2b19c93e8e 100644
--- a/vendor/golang.org/x/tools/cmd/stringer/stringer.go
+++ b/vendor/golang.org/x/tools/cmd/stringer/stringer.go
@@ -188,6 +188,8 @@ type Generator struct {
trimPrefix string
lineComment bool
+
+ logf func(format string, args ...interface{}) // test logging hook; nil when not testing
}
func (g *Generator) Printf(format string, args ...interface{}) {
@@ -221,13 +223,14 @@ func (g *Generator) parsePackage(patterns []string, tags []string) {
// in a separate pass? For later.
Tests: false,
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
+ Logf: g.logf,
}
pkgs, err := packages.Load(cfg, patterns...)
if err != nil {
log.Fatal(err)
}
if len(pkgs) != 1 {
- log.Fatalf("error: %d packages found", len(pkgs))
+ log.Fatalf("error: %d packages matching %v", len(pkgs), strings.Join(patterns, " "))
}
g.addPackage(pkgs[0])
}
diff --git a/vendor/golang.org/x/tools/go/analysis/doc.go b/vendor/golang.org/x/tools/go/analysis/doc.go
index c5429c9e23..44867d599e 100644
--- a/vendor/golang.org/x/tools/go/analysis/doc.go
+++ b/vendor/golang.org/x/tools/go/analysis/doc.go
@@ -191,7 +191,7 @@ and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:
- content, err := ioutil.ReadFile(filename)
+ content, err := os.ReadFile(filename)
if err != nil { ... }
tf := fset.AddFile(filename, -1, len(content))
tf.SetLinesForContent(content)
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
new file mode 100644
index 0000000000..f0b90a4920
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
@@ -0,0 +1,49 @@
+// Copyright 2023 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.
+
+// Package appends defines an Analyzer that detects
+// if there is only one variable in append.
+package appends
+
+import (
+ _ "embed"
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+//go:embed doc.go
+var doc string
+
+var Analyzer = &analysis.Analyzer{
+ Name: "appends",
+ Doc: analysisutil.MustExtractDoc(doc, "appends"),
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/appends",
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ nodeFilter := []ast.Node{
+ (*ast.CallExpr)(nil),
+ }
+ inspect.Preorder(nodeFilter, func(n ast.Node) {
+ call := n.(*ast.CallExpr)
+ if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "append" {
+ if _, ok := pass.TypesInfo.Uses[ident].(*types.Builtin); ok {
+ if len(call.Args) == 1 {
+ pass.ReportRangef(call, "append with no values")
+ }
+ }
+ }
+ })
+
+ return nil, nil
+}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/appends/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/appends/doc.go
new file mode 100644
index 0000000000..2e6a2e010b
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/analysis/passes/appends/doc.go
@@ -0,0 +1,20 @@
+// Copyright 2023 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.
+
+// Package appends defines an Analyzer that detects
+// if there is only one variable in append.
+//
+// # Analyzer appends
+//
+// appends: check for missing values after append
+//
+// This checker reports calls to append that pass
+// no values to be appended to the slice.
+//
+// s := []string{"a", "b", "c"}
+// _ = append(s)
+//
+// Such calls are always no-ops and often indicate an
+// underlying mistake.
+package appends
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/defers/defer.go b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
similarity index 87%
rename from vendor/golang.org/x/tools/go/analysis/passes/defers/defer.go
rename to vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
index 19474bcc4e..ed2a122f2b 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/defers/defer.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
@@ -19,11 +19,12 @@ import (
//go:embed doc.go
var doc string
-// Analyzer is the defer analyzer.
+// Analyzer is the defers analyzer.
var Analyzer = &analysis.Analyzer{
- Name: "defer",
+ Name: "defers",
Requires: []*analysis.Analyzer{inspect.Analyzer},
- Doc: analysisutil.MustExtractDoc(doc, "defer"),
+ URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
+ Doc: analysisutil.MustExtractDoc(doc, "defers"),
Run: run,
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/defers/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/defers/doc.go
index 60ad3c2cac..bdb1351628 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/defers/doc.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/defers/doc.go
@@ -5,11 +5,11 @@
// Package defers defines an Analyzer that checks for common mistakes in defer
// statements.
//
-// # Analyzer defer
+// # Analyzer defers
//
-// defer: report common mistakes in defer statements
+// defers: report common mistakes in defer statements
//
-// The defer analyzer reports a diagnostic when a defer statement would
+// The defers analyzer reports a diagnostic when a defer statement would
// result in a non-deferred call to time.Since, as experience has shown
// that this is nearly always a mistake.
//
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go b/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
index 1146d7be45..2691f189aa 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
@@ -124,7 +124,7 @@ func (check *checker) nonGoFile(pos token.Pos, fullText string) {
for text != "" {
offset := len(fullText) - len(text)
var line string
- line, text, _ = stringsCut(text, "\n")
+ line, text, _ = strings.Cut(text, "\n")
if !inStar && strings.HasPrefix(line, "//") {
check.comment(pos+token.Pos(offset), line)
@@ -137,7 +137,7 @@ func (check *checker) nonGoFile(pos token.Pos, fullText string) {
line = strings.TrimSpace(line)
if inStar {
var ok bool
- _, line, ok = stringsCut(line, "*/")
+ _, line, ok = strings.Cut(line, "*/")
if !ok {
break
}
@@ -200,14 +200,6 @@ func (check *checker) comment(pos token.Pos, line string) {
}
}
-// Go 1.18 strings.Cut.
-func stringsCut(s, sep string) (before, after string, found bool) {
- if i := strings.Index(s, sep); i >= 0 {
- return s[:i], s[i+len(sep):], true
- }
- return s, "", false
-}
-
// Go 1.20 strings.CutPrefix.
func stringsCutPrefix(s, prefix string) (after string, found bool) {
if !strings.HasPrefix(s, prefix) {
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
index ac37e4784e..a8d84034df 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
@@ -12,7 +12,7 @@ import (
"go/printer"
"go/token"
"go/types"
- "io/ioutil"
+ "os"
)
// Format returns a string representation of the expression.
@@ -69,7 +69,7 @@ func Unparen(e ast.Expr) ast.Expr {
// ReadFile reads a file and adds it to the FileSet
// so that we can report errors against it using lineStart.
func ReadFile(fset *token.FileSet, filename string) ([]byte, *token.File, error) {
- content, err := ioutil.ReadFile(filename)
+ content, err := os.ReadFile(filename)
if err != nil {
return nil, nil, err
}
diff --git a/vendor/golang.org/x/tools/go/buildutil/fakecontext.go b/vendor/golang.org/x/tools/go/buildutil/fakecontext.go
index 15025f645f..763d18809b 100644
--- a/vendor/golang.org/x/tools/go/buildutil/fakecontext.go
+++ b/vendor/golang.org/x/tools/go/buildutil/fakecontext.go
@@ -8,7 +8,6 @@ import (
"fmt"
"go/build"
"io"
- "io/ioutil"
"os"
"path"
"path/filepath"
@@ -76,7 +75,7 @@ func FakeContext(pkgs map[string]map[string]string) *build.Context {
if !ok {
return nil, fmt.Errorf("file not found: %s", filename)
}
- return ioutil.NopCloser(strings.NewReader(content)), nil
+ return io.NopCloser(strings.NewReader(content)), nil
}
ctxt.IsAbsPath = func(path string) bool {
path = filepath.ToSlash(path)
diff --git a/vendor/golang.org/x/tools/go/buildutil/overlay.go b/vendor/golang.org/x/tools/go/buildutil/overlay.go
index bdbfd93147..7e371658d9 100644
--- a/vendor/golang.org/x/tools/go/buildutil/overlay.go
+++ b/vendor/golang.org/x/tools/go/buildutil/overlay.go
@@ -10,7 +10,6 @@ import (
"fmt"
"go/build"
"io"
- "io/ioutil"
"path/filepath"
"strconv"
"strings"
@@ -33,7 +32,7 @@ func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Conte
// TODO(dominikh): Implement IsDir, HasSubdir and ReadDir
rc := func(data []byte) (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewBuffer(data)), nil
+ return io.NopCloser(bytes.NewBuffer(data)), nil
}
copy := *orig // make a copy
diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
index 3fce480034..38d5c6c7cd 100644
--- a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
+++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
@@ -57,7 +57,6 @@ import (
"go/build"
"go/parser"
"go/token"
- "io/ioutil"
"log"
"os"
"path/filepath"
@@ -70,7 +69,7 @@ import (
// ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses
// the output and returns the resulting ASTs.
func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) {
- tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
+ tmpdir, err := os.MkdirTemp("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
if err != nil {
return nil, err
}
diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go
index da4ab89fe6..a7a8f73e3d 100644
--- a/vendor/golang.org/x/tools/go/packages/doc.go
+++ b/vendor/golang.org/x/tools/go/packages/doc.go
@@ -35,7 +35,7 @@ The Package struct provides basic information about the package, including
- Imports, a map from source import strings to the Packages they name;
- Types, the type information for the package's exported symbols;
- Syntax, the parsed syntax trees for the package's source code; and
- - TypeInfo, the result of a complete type-check of the package syntax trees.
+ - TypesInfo, the result of a complete type-check of the package syntax trees.
(See the documentation for type Package for the complete list of fields
and more detailed descriptions.)
diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go
index b5de9cf9f2..1f1eade0ac 100644
--- a/vendor/golang.org/x/tools/go/packages/golist.go
+++ b/vendor/golang.org/x/tools/go/packages/golist.go
@@ -9,7 +9,6 @@ import (
"context"
"encoding/json"
"fmt"
- "io/ioutil"
"log"
"os"
"path"
@@ -1109,7 +1108,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
if len(state.cfg.Overlay) == 0 {
return "", func() {}, nil
}
- dir, err := ioutil.TempDir("", "gopackages-*")
+ dir, err := os.MkdirTemp("", "gopackages-*")
if err != nil {
return "", nil, err
}
@@ -1128,7 +1127,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
// Create a unique filename for the overlaid files, to avoid
// creating nested directories.
noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "")
- f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator))
+ f, err := os.CreateTemp(dir, fmt.Sprintf("*-%s", noSeparator))
if err != nil {
return "", func() {}, err
}
@@ -1146,7 +1145,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
}
// Write out the overlay file that contains the filepath mappings.
filename = filepath.Join(dir, "overlay.json")
- if err := ioutil.WriteFile(filename, b, 0665); err != nil {
+ if err := os.WriteFile(filename, b, 0665); err != nil {
return "", func() {}, err
}
return filename, cleanup, nil
diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go
index 124a6fe143..ece0e7c603 100644
--- a/vendor/golang.org/x/tools/go/packages/packages.go
+++ b/vendor/golang.org/x/tools/go/packages/packages.go
@@ -16,7 +16,6 @@ import (
"go/token"
"go/types"
"io"
- "io/ioutil"
"log"
"os"
"path/filepath"
@@ -1127,7 +1126,7 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
var err error
if src == nil {
ioLimit <- true // wait
- src, err = ioutil.ReadFile(filename)
+ src, err = os.ReadFile(filename)
<-ioLimit // signal
}
if err != nil {
diff --git a/vendor/golang.org/x/tools/imports/forward.go b/vendor/golang.org/x/tools/imports/forward.go
index d2547c7433..cb6db8893f 100644
--- a/vendor/golang.org/x/tools/imports/forward.go
+++ b/vendor/golang.org/x/tools/imports/forward.go
@@ -7,8 +7,8 @@
package imports // import "golang.org/x/tools/imports"
import (
- "io/ioutil"
"log"
+ "os"
"golang.org/x/tools/internal/gocommand"
intimp "golang.org/x/tools/internal/imports"
@@ -44,7 +44,7 @@ var LocalPrefix string
func Process(filename string, src []byte, opt *Options) ([]byte, error) {
var err error
if src == nil {
- src, err = ioutil.ReadFile(filename)
+ src, err = os.ReadFile(filename)
if err != nil {
return nil, err
}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
index 085d311600..27e860243e 100644
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
@@ -8,7 +8,6 @@
package fastwalk
import (
- "io/ioutil"
"os"
)
@@ -17,16 +16,20 @@ import (
// If fn returns a non-nil error, readDir returns with that error
// immediately.
func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
- fis, err := ioutil.ReadDir(dirName)
+ fis, err := os.ReadDir(dirName)
if err != nil {
return err
}
skipFiles := false
for _, fi := range fis {
- if fi.Mode().IsRegular() && skipFiles {
+ info, err := fi.Info()
+ if err != nil {
+ return err
+ }
+ if info.Mode().IsRegular() && skipFiles {
continue
}
- if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil {
+ if err := fn(dirName, fi.Name(), info.Mode()&os.ModeType); err != nil {
if err == ErrSkipFiles {
skipFiles = true
continue
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
index b1223713b9..2d078ccb19 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
@@ -29,7 +29,6 @@ import (
"go/token"
"go/types"
"io"
- "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -221,7 +220,7 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func
switch hdr {
case "$$B\n":
var data []byte
- data, err = ioutil.ReadAll(buf)
+ data, err = io.ReadAll(buf)
if err != nil {
break
}
diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go
index d4f1b4e8a0..01e8ba5fa2 100644
--- a/vendor/golang.org/x/tools/internal/imports/fix.go
+++ b/vendor/golang.org/x/tools/internal/imports/fix.go
@@ -13,6 +13,7 @@ import (
"go/build"
"go/parser"
"go/token"
+ "io/fs"
"io/ioutil"
"os"
"path"
@@ -107,7 +108,7 @@ func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File {
considerTests := strings.HasSuffix(filename, "_test.go")
fileBase := filepath.Base(filename)
- packageFileInfos, err := ioutil.ReadDir(srcDir)
+ packageFileInfos, err := os.ReadDir(srcDir)
if err != nil {
return nil
}
@@ -1469,11 +1470,11 @@ func VendorlessPath(ipath string) string {
func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) {
// Look for non-test, buildable .go files which could provide exports.
- all, err := ioutil.ReadDir(dir)
+ all, err := os.ReadDir(dir)
if err != nil {
return "", nil, err
}
- var files []os.FileInfo
+ var files []fs.DirEntry
for _, fi := range all {
name := fi.Name()
if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) {
diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go
index 977d2389da..5f4d435d3c 100644
--- a/vendor/golang.org/x/tools/internal/imports/mod.go
+++ b/vendor/golang.org/x/tools/internal/imports/mod.go
@@ -9,7 +9,6 @@ import (
"context"
"encoding/json"
"fmt"
- "io/ioutil"
"os"
"path"
"path/filepath"
@@ -265,7 +264,7 @@ func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON,
}
// Not cached. Read the filesystem.
- pkgFiles, err := ioutil.ReadDir(pkgDir)
+ pkgFiles, err := os.ReadDir(pkgDir)
if err != nil {
continue
}
@@ -370,7 +369,7 @@ func (r *ModuleResolver) dirIsNestedModule(dir string, mod *gocommand.ModuleJSON
func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) {
readModName := func(modFile string) string {
- modBytes, err := ioutil.ReadFile(modFile)
+ modBytes, err := os.ReadFile(modFile)
if err != nil {
return ""
}
diff --git a/vendor/google.golang.org/grpc/README.md b/vendor/google.golang.org/grpc/README.md
index 1bc92248cb..ab0fbb79b8 100644
--- a/vendor/google.golang.org/grpc/README.md
+++ b/vendor/google.golang.org/grpc/README.md
@@ -1,8 +1,8 @@
# gRPC-Go
-[![Build Status](https://travis-ci.org/grpc/grpc-go.svg)](https://travis-ci.org/grpc/grpc-go)
[![GoDoc](https://pkg.go.dev/badge/google.golang.org/grpc)][API]
[![GoReportCard](https://goreportcard.com/badge/grpc/grpc-go)](https://goreportcard.com/report/github.com/grpc/grpc-go)
+[![codecov](https://codecov.io/gh/grpc/grpc-go/graph/badge.svg)](https://codecov.io/gh/grpc/grpc-go)
The [Go][] implementation of [gRPC][]: A high performance, open source, general
RPC framework that puts mobile and HTTP/2 first. For more information see the
diff --git a/vendor/google.golang.org/grpc/attributes/attributes.go b/vendor/google.golang.org/grpc/attributes/attributes.go
index 712fef4d0f..52d530d7ad 100644
--- a/vendor/google.golang.org/grpc/attributes/attributes.go
+++ b/vendor/google.golang.org/grpc/attributes/attributes.go
@@ -121,9 +121,9 @@ func (a *Attributes) String() string {
return sb.String()
}
-func str(x any) string {
+func str(x any) (s string) {
if v, ok := x.(fmt.Stringer); ok {
- return v.String()
+ return fmt.Sprint(v)
} else if v, ok := x.(string); ok {
return v
}
diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go
index b6377f445a..d79560a2e2 100644
--- a/vendor/google.golang.org/grpc/balancer/balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/balancer.go
@@ -30,6 +30,7 @@ import (
"google.golang.org/grpc/channelz"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/grpclog"
"google.golang.org/grpc/internal"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/resolver"
@@ -39,6 +40,8 @@ import (
var (
// m is a map from name to balancer builder.
m = make(map[string]Builder)
+
+ logger = grpclog.Component("balancer")
)
// Register registers the balancer builder to the balancer map. b.Name
@@ -51,6 +54,12 @@ var (
// an init() function), and is not thread-safe. If multiple Balancers are
// registered with the same name, the one registered last will take effect.
func Register(b Builder) {
+ if strings.ToLower(b.Name()) != b.Name() {
+ // TODO: Skip the use of strings.ToLower() to index the map after v1.59
+ // is released to switch to case sensitive balancer registry. Also,
+ // remove this warning and update the docstrings for Register and Get.
+ logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon", b.Name())
+ }
m[strings.ToLower(b.Name())] = b
}
@@ -70,6 +79,12 @@ func init() {
// Note that the compare is done in a case-insensitive fashion.
// If no builder is register with the name, nil will be returned.
func Get(name string) Builder {
+ if strings.ToLower(name) != name {
+ // TODO: Skip the use of strings.ToLower() to index the map after v1.59
+ // is released to switch to case sensitive balancer registry. Also,
+ // remove this warning and update the docstrings for Register and Get.
+ logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon", name)
+ }
if b, ok := m[strings.ToLower(name)]; ok {
return b
}
diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go
index f2ddfc3788..86ba65be4c 100644
--- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go
+++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go
@@ -32,14 +32,18 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/balancer"
+ "google.golang.org/grpc/balancer/base"
grpclbstate "google.golang.org/grpc/balancer/grpclb/state"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/backoff"
+ internalgrpclog "google.golang.org/grpc/internal/grpclog"
+ "google.golang.org/grpc/internal/pretty"
"google.golang.org/grpc/internal/resolver/dns"
"google.golang.org/grpc/resolver"
+ "google.golang.org/grpc/resolver/manual"
durationpb "github.com/golang/protobuf/ptypes/duration"
lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1"
@@ -132,7 +136,11 @@ func (b *lbBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) bal
// This generates a manual resolver builder with a fixed scheme. This
// scheme will be used to dial to remote LB, so we can send filtered
// address updates to remote LB ClientConn using this manual resolver.
- r := &lbManualResolver{scheme: "grpclb-internal", ccb: cc}
+ mr := manual.NewBuilderWithScheme("grpclb-internal")
+ // ResolveNow() on this manual resolver is forwarded to the parent
+ // ClientConn, so when grpclb client loses contact with the remote balancer,
+ // the parent ClientConn's resolver will re-resolve.
+ mr.ResolveNowCallback = cc.ResolveNow
lb := &lbBalancer{
cc: newLBCacheClientConn(cc),
@@ -142,23 +150,24 @@ func (b *lbBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) bal
fallbackTimeout: b.fallbackTimeout,
doneCh: make(chan struct{}),
- manualResolver: r,
+ manualResolver: mr,
subConns: make(map[resolver.Address]balancer.SubConn),
scStates: make(map[balancer.SubConn]connectivity.State),
- picker: &errPicker{err: balancer.ErrNoSubConnAvailable},
+ picker: base.NewErrPicker(balancer.ErrNoSubConnAvailable),
clientStats: newRPCStats(),
backoff: backoff.DefaultExponential, // TODO: make backoff configurable.
}
+ lb.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[grpclb %p] ", lb))
var err error
if opt.CredsBundle != nil {
lb.grpclbClientConnCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBalancer)
if err != nil {
- logger.Warningf("lbBalancer: client connection creds NewWithMode failed: %v", err)
+ lb.logger.Warningf("Failed to create credentials used for connecting to grpclb: %v", err)
}
lb.grpclbBackendCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBackendFromBalancer)
if err != nil {
- logger.Warningf("lbBalancer: backend creds NewWithMode failed: %v", err)
+ lb.logger.Warningf("Failed to create credentials used for connecting to backends returned by grpclb: %v", err)
}
}
@@ -170,6 +179,7 @@ type lbBalancer struct {
dialTarget string // user's dial target
target string // same as dialTarget unless overridden in service config
opt balancer.BuildOptions
+ logger *internalgrpclog.PrefixLogger
usePickFirst bool
@@ -188,7 +198,7 @@ type lbBalancer struct {
// manualResolver is used in the remote LB ClientConn inside grpclb. When
// resolved address updates are received by grpclb, filtered updates will be
// send to remote LB ClientConn through this resolver.
- manualResolver *lbManualResolver
+ manualResolver *manual.Resolver
// The ClientConn to talk to the remote balancer.
ccRemoteLB *remoteBalancerCCWrapper
// backoff for calling remote balancer.
@@ -236,12 +246,12 @@ type lbBalancer struct {
// Caller must hold lb.mu.
func (lb *lbBalancer) regeneratePicker(resetDrop bool) {
if lb.state == connectivity.TransientFailure {
- lb.picker = &errPicker{err: fmt.Errorf("all SubConns are in TransientFailure, last connection error: %v", lb.connErr)}
+ lb.picker = base.NewErrPicker(fmt.Errorf("all SubConns are in TransientFailure, last connection error: %v", lb.connErr))
return
}
if lb.state == connectivity.Connecting {
- lb.picker = &errPicker{err: balancer.ErrNoSubConnAvailable}
+ lb.picker = base.NewErrPicker(balancer.ErrNoSubConnAvailable)
return
}
@@ -268,7 +278,7 @@ func (lb *lbBalancer) regeneratePicker(resetDrop bool) {
//
// This doesn't seem to be necessary after the connecting check above.
// Kept for safety.
- lb.picker = &errPicker{err: balancer.ErrNoSubConnAvailable}
+ lb.picker = base.NewErrPicker(balancer.ErrNoSubConnAvailable)
return
}
if lb.inFallback {
@@ -322,21 +332,21 @@ func (lb *lbBalancer) aggregateSubConnStates() connectivity.State {
// UpdateSubConnState is unused; NewSubConn's options always specifies
// updateSubConnState as the listener.
func (lb *lbBalancer) UpdateSubConnState(sc balancer.SubConn, scs balancer.SubConnState) {
- logger.Errorf("grpclb: UpdateSubConnState(%v, %+v) called unexpectedly", sc, scs)
+ lb.logger.Errorf("UpdateSubConnState(%v, %+v) called unexpectedly", sc, scs)
}
func (lb *lbBalancer) updateSubConnState(sc balancer.SubConn, scs balancer.SubConnState) {
s := scs.ConnectivityState
- if logger.V(2) {
- logger.Infof("lbBalancer: handle SubConn state change: %p, %v", sc, s)
+ if lb.logger.V(2) {
+ lb.logger.Infof("SubConn state change: %p, %v", sc, s)
}
lb.mu.Lock()
defer lb.mu.Unlock()
oldS, ok := lb.scStates[sc]
if !ok {
- if logger.V(2) {
- logger.Infof("lbBalancer: got state changes for an unknown SubConn: %p, %v", sc, s)
+ if lb.logger.V(2) {
+ lb.logger.Infof("Received state change for an unknown SubConn: %p, %v", sc, s)
}
return
}
@@ -441,8 +451,8 @@ func (lb *lbBalancer) handleServiceConfig(gc *grpclbServiceConfig) {
if lb.usePickFirst == newUsePickFirst {
return
}
- if logger.V(2) {
- logger.Infof("lbBalancer: switching mode, new usePickFirst: %+v", newUsePickFirst)
+ if lb.logger.V(2) {
+ lb.logger.Infof("Switching mode. Is pick_first used for backends? %v", newUsePickFirst)
}
lb.refreshSubConns(lb.backendAddrs, lb.inFallback, newUsePickFirst)
}
@@ -453,8 +463,8 @@ func (lb *lbBalancer) ResolverError(error) {
}
func (lb *lbBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
- if logger.V(2) {
- logger.Infof("lbBalancer: UpdateClientConnState: %+v", ccs)
+ if lb.logger.V(2) {
+ lb.logger.Infof("UpdateClientConnState: %s", pretty.ToJSON(ccs))
}
gc, _ := ccs.BalancerConfig.(*grpclbServiceConfig)
lb.handleServiceConfig(gc)
@@ -482,7 +492,9 @@ func (lb *lbBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error
} else if lb.ccRemoteLB == nil {
// First time receiving resolved addresses, create a cc to remote
// balancers.
- lb.newRemoteBalancerCCWrapper()
+ if err := lb.newRemoteBalancerCCWrapper(); err != nil {
+ return err
+ }
// Start the fallback goroutine.
go lb.fallbackToBackendsAfter(lb.fallbackTimeout)
}
diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go
index 39bc5cc71e..20c5f2ec39 100644
--- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go
+++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go
@@ -98,15 +98,6 @@ func (s *rpcStats) knownReceived() {
atomic.AddInt64(&s.numCallsFinished, 1)
}
-type errPicker struct {
- // Pick always returns this err.
- err error
-}
-
-func (p *errPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
- return balancer.PickResult{}, p.err
-}
-
// rrPicker does roundrobin on subConns. It's typically used when there's no
// response from remote balancer, and grpclb falls back to the resolved
// backends.
diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go
index edb66a90a3..c8fe1edd8e 100644
--- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go
@@ -27,11 +27,8 @@ import (
"time"
"github.com/golang/protobuf/proto"
- timestamppb "github.com/golang/protobuf/ptypes/timestamp"
- "github.com/google/go-cmp/cmp"
"google.golang.org/grpc"
"google.golang.org/grpc/balancer"
- lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/internal/backoff"
@@ -39,13 +36,28 @@ import (
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/resolver"
+
+ timestamppb "github.com/golang/protobuf/ptypes/timestamp"
+ lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1"
)
+func serverListEqual(a, b []*lbpb.Server) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if !proto.Equal(a[i], b[i]) {
+ return false
+ }
+ }
+ return true
+}
+
// processServerList updates balancer's internal state, create/remove SubConns
// and regenerates picker using the received serverList.
func (lb *lbBalancer) processServerList(l *lbpb.ServerList) {
- if logger.V(2) {
- logger.Infof("lbBalancer: processing server list: %+v", l)
+ if lb.logger.V(2) {
+ lb.logger.Infof("Processing server list: %#v", l)
}
lb.mu.Lock()
defer lb.mu.Unlock()
@@ -55,9 +67,9 @@ func (lb *lbBalancer) processServerList(l *lbpb.ServerList) {
lb.serverListReceived = true
// If the new server list == old server list, do nothing.
- if cmp.Equal(lb.fullServerList, l.Servers, cmp.Comparer(proto.Equal)) {
- if logger.V(2) {
- logger.Infof("lbBalancer: new serverlist same as the previous one, ignoring")
+ if serverListEqual(lb.fullServerList, l.Servers) {
+ if lb.logger.V(2) {
+ lb.logger.Infof("Ignoring new server list as it is the same as the previous one")
}
return
}
@@ -78,9 +90,8 @@ func (lb *lbBalancer) processServerList(l *lbpb.ServerList) {
ipStr = fmt.Sprintf("[%s]", ipStr)
}
addr := imetadata.Set(resolver.Address{Addr: fmt.Sprintf("%s:%d", ipStr, s.Port)}, md)
- if logger.V(2) {
- logger.Infof("lbBalancer: server list entry[%d]: ipStr:|%s|, port:|%d|, load balancer token:|%v|",
- i, ipStr, s.Port, s.LoadBalanceToken)
+ if lb.logger.V(2) {
+ lb.logger.Infof("Server list entry:|%d|, ipStr:|%s|, port:|%d|, load balancer token:|%v|", i, ipStr, s.Port, s.LoadBalanceToken)
}
backendAddrs = append(backendAddrs, addr)
}
@@ -149,7 +160,7 @@ func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address, fallback
// This bypasses the cc wrapper with SubConn cache.
sc, err := lb.cc.ClientConn.NewSubConn(backendAddrs, opts)
if err != nil {
- logger.Warningf("grpclb: failed to create new SubConn: %v", err)
+ lb.logger.Warningf("Failed to create new SubConn: %v", err)
return
}
sc.Connect()
@@ -174,7 +185,7 @@ func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address, fallback
opts.StateListener = func(scs balancer.SubConnState) { lb.updateSubConnState(sc, scs) }
sc, err := lb.cc.NewSubConn([]resolver.Address{addr}, opts)
if err != nil {
- logger.Warningf("grpclb: failed to create new SubConn: %v", err)
+ lb.logger.Warningf("Failed to create new SubConn: %v", err)
continue
}
lb.subConns[addrWithoutAttrs] = sc // Use the addr without MD as key for the map.
@@ -217,7 +228,7 @@ type remoteBalancerCCWrapper struct {
wg sync.WaitGroup
}
-func (lb *lbBalancer) newRemoteBalancerCCWrapper() {
+func (lb *lbBalancer) newRemoteBalancerCCWrapper() error {
var dopts []grpc.DialOption
if creds := lb.opt.DialCreds; creds != nil {
dopts = append(dopts, grpc.WithTransportCredentials(creds))
@@ -248,9 +259,10 @@ func (lb *lbBalancer) newRemoteBalancerCCWrapper() {
//
// The grpclb server addresses will set field ServerName, and creds will
// receive ServerName as authority.
- cc, err := grpc.DialContext(context.Background(), lb.manualResolver.Scheme()+":///grpclb.subClientConn", dopts...)
+ target := lb.manualResolver.Scheme() + ":///grpclb.subClientConn"
+ cc, err := grpc.Dial(target, dopts...)
if err != nil {
- logger.Fatalf("failed to dial: %v", err)
+ return fmt.Errorf("grpc.Dial(%s): %v", target, err)
}
ccw := &remoteBalancerCCWrapper{
cc: cc,
@@ -261,6 +273,7 @@ func (lb *lbBalancer) newRemoteBalancerCCWrapper() {
lb.ccRemoteLB = ccw
ccw.wg.Add(1)
go ccw.watchRemoteBalancer()
+ return nil
}
// close closed the ClientConn to remote balancer, and waits until all
@@ -408,9 +421,9 @@ func (ccw *remoteBalancerCCWrapper) watchRemoteBalancer() {
default:
if err != nil {
if err == errServerTerminatedConnection {
- logger.Info(err)
+ ccw.lb.logger.Infof("Call to remote balancer failed: %v", err)
} else {
- logger.Warning(err)
+ ccw.lb.logger.Warningf("Call to remote balancer failed: %v", err)
}
}
}
diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go
index 680779f1c8..c0f762c0c0 100644
--- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go
+++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go
@@ -27,67 +27,6 @@ import (
"google.golang.org/grpc/resolver"
)
-// The parent ClientConn should re-resolve when grpclb loses connection to the
-// remote balancer. When the ClientConn inside grpclb gets a TransientFailure,
-// it calls lbManualResolver.ResolveNow(), which calls parent ClientConn's
-// ResolveNow, and eventually results in re-resolve happening in parent
-// ClientConn's resolver (DNS for example).
-//
-// parent
-// ClientConn
-// +-----------------------------------------------------------------+
-// | parent +---------------------------------+ |
-// | DNS ClientConn | grpclb | |
-// | resolver balancerWrapper | | |
-// | + + | grpclb grpclb | |
-// | | | | ManualResolver ClientConn | |
-// | | | | + + | |
-// | | | | | | Transient | |
-// | | | | | | Failure | |
-// | | | | | <--------- | | |
-// | | | <--------------- | ResolveNow | | |
-// | | <--------- | ResolveNow | | | | |
-// | | ResolveNow | | | | | |
-// | | | | | | | |
-// | + + | + + | |
-// | +---------------------------------+ |
-// +-----------------------------------------------------------------+
-
-// lbManualResolver is used by the ClientConn inside grpclb. It's a manual
-// resolver with a special ResolveNow() function.
-//
-// When ResolveNow() is called, it calls ResolveNow() on the parent ClientConn,
-// so when grpclb client lose contact with remote balancers, the parent
-// ClientConn's resolver will re-resolve.
-type lbManualResolver struct {
- scheme string
- ccr resolver.ClientConn
-
- ccb balancer.ClientConn
-}
-
-func (r *lbManualResolver) Build(_ resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) {
- r.ccr = cc
- return r, nil
-}
-
-func (r *lbManualResolver) Scheme() string {
- return r.scheme
-}
-
-// ResolveNow calls resolveNow on the parent ClientConn.
-func (r *lbManualResolver) ResolveNow(o resolver.ResolveNowOptions) {
- r.ccb.ResolveNow(o)
-}
-
-// Close is a noop for Resolver.
-func (*lbManualResolver) Close() {}
-
-// UpdateState calls cc.UpdateState.
-func (r *lbManualResolver) UpdateState(s resolver.State) {
- r.ccr.UpdateState(s)
-}
-
const subConnCacheTime = time.Second * 10
// lbCacheClientConn is a wrapper balancer.ClientConn with a SubConn cache.
diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go
index ff7fea1022..429c389e47 100644
--- a/vendor/google.golang.org/grpc/clientconn.go
+++ b/vendor/google.golang.org/grpc/clientconn.go
@@ -337,8 +337,8 @@ func (cc *ClientConn) exitIdleMode() error {
return errConnClosing
}
if cc.idlenessState != ccIdlenessStateIdle {
- cc.mu.Unlock()
channelz.Infof(logger, cc.channelzID, "ClientConn asked to exit idle mode, current mode is %v", cc.idlenessState)
+ cc.mu.Unlock()
return nil
}
@@ -404,13 +404,13 @@ func (cc *ClientConn) exitIdleMode() error {
// name resolver, load balancer and any subchannels.
func (cc *ClientConn) enterIdleMode() error {
cc.mu.Lock()
+ defer cc.mu.Unlock()
+
if cc.conns == nil {
- cc.mu.Unlock()
return ErrClientConnClosing
}
if cc.idlenessState != ccIdlenessStateActive {
- channelz.Errorf(logger, cc.channelzID, "ClientConn asked to enter idle mode, current mode is %v", cc.idlenessState)
- cc.mu.Unlock()
+ channelz.Warningf(logger, cc.channelzID, "ClientConn asked to enter idle mode, current mode is %v", cc.idlenessState)
return nil
}
@@ -431,14 +431,14 @@ func (cc *ClientConn) enterIdleMode() error {
cc.balancerWrapper.enterIdleMode()
cc.csMgr.updateState(connectivity.Idle)
cc.idlenessState = ccIdlenessStateIdle
- cc.mu.Unlock()
+ cc.addTraceEvent("entering idle mode")
go func() {
- cc.addTraceEvent("entering idle mode")
for ac := range conns {
ac.tearDown(errConnIdling)
}
}()
+
return nil
}
@@ -804,6 +804,12 @@ func init() {
internal.SubscribeToConnectivityStateChanges = func(cc *ClientConn, s grpcsync.Subscriber) func() {
return cc.csMgr.pubSub.Subscribe(s)
}
+ internal.EnterIdleModeForTesting = func(cc *ClientConn) error {
+ return cc.enterIdleMode()
+ }
+ internal.ExitIdleModeForTesting = func(cc *ClientConn) error {
+ return cc.exitIdleMode()
+ }
}
func (cc *ClientConn) maybeApplyDefaultServiceConfig(addrs []resolver.Address) {
diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go
index 1fd0d5c127..cfc9fd85e8 100644
--- a/vendor/google.golang.org/grpc/dialoptions.go
+++ b/vendor/google.golang.org/grpc/dialoptions.go
@@ -644,6 +644,7 @@ func defaultDialOptions() dialOptions {
UseProxy: true,
},
recvBufferPool: nopBufferPool{},
+ idleTimeout: 30 * time.Minute,
}
}
@@ -680,8 +681,8 @@ func WithResolvers(rs ...resolver.Builder) DialOption {
// channel will exit idle mode when the Connect() method is called or when an
// RPC is initiated.
//
-// By default this feature is disabled, which can also be explicitly configured
-// by passing zero to this function.
+// A default timeout of 30 minutes will be used if this dial option is not set
+// at dial time and idleness can be disabled by passing a timeout of zero.
//
// # Experimental
//
diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go
index 69d5580b6a..5ebf88d714 100644
--- a/vendor/google.golang.org/grpc/encoding/encoding.go
+++ b/vendor/google.golang.org/grpc/encoding/encoding.go
@@ -38,6 +38,10 @@ const Identity = "identity"
// Compressor is used for compressing and decompressing when sending or
// receiving messages.
+//
+// If a Compressor implements `DecompressedSize(compressedBytes []byte) int`,
+// gRPC will invoke it to determine the size of the buffer allocated for the
+// result of decompression. A return value of -1 indicates unknown size.
type Compressor interface {
// Compress writes the data written to wc to w after compressing it. If an
// error occurs while initializing the compressor, that error is returned
@@ -51,15 +55,6 @@ type Compressor interface {
// coding header. The result must be static; the result cannot change
// between calls.
Name() string
- // If a Compressor implements
- // DecompressedSize(compressedBytes []byte) int, gRPC will call it
- // to determine the size of the buffer allocated for the result of decompression.
- // Return -1 to indicate unknown size.
- //
- // Experimental
- //
- // Notice: This API is EXPERIMENTAL and may be changed or removed in a
- // later release.
}
var registeredCompressor = make(map[string]Compressor)
diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
index a01a1b4d54..4439cda0f3 100644
--- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
@@ -44,8 +44,15 @@ const (
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type HealthClient interface {
- // If the requested service is unknown, the call will fail with status
- // NOT_FOUND.
+ // Check gets the health of the specified service. If the requested service
+ // is unknown, the call will fail with status NOT_FOUND. If the caller does
+ // not specify a service name, the server should respond with its overall
+ // health status.
+ //
+ // Clients should set a deadline when calling Check, and can declare the
+ // server unhealthy if they do not receive a timely response.
+ //
+ // Check implementations should be idempotent and side effect free.
Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
// Performs a watch for the serving status of the requested service.
// The server will immediately send back a message indicating the current
@@ -118,8 +125,15 @@ func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) {
// All implementations should embed UnimplementedHealthServer
// for forward compatibility
type HealthServer interface {
- // If the requested service is unknown, the call will fail with status
- // NOT_FOUND.
+ // Check gets the health of the specified service. If the requested service
+ // is unknown, the call will fail with status NOT_FOUND. If the caller does
+ // not specify a service name, the server should respond with its overall
+ // health status.
+ //
+ // Clients should set a deadline when calling Check, and can declare the
+ // server unhealthy if they do not receive a timely response.
+ //
+ // Check implementations should be idempotent and side effect free.
Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error)
// Performs a watch for the serving status of the requested service.
// The server will immediately send back a message indicating the current
diff --git a/vendor/google.golang.org/grpc/internal/backoff/backoff.go b/vendor/google.golang.org/grpc/internal/backoff/backoff.go
index 5fc0ee3da5..fed1c011a3 100644
--- a/vendor/google.golang.org/grpc/internal/backoff/backoff.go
+++ b/vendor/google.golang.org/grpc/internal/backoff/backoff.go
@@ -23,6 +23,8 @@
package backoff
import (
+ "context"
+ "errors"
"time"
grpcbackoff "google.golang.org/grpc/backoff"
@@ -71,3 +73,37 @@ func (bc Exponential) Backoff(retries int) time.Duration {
}
return time.Duration(backoff)
}
+
+// ErrResetBackoff is the error to be returned by the function executed by RunF,
+// to instruct the latter to reset its backoff state.
+var ErrResetBackoff = errors.New("reset backoff state")
+
+// RunF provides a convenient way to run a function f repeatedly until the
+// context expires or f returns a non-nil error that is not ErrResetBackoff.
+// When f returns ErrResetBackoff, RunF continues to run f, but resets its
+// backoff state before doing so. backoff accepts an integer representing the
+// number of retries, and returns the amount of time to backoff.
+func RunF(ctx context.Context, f func() error, backoff func(int) time.Duration) {
+ attempt := 0
+ timer := time.NewTimer(0)
+ for ctx.Err() == nil {
+ select {
+ case <-timer.C:
+ case <-ctx.Done():
+ timer.Stop()
+ return
+ }
+
+ err := f()
+ if errors.Is(err, ErrResetBackoff) {
+ timer.Reset(0)
+ attempt = 0
+ continue
+ }
+ if err != nil {
+ return
+ }
+ timer.Reset(backoff(attempt))
+ attempt++
+ }
+}
diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go
index c8a8c76d62..0d94c63e06 100644
--- a/vendor/google.golang.org/grpc/internal/internal.go
+++ b/vendor/google.golang.org/grpc/internal/internal.go
@@ -175,6 +175,12 @@ var (
// GRPCResolverSchemeExtraMetadata determines when gRPC will add extra
// metadata to RPCs.
GRPCResolverSchemeExtraMetadata string = "xds"
+
+ // EnterIdleModeForTesting gets the ClientConn to enter IDLE mode.
+ EnterIdleModeForTesting any // func(*grpc.ClientConn) error
+
+ // ExitIdleModeForTesting gets the ClientConn to exit IDLE mode.
+ ExitIdleModeForTesting any // func(*grpc.ClientConn) error
)
// HealthChecker defines the signature of the client-side LB channel health checking function.
diff --git a/vendor/google.golang.org/grpc/internal/status/status.go b/vendor/google.golang.org/grpc/internal/status/status.go
index 4cf85cad9f..03ef2fedd5 100644
--- a/vendor/google.golang.org/grpc/internal/status/status.go
+++ b/vendor/google.golang.org/grpc/internal/status/status.go
@@ -43,6 +43,34 @@ type Status struct {
s *spb.Status
}
+// NewWithProto returns a new status including details from statusProto. This
+// is meant to be used by the gRPC library only.
+func NewWithProto(code codes.Code, message string, statusProto []string) *Status {
+ if len(statusProto) != 1 {
+ // No grpc-status-details bin header, or multiple; just ignore.
+ return &Status{s: &spb.Status{Code: int32(code), Message: message}}
+ }
+ st := &spb.Status{}
+ if err := proto.Unmarshal([]byte(statusProto[0]), st); err != nil {
+ // Probably not a google.rpc.Status proto; do not provide details.
+ return &Status{s: &spb.Status{Code: int32(code), Message: message}}
+ }
+ if st.Code == int32(code) {
+ // The codes match between the grpc-status header and the
+ // grpc-status-details-bin header; use the full details proto.
+ return &Status{s: st}
+ }
+ return &Status{
+ s: &spb.Status{
+ Code: int32(codes.Internal),
+ Message: fmt.Sprintf(
+ "grpc-status-details-bin mismatch: grpc-status=%v, grpc-message=%q, grpc-status-details-bin=%+v",
+ code, message, st,
+ ),
+ },
+ }
+}
+
// New returns a Status representing c and msg.
func New(c codes.Code, msg string) *Status {
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
index 98f80e3fa0..17f7a21b5a 100644
--- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
@@ -220,18 +220,20 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
h.Set("Grpc-Message", encodeGrpcMessage(m))
}
+ s.hdrMu.Lock()
if p := st.Proto(); p != nil && len(p.Details) > 0 {
+ delete(s.trailer, grpcStatusDetailsBinHeader)
stBytes, err := proto.Marshal(p)
if err != nil {
// TODO: return error instead, when callers are able to handle it.
panic(err)
}
- h.Set("Grpc-Status-Details-Bin", encodeBinHeader(stBytes))
+ h.Set(grpcStatusDetailsBinHeader, encodeBinHeader(stBytes))
}
- if md := s.Trailer(); len(md) > 0 {
- for k, vv := range md {
+ if len(s.trailer) > 0 {
+ for k, vv := range s.trailer {
// Clients don't tolerate reading restricted headers after some non restricted ones were sent.
if isReservedHeader(k) {
continue
@@ -243,6 +245,7 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
}
}
}
+ s.hdrMu.Unlock()
})
if err == nil { // transport has not been closed
@@ -287,7 +290,7 @@ func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
}
// writeCustomHeaders sets custom headers set on the stream via SetHeader
-// on the first write call (Write, WriteHeader, or WriteStatus).
+// on the first write call (Write, WriteHeader, or WriteStatus)
func (ht *serverHandlerTransport) writeCustomHeaders(s *Stream) {
h := ht.rw.Header()
@@ -344,7 +347,7 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
return err
}
-func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) {
+func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream)) {
// With this transport type there will be exactly 1 stream: this HTTP request.
ctx := ht.req.Context()
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
index badab8acf3..d6f5c49358 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
@@ -1399,7 +1399,6 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
mdata = make(map[string][]string)
contentTypeErr = "malformed header: missing HTTP content-type"
grpcMessage string
- statusGen *status.Status
recvCompress string
httpStatusCode *int
httpStatusErr string
@@ -1434,12 +1433,6 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
rawStatusCode = codes.Code(uint32(code))
case "grpc-message":
grpcMessage = decodeGrpcMessage(hf.Value)
- case "grpc-status-details-bin":
- var err error
- statusGen, err = decodeGRPCStatusDetails(hf.Value)
- if err != nil {
- headerError = fmt.Sprintf("transport: malformed grpc-status-details-bin: %v", err)
- }
case ":status":
if hf.Value == "200" {
httpStatusErr = ""
@@ -1548,14 +1541,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
return
}
- if statusGen == nil {
- statusGen = status.New(rawStatusCode, grpcMessage)
- }
+ status := istatus.NewWithProto(rawStatusCode, grpcMessage, mdata[grpcStatusDetailsBinHeader])
// If client received END_STREAM from server while stream was still active,
// send RST_STREAM.
rstStream := s.getState() == streamActive
- t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, statusGen, mdata, true)
+ t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, status, mdata, true)
}
// readServerPreface reads and handles the initial settings frame from the
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
index c06db679d8..6fa1eb4199 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
@@ -342,7 +342,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
// operateHeaders takes action on the decoded headers. Returns an error if fatal
// error encountered and transport needs to close, otherwise returns nil.
-func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) error {
+func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream)) error {
// Acquire max stream ID lock for entire duration
t.maxStreamMu.Lock()
defer t.maxStreamMu.Unlock()
@@ -561,7 +561,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
}
if t.inTapHandle != nil {
var err error
- if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method}); err != nil {
+ if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method, Header: mdata}); err != nil {
t.mu.Unlock()
if t.logger.V(logLevel) {
t.logger.Infof("Aborting the stream early due to InTapHandle failure: %v", err)
@@ -592,7 +592,6 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
s.requestRead = func(n int) {
t.adjustWindow(s, uint32(n))
}
- s.ctx = traceCtx(s.ctx, s.method)
for _, sh := range t.stats {
s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
inHeader := &stats.InHeader{
@@ -630,7 +629,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
// HandleStreams receives incoming streams using the given handler. This is
// typically run in a separate goroutine.
// traceCtx attaches trace to ctx and returns the new context.
-func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.Context, string) context.Context) {
+func (t *http2Server) HandleStreams(handle func(*Stream)) {
defer close(t.readerDone)
for {
t.controlBuf.throttle()
@@ -665,7 +664,7 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.
}
switch frame := frame.(type) {
case *http2.MetaHeadersFrame:
- if err := t.operateHeaders(frame, handle, traceCtx); err != nil {
+ if err := t.operateHeaders(frame, handle); err != nil {
t.Close(err)
break
}
@@ -1053,12 +1052,15 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error {
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())})
if p := st.Proto(); p != nil && len(p.Details) > 0 {
+ // Do not use the user's grpc-status-details-bin (if present) if we are
+ // even attempting to set our own.
+ delete(s.trailer, grpcStatusDetailsBinHeader)
stBytes, err := proto.Marshal(p)
if err != nil {
// TODO: return error instead, when callers are able to handle it.
t.logger.Errorf("Failed to marshal rpc status: %s, error: %v", pretty.ToJSON(p), err)
} else {
- headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)})
+ headerFields = append(headerFields, hpack.HeaderField{Name: grpcStatusDetailsBinHeader, Value: encodeBinHeader(stBytes)})
}
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go
index 1958140082..dc29d590e9 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http_util.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go
@@ -34,12 +34,9 @@ import (
"time"
"unicode/utf8"
- "github.com/golang/protobuf/proto"
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
- spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
)
const (
@@ -88,6 +85,8 @@ var (
}
)
+var grpcStatusDetailsBinHeader = "grpc-status-details-bin"
+
// isReservedHeader checks whether hdr belongs to HTTP2 headers
// reserved by gRPC protocol. Any other headers are classified as the
// user-specified metadata.
@@ -103,7 +102,6 @@ func isReservedHeader(hdr string) bool {
"grpc-message",
"grpc-status",
"grpc-timeout",
- "grpc-status-details-bin",
// Intentionally exclude grpc-previous-rpc-attempts and
// grpc-retry-pushback-ms, which are "reserved", but their API
// intentionally works via metadata.
@@ -154,18 +152,6 @@ func decodeMetadataHeader(k, v string) (string, error) {
return v, nil
}
-func decodeGRPCStatusDetails(rawDetails string) (*status.Status, error) {
- v, err := decodeBinHeader(rawDetails)
- if err != nil {
- return nil, err
- }
- st := &spb.Status{}
- if err = proto.Unmarshal(v, st); err != nil {
- return nil, err
- }
- return status.FromProto(st), nil
-}
-
type timeoutUnit uint8
const (
diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go
index 74a811fc05..aac056e723 100644
--- a/vendor/google.golang.org/grpc/internal/transport/transport.go
+++ b/vendor/google.golang.org/grpc/internal/transport/transport.go
@@ -698,7 +698,7 @@ type ClientTransport interface {
// Write methods for a given Stream will be called serially.
type ServerTransport interface {
// HandleStreams receives incoming streams using the given handler.
- HandleStreams(func(*Stream), func(context.Context, string) context.Context)
+ HandleStreams(func(*Stream))
// WriteHeader sends the header metadata for the given stream.
// WriteHeader may not be called on all streams.
diff --git a/vendor/google.golang.org/grpc/resolver/manual/manual.go b/vendor/google.golang.org/grpc/resolver/manual/manual.go
new file mode 100644
index 0000000000..0a4262342f
--- /dev/null
+++ b/vendor/google.golang.org/grpc/resolver/manual/manual.go
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Package manual defines a resolver that can be used to manually send resolved
+// addresses to ClientConn.
+package manual
+
+import (
+ "sync"
+
+ "google.golang.org/grpc/resolver"
+)
+
+// NewBuilderWithScheme creates a new manual resolver builder with the given
+// scheme. Every instance of the manual resolver may only ever be used with a
+// single grpc.ClientConn. Otherwise, bad things will happen.
+func NewBuilderWithScheme(scheme string) *Resolver {
+ return &Resolver{
+ BuildCallback: func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) {},
+ UpdateStateCallback: func(error) {},
+ ResolveNowCallback: func(resolver.ResolveNowOptions) {},
+ CloseCallback: func() {},
+ scheme: scheme,
+ }
+}
+
+// Resolver is also a resolver builder.
+// It's build() function always returns itself.
+type Resolver struct {
+ // BuildCallback is called when the Build method is called. Must not be
+ // nil. Must not be changed after the resolver may be built.
+ BuildCallback func(resolver.Target, resolver.ClientConn, resolver.BuildOptions)
+ // UpdateStateCallback is called when the UpdateState method is called on
+ // the resolver. The value passed as argument to this callback is the value
+ // returned by the resolver.ClientConn. Must not be nil. Must not be
+ // changed after the resolver may be built.
+ UpdateStateCallback func(err error)
+ // ResolveNowCallback is called when the ResolveNow method is called on the
+ // resolver. Must not be nil. Must not be changed after the resolver may
+ // be built.
+ ResolveNowCallback func(resolver.ResolveNowOptions)
+ // CloseCallback is called when the Close method is called. Must not be
+ // nil. Must not be changed after the resolver may be built.
+ CloseCallback func()
+ scheme string
+
+ // Fields actually belong to the resolver.
+ // Guards access to below fields.
+ mu sync.Mutex
+ CC resolver.ClientConn
+ // Storing the most recent state update makes this resolver resilient to
+ // restarts, which is possible with channel idleness.
+ lastSeenState *resolver.State
+}
+
+// InitialState adds initial state to the resolver so that UpdateState doesn't
+// need to be explicitly called after Dial.
+func (r *Resolver) InitialState(s resolver.State) {
+ r.lastSeenState = &s
+}
+
+// Build returns itself for Resolver, because it's both a builder and a resolver.
+func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
+ r.BuildCallback(target, cc, opts)
+ r.mu.Lock()
+ r.CC = cc
+ if r.lastSeenState != nil {
+ err := r.CC.UpdateState(*r.lastSeenState)
+ go r.UpdateStateCallback(err)
+ }
+ r.mu.Unlock()
+ return r, nil
+}
+
+// Scheme returns the manual resolver's scheme.
+func (r *Resolver) Scheme() string {
+ return r.scheme
+}
+
+// ResolveNow is a noop for Resolver.
+func (r *Resolver) ResolveNow(o resolver.ResolveNowOptions) {
+ r.ResolveNowCallback(o)
+}
+
+// Close is a noop for Resolver.
+func (r *Resolver) Close() {
+ r.CloseCallback()
+}
+
+// UpdateState calls CC.UpdateState.
+func (r *Resolver) UpdateState(s resolver.State) {
+ r.mu.Lock()
+ err := r.CC.UpdateState(s)
+ r.lastSeenState = &s
+ r.mu.Unlock()
+ r.UpdateStateCallback(err)
+}
+
+// ReportError calls CC.ReportError.
+func (r *Resolver) ReportError(err error) {
+ r.mu.Lock()
+ r.CC.ReportError(err)
+ r.mu.Unlock()
+}
diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go
index eeae92fbe0..8f60d42143 100644
--- a/vendor/google.golang.org/grpc/server.go
+++ b/vendor/google.golang.org/grpc/server.go
@@ -983,7 +983,7 @@ func (s *Server) serveStreams(st transport.ServerTransport) {
f := func() {
defer streamQuota.release()
defer wg.Done()
- s.handleStream(st, stream, s.traceInfo(st, stream))
+ s.handleStream(st, stream)
}
if s.opts.numServerWorkers > 0 {
@@ -995,12 +995,6 @@ func (s *Server) serveStreams(st transport.ServerTransport) {
}
}
go f()
- }, func(ctx context.Context, method string) context.Context {
- if !EnableTracing {
- return ctx
- }
- tr := trace.New("grpc.Recv."+methodFamily(method), method)
- return trace.NewContext(ctx, tr)
})
wg.Wait()
}
@@ -1049,30 +1043,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.serveStreams(st)
}
-// traceInfo returns a traceInfo and associates it with stream, if tracing is enabled.
-// If tracing is not enabled, it returns nil.
-func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Stream) (trInfo *traceInfo) {
- if !EnableTracing {
- return nil
- }
- tr, ok := trace.FromContext(stream.Context())
- if !ok {
- return nil
- }
-
- trInfo = &traceInfo{
- tr: tr,
- firstLine: firstLine{
- client: false,
- remoteAddr: st.RemoteAddr(),
- },
- }
- if dl, ok := stream.Context().Deadline(); ok {
- trInfo.firstLine.deadline = time.Until(dl)
- }
- return trInfo
-}
-
func (s *Server) addConn(addr string, st transport.ServerTransport) bool {
s.mu.Lock()
defer s.mu.Unlock()
@@ -1133,7 +1103,7 @@ func (s *Server) incrCallsFailed() {
atomic.AddInt64(&s.czData.callsFailed, 1)
}
-func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg any, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
+func (s *Server) sendResponse(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, msg any, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
if err != nil {
channelz.Error(logger, s.channelzID, "grpc: server failed to encode response: ", err)
@@ -1152,7 +1122,7 @@ func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Str
err = t.Write(stream, hdr, payload, opts)
if err == nil {
for _, sh := range s.opts.statsHandlers {
- sh.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now()))
+ sh.HandleRPC(ctx, outPayload(false, msg, data, payload, time.Now()))
}
}
return err
@@ -1194,7 +1164,7 @@ func getChainUnaryHandler(interceptors []UnaryServerInterceptor, curr int, info
}
}
-func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
+func (s *Server) processUnaryRPC(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
shs := s.opts.statsHandlers
if len(shs) != 0 || trInfo != nil || channelz.IsOn() {
if channelz.IsOn() {
@@ -1208,7 +1178,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
IsClientStream: false,
IsServerStream: false,
}
- sh.HandleRPC(stream.Context(), statsBegin)
+ sh.HandleRPC(ctx, statsBegin)
}
if trInfo != nil {
trInfo.tr.LazyLog(&trInfo.firstLine, false)
@@ -1240,7 +1210,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if err != nil && err != io.EOF {
end.Error = toRPCErr(err)
}
- sh.HandleRPC(stream.Context(), end)
+ sh.HandleRPC(ctx, end)
}
if channelz.IsOn() {
@@ -1262,7 +1232,6 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
}
if len(binlogs) != 0 {
- ctx := stream.Context()
md, _ := metadata.FromIncomingContext(ctx)
logEntry := &binarylog.ClientHeader{
Header: md,
@@ -1348,7 +1317,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), &stats.InPayload{
+ sh.HandleRPC(ctx, &stats.InPayload{
RecvTime: time.Now(),
Payload: v,
Length: len(d),
@@ -1362,7 +1331,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Message: d,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), cm)
+ binlog.Log(ctx, cm)
}
}
if trInfo != nil {
@@ -1370,7 +1339,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
return nil
}
- ctx := NewContextWithServerTransportStream(stream.Context(), stream)
+ ctx = NewContextWithServerTransportStream(ctx, stream)
reply, appErr := md.Handler(info.serviceImpl, ctx, df, s.opts.unaryInt)
if appErr != nil {
appStatus, ok := status.FromError(appErr)
@@ -1395,7 +1364,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Header: h,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
+ binlog.Log(ctx, sh)
}
}
st := &binarylog.ServerTrailer{
@@ -1403,7 +1372,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return appErr
@@ -1418,7 +1387,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if stream.SendCompress() != sendCompressorName {
comp = encoding.GetCompressor(stream.SendCompress())
}
- if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil {
+ if err := s.sendResponse(ctx, t, stream, reply, cp, opts, comp); err != nil {
if err == io.EOF {
// The entire stream is done (for unary RPC only).
return err
@@ -1445,8 +1414,8 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, sh)
+ binlog.Log(ctx, st)
}
}
return err
@@ -1460,8 +1429,8 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Message: reply,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
- binlog.Log(stream.Context(), sm)
+ binlog.Log(ctx, sh)
+ binlog.Log(ctx, sm)
}
}
if channelz.IsOn() {
@@ -1479,7 +1448,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return t.WriteStatus(stream, statusOK)
@@ -1521,7 +1490,7 @@ func getChainStreamHandler(interceptors []StreamServerInterceptor, curr int, inf
}
}
-func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
+func (s *Server) processStreamingRPC(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
if channelz.IsOn() {
s.incrCallsStarted()
}
@@ -1535,10 +1504,10 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
IsServerStream: sd.ServerStreams,
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), statsBegin)
+ sh.HandleRPC(ctx, statsBegin)
}
}
- ctx := NewContextWithServerTransportStream(stream.Context(), stream)
+ ctx = NewContextWithServerTransportStream(ctx, stream)
ss := &serverStream{
ctx: ctx,
t: t,
@@ -1574,7 +1543,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
end.Error = toRPCErr(err)
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), end)
+ sh.HandleRPC(ctx, end)
}
}
@@ -1616,7 +1585,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
logEntry.PeerAddr = peer.Addr
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), logEntry)
+ binlog.Log(ctx, logEntry)
}
}
@@ -1694,7 +1663,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
Err: appErr,
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
t.WriteStatus(ss.s, appStatus)
@@ -1712,33 +1681,50 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
Err: appErr,
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return t.WriteStatus(ss.s, statusOK)
}
-func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) {
+func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream) {
+ ctx := stream.Context()
+ var ti *traceInfo
+ if EnableTracing {
+ tr := trace.New("grpc.Recv."+methodFamily(stream.Method()), stream.Method())
+ ctx = trace.NewContext(ctx, tr)
+ ti = &traceInfo{
+ tr: tr,
+ firstLine: firstLine{
+ client: false,
+ remoteAddr: t.RemoteAddr(),
+ },
+ }
+ if dl, ok := ctx.Deadline(); ok {
+ ti.firstLine.deadline = time.Until(dl)
+ }
+ }
+
sm := stream.Method()
if sm != "" && sm[0] == '/' {
sm = sm[1:]
}
pos := strings.LastIndex(sm, "/")
if pos == -1 {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"Malformed method name %q", []any{sm}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"Malformed method name %q", []any{sm}}, true)
+ ti.tr.SetError()
}
errDesc := fmt.Sprintf("malformed method name: %q", stream.Method())
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
+ ti.tr.SetError()
}
channelz.Warningf(logger, s.channelzID, "grpc: Server.handleStream failed to write status: %v", err)
}
- if trInfo != nil {
- trInfo.tr.Finish()
+ if ti != nil {
+ ti.tr.Finish()
}
return
}
@@ -1748,17 +1734,17 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
srv, knownService := s.services[service]
if knownService {
if md, ok := srv.methods[method]; ok {
- s.processUnaryRPC(t, stream, srv, md, trInfo)
+ s.processUnaryRPC(ctx, t, stream, srv, md, ti)
return
}
if sd, ok := srv.streams[method]; ok {
- s.processStreamingRPC(t, stream, srv, sd, trInfo)
+ s.processStreamingRPC(ctx, t, stream, srv, sd, ti)
return
}
}
// Unknown service, or known server unknown method.
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
- s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo)
+ s.processStreamingRPC(ctx, t, stream, nil, unknownDesc, ti)
return
}
var errDesc string
@@ -1767,19 +1753,19 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
} else {
errDesc = fmt.Sprintf("unknown method %v for service %v", method, service)
}
- if trInfo != nil {
- trInfo.tr.LazyPrintf("%s", errDesc)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyPrintf("%s", errDesc)
+ ti.tr.SetError()
}
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
+ ti.tr.SetError()
}
channelz.Warningf(logger, s.channelzID, "grpc: Server.handleStream failed to write status: %v", err)
}
- if trInfo != nil {
- trInfo.tr.Finish()
+ if ti != nil {
+ ti.tr.Finish()
}
}
diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go
index bfa5dfa40e..07f0125768 100644
--- a/vendor/google.golang.org/grpc/tap/tap.go
+++ b/vendor/google.golang.org/grpc/tap/tap.go
@@ -27,6 +27,8 @@ package tap
import (
"context"
+
+ "google.golang.org/grpc/metadata"
)
// Info defines the relevant information needed by the handles.
@@ -34,6 +36,10 @@ type Info struct {
// FullMethodName is the string of grpc method (in the format of
// /package.service/method).
FullMethodName string
+
+ // Header contains the header metadata received.
+ Header metadata.MD
+
// TODO: More to be added.
}
diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go
index 724ad21021..6d2cadd79a 100644
--- a/vendor/google.golang.org/grpc/version.go
+++ b/vendor/google.golang.org/grpc/version.go
@@ -19,4 +19,4 @@
package grpc
// Version is the current grpc version.
-const Version = "1.58.3"
+const Version = "1.59.0"
diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh
index bbc9e2e3c8..bb480f1f9c 100644
--- a/vendor/google.golang.org/grpc/vet.sh
+++ b/vendor/google.golang.org/grpc/vet.sh
@@ -93,6 +93,9 @@ git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpc
# - Ensure all ptypes proto packages are renamed when importing.
not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go"
+# - Ensure all usages of grpc_testing package are renamed when importing.
+not git grep "\(import \|^\s*\)\"google.golang.org/grpc/interop/grpc_testing" -- "*.go"
+
# - Ensure all xds proto imports are renamed to *pb or *grpc.
git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "'
diff --git a/vendor/honnef.co/go/tools/go/types/typeutil/util.go b/vendor/honnef.co/go/tools/go/types/typeutil/util.go
index b0aca16bdb..3a2ad973bb 100644
--- a/vendor/honnef.co/go/tools/go/types/typeutil/util.go
+++ b/vendor/honnef.co/go/tools/go/types/typeutil/util.go
@@ -122,6 +122,8 @@ func flattenFields(T *types.Struct, path []int, seen map[types.Type]bool) []Fiel
if field.Anonymous() {
if s, ok := Dereference(field.Type()).Underlying().(*types.Struct); ok {
out = append(out, flattenFields(s, np, seen)...)
+ } else {
+ out = append(out, Field{field, tag, np})
}
} else {
out = append(out, Field{field, tag, np})
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 08f1630d45..a58261a2c1 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -49,10 +49,10 @@ contrib.go.opencensus.io/exporter/prometheus
## explicit; go 1.17
filippo.io/edwards25519
filippo.io/edwards25519/field
-# github.com/4meepo/tagalign v1.3.2
+# github.com/4meepo/tagalign v1.3.3
## explicit; go 1.19
github.com/4meepo/tagalign
-# github.com/Abirdcfly/dupword v0.0.12
+# github.com/Abirdcfly/dupword v0.0.13
## explicit; go 1.20
github.com/Abirdcfly/dupword
# github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0
@@ -64,6 +64,13 @@ github.com/Antonboom/errname/pkg/analyzer
# github.com/Antonboom/nilnil v0.1.7
## explicit; go 1.20
github.com/Antonboom/nilnil/pkg/analyzer
+# github.com/Antonboom/testifylint v0.2.3
+## explicit; go 1.20
+github.com/Antonboom/testifylint/analyzer
+github.com/Antonboom/testifylint/internal/analysisutil
+github.com/Antonboom/testifylint/internal/checkers
+github.com/Antonboom/testifylint/internal/config
+github.com/Antonboom/testifylint/internal/testify
# github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
## explicit
github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry
@@ -239,6 +246,9 @@ github.com/Shopify/sarama
# github.com/ThalesIgnite/crypto11 v1.2.5
## explicit; go 1.13
github.com/ThalesIgnite/crypto11
+# github.com/alecthomas/go-check-sumtype v0.1.3
+## explicit; go 1.18
+github.com/alecthomas/go-check-sumtype
# github.com/alexkohler/nakedret/v2 v2.0.2
## explicit; go 1.18
github.com/alexkohler/nakedret/v2
@@ -475,11 +485,11 @@ github.com/bmatcuk/doublestar/v4
# github.com/bombsimon/wsl/v3 v3.4.0
## explicit; go 1.19
github.com/bombsimon/wsl/v3
-# github.com/breml/bidichk v0.2.4
-## explicit; go 1.19
+# github.com/breml/bidichk v0.2.7
+## explicit; go 1.20
github.com/breml/bidichk/pkg/bidichk
-# github.com/breml/errchkjson v0.3.1
-## explicit; go 1.17
+# github.com/breml/errchkjson v0.3.6
+## explicit; go 1.20
github.com/breml/errchkjson
# github.com/buildkite/agent/v3 v3.52.1
## explicit; go 1.18
@@ -493,8 +503,8 @@ github.com/buildkite/agent/v3/version
# github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251
## explicit
github.com/buildkite/interpolate
-# github.com/butuzov/ireturn v0.2.0
-## explicit; go 1.15
+# github.com/butuzov/ireturn v0.2.1
+## explicit; go 1.18
github.com/butuzov/ireturn/analyzer
github.com/butuzov/ireturn/analyzer/internal/config
github.com/butuzov/ireturn/analyzer/internal/types
@@ -502,6 +512,9 @@ github.com/butuzov/ireturn/analyzer/internal/types
## explicit; go 1.19
github.com/butuzov/mirror
github.com/butuzov/mirror/internal/checker
+# github.com/catenacyber/perfsprint v0.2.0
+## explicit; go 1.20
+github.com/catenacyber/perfsprint/analyzer
# github.com/ccojocar/zxcvbn-go v1.0.1
## explicit; go 1.20
github.com/ccojocar/zxcvbn-go
@@ -530,7 +543,7 @@ github.com/cespare/xxhash/v2
# github.com/charithe/durationcheck v0.0.10
## explicit; go 1.14
github.com/charithe/durationcheck
-# github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8
+# github.com/chavacava/garif v0.1.0
## explicit; go 1.16
github.com/chavacava/garif
# github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589
@@ -588,7 +601,7 @@ github.com/curioswitch/go-reassign/internal/analyzer
# github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7
## explicit
github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer
-# github.com/daixiang0/gci v0.11.0
+# github.com/daixiang0/gci v0.11.2
## explicit; go 1.18
github.com/daixiang0/gci/pkg/config
github.com/daixiang0/gci/pkg/format
@@ -697,6 +710,9 @@ github.com/gabriel-vasile/mimetype
github.com/gabriel-vasile/mimetype/internal/charset
github.com/gabriel-vasile/mimetype/internal/json
github.com/gabriel-vasile/mimetype/internal/magic
+# github.com/ghostiam/protogetter v0.2.3
+## explicit; go 1.19
+github.com/ghostiam/protogetter
# github.com/go-chi/chi v4.1.2+incompatible
## explicit
github.com/go-chi/chi
@@ -872,13 +888,12 @@ github.com/golangci/dupl/syntax/golang
# github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe
## explicit; go 1.17
github.com/golangci/go-misc/deadcode
-# github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2
-## explicit; go 1.18
+# github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e
+## explicit; go 1.20
github.com/golangci/gofmt/gofmt
github.com/golangci/gofmt/gofmt/internal/diff
-github.com/golangci/gofmt/gofmt/internal/execabs
github.com/golangci/gofmt/goimports
-# github.com/golangci/golangci-lint v1.54.2
+# github.com/golangci/golangci-lint v1.55.0
## explicit; go 1.20
github.com/golangci/golangci-lint/cmd/golangci-lint
github.com/golangci/golangci-lint/internal/cache
@@ -914,8 +929,8 @@ github.com/golangci/maligned
# github.com/golangci/misspell v0.4.1
## explicit; go 1.19
github.com/golangci/misspell
-# github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6
-## explicit; go 1.17
+# github.com/golangci/revgrep v0.5.0
+## explicit; go 1.19
github.com/golangci/revgrep
# github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4
## explicit
@@ -1197,7 +1212,7 @@ github.com/jedisct1/go-minisign
# github.com/jellydator/ttlcache/v3 v3.1.0
## explicit; go 1.18
github.com/jellydator/ttlcache/v3
-# github.com/jgautheron/goconst v1.5.1
+# github.com/jgautheron/goconst v1.6.0
## explicit; go 1.13
github.com/jgautheron/goconst
# github.com/jingyugao/rowserrcheck v1.1.1
@@ -1316,6 +1331,9 @@ github.com/letsencrypt/boulder/sa/proto
# github.com/lufeee/execinquery v1.2.1
## explicit; go 1.17
github.com/lufeee/execinquery
+# github.com/macabu/inamedparam v0.1.2
+## explicit; go 1.19
+github.com/macabu/inamedparam
# github.com/magiconair/properties v1.8.7
## explicit; go 1.19
github.com/magiconair/properties
@@ -1348,10 +1366,11 @@ github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/mbilski/exhaustivestruct v1.2.0
## explicit; go 1.15
github.com/mbilski/exhaustivestruct/pkg/analyzer
-# github.com/mgechev/revive v1.3.2
-## explicit; go 1.19
+# github.com/mgechev/revive v1.3.4
+## explicit; go 1.20
github.com/mgechev/revive/config
github.com/mgechev/revive/formatter
+github.com/mgechev/revive/internal/ifelse
github.com/mgechev/revive/internal/typeparams
github.com/mgechev/revive/lint
github.com/mgechev/revive/rule
@@ -1398,7 +1417,7 @@ github.com/nishanths/predeclared/passes/predeclared
# github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481
## explicit
github.com/nozzle/throttler
-# github.com/nunnatsa/ginkgolinter v0.13.5
+# github.com/nunnatsa/ginkgolinter v0.14.0
## explicit; go 1.20
github.com/nunnatsa/ginkgolinter
github.com/nunnatsa/ginkgolinter/ginkgohandler
@@ -1464,7 +1483,7 @@ github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
## explicit
github.com/pmezard/go-difflib/difflib
-# github.com/polyfloyd/go-errorlint v1.4.4
+# github.com/polyfloyd/go-errorlint v1.4.5
## explicit; go 1.20
github.com/polyfloyd/go-errorlint/errorlint
# github.com/prometheus/client_golang v1.17.0
@@ -1530,8 +1549,8 @@ github.com/rivo/uniseg
# github.com/ryancurrah/gomodguard v1.3.0
## explicit; go 1.19
github.com/ryancurrah/gomodguard
-# github.com/ryanrolds/sqlclosecheck v0.4.0
-## explicit; go 1.19
+# github.com/ryanrolds/sqlclosecheck v0.5.1
+## explicit; go 1.20
github.com/ryanrolds/sqlclosecheck/pkg/analyzer
# github.com/ryanuber/go-glob v1.0.0
## explicit
@@ -1562,7 +1581,7 @@ github.com/secure-systems-lab/go-securesystemslib/cjson
github.com/secure-systems-lab/go-securesystemslib/dsse
github.com/secure-systems-lab/go-securesystemslib/encrypted
github.com/secure-systems-lab/go-securesystemslib/signerverifier
-# github.com/securego/gosec/v2 v2.17.0
+# github.com/securego/gosec/v2 v2.18.1
## explicit; go 1.20
github.com/securego/gosec/v2
github.com/securego/gosec/v2/analyzers
@@ -1896,7 +1915,7 @@ github.com/tektoncd/pipeline/test/diff
## explicit; go 1.19
github.com/tektoncd/plumbing
github.com/tektoncd/plumbing/scripts
-# github.com/tetafro/godot v1.4.14
+# github.com/tetafro/godot v1.4.15
## explicit; go 1.20
github.com/tetafro/godot
# github.com/thales-e-security/pool v0.0.2
@@ -1959,7 +1978,7 @@ github.com/ultraware/funlen
# github.com/ultraware/whitespace v0.0.5
## explicit
github.com/ultraware/whitespace
-# github.com/uudashr/gocognit v1.0.7
+# github.com/uudashr/gocognit v1.1.2
## explicit; go 1.16
github.com/uudashr/gocognit
# github.com/vbatts/tar-split v0.11.3
@@ -1980,7 +1999,7 @@ github.com/xdg-go/scram
# github.com/xdg-go/stringprep v1.0.4
## explicit; go 1.11
github.com/xdg-go/stringprep
-# github.com/xen0n/gosmopolitan v1.2.1
+# github.com/xen0n/gosmopolitan v1.2.2
## explicit; go 1.19
github.com/xen0n/gosmopolitan
# github.com/yagipy/maintidx v1.0.0
@@ -2000,9 +2019,12 @@ github.com/youmark/pkcs8
# github.com/zeebo/errs v1.3.0
## explicit; go 1.12
github.com/zeebo/errs
-# gitlab.com/bosi/decorder v0.4.0
-## explicit; go 1.17
+# gitlab.com/bosi/decorder v0.4.1
+## explicit; go 1.20
gitlab.com/bosi/decorder
+# go-simpler.org/sloglint v0.1.2
+## explicit; go 1.20
+go-simpler.org/sloglint
# go.mongodb.org/mongo-driver v1.12.0
## explicit; go 1.13
go.mongodb.org/mongo-driver/bson
@@ -2273,10 +2295,11 @@ golang.org/x/text/width
# golang.org/x/time v0.3.0
## explicit
golang.org/x/time/rate
-# golang.org/x/tools v0.13.0
+# golang.org/x/tools v0.14.0
## explicit; go 1.18
golang.org/x/tools/cmd/stringer
golang.org/x/tools/go/analysis
+golang.org/x/tools/go/analysis/passes/appends
golang.org/x/tools/go/analysis/passes/asmdecl
golang.org/x/tools/go/analysis/passes/assign
golang.org/x/tools/go/analysis/passes/atomic
@@ -2409,7 +2432,7 @@ google.golang.org/genproto/googleapis/api/httpbody
google.golang.org/genproto/googleapis/rpc/code
google.golang.org/genproto/googleapis/rpc/errdetails
google.golang.org/genproto/googleapis/rpc/status
-# google.golang.org/grpc v1.58.3
+# google.golang.org/grpc v1.59.0
## explicit; go 1.19
google.golang.org/grpc
google.golang.org/grpc/attributes
@@ -2469,6 +2492,7 @@ google.golang.org/grpc/keepalive
google.golang.org/grpc/metadata
google.golang.org/grpc/peer
google.golang.org/grpc/resolver
+google.golang.org/grpc/resolver/manual
google.golang.org/grpc/serviceconfig
google.golang.org/grpc/stats
google.golang.org/grpc/status
@@ -2616,7 +2640,7 @@ gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.1
## explicit
gopkg.in/yaml.v3
-# honnef.co/go/tools v0.4.5
+# honnef.co/go/tools v0.4.6
## explicit; go 1.19
honnef.co/go/tools/analysis/code
honnef.co/go/tools/analysis/edit