diff --git a/tools/go.mod b/tools/go.mod index 5ff2ec76..aa53e0ad 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/axw/gocov v1.1.0 - github.com/golangci/golangci-lint v1.49.0 + github.com/golangci/golangci-lint v1.50.0 github.com/goreleaser/goreleaser v1.11.4 github.com/matm/gocov-html v0.0.0-20200509184451-71874e2e203b github.com/mattn/goveralls v0.0.11 @@ -21,6 +21,7 @@ require ( cloud.google.com/go/kms v1.4.0 // indirect cloud.google.com/go/storage v1.22.1 // indirect code.gitea.io/sdk/gitea v0.15.1 // indirect + github.com/Abirdcfly/dupword v0.0.7 // indirect github.com/AlekSi/pointer v1.2.0 // indirect github.com/Antonboom/errname v0.1.7 // indirect github.com/Antonboom/nilnil v0.1.1 // indirect @@ -45,7 +46,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Microsoft/go-winio v0.5.1 // indirect - github.com/OpenPeeDeeP/depguard v1.1.0 // indirect + github.com/OpenPeeDeeP/depguard v1.1.1 // indirect github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect @@ -93,8 +94,8 @@ require ( github.com/charmbracelet/lipgloss v0.6.1-0.20220911181249-6304a734e792 // indirect github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/curioswitch/go-reassign v0.1.2 // indirect - github.com/daixiang0/gci v0.6.3 // indirect + github.com/curioswitch/go-reassign v0.2.0 // indirect + github.com/daixiang0/gci v0.8.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb // indirect @@ -113,14 +114,14 @@ require ( github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/go-critic/go-critic v0.6.4 // indirect + github.com/go-critic/go-critic v0.6.5 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.3.1 // indirect github.com/go-git/go-git/v5 v5.4.2 // indirect github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect github.com/go-toolsmith/astcast v1.0.0 // indirect - github.com/go-toolsmith/astcopy v1.0.1 // indirect - github.com/go-toolsmith/astequal v1.0.2 // indirect + github.com/go-toolsmith/astcopy v1.0.2 // indirect + github.com/go-toolsmith/astequal v1.0.3 // indirect github.com/go-toolsmith/astfmt v1.0.0 // indirect github.com/go-toolsmith/astp v1.0.0 // indirect github.com/go-toolsmith/strparse v1.0.0 // indirect @@ -134,13 +135,13 @@ 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-20190930125516-244bba706f1a // indirect + github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // 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.3.5 // indirect github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-github/v47 v47.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e // indirect @@ -180,6 +181,7 @@ require ( github.com/kevinburke/ssh_config v1.1.0 // indirect github.com/kisielk/errcheck v1.6.2 // indirect github.com/kisielk/gotool v1.0.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.2 // indirect github.com/klauspost/compress v1.15.1 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/kulti/thelper v0.6.3 // indirect @@ -191,6 +193,7 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect + github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.0 // indirect github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -199,7 +202,7 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mgechev/revive v1.2.3 // indirect + github.com/mgechev/revive v1.2.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -213,22 +216,22 @@ require ( github.com/muesli/termenv v0.12.1-0.20220901123159-d729275e0977 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect - github.com/nishanths/exhaustive v0.8.1 // indirect + github.com/nishanths/exhaustive v0.8.3 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/obalunenko/version v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/polyfloyd/go-errorlint v1.0.2 // indirect + github.com/polyfloyd/go-errorlint v1.0.5 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/quasilyte/go-ruleguard v0.3.17 // indirect - github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect + github.com/quasilyte/go-ruleguard v0.3.18 // indirect + github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/rivo/uniseg v0.4.2 // indirect @@ -238,7 +241,7 @@ require ( github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.13.0 // indirect + github.com/sashamelentyev/usestdlibvars v1.20.0 // indirect github.com/securego/gosec/v2 v2.13.1 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect @@ -254,18 +257,17 @@ require ( github.com/spf13/cobra v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect + github.com/spf13/viper v1.13.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect github.com/stretchr/objx v0.4.0 // indirect github.com/stretchr/testify v1.8.0 // indirect - github.com/subosito/gotenv v1.4.0 // indirect - github.com/sylvia7788/contextcheck v1.0.6 // indirect + github.com/subosito/gotenv v1.4.1 // indirect github.com/tdakkota/asciicheck v0.1.1 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tetafro/godot v1.4.11 // indirect github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect - github.com/timonwong/logrlint v0.1.0 // indirect + github.com/timonwong/loggercheck v0.9.3 // indirect github.com/tomarrell/wrapcheck/v2 v2.6.2 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect github.com/ulikunitz/xz v0.5.10 // indirect @@ -286,12 +288,12 @@ require ( gocloud.dev v0.26.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d // indirect + golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 // indirect + golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect @@ -302,13 +304,13 @@ require ( google.golang.org/grpc v1.47.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/ini.v1 v1.66.6 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect 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.3.3 // indirect - mvdan.cc/gofumpt v0.3.1 // indirect + mvdan.cc/gofumpt v0.4.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect diff --git a/tools/go.sum b/tools/go.sum index 204fcc26..c667386c 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -85,6 +85,8 @@ contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Abirdcfly/dupword v0.0.7 h1:z14n0yytA3wNO2gpCD/jVtp/acEXPGmYu0esewpBt6Q= +github.com/Abirdcfly/dupword v0.0.7/go.mod h1:K/4M1kj+Zh39d2aotRwypvasonOyAMH1c/IZJzE0dmk= github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwkako= @@ -162,8 +164,8 @@ github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpz github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.1.0 h1:pjK9nLPS1FwQYGGpPxoMYpe7qACHOhAWQMQzV71i49o= -github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA= +github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 h1:XcF0cTDJeiuZ5NU8w7WUDge0HRwwNRmxj/GGk6KSA6g= github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= @@ -312,11 +314,11 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cristalhq/acmd v0.7.0/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= -github.com/curioswitch/go-reassign v0.1.2 h1:ekM07+z+VFT560Exz4mTv0/s1yU9gem6CJc/tlYpkmI= -github.com/curioswitch/go-reassign v0.1.2/go.mod h1:bFJIHgtTM3hRm2sKXSPkbwNjSFyGURQXyn4IXD2qwfQ= -github.com/daixiang0/gci v0.6.3 h1:wUAqXChk8HbwXn8AfxD9DYSCp9Bpz1L3e6Q4Roe+q9E= -github.com/daixiang0/gci v0.6.3/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= +github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/daixiang0/gci v0.8.0 h1:DzWYUm4+bc+taVUtuq1tsIMb/QFMMYgDIiykSoO98ZU= +github.com/daixiang0/gci v0.8.0/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -379,8 +381,8 @@ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwv github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-critic/go-critic v0.6.4 h1:tucuG1pvOyYgpBIrVxw0R6gwO42lNa92Aq3VaDoIs+E= -github.com/go-critic/go-critic v0.6.4/go.mod h1:qL5SOlk7NtY6sJPoVCTKDIgzNOxHkkkOCVDyi9wJe1U= +github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo= +github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= @@ -414,13 +416,12 @@ github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astcopy v1.0.1 h1:l09oBhAPyV74kLJ3ZO31iBU8htZGTwr9LTjuMCyL8go= -github.com/go-toolsmith/astcopy v1.0.1/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= +github.com/go-toolsmith/astcopy v1.0.2 h1:YnWf5Rnh1hUudj11kei53kI57quN/VH6Hp1n+erozn0= +github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= -github.com/go-toolsmith/astequal v1.0.2 h1:+XvaV8zNxua+9+Oa4AHmgmpo4RYAbwr/qjNppLfX2yM= github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.0.3 h1:+LVdyRatFS+XO78SGV4I3TCEA0AC7fKEGma+fH+674o= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k= github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= @@ -488,10 +489,10 @@ 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-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.49.0 h1:I8WHOavragDttlLHtSraHn/h39C+R60bEQ5NoGcHQr8= -github.com/golangci/golangci-lint v1.49.0/go.mod h1:+V/7lLv449R6w9mQ3WdV0EKh7Je/jTylMeSwBZcLeWE= +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.50.0 h1:+Xmyt8rKLauNLp2gzcxKMN8VNGqGc5Avc2ZLTwIOpEA= +github.com/golangci/golangci-lint v1.50.0/go.mod h1:UqtDvK24R9OizqRF06foPX8opRMzQB0HQK90uI2JgKc= 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= @@ -517,8 +518,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v47 v47.0.0 h1:eQap5bIRZibukP0VhngWgpuM0zhY4xntqOzn6DhdkE4= github.com/google/go-github/v47 v47.0.0/go.mod h1:DRjdvizXE876j0YOZwInB1ESpOcU/xFBClNiQLSdorE= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -719,6 +721,8 @@ github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7 github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.2 h1:BYUSG/GhMhqVz//yjl8IkBDlMEws+9DtCmkz18QO1gg= +github.com/kkHAIKE/contextcheck v1.1.2/go.mod h1:PG/cwd6c0705/LM0KTr1acO2gORUxkSVWyLJOFW5qoo= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= @@ -763,6 +767,8 @@ github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCE github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= github.com/maratori/testpackage v1.1.0 h1:GJY4wlzQhuBusMF1oahQCBtUV/AQ/k69IZ68vxaac2Q= github.com/maratori/testpackage v1.1.0/go.mod h1:PeAhzU8qkCwdGEMTEupsHJNlQu2gZopMC6RjbhmHeDc= github.com/matm/gocov-html v0.0.0-20200509184451-71874e2e203b h1:5Wc/N1FIBnExmX0/SEdKe0A0COvdJc3rCGHQ7s1oBPQ= @@ -798,8 +804,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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.2.3 h1:NzIEEa9+WimQ6q2Ov7OcNeySS/IOcwtkQ8RAh0R5UJ4= -github.com/mgechev/revive v1.2.3/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q= +github.com/mgechev/revive v1.2.4 h1:+2Hd/S8oO2H0Ikq2+egtNwQsVhAeELHjxjIUFX5ajLI= +github.com/mgechev/revive v1.2.4/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -838,8 +844,8 @@ github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4N github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/exhaustive v0.8.1 h1:0QKNascWv9qIHY7zRoZSxeRr6kuk5aAT3YXLTiDmjTo= -github.com/nishanths/exhaustive v0.8.1/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= +github.com/nishanths/exhaustive v0.8.3 h1:pw5O09vwg8ZaditDp/nQRqVnrMczSJDxRDJMowvhsrM= +github.com/nishanths/exhaustive v0.8.3/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/obalunenko/coverbadger v1.2.0 h1:MI69h8POfZrnSpiC8BUS8f3fHYiznngCVbIpNAgVpCI= @@ -858,8 +864,8 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= @@ -870,8 +876,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.0.2 h1:kp1yvHflYhTmw5m3MmBy8SCyQkKPjwDthVuMH0ug6Yk= -github.com/polyfloyd/go-errorlint v1.0.2/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI= +github.com/polyfloyd/go-errorlint v1.0.5 h1:AHB5JRCjlmelh9RrLxT9sgzpalIwwq4hqE8EkwIwKdY= +github.com/polyfloyd/go-errorlint v1.0.5/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -895,14 +901,14 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.17 h1:cDdoaSbQg11LXPDQqiCK54QmQXsEQQCTIgdcpeULGSI= -github.com/quasilyte/go-ruleguard v0.3.17/go.mod h1:sST5PvaR7yb/Az5ksX8oc88usJ4EGjmJv7cK7y3jyig= +github.com/quasilyte/go-ruleguard v0.3.18 h1:sd+abO1PEI9fkYennwzHn9kl3nqP6M5vE7FiOzZ+5CE= +github.com/quasilyte/go-ruleguard v0.3.18/go.mod h1:lOIzcYlgxrQ2sGJ735EHXmf/e9MJ516j16K/Ifcttvs= github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= -github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 h1:PDWGei+Rf2bBiuZIbZmM20J2ftEy9IeUCHA8HbQqed8= -github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= +github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f h1:6Gtn2i04RD0gVyYf2/IUMTIs+qYleBt4zxDqkLTcu4U= +github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= @@ -913,7 +919,7 @@ github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -929,8 +935,8 @@ github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b h1:qYTY2tN72LhgDj github.com/sasha-s/go-csync v0.0.0-20210812194225-61421b77c44b/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.13.0 h1:uObNudVEEHf6JbOJy5bgKJloA1bWjxR9fwgNFpPzKnI= -github.com/sashamelentyev/usestdlibvars v1.13.0/go.mod h1:D2Wb7niIYmTB+gB8z7kh8tyP5ccof1dQ+SFk+WW5NtY= +github.com/sashamelentyev/usestdlibvars v1.20.0 h1:K6CXjqqtSYSsuyRDDC7Sjn6vTMLiSJa4ZmDkiokoqtw= +github.com/sashamelentyev/usestdlibvars v1.20.0/go.mod h1:0GaP+ecfZMXShS0A94CJn6aEuPRILv8h/VuWI9n1ygg= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/securego/gosec/v2 v2.13.1 h1:7mU32qn2dyC81MH9L2kefnQyRMUarfDER3iQyMHcjYM= github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo= @@ -976,8 +982,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= @@ -996,13 +1002,10 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= -github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= -github.com/sylvia7788/contextcheck v1.0.6 h1:o2EZgVPyMKE/Mtoqym61DInKEjwEbsmyoxg3VrmjNO4= -github.com/sylvia7788/contextcheck v1.0.6/go.mod h1:9XDxwvxyuKD+8N+a7Gs7bfWLityh5t70g/GjdEt2N2M= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= @@ -1015,8 +1018,8 @@ github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/timonwong/logrlint v0.1.0 h1:phZCcypL/vtx6cGxObJgWZ5wexZF5SXFPLOM+ru0e/M= -github.com/timonwong/logrlint v0.1.0/go.mod h1:Zleg4Gw+kRxNej+Ra7o+tEaW5k1qthTaYKU7rSD39LU= +github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI= +github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= github.com/tomarrell/wrapcheck/v2 v2.6.2 h1:3dI6YNcrJTQ/CJQ6M/DUkc0gnqYSIk6o0rChn9E/D0M= github.com/tomarrell/wrapcheck/v2 v2.6.2/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= github.com/tommy-muehle/go-mnd/v2 v2.5.0 h1:iAj0a8e6+dXSL7Liq0aXPox36FiN1dBbjA6lt9fl65s= @@ -1123,8 +1126,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic= -golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk= +golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1247,8 +1250,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1341,8 +1345,9 @@ golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1677,8 +1682,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= @@ -1710,8 +1715,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= -mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8= -mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= +mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= +mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= diff --git a/tools/vendor/github.com/Abirdcfly/dupword/.gitignore b/tools/vendor/github.com/Abirdcfly/dupword/.gitignore new file mode 100644 index 00000000..b5109d2b --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/.gitignore @@ -0,0 +1,183 @@ + +# Godot-specific ignores +.import/ +export.cfg +export_presets.cfg + +# Mono-specific ignores +.mono/ +data_*/ + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +.idea/artifacts +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Emacs template +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Vim template +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + diff --git a/tools/vendor/github.com/Abirdcfly/dupword/.goreleaser.yml b/tools/vendor/github.com/Abirdcfly/dupword/.goreleaser.yml new file mode 100644 index 00000000..c3401787 --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/.goreleaser.yml @@ -0,0 +1,72 @@ +--- +project_name: dupword + +release: + github: + owner: Abirdcfly + name: dupword + +builds: + - binary: dupword + goos: + - darwin + - windows + - linux + - freebsd + goarch: + - amd64 + - arm64 + - arm + - 386 + - ppc64le + - s390x + - mips64 + - mips64le + - riscv64 + goarm: + - 6 + - 7 + gomips: + - hardfloat + env: + - CGO_ENABLED=0 + ignore: + - goos: darwin + goarch: 386 + - goos: freebsd + goarch: arm64 + main: ./cmd/dupword/ + flags: + - -trimpath + ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{.Date}} + +archives: + - format: tar.gz + wrap_in_directory: true + format_overrides: + - goos: windows + format: zip + name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + files: + - LICENSE + - README.md + +snapshot: + name_template: SNAPSHOT-{{ .Commit }} + +checksum: + name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt' + +changelog: + sort: asc + filters: + exclude: + - '(?i)^docs?:' + - '(?i)^docs\([^:]+\):' + - '(?i)^docs\[[^:]+\]:' + - '^tests?:' + - '(?i)^dev:' + - '^build\(deps\): bump .* in /docs \(#\d+\)' + - '^build\(deps\): bump .* in /\.github/peril \(#\d+\)' + - Merge pull request + - Merge branch diff --git a/tools/vendor/github.com/Abirdcfly/dupword/LICENSE b/tools/vendor/github.com/Abirdcfly/dupword/LICENSE new file mode 100644 index 00000000..afa64c6e --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Abirdcfly + +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/tools/vendor/github.com/Abirdcfly/dupword/README.md b/tools/vendor/github.com/Abirdcfly/dupword/README.md new file mode 100644 index 00000000..f12c53e2 --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/README.md @@ -0,0 +1,151 @@ +# dupword + +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/Abirdcfly/dupword?style=flat-square) +[![GoDoc](https://godoc.org/github.com/Abirdcfly/dupword?status.svg)](https://pkg.go.dev/github.com/Abirdcfly/dupword) +[![Actions Status](https://github.com/Abirdcfly/dupword/actions/workflows/lint.yml/badge.svg)](https://github.com/Abirdcfly/dupword/actions) +[![Go Report Card](https://goreportcard.com/badge/github.com/Abirdcfly/dupword)](https://goreportcard.com/report/github.com/Abirdcfly/dupword) + +A linter that checks for duplicate words in the source code (usually miswritten) + +Examples in real code and related issues can be viewed in [dupword#3](https://github.com/Abirdcfly/dupword/issues/3) + +## example + +1. Repeated words appear on two adjacent lines [commit](https://github.com/golang/go/commit/d8f90ce0f8119bf593efb6fb91825de5b61fcda7) + +```diff +--- a/src/cmd/compile/internal/ssa/schedule.go ++++ b/src/cmd/compile/internal/ssa/schedule.go +@@ -179,7 +179,7 @@ func schedule(f *Func) { + // scored CarryChainTail (and prove w is not a tail). + score[w.ID] = ScoreFlags + } +- // Verify v has not been scored. If v has not been visited, v may be the ++ // Verify v has not been scored. If v has not been visited, v may be + // the final (tail) operation in a carry chain. If v is not, v will be + // rescored above when v's carry-using op is scored. When scoring is done, + // only tail operations will retain the CarryChainTail score. +``` + +2. Repeated words appearing on the same line [commit](https://github.com/golang/go/commit/48da729e8468b630ee003ac51cbaac595d53bec8) + +```diff +--- a/src/net/http/cookiejar/jar.go ++++ b/src/net/http/cookiejar/jar.go +@@ -465,7 +465,7 @@ func (j *Jar) domainAndType(host, domain string) (string, bool, error) { + // dot in the domain-attribute before processing the cookie. + // + // Most browsers don't do that for IP addresses, only curl +- // version 7.54) and and IE (version 11) do not reject a ++ // version 7.54) and IE (version 11) do not reject a + // Set-Cookie: a=1; domain=.127.0.0.1 + // This leading dot is optional and serves only as hint for + // humans to indicate that a cookie with "domain=.bbc.co.uk" +``` + +## Install + +```bash +go install github.com/Abirdcfly/dupword/cmd/dupword@latest +``` + +**Or** install the main branch (including the last commit) with: + +```bash +go install github.com/Abirdcfly/dupword/cmd/dupword@main +``` + +## Usage + +### 1. default + +Run with default settings(include test file): + +**But note that not all repeated words are wrong** see [dupword#4](https://github.com/Abirdcfly/dupword/issues/4) for real code example. + +```bash +$ dupword ./... +/Users/xxx/go/src/dupword/dupword_test.go:88:10: Duplicate words (the) found +exit status 3 +``` + +### 2. skip test file + +Skip detection test file(`*_test.go`): + +```bash +$ dupword -test=false ./... +``` + +### 3. auto-fix + +```bash +$ dupword -fix ./... +``` + +### 4. all options + +All options: + +```bash +$ dupword --help +dupword: checks for duplicate words in the source code (usually miswritten) + +Usage: dupword [-flag] [package] + +This analyzer checks miswritten duplicate words in comments or package doc or string declaration + +Flags: + -V print version and exit + -all + no effect (deprecated) + -c int + display offending line with this many lines of context (default -1) + -cpuprofile string + write CPU profile to this file + -debug string + debug flags, any subset of "fpstv" + -fix + apply all suggested fixes + -flags + print analyzer flags in JSON + -json + emit JSON output + -keyword value + key words for detecting duplicate words + -memprofile string + write memory profile to this file + -source + no effect (deprecated) + -tags string + no effect (deprecated) + -test + indicates whether test files should be analyzed, too (default true) + -trace string + write trace log to this file + -v no effect (deprecated) +``` + +### 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. + +see [dupword#4](https://github.com/Abirdcfly/dupword/issues/4) for real code example. + +```bash +$ dupword --keyword=the,and,a -fix ./... +``` + +## TODO + +- [ ] add this linter to golangci-lint +- [ ] rewrite the detection logic to make it more efficient + +## Limitation + +1. Only for `*.go` file.But some miswritten occurs in `*.md` or `*.json` file.(example: kubernetes), In this case, my advice is to use [rg](https://github.com/BurntSushi/ripgrep) to do the lookup and replace manually. +2. When use `-fix`, also running `go fmt` in the dark.([This logic is determined upstream](https://github.com/golang/tools/blob/248c34b88a4148128f89e41923498bd86f805b7d/go/analysis/internal/checker/checker.go#L424-L433), the project does not have this part of the code.) + +## License + +MIT diff --git a/tools/vendor/github.com/Abirdcfly/dupword/dupword.go b/tools/vendor/github.com/Abirdcfly/dupword/dupword.go new file mode 100644 index 00000000..7b8eb712 --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/dupword.go @@ -0,0 +1,299 @@ +// MIT License +// +// Copyright (c) 2022 Abirdcfly +// +// 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. + +// Package dupword defines an Analyzer that checks that duplicate words +// int the source code. +package dupword + +import ( + "flag" + "fmt" + "go/ast" + "go/token" + "sort" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +const ( + Name = "dupword" + Doc = `checks for duplicate words in the source code (usually miswritten) + +This analyzer checks miswritten duplicate words in comments or package doc or string declaration` + Message = "Duplicate words (%s) found" + CommentPrefix = `//` +) + +var ( + defaultWord = []string{} + // defaultWord = []string{"the", "and", "a"} +) + +type analyzer struct { + KeyWord []string +} + +func (a *analyzer) String() string { + return strings.Join(a.KeyWord, ",") +} + +func (a *analyzer) Set(w string) error { + if len(w) != 0 { + a.KeyWord = make([]string, 0) + a.KeyWord = append(a.KeyWord, strings.Split(w, ",")...) + } + return nil +} + +func NewAnalyzer() *analysis.Analyzer { + analyzer := &analyzer{KeyWord: defaultWord} + a := &analysis.Analyzer{ + Name: Name, + Doc: Doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: analyzer.run, + RunDespiteErrors: true, + } + a.Flags.Init(Name, flag.ExitOnError) + a.Flags.Var(analyzer, "keyword", "key words for detecting duplicate words") + a.Flags.Var(version{}, "V", "print version and exit") + return a +} + +func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { + for _, file := range pass.Files { + a.fixDuplicateWordInComment(pass, file) + } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.BasicLit)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + if lit, ok := n.(*ast.BasicLit); ok { + a.fixDuplicateWordInString(pass, lit) + } + }) + return nil, nil +} + +func (a *analyzer) fixDuplicateWordInComment(pass *analysis.Pass, f *ast.File) { + for _, cg := range f.Comments { + var preLine *ast.Comment + for _, c := range cg.List { + update, keyword, find := a.Check(c.Text) + if find { + pass.Report(analysis.Diagnostic{Pos: c.Slash, End: c.End(), Message: fmt.Sprintf(Message, keyword), SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Update", + TextEdits: []analysis.TextEdit{{ + Pos: c.Slash, + End: c.End(), + NewText: []byte(update), + }}, + }}}) + } + if preLine != nil { + fields := strings.Fields(preLine.Text) + if len(fields) < 1 { + continue + } + preLineContent := fields[len(fields)-1] + "\n" + thisLineContent := c.Text + if find { + thisLineContent = update + } + before, after, _ := strings.Cut(thisLineContent, CommentPrefix) + update, keyword, find := a.Check(preLineContent + after) + if find { + var suggestedFixes []analysis.SuggestedFix + if strings.Contains(update, preLineContent) { + update = before + CommentPrefix + strings.TrimPrefix(update, preLineContent) + suggestedFixes = []analysis.SuggestedFix{{ + Message: "Update", + TextEdits: []analysis.TextEdit{{ + Pos: c.Slash, + End: c.End(), + NewText: []byte(update), + }}, + }} + } + pass.Report(analysis.Diagnostic{Pos: c.Slash, End: c.End(), Message: fmt.Sprintf(Message, keyword), SuggestedFixes: suggestedFixes}) + } + } + preLine = c + } + } +} + +func (a *analyzer) fixDuplicateWordInString(pass *analysis.Pass, lit *ast.BasicLit) { + if lit.Kind != token.STRING { + return + } + value, err := strconv.Unquote(lit.Value) + if err != nil { + fmt.Printf("lit.Value:%v, err: %v\n", lit.Value, err) + // fall back to default + value = lit.Value + } + quote := value != lit.Value + update, keyword, find := a.Check(value) + if quote { + update = strconv.Quote(update) + } + if find { + pass.Report(analysis.Diagnostic{Pos: lit.Pos(), End: lit.End(), Message: fmt.Sprintf(Message, keyword), SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Update", + TextEdits: []analysis.TextEdit{{ + Pos: lit.Pos(), + End: lit.End(), + NewText: []byte(update), + }}, + }}}) + } +} + +// CheckOneKey use to check there is 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 == "" { + has := false + fields := strings.Fields(raw) + for i := range fields { + if i == len(fields)-1 { + break + } + if fields[i] == fields[i+1] { + has = true + } + } + if !has { + return + } + } else { + if x := strings.Split(raw, key); len(x) < 2 { + return + } + } + + findWordMap := make(map[string]bool, 4) + newLine := strings.Builder{} + wordStart, spaceStart := 0, 0 + curWord, preWord := "", "" + lastSpace := "" + var lastRune int32 + for i, r := range raw { + if !unicode.IsSpace(r) && unicode.IsSpace(lastRune) { + // word start position + /* + i + | + hello[ spaceA ]the[ spaceB ]the[ spaceC ]word + ^ ^ + | curWord: the + preWord: the + */ + symbol := raw[spaceStart:i] + if ((key != "" && curWord == key) || key == "") && curWord == preWord && curWord != "" { + if !ExcludeWords(curWord) { + find = true + findWordMap[curWord] = true + newLine.WriteString(lastSpace) + symbol = "" + } + } else { + newLine.WriteString(lastSpace) + newLine.WriteString(curWord) + } + lastSpace = symbol + preWord = curWord + wordStart = i + } else if unicode.IsSpace(r) && !unicode.IsSpace(lastRune) { + // space start position + spaceStart = i + curWord = raw[wordStart:i] + } else if i == len(raw)-1 { + // last position + word := raw[wordStart:] + if ((key != "" && word == key) || key == "") && word == preWord { + if !ExcludeWords(word) { + find = true + findWordMap[word] = true + } + } else { + newLine.WriteString(lastSpace) + newLine.WriteString(word) + } + } + lastRune = r + } + if find { + new = newLine.String() + findWordSlice := make([]string, len(findWordMap)) + i := 0 + for k := range findWordMap { + findWordSlice[i] = k + i++ + } + sort.Strings(findWordSlice) + findWord = strings.Join(findWordSlice, ",") + } + return +} + +func (a *analyzer) Check(raw string) (update string, keyword string, find bool) { + for _, key := range a.KeyWord { + updateOne, _, findOne := CheckOneKey(raw, key) + if findOne { + raw = updateOne + find = findOne + update = updateOne + if keyword == "" { + keyword = key + } else { + keyword = keyword + "," + key + } + } + } + if len(a.KeyWord) == 0 { + return CheckOneKey(raw, "") + } + return +} + +// ExcludeWords determines whether duplicate words should be reported, +// +// e.g. %s, should not be reported. +func ExcludeWords(word string) (exclude bool) { + firstRune, _ := utf8.DecodeRuneInString(word) + if unicode.IsPunct(firstRune) { + return true + } + if unicode.IsSymbol(firstRune) { + return true + } + return false +} diff --git a/tools/vendor/github.com/Abirdcfly/dupword/version.go b/tools/vendor/github.com/Abirdcfly/dupword/version.go new file mode 100644 index 00000000..9d892d0c --- /dev/null +++ b/tools/vendor/github.com/Abirdcfly/dupword/version.go @@ -0,0 +1,41 @@ +// MIT License +// +// # Copyright (c) 2022 Abirdcfly +// +// 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. + +package dupword + +import ( + "fmt" + "os" +) + +var Version = "dev" + +type version struct{} + +func (version) IsBoolFlag() bool { return true } +func (version) Get() interface{} { return nil } +func (version) String() string { return "" } +func (version) Set(_ string) error { + fmt.Println(Version) + os.Exit(0) + return nil +} diff --git a/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md b/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md index b9422757..07e9f915 100644 --- a/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md +++ b/tools/vendor/github.com/OpenPeeDeeP/depguard/README.md @@ -79,7 +79,7 @@ Like the `packages` field, the `ignoreFileRules` field can accept both string pr ## Gometalinter The binary installation of this linter can be used with -[Gometalinter](github.com/alecthomas/gometalinter). +[Gometalinter](https://github.com/alecthomas/gometalinter). If you use a configuration file for Gometalinter then the following will need to be added to your configuration file. diff --git a/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go b/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go index b7275491..d7011cd9 100644 --- a/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go +++ b/tools/vendor/github.com/OpenPeeDeeP/depguard/depguard.go @@ -7,6 +7,7 @@ import ( "path" "sort" "strings" + "sync" "github.com/gobwas/glob" "golang.org/x/tools/go/loader" @@ -61,6 +62,9 @@ type Depguard struct { globIgnoreFileRules []negatableGlob prefixRoot []string + + isInitialized bool + isInitializedMutex sync.Mutex } // Run checks for dependencies given the program and validates them against @@ -102,6 +106,13 @@ func (dg *Depguard) Run(config *loader.Config, prog *loader.Program) ([]*Issue, } func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) error { + dg.isInitializedMutex.Lock() + defer dg.isInitializedMutex.Unlock() + + if dg.isInitialized { + return nil + } + // parse ordinary guarded packages for _, pkg := range dg.Packages { if strings.ContainsAny(pkg, "!?*[]{}") { @@ -168,6 +179,7 @@ func (dg *Depguard) initialize(config *loader.Config, prog *loader.Program) erro } } + dg.isInitialized = true return nil } diff --git a/tools/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go b/tools/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go index c4d5fd8c..e1b47d5b 100644 --- a/tools/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go +++ b/tools/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go @@ -3,20 +3,22 @@ package analyzer import ( "fmt" "go/ast" + "go/types" "regexp" - "strconv" - "strings" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" ) const FlagPattern = "pattern" func New() *analysis.Analyzer { a := &analysis.Analyzer{ - Name: "reassign", - Doc: "Checks that package variables are not reassigned", - Run: run, + Name: "reassign", + Doc: "Checks that package variables are not reassigned", + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, } a.Flags.String(FlagPattern, `^(Err.*|EOF)$`, "Pattern to match package variables against to prevent reassignment") return a @@ -27,60 +29,56 @@ func run(pass *analysis.Pass) (interface{}, error) { if err != nil { return nil, fmt.Errorf("invalid pattern: %w", err) } - for _, f := range pass.Files { - state := &fileState{imports: make(map[string]struct{})} - ast.Inspect(f, func(node ast.Node) bool { - return inspect(pass, node, checkRE, state) - }) - } + + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + inspect.Preorder([]ast.Node{(*ast.AssignStmt)(nil), (*ast.UnaryExpr)(nil)}, func(node ast.Node) { + switch node := node.(type) { + case *ast.AssignStmt: + for _, lhs := range node.Lhs { + reportImported(pass, lhs, checkRE, "reassigning") + } + default: + // TODO(chokoswitch): Consider handling operations other than assignment on globals, for example + // taking their address. + } + }) return nil, nil } -type fileState struct { - imports map[string]struct{} -} +func reportImported(pass *analysis.Pass, expr ast.Expr, checkRE *regexp.Regexp, prefix string) { + switch x := expr.(type) { + case *ast.SelectorExpr: + if !checkRE.MatchString(x.Sel.Name) { + return + } -func inspect(pass *analysis.Pass, node ast.Node, checkRE *regexp.Regexp, state *fileState) bool { - if importSpec, ok := node.(*ast.ImportSpec); ok { - if importSpec.Name != nil { - state.imports[importSpec.Name.Name] = struct{}{} - } else { - n, err := strconv.Unquote(importSpec.Path.Value) - if err != nil { - return true - } - if idx := strings.LastIndexByte(n, '/'); idx != -1 { - n = n[idx+1:] + selectIdent, ok := x.X.(*ast.Ident) + if !ok { + return + } + + if selectObj, ok := pass.TypesInfo.Uses[selectIdent]; ok { + if pkg, ok := selectObj.(*types.PkgName); !ok || pkg.Imported() == pass.Pkg { + return } - state.imports[n] = struct{}{} } - return true - } - assignStmt, ok := node.(*ast.AssignStmt) - if !ok { - return true - } + pass.Reportf(expr.Pos(), "%s variable %s in other package %s", prefix, x.Sel.Name, selectIdent.Name) - for _, lhs := range assignStmt.Lhs { - selector, ok := lhs.(*ast.SelectorExpr) + case *ast.Ident: + use, ok := pass.TypesInfo.Uses[x].(*types.Var) if !ok { - return true + return } - if !checkRE.MatchString(selector.Sel.Name) { - return true + if use.Pkg() == pass.Pkg { + return } - selectIdent, ok := selector.X.(*ast.Ident) - if !ok { - return true + if !checkRE.MatchString(x.Name) { + return } - if _, ok := state.imports[selectIdent.Name]; ok { - pass.Reportf(node.Pos(), "reassigning variable %s in other package %s", selector.Sel.Name, selectIdent.Name) - } + pass.Reportf(expr.Pos(), "%s variable %s from other package %s", prefix, x.Name, use.Pkg().Path()) } - - return true } diff --git a/tools/vendor/github.com/daixiang0/gci/pkg/gci/gci.go b/tools/vendor/github.com/daixiang0/gci/pkg/gci/gci.go index a8a64a27..2980e7d7 100644 --- a/tools/vendor/github.com/daixiang0/gci/pkg/gci/gci.go +++ b/tools/vendor/github.com/daixiang0/gci/pkg/gci/gci.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + goFormat "go/format" "os" "sync" @@ -129,7 +130,7 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err } // do not do format if only one import - if len(imports) == 1 { + if len(imports) <= 1 { return src, src, nil } @@ -138,8 +139,22 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err return nil, nil, err } - head := src[:headEnd] + var head []byte + if src[headEnd-1] == '\t' { + head = src[:headEnd] + } else { + // handle multiple import blocks + // cover `import ` to `import (` + head = make([]byte, headEnd) + copy(head, src[:headEnd]) + head = append(head, []byte{40, 10, 9}...) + } + tail := src[tailStart:] + // for test + if len(tail) == 0 { + tail = []byte(")\n") + } firstWithIndex := true @@ -158,11 +173,6 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err } } - // remove breakline in the end - for body[len(body)-1] == utils.Linebreak { - body = body[:len(body)-1] - } - if tail[0] != utils.Linebreak { body = append(body, utils.Linebreak) } @@ -178,6 +188,11 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err i += copy(dist[i:], s) } + dist, err = goFormat.Source(dist) + if err != nil { + return nil, nil, err + } + return src, dist, nil } diff --git a/tools/vendor/github.com/daixiang0/gci/pkg/parse/parse.go b/tools/vendor/github.com/daixiang0/gci/pkg/parse/parse.go index d84ed133..df4cfdce 100644 --- a/tools/vendor/github.com/daixiang0/gci/pkg/parse/parse.go +++ b/tools/vendor/github.com/daixiang0/gci/pkg/parse/parse.go @@ -8,6 +8,8 @@ import ( "strings" ) +const C = "\"C\"" + type GciImports struct { // original index of import group, include doc, name, path and comment Start, End int @@ -79,14 +81,17 @@ func ParseFile(src []byte, filename string) (ImportList, int, int, error) { return nil, 0, 0, NoImportError{} } - var headEnd int - var tailStart int + var headEnd, tailStart int var data ImportList for i, imp := range f.Imports { + if imp.Path.Value == C { + continue + } + start, end, name := getImports(imp) - if i == 0 { + if headEnd == 0 { headEnd = start } if i == len(f.Imports)-1 { diff --git a/tools/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go b/tools/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go index b5d884d3..95c0d225 100644 --- a/tools/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go +++ b/tools/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go @@ -1,6 +1,6 @@ package section -// Code generated based on go1.18.4. DO NOT EDIT. +// Code generated based on go1.19.1. DO NOT EDIT. var standardPackages = map[string]struct{}{ "archive/tar": {}, @@ -67,6 +67,7 @@ var standardPackages = map[string]struct{}{ "go/build/constraint": {}, "go/constant": {}, "go/doc": {}, + "go/doc/comment": {}, "go/format": {}, "go/importer": {}, "go/parser": {}, diff --git a/tools/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go b/tools/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go index 8a53ee5e..b17178e0 100644 --- a/tools/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go +++ b/tools/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go @@ -15,7 +15,7 @@ import ( //go:generate go run ./rules/precompile.go -rules ./rules/rules.go -o ./rulesdata/rulesdata.go -func InitEmbeddedRules() { +func InitEmbeddedRules() error { filename := "rules/rules.go" fset := token.NewFileSet() @@ -44,7 +44,7 @@ func InitEmbeddedRules() { }, } if err := rootEngine.LoadFromIR(loadContext, filename, rulesdata.PrecompiledRules); err != nil { - panic(fmt.Sprintf("load embedded ruleguard rules: %v", err)) + return fmt.Errorf("load embedded ruleguard rules: %w", err) } groups = rootEngine.LoadedGroups() } @@ -87,6 +87,8 @@ func InitEmbeddedRules() { return c, nil }) } + + return nil } type embeddedRuleguardChecker struct { diff --git a/tools/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go b/tools/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go index 9c198e73..bc9bdef4 100644 --- a/tools/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go +++ b/tools/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go @@ -97,7 +97,10 @@ func (w *typeExprWalker) walk(x ast.Node) bool { func (w *typeExprWalker) inspectInner(x ast.Expr) bool { parens, ok := x.(*ast.ParenExpr) - if ok && typep.IsTypeExpr(w.info, parens.X) && astp.IsStarExpr(parens.X) { + shouldInspect := ok && + typep.IsTypeExpr(w.info, parens.X) && + (astp.IsStarExpr(parens.X) || astp.IsFuncType(parens.X)) + if shouldInspect { ast.Inspect(parens.X, w.walk) return false } diff --git a/tools/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go b/tools/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go index fd63c9b1..b5dc5823 100644 --- a/tools/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go +++ b/tools/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go @@ -28,11 +28,30 @@ var PrecompiledRules = &ir.File{ ReportTemplate: "use $x.String() instead", SuggestTemplate: "$x.String()", WhereExpr: ir.FilterExpr{ - Line: 13, - Op: ir.FilterVarTypeImplementsOp, - Src: "m[\"x\"].Type.Implements(`fmt.Stringer`)", - Value: "x", - Args: []ir.FilterExpr{{Line: 13, Op: ir.FilterStringOp, Src: "`fmt.Stringer`", Value: "fmt.Stringer"}}, + Line: 13, + Op: ir.FilterAndOp, + Src: "!m[\"x\"].Type.Is(`reflect.Value`) && m[\"x\"].Type.Implements(`fmt.Stringer`)", + Args: []ir.FilterExpr{ + { + Line: 13, + Op: ir.FilterNotOp, + Src: "!m[\"x\"].Type.Is(`reflect.Value`)", + Args: []ir.FilterExpr{{ + Line: 13, + Op: ir.FilterVarTypeIsOp, + Src: "m[\"x\"].Type.Is(`reflect.Value`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 13, Op: ir.FilterStringOp, Src: "`reflect.Value`", Value: "reflect.Value"}}, + }}, + }, + { + Line: 13, + Op: ir.FilterVarTypeImplementsOp, + Src: "m[\"x\"].Type.Implements(`fmt.Stringer`)", + Value: "x", + Args: []ir.FilterExpr{{Line: 13, Op: ir.FilterStringOp, Src: "`fmt.Stringer`", Value: "fmt.Stringer"}}, + }, + }, }, }, { @@ -379,28 +398,26 @@ var PrecompiledRules = &ir.File{ {Line: 119, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, - LocationVar: "nil", }, { - Line: 124, - SyntaxPatterns: []ir.PatternString{{Line: 124, Value: "http.NewRequestWithContext($ctx, $method, $url, $nil)"}}, + Line: 123, + SyntaxPatterns: []ir.PatternString{{Line: 123, Value: "http.NewRequestWithContext($ctx, $method, $url, $nil)"}}, ReportTemplate: "http.NoBody should be preferred to the nil request body", SuggestTemplate: "http.NewRequestWithContext($ctx, $method, $url, http.NoBody)", WhereExpr: ir.FilterExpr{ - Line: 125, + Line: 124, Op: ir.FilterEqOp, Src: "m[\"nil\"].Text == \"nil\"", Args: []ir.FilterExpr{ - {Line: 125, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, - {Line: 125, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, + {Line: 124, Op: ir.FilterVarTextOp, Src: "m[\"nil\"].Text", Value: "nil"}, + {Line: 124, Op: ir.FilterStringOp, Src: "\"nil\"", Value: "nil"}, }, }, - LocationVar: "nil", }, }, }, { - Line: 136, + Line: 134, Name: "preferDecodeRune", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -409,20 +426,20 @@ var PrecompiledRules = &ir.File{ DocAfter: "r, _ := utf8.DecodeRuneInString(s)", DocNote: "See Go issue for details: https://github.com/golang/go/issues/45260", Rules: []ir.Rule{{ - Line: 137, - SyntaxPatterns: []ir.PatternString{{Line: 137, Value: "[]rune($s)[0]"}}, + Line: 135, + SyntaxPatterns: []ir.PatternString{{Line: 135, Value: "[]rune($s)[0]"}}, ReportTemplate: "consider replacing $$ with utf8.DecodeRuneInString($s)", WhereExpr: ir.FilterExpr{ - Line: 138, + Line: 136, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 138, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 136, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }}, }, { - Line: 146, + Line: 144, Name: "sloppyLen", MatcherName: "m", DocTags: []string{"style"}, @@ -431,24 +448,24 @@ var PrecompiledRules = &ir.File{ DocAfter: "len(arr) == 0", Rules: []ir.Rule{ { - Line: 147, - SyntaxPatterns: []ir.PatternString{{Line: 147, Value: "len($_) >= 0"}}, + Line: 145, + SyntaxPatterns: []ir.PatternString{{Line: 145, Value: "len($_) >= 0"}}, ReportTemplate: "$$ is always true", }, { - Line: 148, - SyntaxPatterns: []ir.PatternString{{Line: 148, Value: "len($_) < 0"}}, + Line: 146, + SyntaxPatterns: []ir.PatternString{{Line: 146, Value: "len($_) < 0"}}, ReportTemplate: "$$ is always false", }, { - Line: 149, - SyntaxPatterns: []ir.PatternString{{Line: 149, Value: "len($x) <= 0"}}, + Line: 147, + SyntaxPatterns: []ir.PatternString{{Line: 147, Value: "len($x) <= 0"}}, ReportTemplate: "$$ can be len($x) == 0", }, }, }, { - Line: 156, + Line: 154, Name: "valSwap", MatcherName: "m", DocTags: []string{"style"}, @@ -456,13 +473,13 @@ var PrecompiledRules = &ir.File{ DocBefore: "*tmp = *x; *x = *y; *y = *tmp", DocAfter: "*x, *y = *y, *x", Rules: []ir.Rule{{ - Line: 157, - SyntaxPatterns: []ir.PatternString{{Line: 157, Value: "$tmp := $y; $y = $x; $x = $tmp"}}, + Line: 155, + SyntaxPatterns: []ir.PatternString{{Line: 155, Value: "$tmp := $y; $y = $x; $x = $tmp"}}, ReportTemplate: "can re-write as `$y, $x = $x, $y`", }}, }, { - Line: 165, + Line: 163, Name: "switchTrue", MatcherName: "m", DocTags: []string{"style"}, @@ -471,19 +488,19 @@ var PrecompiledRules = &ir.File{ DocAfter: "switch {...}", Rules: []ir.Rule{ { - Line: 166, - SyntaxPatterns: []ir.PatternString{{Line: 166, Value: "switch true { $*_ }"}}, + Line: 164, + SyntaxPatterns: []ir.PatternString{{Line: 164, Value: "switch true { $*_ }"}}, ReportTemplate: "replace 'switch true {}' with 'switch {}'", }, { - Line: 168, - SyntaxPatterns: []ir.PatternString{{Line: 168, Value: "switch $x; true { $*_ }"}}, + Line: 166, + SyntaxPatterns: []ir.PatternString{{Line: 166, Value: "switch $x; true { $*_ }"}}, ReportTemplate: "replace 'switch $x; true {}' with 'switch $x; {}'", }, }, }, { - Line: 176, + Line: 174, Name: "flagDeref", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -492,49 +509,49 @@ var PrecompiledRules = &ir.File{ DocAfter: "var b bool; flag.BoolVar(&b, \"b\", false, \"b docs\")", Rules: []ir.Rule{ { - Line: 177, - SyntaxPatterns: []ir.PatternString{{Line: 177, Value: "*flag.Bool($*_)"}}, + Line: 175, + SyntaxPatterns: []ir.PatternString{{Line: 175, Value: "*flag.Bool($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.BoolVar", }, { - Line: 178, - SyntaxPatterns: []ir.PatternString{{Line: 178, Value: "*flag.Duration($*_)"}}, + Line: 176, + SyntaxPatterns: []ir.PatternString{{Line: 176, Value: "*flag.Duration($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.DurationVar", }, { - Line: 179, - SyntaxPatterns: []ir.PatternString{{Line: 179, Value: "*flag.Float64($*_)"}}, + Line: 177, + SyntaxPatterns: []ir.PatternString{{Line: 177, Value: "*flag.Float64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Float64Var", }, { - Line: 180, - SyntaxPatterns: []ir.PatternString{{Line: 180, Value: "*flag.Int($*_)"}}, + Line: 178, + SyntaxPatterns: []ir.PatternString{{Line: 178, Value: "*flag.Int($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.IntVar", }, { - Line: 181, - SyntaxPatterns: []ir.PatternString{{Line: 181, Value: "*flag.Int64($*_)"}}, + Line: 179, + SyntaxPatterns: []ir.PatternString{{Line: 179, Value: "*flag.Int64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Int64Var", }, { - Line: 182, - SyntaxPatterns: []ir.PatternString{{Line: 182, Value: "*flag.String($*_)"}}, + Line: 180, + SyntaxPatterns: []ir.PatternString{{Line: 180, Value: "*flag.String($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.StringVar", }, { - Line: 183, - SyntaxPatterns: []ir.PatternString{{Line: 183, Value: "*flag.Uint($*_)"}}, + Line: 181, + SyntaxPatterns: []ir.PatternString{{Line: 181, Value: "*flag.Uint($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.UintVar", }, { - Line: 184, - SyntaxPatterns: []ir.PatternString{{Line: 184, Value: "*flag.Uint64($*_)"}}, + Line: 182, + SyntaxPatterns: []ir.PatternString{{Line: 182, Value: "*flag.Uint64($*_)"}}, ReportTemplate: "immediate deref in $$ is most likely an error; consider using flag.Uint64Var", }, }, }, { - Line: 191, + Line: 189, Name: "emptyStringTest", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -543,33 +560,33 @@ var PrecompiledRules = &ir.File{ DocAfter: "s == \"\"", Rules: []ir.Rule{ { - Line: 192, - SyntaxPatterns: []ir.PatternString{{Line: 192, Value: "len($s) != 0"}}, + Line: 190, + SyntaxPatterns: []ir.PatternString{{Line: 190, Value: "len($s) != 0"}}, ReportTemplate: "replace `$$` with `$s != \"\"`", WhereExpr: ir.FilterExpr{ - Line: 193, + Line: 191, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 193, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 191, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, { - Line: 196, - SyntaxPatterns: []ir.PatternString{{Line: 196, Value: "len($s) == 0"}}, + Line: 194, + SyntaxPatterns: []ir.PatternString{{Line: 194, Value: "len($s) == 0"}}, ReportTemplate: "replace `$$` with `$s == \"\"`", WhereExpr: ir.FilterExpr{ - Line: 197, + Line: 195, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 197, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 195, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, { - Line: 205, + Line: 203, Name: "stringXbytes", MatcherName: "m", DocTags: []string{"performance"}, @@ -578,180 +595,180 @@ var PrecompiledRules = &ir.File{ DocAfter: "copy(b, s)", Rules: []ir.Rule{ { - Line: 206, - SyntaxPatterns: []ir.PatternString{{Line: 206, Value: "copy($_, []byte($s))"}}, + Line: 204, + SyntaxPatterns: []ir.PatternString{{Line: 204, Value: "copy($_, []byte($s))"}}, ReportTemplate: "can simplify `[]byte($s)` to `$s`", }, { - Line: 208, - SyntaxPatterns: []ir.PatternString{{Line: 208, Value: "string($b) == \"\""}}, + Line: 206, + SyntaxPatterns: []ir.PatternString{{Line: 206, Value: "string($b) == \"\""}}, ReportTemplate: "suggestion: len($b) == 0", SuggestTemplate: "len($b) == 0", WhereExpr: ir.FilterExpr{ - Line: 208, + Line: 206, Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{{Line: 208, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 206, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, { - Line: 209, - SyntaxPatterns: []ir.PatternString{{Line: 209, Value: "string($b) != \"\""}}, + Line: 207, + SyntaxPatterns: []ir.PatternString{{Line: 207, Value: "string($b) != \"\""}}, ReportTemplate: "suggestion: len($b) != 0", SuggestTemplate: "len($b) != 0", WhereExpr: ir.FilterExpr{ - Line: 209, + Line: 207, Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{{Line: 209, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 207, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, { - Line: 211, - SyntaxPatterns: []ir.PatternString{{Line: 211, Value: "len(string($b))"}}, + Line: 209, + SyntaxPatterns: []ir.PatternString{{Line: 209, Value: "len(string($b))"}}, ReportTemplate: "suggestion: len($b)", SuggestTemplate: "len($b)", WhereExpr: ir.FilterExpr{ - Line: 211, + Line: 209, Op: ir.FilterVarTypeIsOp, Src: "m[\"b\"].Type.Is(`[]byte`)", Value: "b", - Args: []ir.FilterExpr{{Line: 211, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 209, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, { - Line: 213, - SyntaxPatterns: []ir.PatternString{{Line: 213, Value: "string($x) == string($y)"}}, + Line: 211, + SyntaxPatterns: []ir.PatternString{{Line: 211, Value: "string($x) == string($y)"}}, ReportTemplate: "suggestion: bytes.Equal($x, $y)", SuggestTemplate: "bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 214, + Line: 212, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ { - Line: 214, + Line: 212, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", - Args: []ir.FilterExpr{{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 212, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, { - Line: 214, + Line: 212, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", - Args: []ir.FilterExpr{{Line: 214, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 212, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, }, }, { - Line: 217, - SyntaxPatterns: []ir.PatternString{{Line: 217, Value: "string($x) != string($y)"}}, + Line: 215, + SyntaxPatterns: []ir.PatternString{{Line: 215, Value: "string($x) != string($y)"}}, ReportTemplate: "suggestion: !bytes.Equal($x, $y)", SuggestTemplate: "!bytes.Equal($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 218, + Line: 216, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`[]byte`) && m[\"y\"].Type.Is(`[]byte`)", Args: []ir.FilterExpr{ { - Line: 218, + Line: 216, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]byte`)", Value: "x", - Args: []ir.FilterExpr{{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 216, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, { - Line: 218, + Line: 216, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`[]byte`)", Value: "y", - Args: []ir.FilterExpr{{Line: 218, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, + Args: []ir.FilterExpr{{Line: 216, Op: ir.FilterStringOp, Src: "`[]byte`", Value: "[]byte"}}, }, }, }, }, { - Line: 221, - SyntaxPatterns: []ir.PatternString{{Line: 221, Value: "$re.Match([]byte($s))"}}, + Line: 219, + SyntaxPatterns: []ir.PatternString{{Line: 219, Value: "$re.Match([]byte($s))"}}, ReportTemplate: "suggestion: $re.MatchString($s)", SuggestTemplate: "$re.MatchString($s)", WhereExpr: ir.FilterExpr{ - Line: 222, + Line: 220, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ { - Line: 222, + Line: 220, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{{Line: 222, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, + Args: []ir.FilterExpr{{Line: 220, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, { - Line: 222, + Line: 220, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 222, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 220, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, { - Line: 225, - SyntaxPatterns: []ir.PatternString{{Line: 225, Value: "$re.FindIndex([]byte($s))"}}, + Line: 223, + SyntaxPatterns: []ir.PatternString{{Line: 223, Value: "$re.FindIndex([]byte($s))"}}, ReportTemplate: "suggestion: $re.FindStringIndex($s)", SuggestTemplate: "$re.FindStringIndex($s)", WhereExpr: ir.FilterExpr{ - Line: 226, + Line: 224, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ { - Line: 226, + Line: 224, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{{Line: 226, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, + Args: []ir.FilterExpr{{Line: 224, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, { - Line: 226, + Line: 224, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 226, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 224, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }, { - Line: 229, - SyntaxPatterns: []ir.PatternString{{Line: 229, Value: "$re.FindAllIndex([]byte($s), $n)"}}, + Line: 227, + SyntaxPatterns: []ir.PatternString{{Line: 227, Value: "$re.FindAllIndex([]byte($s), $n)"}}, ReportTemplate: "suggestion: $re.FindAllStringIndex($s, $n)", SuggestTemplate: "$re.FindAllStringIndex($s, $n)", WhereExpr: ir.FilterExpr{ - Line: 230, + Line: 228, Op: ir.FilterAndOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`) && m[\"s\"].Type.Is(`string`)", Args: []ir.FilterExpr{ { - Line: 230, + Line: 228, Op: ir.FilterVarTypeIsOp, Src: "m[\"re\"].Type.Is(`*regexp.Regexp`)", Value: "re", - Args: []ir.FilterExpr{{Line: 230, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, + Args: []ir.FilterExpr{{Line: 228, Op: ir.FilterStringOp, Src: "`*regexp.Regexp`", Value: "*regexp.Regexp"}}, }, { - Line: 230, + Line: 228, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 230, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 228, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, @@ -759,7 +776,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 239, + Line: 237, Name: "indexAlloc", MatcherName: "m", DocTags: []string{"performance"}, @@ -768,22 +785,22 @@ var PrecompiledRules = &ir.File{ DocAfter: "bytes.Index(x, []byte(y))", DocNote: "See Go issue for details: https://github.com/golang/go/issues/25864", Rules: []ir.Rule{{ - Line: 240, - SyntaxPatterns: []ir.PatternString{{Line: 240, Value: "strings.Index(string($x), $y)"}}, + Line: 238, + SyntaxPatterns: []ir.PatternString{{Line: 238, Value: "strings.Index(string($x), $y)"}}, ReportTemplate: "consider replacing $$ with bytes.Index($x, []byte($y))", WhereExpr: ir.FilterExpr{ - Line: 241, + Line: 239, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 241, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 239, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 239, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, }}, }, { - Line: 249, + Line: 247, Name: "wrapperFunc", MatcherName: "m", DocTags: []string{"style"}, @@ -792,83 +809,83 @@ var PrecompiledRules = &ir.File{ DocAfter: "wg.Done()", Rules: []ir.Rule{ { - Line: 250, - SyntaxPatterns: []ir.PatternString{{Line: 250, Value: "$wg.Add(-1)"}}, + Line: 248, + SyntaxPatterns: []ir.PatternString{{Line: 248, Value: "$wg.Add(-1)"}}, ReportTemplate: "use WaitGroup.Done method in `$$`", WhereExpr: ir.FilterExpr{ - Line: 251, + Line: 249, Op: ir.FilterVarTypeIsOp, Src: "m[\"wg\"].Type.Is(`sync.WaitGroup`)", Value: "wg", - Args: []ir.FilterExpr{{Line: 251, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}}, + Args: []ir.FilterExpr{{Line: 249, Op: ir.FilterStringOp, Src: "`sync.WaitGroup`", Value: "sync.WaitGroup"}}, }, }, { - Line: 254, - SyntaxPatterns: []ir.PatternString{{Line: 254, Value: "$buf.Truncate(0)"}}, + Line: 252, + SyntaxPatterns: []ir.PatternString{{Line: 252, Value: "$buf.Truncate(0)"}}, ReportTemplate: "use Buffer.Reset method in `$$`", WhereExpr: ir.FilterExpr{ - Line: 255, + Line: 253, Op: ir.FilterVarTypeIsOp, Src: "m[\"buf\"].Type.Is(`bytes.Buffer`)", Value: "buf", - Args: []ir.FilterExpr{{Line: 255, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}}, + Args: []ir.FilterExpr{{Line: 253, Op: ir.FilterStringOp, Src: "`bytes.Buffer`", Value: "bytes.Buffer"}}, }, }, { - Line: 258, - SyntaxPatterns: []ir.PatternString{{Line: 258, Value: "http.HandlerFunc(http.NotFound)"}}, + Line: 256, + SyntaxPatterns: []ir.PatternString{{Line: 256, Value: "http.HandlerFunc(http.NotFound)"}}, ReportTemplate: "use http.NotFoundHandler method in `$$`", }, { - Line: 260, - SyntaxPatterns: []ir.PatternString{{Line: 260, Value: "strings.SplitN($_, $_, -1)"}}, + Line: 258, + SyntaxPatterns: []ir.PatternString{{Line: 258, Value: "strings.SplitN($_, $_, -1)"}}, ReportTemplate: "use strings.Split method in `$$`", }, { - Line: 261, - SyntaxPatterns: []ir.PatternString{{Line: 261, Value: "strings.Replace($_, $_, $_, -1)"}}, + Line: 259, + SyntaxPatterns: []ir.PatternString{{Line: 259, Value: "strings.Replace($_, $_, $_, -1)"}}, ReportTemplate: "use strings.ReplaceAll method in `$$`", }, { - Line: 262, - SyntaxPatterns: []ir.PatternString{{Line: 262, Value: "strings.Map(unicode.ToTitle, $_)"}}, + Line: 260, + SyntaxPatterns: []ir.PatternString{{Line: 260, Value: "strings.Map(unicode.ToTitle, $_)"}}, ReportTemplate: "use strings.ToTitle method in `$$`", }, { - Line: 264, - SyntaxPatterns: []ir.PatternString{{Line: 264, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}}, + Line: 262, + SyntaxPatterns: []ir.PatternString{{Line: 262, Value: "bytes.SplitN(b, []byte(\".\"), -1)"}}, ReportTemplate: "use bytes.Split method in `$$`", }, { - Line: 265, - SyntaxPatterns: []ir.PatternString{{Line: 265, Value: "bytes.Replace($_, $_, $_, -1)"}}, + Line: 263, + SyntaxPatterns: []ir.PatternString{{Line: 263, Value: "bytes.Replace($_, $_, $_, -1)"}}, ReportTemplate: "use bytes.ReplaceAll method in `$$`", }, { - Line: 266, - SyntaxPatterns: []ir.PatternString{{Line: 266, Value: "bytes.Map(unicode.ToUpper, $_)"}}, + Line: 264, + SyntaxPatterns: []ir.PatternString{{Line: 264, Value: "bytes.Map(unicode.ToUpper, $_)"}}, ReportTemplate: "use bytes.ToUpper method in `$$`", }, { - Line: 267, - SyntaxPatterns: []ir.PatternString{{Line: 267, Value: "bytes.Map(unicode.ToLower, $_)"}}, + Line: 265, + SyntaxPatterns: []ir.PatternString{{Line: 265, Value: "bytes.Map(unicode.ToLower, $_)"}}, ReportTemplate: "use bytes.ToLower method in `$$`", }, { - Line: 268, - SyntaxPatterns: []ir.PatternString{{Line: 268, Value: "bytes.Map(unicode.ToTitle, $_)"}}, + Line: 266, + SyntaxPatterns: []ir.PatternString{{Line: 266, Value: "bytes.Map(unicode.ToTitle, $_)"}}, ReportTemplate: "use bytes.ToTitle method in `$$`", }, { - Line: 270, - SyntaxPatterns: []ir.PatternString{{Line: 270, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}}, + Line: 268, + SyntaxPatterns: []ir.PatternString{{Line: 268, Value: "draw.DrawMask($_, $_, $_, $_, nil, image.Point{}, $_)"}}, ReportTemplate: "use draw.Draw method in `$$`", }, }, }, { - Line: 278, + Line: 276, Name: "regexpMust", MatcherName: "m", DocTags: []string{"style"}, @@ -877,22 +894,22 @@ var PrecompiledRules = &ir.File{ DocAfter: "re := regexp.MustCompile(\"const pattern\")", Rules: []ir.Rule{ { - Line: 279, - SyntaxPatterns: []ir.PatternString{{Line: 279, Value: "regexp.Compile($pat)"}}, + Line: 277, + SyntaxPatterns: []ir.PatternString{{Line: 277, Value: "regexp.Compile($pat)"}}, ReportTemplate: "for const patterns like $pat, use regexp.MustCompile", WhereExpr: ir.FilterExpr{ - Line: 280, + Line: 278, Op: ir.FilterVarConstOp, Src: "m[\"pat\"].Const", Value: "pat", }, }, { - Line: 283, - SyntaxPatterns: []ir.PatternString{{Line: 283, Value: "regexp.CompilePOSIX($pat)"}}, + Line: 281, + SyntaxPatterns: []ir.PatternString{{Line: 281, Value: "regexp.CompilePOSIX($pat)"}}, ReportTemplate: "for const patterns like $pat, use regexp.MustCompilePOSIX", WhereExpr: ir.FilterExpr{ - Line: 284, + Line: 282, Op: ir.FilterVarConstOp, Src: "m[\"pat\"].Const", Value: "pat", @@ -901,7 +918,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 292, + Line: 290, Name: "badCall", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -910,22 +927,22 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.Replace(s, from, to, -1)", Rules: []ir.Rule{ { - Line: 293, - SyntaxPatterns: []ir.PatternString{{Line: 293, Value: "strings.Replace($_, $_, $_, $zero)"}}, + Line: 291, + SyntaxPatterns: []ir.PatternString{{Line: 291, Value: "strings.Replace($_, $_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 294, + Line: 292, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 294, + Line: 292, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 294, + Line: 292, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -935,22 +952,22 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, { - Line: 296, - SyntaxPatterns: []ir.PatternString{{Line: 296, Value: "bytes.Replace($_, $_, $_, $zero)"}}, + Line: 294, + SyntaxPatterns: []ir.PatternString{{Line: 294, Value: "bytes.Replace($_, $_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 297, + Line: 295, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 297, + Line: 295, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 297, + Line: 295, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -960,22 +977,22 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, { - Line: 300, - SyntaxPatterns: []ir.PatternString{{Line: 300, Value: "strings.SplitN($_, $_, $zero)"}}, + Line: 298, + SyntaxPatterns: []ir.PatternString{{Line: 298, Value: "strings.SplitN($_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 301, + Line: 299, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 301, + Line: 299, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 301, + Line: 299, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -985,22 +1002,22 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, { - Line: 303, - SyntaxPatterns: []ir.PatternString{{Line: 303, Value: "bytes.SplitN($_, $_, $zero)"}}, + Line: 301, + SyntaxPatterns: []ir.PatternString{{Line: 301, Value: "bytes.SplitN($_, $_, $zero)"}}, ReportTemplate: "suspicious arg 0, probably meant -1", WhereExpr: ir.FilterExpr{ - Line: 304, + Line: 302, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 304, + Line: 302, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 304, + Line: 302, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1010,19 +1027,19 @@ var PrecompiledRules = &ir.File{ LocationVar: "zero", }, { - Line: 307, - SyntaxPatterns: []ir.PatternString{{Line: 307, Value: "append($_)"}}, + Line: 305, + SyntaxPatterns: []ir.PatternString{{Line: 305, Value: "append($_)"}}, ReportTemplate: "no-op append call, probably missing arguments", }, { - Line: 309, - SyntaxPatterns: []ir.PatternString{{Line: 309, Value: "filepath.Join($_)"}}, + Line: 307, + SyntaxPatterns: []ir.PatternString{{Line: 307, Value: "filepath.Join($_)"}}, ReportTemplate: "suspicious Join on 1 argument", }, }, }, { - Line: 316, + Line: 314, Name: "assignOp", MatcherName: "m", DocTags: []string{"style"}, @@ -1031,87 +1048,87 @@ var PrecompiledRules = &ir.File{ DocAfter: "x *= 2", Rules: []ir.Rule{ { - Line: 317, - SyntaxPatterns: []ir.PatternString{{Line: 317, Value: "$x = $x + 1"}}, + Line: 315, + SyntaxPatterns: []ir.PatternString{{Line: 315, Value: "$x = $x + 1"}}, ReportTemplate: "replace `$$` with `$x++`", - WhereExpr: ir.FilterExpr{Line: 317, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 315, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { - Line: 318, - SyntaxPatterns: []ir.PatternString{{Line: 318, Value: "$x = $x - 1"}}, + Line: 316, + SyntaxPatterns: []ir.PatternString{{Line: 316, Value: "$x = $x - 1"}}, ReportTemplate: "replace `$$` with `$x--`", - WhereExpr: ir.FilterExpr{Line: 318, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 316, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { - Line: 320, - SyntaxPatterns: []ir.PatternString{{Line: 320, Value: "$x = $x + $y"}}, + Line: 318, + SyntaxPatterns: []ir.PatternString{{Line: 318, Value: "$x = $x + $y"}}, ReportTemplate: "replace `$$` with `$x += $y`", - WhereExpr: ir.FilterExpr{Line: 320, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 318, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { - Line: 321, - SyntaxPatterns: []ir.PatternString{{Line: 321, Value: "$x = $x - $y"}}, + Line: 319, + SyntaxPatterns: []ir.PatternString{{Line: 319, Value: "$x = $x - $y"}}, ReportTemplate: "replace `$$` with `$x -= $y`", + WhereExpr: ir.FilterExpr{Line: 319, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + }, + { + Line: 321, + SyntaxPatterns: []ir.PatternString{{Line: 321, Value: "$x = $x * $y"}}, + ReportTemplate: "replace `$$` with `$x *= $y`", WhereExpr: ir.FilterExpr{Line: 321, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, + { + Line: 322, + SyntaxPatterns: []ir.PatternString{{Line: 322, Value: "$x = $x / $y"}}, + ReportTemplate: "replace `$$` with `$x /= $y`", + WhereExpr: ir.FilterExpr{Line: 322, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + }, { Line: 323, - SyntaxPatterns: []ir.PatternString{{Line: 323, Value: "$x = $x * $y"}}, - ReportTemplate: "replace `$$` with `$x *= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 323, Value: "$x = $x % $y"}}, + ReportTemplate: "replace `$$` with `$x %= $y`", WhereExpr: ir.FilterExpr{Line: 323, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 324, - SyntaxPatterns: []ir.PatternString{{Line: 324, Value: "$x = $x / $y"}}, - ReportTemplate: "replace `$$` with `$x /= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 324, Value: "$x = $x & $y"}}, + ReportTemplate: "replace `$$` with `$x &= $y`", WhereExpr: ir.FilterExpr{Line: 324, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 325, - SyntaxPatterns: []ir.PatternString{{Line: 325, Value: "$x = $x % $y"}}, - ReportTemplate: "replace `$$` with `$x %= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 325, Value: "$x = $x | $y"}}, + ReportTemplate: "replace `$$` with `$x |= $y`", WhereExpr: ir.FilterExpr{Line: 325, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 326, - SyntaxPatterns: []ir.PatternString{{Line: 326, Value: "$x = $x & $y"}}, - ReportTemplate: "replace `$$` with `$x &= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 326, Value: "$x = $x ^ $y"}}, + ReportTemplate: "replace `$$` with `$x ^= $y`", WhereExpr: ir.FilterExpr{Line: 326, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 327, - SyntaxPatterns: []ir.PatternString{{Line: 327, Value: "$x = $x | $y"}}, - ReportTemplate: "replace `$$` with `$x |= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 327, Value: "$x = $x << $y"}}, + ReportTemplate: "replace `$$` with `$x <<= $y`", WhereExpr: ir.FilterExpr{Line: 327, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 328, - SyntaxPatterns: []ir.PatternString{{Line: 328, Value: "$x = $x ^ $y"}}, - ReportTemplate: "replace `$$` with `$x ^= $y`", + SyntaxPatterns: []ir.PatternString{{Line: 328, Value: "$x = $x >> $y"}}, + ReportTemplate: "replace `$$` with `$x >>= $y`", WhereExpr: ir.FilterExpr{Line: 328, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { Line: 329, - SyntaxPatterns: []ir.PatternString{{Line: 329, Value: "$x = $x << $y"}}, - ReportTemplate: "replace `$$` with `$x <<= $y`", - WhereExpr: ir.FilterExpr{Line: 329, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - }, - { - Line: 330, - SyntaxPatterns: []ir.PatternString{{Line: 330, Value: "$x = $x >> $y"}}, - ReportTemplate: "replace `$$` with `$x >>= $y`", - WhereExpr: ir.FilterExpr{Line: 330, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - }, - { - Line: 331, - SyntaxPatterns: []ir.PatternString{{Line: 331, Value: "$x = $x &^ $y"}}, + SyntaxPatterns: []ir.PatternString{{Line: 329, Value: "$x = $x &^ $y"}}, ReportTemplate: "replace `$$` with `$x &^= $y`", - WhereExpr: ir.FilterExpr{Line: 331, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 329, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, { - Line: 338, + Line: 336, Name: "preferWriteByte", MatcherName: "m", DocTags: []string{"performance", "experimental", "opinionated"}, @@ -1119,45 +1136,45 @@ var PrecompiledRules = &ir.File{ DocBefore: "w.WriteRune('\\n')", DocAfter: "w.WriteByte('\\n')", Rules: []ir.Rule{{ - Line: 342, - SyntaxPatterns: []ir.PatternString{{Line: 342, Value: "$w.WriteRune($c)"}}, + Line: 340, + SyntaxPatterns: []ir.PatternString{{Line: 340, Value: "$w.WriteRune($c)"}}, ReportTemplate: "consider writing single byte rune $c with $w.WriteByte($c)", WhereExpr: ir.FilterExpr{ - Line: 343, + Line: 341, Op: ir.FilterAndOp, Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\") && (m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", Args: []ir.FilterExpr{ { - Line: 343, + Line: 341, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.ByteWriter\")", Value: "w", - Args: []ir.FilterExpr{{Line: 343, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}}, + Args: []ir.FilterExpr{{Line: 341, Op: ir.FilterStringOp, Src: "\"io.ByteWriter\"", Value: "io.ByteWriter"}}, }, { - Line: 343, + Line: 341, Op: ir.FilterAndOp, Src: "(m[\"c\"].Const && m[\"c\"].Value.Int() < runeSelf)", Args: []ir.FilterExpr{ { - Line: 343, + Line: 341, Op: ir.FilterVarConstOp, Src: "m[\"c\"].Const", Value: "c", }, { - Line: 343, + Line: 341, Op: ir.FilterLtOp, Src: "m[\"c\"].Value.Int() < runeSelf", Args: []ir.FilterExpr{ { - Line: 343, + Line: 341, Op: ir.FilterVarValueIntOp, Src: "m[\"c\"].Value.Int()", Value: "c", }, { - Line: 343, + Line: 341, Op: ir.FilterIntOp, Src: "runeSelf", Value: int64(128), @@ -1171,7 +1188,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 351, + Line: 349, Name: "preferFprint", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1180,66 +1197,66 @@ var PrecompiledRules = &ir.File{ DocAfter: "fmt.Fprintf(w, \"%x\", 10)", Rules: []ir.Rule{ { - Line: 352, - SyntaxPatterns: []ir.PatternString{{Line: 352, Value: "$w.Write([]byte(fmt.Sprint($*args)))"}}, + Line: 350, + SyntaxPatterns: []ir.PatternString{{Line: 350, Value: "$w.Write([]byte(fmt.Sprint($*args)))"}}, ReportTemplate: "fmt.Fprint($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprint($w, $args)", WhereExpr: ir.FilterExpr{ - Line: 353, + Line: 351, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{{Line: 353, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, + Args: []ir.FilterExpr{{Line: 351, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, { - Line: 357, - SyntaxPatterns: []ir.PatternString{{Line: 357, Value: "$w.Write([]byte(fmt.Sprintf($*args)))"}}, + Line: 355, + SyntaxPatterns: []ir.PatternString{{Line: 355, Value: "$w.Write([]byte(fmt.Sprintf($*args)))"}}, ReportTemplate: "fmt.Fprintf($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprintf($w, $args)", WhereExpr: ir.FilterExpr{ - Line: 358, + Line: 356, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{{Line: 358, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, + Args: []ir.FilterExpr{{Line: 356, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, { - Line: 362, - SyntaxPatterns: []ir.PatternString{{Line: 362, Value: "$w.Write([]byte(fmt.Sprintln($*args)))"}}, + Line: 360, + SyntaxPatterns: []ir.PatternString{{Line: 360, Value: "$w.Write([]byte(fmt.Sprintln($*args)))"}}, ReportTemplate: "fmt.Fprintln($w, $args) should be preferred to the $$", SuggestTemplate: "fmt.Fprintln($w, $args)", WhereExpr: ir.FilterExpr{ - Line: 363, + Line: 361, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.Writer\")", Value: "w", - Args: []ir.FilterExpr{{Line: 363, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, + Args: []ir.FilterExpr{{Line: 361, Op: ir.FilterStringOp, Src: "\"io.Writer\"", Value: "io.Writer"}}, }, }, { - Line: 367, - SyntaxPatterns: []ir.PatternString{{Line: 367, Value: "io.WriteString($w, fmt.Sprint($*args))"}}, + Line: 365, + SyntaxPatterns: []ir.PatternString{{Line: 365, Value: "io.WriteString($w, fmt.Sprint($*args))"}}, ReportTemplate: "suggestion: fmt.Fprint($w, $args)", SuggestTemplate: "fmt.Fprint($w, $args)", }, { - Line: 368, - SyntaxPatterns: []ir.PatternString{{Line: 368, Value: "io.WriteString($w, fmt.Sprintf($*args))"}}, + Line: 366, + SyntaxPatterns: []ir.PatternString{{Line: 366, Value: "io.WriteString($w, fmt.Sprintf($*args))"}}, ReportTemplate: "suggestion: fmt.Fprintf($w, $args)", SuggestTemplate: "fmt.Fprintf($w, $args)", }, { - Line: 369, - SyntaxPatterns: []ir.PatternString{{Line: 369, Value: "io.WriteString($w, fmt.Sprintln($*args))"}}, + Line: 367, + SyntaxPatterns: []ir.PatternString{{Line: 367, Value: "io.WriteString($w, fmt.Sprintln($*args))"}}, ReportTemplate: "suggestion: fmt.Fprintln($w, $args)", SuggestTemplate: "fmt.Fprintln($w, $args)", }, }, }, { - Line: 376, + Line: 374, Name: "dupArg", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -1248,62 +1265,62 @@ var PrecompiledRules = &ir.File{ DocAfter: "copy(dst, src)", Rules: []ir.Rule{ { - Line: 377, + Line: 375, SyntaxPatterns: []ir.PatternString{ - {Line: 377, Value: "$x.Equal($x)"}, - {Line: 377, Value: "$x.Equals($x)"}, - {Line: 377, Value: "$x.Compare($x)"}, - {Line: 377, Value: "$x.Cmp($x)"}, + {Line: 375, Value: "$x.Equal($x)"}, + {Line: 375, Value: "$x.Equals($x)"}, + {Line: 375, Value: "$x.Compare($x)"}, + {Line: 375, Value: "$x.Cmp($x)"}, }, ReportTemplate: "suspicious method call with the same argument and receiver", - WhereExpr: ir.FilterExpr{Line: 378, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 376, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, { - Line: 381, + Line: 379, SyntaxPatterns: []ir.PatternString{ - {Line: 381, Value: "copy($x, $x)"}, - {Line: 382, Value: "math.Max($x, $x)"}, - {Line: 383, Value: "math.Min($x, $x)"}, - {Line: 384, Value: "reflect.Copy($x, $x)"}, - {Line: 385, Value: "reflect.DeepEqual($x, $x)"}, - {Line: 386, Value: "strings.Contains($x, $x)"}, - {Line: 387, Value: "strings.Compare($x, $x)"}, - {Line: 388, Value: "strings.EqualFold($x, $x)"}, - {Line: 389, Value: "strings.HasPrefix($x, $x)"}, - {Line: 390, Value: "strings.HasSuffix($x, $x)"}, - {Line: 391, Value: "strings.Index($x, $x)"}, - {Line: 392, Value: "strings.LastIndex($x, $x)"}, - {Line: 393, Value: "strings.Split($x, $x)"}, - {Line: 394, Value: "strings.SplitAfter($x, $x)"}, - {Line: 395, Value: "strings.SplitAfterN($x, $x, $_)"}, - {Line: 396, Value: "strings.SplitN($x, $x, $_)"}, - {Line: 397, Value: "strings.Replace($_, $x, $x, $_)"}, - {Line: 398, Value: "strings.ReplaceAll($_, $x, $x)"}, - {Line: 399, Value: "bytes.Contains($x, $x)"}, - {Line: 400, Value: "bytes.Compare($x, $x)"}, - {Line: 401, Value: "bytes.Equal($x, $x)"}, - {Line: 402, Value: "bytes.EqualFold($x, $x)"}, - {Line: 403, Value: "bytes.HasPrefix($x, $x)"}, - {Line: 404, Value: "bytes.HasSuffix($x, $x)"}, - {Line: 405, Value: "bytes.Index($x, $x)"}, - {Line: 406, Value: "bytes.LastIndex($x, $x)"}, - {Line: 407, Value: "bytes.Split($x, $x)"}, - {Line: 408, Value: "bytes.SplitAfter($x, $x)"}, - {Line: 409, Value: "bytes.SplitAfterN($x, $x, $_)"}, - {Line: 410, Value: "bytes.SplitN($x, $x, $_)"}, - {Line: 411, Value: "bytes.Replace($_, $x, $x, $_)"}, - {Line: 412, Value: "bytes.ReplaceAll($_, $x, $x)"}, - {Line: 413, Value: "types.Identical($x, $x)"}, - {Line: 414, Value: "types.IdenticalIgnoreTags($x, $x)"}, - {Line: 415, Value: "draw.Draw($x, $_, $x, $_, $_)"}, + {Line: 379, Value: "copy($x, $x)"}, + {Line: 380, Value: "math.Max($x, $x)"}, + {Line: 381, Value: "math.Min($x, $x)"}, + {Line: 382, Value: "reflect.Copy($x, $x)"}, + {Line: 383, Value: "reflect.DeepEqual($x, $x)"}, + {Line: 384, Value: "strings.Contains($x, $x)"}, + {Line: 385, Value: "strings.Compare($x, $x)"}, + {Line: 386, Value: "strings.EqualFold($x, $x)"}, + {Line: 387, Value: "strings.HasPrefix($x, $x)"}, + {Line: 388, Value: "strings.HasSuffix($x, $x)"}, + {Line: 389, Value: "strings.Index($x, $x)"}, + {Line: 390, Value: "strings.LastIndex($x, $x)"}, + {Line: 391, Value: "strings.Split($x, $x)"}, + {Line: 392, Value: "strings.SplitAfter($x, $x)"}, + {Line: 393, Value: "strings.SplitAfterN($x, $x, $_)"}, + {Line: 394, Value: "strings.SplitN($x, $x, $_)"}, + {Line: 395, Value: "strings.Replace($_, $x, $x, $_)"}, + {Line: 396, Value: "strings.ReplaceAll($_, $x, $x)"}, + {Line: 397, Value: "bytes.Contains($x, $x)"}, + {Line: 398, Value: "bytes.Compare($x, $x)"}, + {Line: 399, Value: "bytes.Equal($x, $x)"}, + {Line: 400, Value: "bytes.EqualFold($x, $x)"}, + {Line: 401, Value: "bytes.HasPrefix($x, $x)"}, + {Line: 402, Value: "bytes.HasSuffix($x, $x)"}, + {Line: 403, Value: "bytes.Index($x, $x)"}, + {Line: 404, Value: "bytes.LastIndex($x, $x)"}, + {Line: 405, Value: "bytes.Split($x, $x)"}, + {Line: 406, Value: "bytes.SplitAfter($x, $x)"}, + {Line: 407, Value: "bytes.SplitAfterN($x, $x, $_)"}, + {Line: 408, Value: "bytes.SplitN($x, $x, $_)"}, + {Line: 409, Value: "bytes.Replace($_, $x, $x, $_)"}, + {Line: 410, Value: "bytes.ReplaceAll($_, $x, $x)"}, + {Line: 411, Value: "types.Identical($x, $x)"}, + {Line: 412, Value: "types.IdenticalIgnoreTags($x, $x)"}, + {Line: 413, Value: "draw.Draw($x, $_, $x, $_, $_)"}, }, ReportTemplate: "suspicious duplicated args in $$", - WhereExpr: ir.FilterExpr{Line: 416, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + WhereExpr: ir.FilterExpr{Line: 414, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, }, }, }, { - Line: 424, + Line: 422, Name: "returnAfterHttpError", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1311,14 +1328,14 @@ var PrecompiledRules = &ir.File{ DocBefore: "if err != nil { http.Error(...); }", DocAfter: "if err != nil { http.Error(...); return; }", Rules: []ir.Rule{{ - Line: 425, - SyntaxPatterns: []ir.PatternString{{Line: 425, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}}, + Line: 423, + SyntaxPatterns: []ir.PatternString{{Line: 423, Value: "if $_ { $*_; http.Error($w, $err, $code) }"}}, ReportTemplate: "Possibly return is missed after the http.Error call", LocationVar: "w", }}, }, { - Line: 434, + Line: 432, Name: "preferFilepathJoin", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1326,35 +1343,35 @@ var PrecompiledRules = &ir.File{ DocBefore: "x + string(os.PathSeparator) + y", DocAfter: "filepath.Join(x, y)", Rules: []ir.Rule{{ - Line: 435, - SyntaxPatterns: []ir.PatternString{{Line: 435, Value: "$x + string(os.PathSeparator) + $y"}}, + Line: 433, + SyntaxPatterns: []ir.PatternString{{Line: 433, Value: "$x + string(os.PathSeparator) + $y"}}, ReportTemplate: "filepath.Join($x, $y) should be preferred to the $$", SuggestTemplate: "filepath.Join($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 436, + Line: 434, Op: ir.FilterAndOp, Src: "m[\"x\"].Type.Is(`string`) && m[\"y\"].Type.Is(`string`)", Args: []ir.FilterExpr{ { - Line: 436, + Line: 434, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`string`)", Value: "x", - Args: []ir.FilterExpr{{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 434, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, { - Line: 436, + Line: 434, Op: ir.FilterVarTypeIsOp, Src: "m[\"y\"].Type.Is(`string`)", Value: "y", - Args: []ir.FilterExpr{{Line: 436, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 434, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, }, }, }}, }, { - Line: 445, + Line: 443, Name: "preferStringWriter", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1363,35 +1380,35 @@ var PrecompiledRules = &ir.File{ DocAfter: "w.WriteString(\"foo\")", Rules: []ir.Rule{ { - Line: 446, - SyntaxPatterns: []ir.PatternString{{Line: 446, Value: "$w.Write([]byte($s))"}}, + Line: 444, + SyntaxPatterns: []ir.PatternString{{Line: 444, Value: "$w.Write([]byte($s))"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ - Line: 447, + Line: 445, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{{Line: 447, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, + Args: []ir.FilterExpr{{Line: 445, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, { - Line: 451, - SyntaxPatterns: []ir.PatternString{{Line: 451, Value: "io.WriteString($w, $s)"}}, + Line: 449, + SyntaxPatterns: []ir.PatternString{{Line: 449, Value: "io.WriteString($w, $s)"}}, ReportTemplate: "$w.WriteString($s) should be preferred to the $$", SuggestTemplate: "$w.WriteString($s)", WhereExpr: ir.FilterExpr{ - Line: 452, + Line: 450, Op: ir.FilterVarTypeImplementsOp, Src: "m[\"w\"].Type.Implements(\"io.StringWriter\")", Value: "w", - Args: []ir.FilterExpr{{Line: 452, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, + Args: []ir.FilterExpr{{Line: 450, Op: ir.FilterStringOp, Src: "\"io.StringWriter\"", Value: "io.StringWriter"}}, }, }, }, }, { - Line: 461, + Line: 459, Name: "sliceClear", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1399,22 +1416,22 @@ var PrecompiledRules = &ir.File{ DocBefore: "for i := 0; i < len(buf); i++ { buf[i] = 0 }", DocAfter: "for i := range buf { buf[i] = 0 }", Rules: []ir.Rule{{ - Line: 462, - SyntaxPatterns: []ir.PatternString{{Line: 462, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}}, + Line: 460, + SyntaxPatterns: []ir.PatternString{{Line: 460, Value: "for $i := 0; $i < len($xs); $i++ { $xs[$i] = $zero }"}}, ReportTemplate: "rewrite as for-range so compiler can recognize this pattern", WhereExpr: ir.FilterExpr{ - Line: 463, + Line: 461, Op: ir.FilterEqOp, Src: "m[\"zero\"].Value.Int() == 0", Args: []ir.FilterExpr{ { - Line: 463, + Line: 461, Op: ir.FilterVarValueIntOp, Src: "m[\"zero\"].Value.Int()", Value: "zero", }, { - Line: 463, + Line: 461, Op: ir.FilterIntOp, Src: "0", Value: int64(0), @@ -1424,7 +1441,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 471, + Line: 469, Name: "syncMapLoadAndDelete", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1432,33 +1449,33 @@ var PrecompiledRules = &ir.File{ DocBefore: "v, ok := m.Load(k); if ok { m.Delete($k); f(v); }", DocAfter: "v, deleted := m.LoadAndDelete(k); if deleted { f(v) }", Rules: []ir.Rule{{ - Line: 472, - SyntaxPatterns: []ir.PatternString{{Line: 472, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}}, + Line: 470, + SyntaxPatterns: []ir.PatternString{{Line: 470, Value: "$_, $ok := $m.Load($k); if $ok { $m.Delete($k); $*_ }"}}, ReportTemplate: "use $m.LoadAndDelete to perform load+delete operations atomically", WhereExpr: ir.FilterExpr{ - Line: 473, + Line: 471, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\") &&\n\tm[\"m\"].Type.Is(`*sync.Map`)", Args: []ir.FilterExpr{ { - Line: 473, + Line: 471, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.15\")", Value: "1.15", }, { - Line: 474, + Line: 472, Op: ir.FilterVarTypeIsOp, Src: "m[\"m\"].Type.Is(`*sync.Map`)", Value: "m", - Args: []ir.FilterExpr{{Line: 474, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}}, + Args: []ir.FilterExpr{{Line: 472, Op: ir.FilterStringOp, Src: "`*sync.Map`", Value: "*sync.Map"}}, }, }, }, }}, }, { - Line: 482, + Line: 480, Name: "sprintfQuotedString", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -1466,34 +1483,34 @@ var PrecompiledRules = &ir.File{ DocBefore: "fmt.Sprintf(`\"%s\"`, s)", DocAfter: "fmt.Sprintf(`%q`, s)", Rules: []ir.Rule{{ - Line: 483, - SyntaxPatterns: []ir.PatternString{{Line: 483, Value: "fmt.Sprintf($s, $*_)"}}, + Line: 481, + SyntaxPatterns: []ir.PatternString{{Line: 481, Value: "fmt.Sprintf($s, $*_)"}}, ReportTemplate: "use %q instead of \"%s\" for quoted strings", WhereExpr: ir.FilterExpr{ - Line: 484, + Line: 482, Op: ir.FilterOrOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\") ||\n\tm[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Args: []ir.FilterExpr{ { - Line: 484, + Line: 482, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(\"^`.*\\\"%s\\\".*`$\")", Value: "s", - Args: []ir.FilterExpr{{Line: 484, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}}, + Args: []ir.FilterExpr{{Line: 482, Op: ir.FilterStringOp, Src: "\"^`.*\\\"%s\\\".*`$\"", Value: "^`.*\"%s\".*`$"}}, }, { - Line: 485, + Line: 483, Op: ir.FilterVarTextMatchesOp, Src: "m[\"s\"].Text.Matches(`^\".*\\\\\"%s\\\\\".*\"$`)", Value: "s", - Args: []ir.FilterExpr{{Line: 485, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}}, + Args: []ir.FilterExpr{{Line: 483, Op: ir.FilterStringOp, Src: "`^\".*\\\\\"%s\\\\\".*\"$`", Value: "^\".*\\\\\"%s\\\\\".*\"$"}}, }, }, }, }}, }, { - Line: 493, + Line: 491, Name: "offBy1", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -1502,80 +1519,80 @@ var PrecompiledRules = &ir.File{ DocAfter: "xs[len(xs)-1]", Rules: []ir.Rule{ { - Line: 494, - SyntaxPatterns: []ir.PatternString{{Line: 494, Value: "$x[len($x)]"}}, + Line: 492, + SyntaxPatterns: []ir.PatternString{{Line: 492, Value: "$x[len($x)]"}}, ReportTemplate: "index expr always panics; maybe you wanted $x[len($x)-1]?", SuggestTemplate: "$x[len($x)-1]", WhereExpr: ir.FilterExpr{ - Line: 495, + Line: 493, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"x\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ - {Line: 495, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 493, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, { - Line: 495, + Line: 493, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]$_`)", Value: "x", - Args: []ir.FilterExpr{{Line: 495, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, + Args: []ir.FilterExpr{{Line: 493, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, }, }, }, }, { - Line: 502, + Line: 500, SyntaxPatterns: []ir.PatternString{ - {Line: 503, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, - {Line: 504, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, - {Line: 505, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, - {Line: 506, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 501, Value: "$i := strings.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 502, Value: "$i := strings.Index($s, $_); $_ = $slicing[$i:]"}, + {Line: 503, Value: "$i := bytes.Index($s, $_); $_ := $slicing[$i:]"}, + {Line: 504, Value: "$i := bytes.Index($s, $_); $_ = $slicing[$i:]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[$i+1:]", WhereExpr: ir.FilterExpr{ - Line: 507, + Line: 505, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - {Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - {Line: 507, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 505, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 505, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, { - Line: 511, + Line: 509, SyntaxPatterns: []ir.PatternString{ - {Line: 512, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, - {Line: 513, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, - {Line: 514, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, - {Line: 515, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 510, Value: "$i := strings.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 511, Value: "$i := strings.Index($s, $_); $_ = $slicing[:$i]"}, + {Line: 512, Value: "$i := bytes.Index($s, $_); $_ := $slicing[:$i]"}, + {Line: 513, Value: "$i := bytes.Index($s, $_); $_ = $slicing[:$i]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do $s[:$i+1]", WhereExpr: ir.FilterExpr{ - Line: 516, + Line: 514, Op: ir.FilterEqOp, Src: "m[\"s\"].Text == m[\"slicing\"].Text", Args: []ir.FilterExpr{ - {Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, - {Line: 516, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, + {Line: 514, Op: ir.FilterVarTextOp, Src: "m[\"s\"].Text", Value: "s"}, + {Line: 514, Op: ir.FilterVarTextOp, Src: "m[\"slicing\"].Text", Value: "slicing"}, }, }, LocationVar: "slicing", }, { - Line: 520, + Line: 518, SyntaxPatterns: []ir.PatternString{ - {Line: 521, Value: "$s[strings.Index($s, $_):]"}, - {Line: 522, Value: "$s[:strings.Index($s, $_)]"}, - {Line: 523, Value: "$s[bytes.Index($s, $_):]"}, - {Line: 524, Value: "$s[:bytes.Index($s, $_)]"}, + {Line: 519, Value: "$s[strings.Index($s, $_):]"}, + {Line: 520, Value: "$s[:strings.Index($s, $_)]"}, + {Line: 521, Value: "$s[bytes.Index($s, $_):]"}, + {Line: 522, Value: "$s[:bytes.Index($s, $_)]"}, }, ReportTemplate: "Index() can return -1; maybe you wanted to do Index()+1", }, }, }, { - Line: 532, + Line: 530, Name: "unslice", MatcherName: "m", DocTags: []string{"style"}, @@ -1583,35 +1600,35 @@ var PrecompiledRules = &ir.File{ DocBefore: "copy(b[:], values...)", DocAfter: "copy(b, values...)", Rules: []ir.Rule{{ - Line: 533, - SyntaxPatterns: []ir.PatternString{{Line: 533, Value: "$s[:]"}}, + Line: 531, + SyntaxPatterns: []ir.PatternString{{Line: 531, Value: "$s[:]"}}, ReportTemplate: "could simplify $$ to $s", SuggestTemplate: "$s", WhereExpr: ir.FilterExpr{ - Line: 534, + Line: 532, Op: ir.FilterOrOp, Src: "m[\"s\"].Type.Is(`string`) || m[\"s\"].Type.Is(`[]$_`)", Args: []ir.FilterExpr{ { - Line: 534, + Line: 532, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`string`)", Value: "s", - Args: []ir.FilterExpr{{Line: 534, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, + Args: []ir.FilterExpr{{Line: 532, Op: ir.FilterStringOp, Src: "`string`", Value: "string"}}, }, { - Line: 534, + Line: 532, Op: ir.FilterVarTypeIsOp, Src: "m[\"s\"].Type.Is(`[]$_`)", Value: "s", - Args: []ir.FilterExpr{{Line: 534, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, + Args: []ir.FilterExpr{{Line: 532, Op: ir.FilterStringOp, Src: "`[]$_`", Value: "[]$_"}}, }, }, }, }}, }, { - Line: 543, + Line: 541, Name: "yodaStyleExpr", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1620,105 +1637,105 @@ var PrecompiledRules = &ir.File{ DocAfter: "return ptr != nil", Rules: []ir.Rule{ { - Line: 544, - SyntaxPatterns: []ir.PatternString{{Line: 544, Value: "$constval != $x"}}, + Line: 542, + SyntaxPatterns: []ir.PatternString{{Line: 542, Value: "$constval != $x"}}, ReportTemplate: "consider to change order in expression to $x != $constval", WhereExpr: ir.FilterExpr{ - Line: 544, + Line: 542, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ { - Line: 544, + Line: 542, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 542, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, { - Line: 544, + Line: 542, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 544, + Line: 542, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 542, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 546, - SyntaxPatterns: []ir.PatternString{{Line: 546, Value: "$constval == $x"}}, + Line: 544, + SyntaxPatterns: []ir.PatternString{{Line: 544, Value: "$constval == $x"}}, ReportTemplate: "consider to change order in expression to $x == $constval", WhereExpr: ir.FilterExpr{ - Line: 546, + Line: 544, Op: ir.FilterAndOp, Src: "m[\"constval\"].Node.Is(`BasicLit`) && !m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{ { - Line: 546, + Line: 544, Op: ir.FilterVarNodeIsOp, Src: "m[\"constval\"].Node.Is(`BasicLit`)", Value: "constval", - Args: []ir.FilterExpr{{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }, { - Line: 546, + Line: 544, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 546, + Line: 544, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 546, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 544, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 549, - SyntaxPatterns: []ir.PatternString{{Line: 549, Value: "nil != $x"}}, + Line: 547, + SyntaxPatterns: []ir.PatternString{{Line: 547, Value: "nil != $x"}}, ReportTemplate: "consider to change order in expression to $x != nil", WhereExpr: ir.FilterExpr{ - Line: 549, + Line: 547, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 549, + Line: 547, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 547, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, { - Line: 551, - SyntaxPatterns: []ir.PatternString{{Line: 551, Value: "nil == $x"}}, + Line: 549, + SyntaxPatterns: []ir.PatternString{{Line: 549, Value: "nil == $x"}}, ReportTemplate: "consider to change order in expression to $x == nil", WhereExpr: ir.FilterExpr{ - Line: 551, + Line: 549, Op: ir.FilterNotOp, Src: "!m[\"x\"].Node.Is(`BasicLit`)", Args: []ir.FilterExpr{{ - Line: 551, + Line: 549, Op: ir.FilterVarNodeIsOp, Src: "m[\"x\"].Node.Is(`BasicLit`)", Value: "x", - Args: []ir.FilterExpr{{Line: 551, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, + Args: []ir.FilterExpr{{Line: 549, Op: ir.FilterStringOp, Src: "`BasicLit`", Value: "BasicLit"}}, }}, }, }, }, }, { - Line: 559, + Line: 557, Name: "equalFold", MatcherName: "m", DocTags: []string{"performance", "experimental"}, @@ -1727,114 +1744,114 @@ var PrecompiledRules = &ir.File{ DocAfter: "strings.EqualFold(x, y)", Rules: []ir.Rule{ { - Line: 568, + Line: 566, SyntaxPatterns: []ir.PatternString{ - {Line: 569, Value: "strings.ToLower($x) == $y"}, - {Line: 570, Value: "strings.ToLower($x) == strings.ToLower($y)"}, - {Line: 571, Value: "$x == strings.ToLower($y)"}, - {Line: 572, Value: "strings.ToUpper($x) == $y"}, - {Line: 573, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, - {Line: 574, Value: "$x == strings.ToUpper($y)"}, + {Line: 567, Value: "strings.ToLower($x) == $y"}, + {Line: 568, Value: "strings.ToLower($x) == strings.ToLower($y)"}, + {Line: 569, Value: "$x == strings.ToLower($y)"}, + {Line: 570, Value: "strings.ToUpper($x) == $y"}, + {Line: 571, Value: "strings.ToUpper($x) == strings.ToUpper($y)"}, + {Line: 572, Value: "$x == strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with strings.EqualFold($x, $y)", SuggestTemplate: "strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 575, + Line: 573, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 575, + Line: 573, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 575, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 573, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 573, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 575, + Line: 573, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 575, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 573, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 573, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, { - Line: 580, + Line: 578, SyntaxPatterns: []ir.PatternString{ - {Line: 581, Value: "strings.ToLower($x) != $y"}, - {Line: 582, Value: "strings.ToLower($x) != strings.ToLower($y)"}, - {Line: 583, Value: "$x != strings.ToLower($y)"}, - {Line: 584, Value: "strings.ToUpper($x) != $y"}, - {Line: 585, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, - {Line: 586, Value: "$x != strings.ToUpper($y)"}, + {Line: 579, Value: "strings.ToLower($x) != $y"}, + {Line: 580, Value: "strings.ToLower($x) != strings.ToLower($y)"}, + {Line: 581, Value: "$x != strings.ToLower($y)"}, + {Line: 582, Value: "strings.ToUpper($x) != $y"}, + {Line: 583, Value: "strings.ToUpper($x) != strings.ToUpper($y)"}, + {Line: 584, Value: "$x != strings.ToUpper($y)"}, }, ReportTemplate: "consider replacing with !strings.EqualFold($x, $y)", SuggestTemplate: "!strings.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 587, + Line: 585, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 587, + Line: 585, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 587, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 585, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 585, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 587, + Line: 585, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 587, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 585, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 585, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, }, }, { - Line: 592, + Line: 590, SyntaxPatterns: []ir.PatternString{ - {Line: 593, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, - {Line: 594, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, - {Line: 595, Value: "bytes.Equal($x, bytes.ToLower($y))"}, - {Line: 596, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, - {Line: 597, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, - {Line: 598, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, + {Line: 591, Value: "bytes.Equal(bytes.ToLower($x), $y)"}, + {Line: 592, Value: "bytes.Equal(bytes.ToLower($x), bytes.ToLower($y))"}, + {Line: 593, Value: "bytes.Equal($x, bytes.ToLower($y))"}, + {Line: 594, Value: "bytes.Equal(bytes.ToUpper($x), $y)"}, + {Line: 595, Value: "bytes.Equal(bytes.ToUpper($x), bytes.ToUpper($y))"}, + {Line: 596, Value: "bytes.Equal($x, bytes.ToUpper($y))"}, }, ReportTemplate: "consider replacing with bytes.EqualFold($x, $y)", SuggestTemplate: "bytes.EqualFold($x, $y)", WhereExpr: ir.FilterExpr{ - Line: 599, + Line: 597, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure && m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ { - Line: 599, + Line: 597, Op: ir.FilterAndOp, Src: "m[\"x\"].Pure && m[\"y\"].Pure", Args: []ir.FilterExpr{ - {Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, - {Line: 599, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, + {Line: 597, Op: ir.FilterVarPureOp, Src: "m[\"x\"].Pure", Value: "x"}, + {Line: 597, Op: ir.FilterVarPureOp, Src: "m[\"y\"].Pure", Value: "y"}, }, }, { - Line: 599, + Line: 597, Op: ir.FilterNeqOp, Src: "m[\"x\"].Text != m[\"y\"].Text", Args: []ir.FilterExpr{ - {Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, - {Line: 599, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, + {Line: 597, Op: ir.FilterVarTextOp, Src: "m[\"x\"].Text", Value: "x"}, + {Line: 597, Op: ir.FilterVarTextOp, Src: "m[\"y\"].Text", Value: "y"}, }, }, }, @@ -1843,7 +1860,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 608, + Line: 606, Name: "argOrder", MatcherName: "m", DocTags: []string{"diagnostic"}, @@ -1851,45 +1868,45 @@ var PrecompiledRules = &ir.File{ DocBefore: "strings.HasPrefix(\"#\", userpass)", DocAfter: "strings.HasPrefix(userpass, \"#\")", Rules: []ir.Rule{{ - Line: 609, + Line: 607, SyntaxPatterns: []ir.PatternString{ - {Line: 610, Value: "strings.HasPrefix($lit, $s)"}, - {Line: 611, Value: "bytes.HasPrefix($lit, $s)"}, - {Line: 612, Value: "strings.HasSuffix($lit, $s)"}, - {Line: 613, Value: "bytes.HasSuffix($lit, $s)"}, - {Line: 614, Value: "strings.Contains($lit, $s)"}, - {Line: 615, Value: "bytes.Contains($lit, $s)"}, - {Line: 616, Value: "strings.TrimPrefix($lit, $s)"}, - {Line: 617, Value: "bytes.TrimPrefix($lit, $s)"}, - {Line: 618, Value: "strings.TrimSuffix($lit, $s)"}, - {Line: 619, Value: "bytes.TrimSuffix($lit, $s)"}, - {Line: 620, Value: "strings.Split($lit, $s)"}, - {Line: 621, Value: "bytes.Split($lit, $s)"}, + {Line: 608, Value: "strings.HasPrefix($lit, $s)"}, + {Line: 609, Value: "bytes.HasPrefix($lit, $s)"}, + {Line: 610, Value: "strings.HasSuffix($lit, $s)"}, + {Line: 611, Value: "bytes.HasSuffix($lit, $s)"}, + {Line: 612, Value: "strings.Contains($lit, $s)"}, + {Line: 613, Value: "bytes.Contains($lit, $s)"}, + {Line: 614, Value: "strings.TrimPrefix($lit, $s)"}, + {Line: 615, Value: "bytes.TrimPrefix($lit, $s)"}, + {Line: 616, Value: "strings.TrimSuffix($lit, $s)"}, + {Line: 617, Value: "bytes.TrimSuffix($lit, $s)"}, + {Line: 618, Value: "strings.Split($lit, $s)"}, + {Line: 619, Value: "bytes.Split($lit, $s)"}, }, ReportTemplate: "$lit and $s arguments order looks reversed", WhereExpr: ir.FilterExpr{ - Line: 622, + Line: 620, Op: ir.FilterAndOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice) &&\n\t!m[\"lit\"].Node.Is(`Ident`)", Args: []ir.FilterExpr{ { - Line: 622, + Line: 620, Op: ir.FilterAndOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice) &&\n\t!(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 622, + Line: 620, Op: ir.FilterOrOp, Src: "(m[\"lit\"].Const || m[\"lit\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 622, + Line: 620, Op: ir.FilterVarConstOp, Src: "m[\"lit\"].Const", Value: "lit", }, { - Line: 622, + Line: 620, Op: ir.FilterVarConstSliceOp, Src: "m[\"lit\"].ConstSlice", Value: "lit", @@ -1897,22 +1914,22 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 623, + Line: 621, Op: ir.FilterNotOp, Src: "!(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{{ - Line: 623, + Line: 621, Op: ir.FilterOrOp, Src: "(m[\"s\"].Const || m[\"s\"].ConstSlice)", Args: []ir.FilterExpr{ { - Line: 623, + Line: 621, Op: ir.FilterVarConstOp, Src: "m[\"s\"].Const", Value: "s", }, { - Line: 623, + Line: 621, Op: ir.FilterVarConstSliceOp, Src: "m[\"s\"].ConstSlice", Value: "s", @@ -1923,15 +1940,15 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 624, + Line: 622, Op: ir.FilterNotOp, Src: "!m[\"lit\"].Node.Is(`Ident`)", Args: []ir.FilterExpr{{ - Line: 624, + Line: 622, Op: ir.FilterVarNodeIsOp, Src: "m[\"lit\"].Node.Is(`Ident`)", Value: "lit", - Args: []ir.FilterExpr{{Line: 624, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, + Args: []ir.FilterExpr{{Line: 622, Op: ir.FilterStringOp, Src: "`Ident`", Value: "Ident"}}, }}, }, }, @@ -1939,7 +1956,7 @@ var PrecompiledRules = &ir.File{ }}, }, { - Line: 632, + Line: 630, Name: "stringConcatSimplify", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1948,27 +1965,27 @@ var PrecompiledRules = &ir.File{ DocAfter: "x + \"_\" + y", Rules: []ir.Rule{ { - Line: 633, - SyntaxPatterns: []ir.PatternString{{Line: 633, Value: "strings.Join([]string{$x, $y}, \"\")"}}, + Line: 631, + SyntaxPatterns: []ir.PatternString{{Line: 631, Value: "strings.Join([]string{$x, $y}, \"\")"}}, ReportTemplate: "suggestion: $x + $y", SuggestTemplate: "$x + $y", }, { - Line: 634, - SyntaxPatterns: []ir.PatternString{{Line: 634, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}}, + Line: 632, + SyntaxPatterns: []ir.PatternString{{Line: 632, Value: "strings.Join([]string{$x, $y, $z}, \"\")"}}, ReportTemplate: "suggestion: $x + $y + $z", SuggestTemplate: "$x + $y + $z", }, { - Line: 635, - SyntaxPatterns: []ir.PatternString{{Line: 635, Value: "strings.Join([]string{$x, $y}, $glue)"}}, + Line: 633, + SyntaxPatterns: []ir.PatternString{{Line: 633, Value: "strings.Join([]string{$x, $y}, $glue)"}}, ReportTemplate: "suggestion: $x + $glue + $y", SuggestTemplate: "$x + $glue + $y", }, }, }, { - Line: 642, + Line: 640, Name: "timeExprSimplify", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -1977,39 +1994,39 @@ var PrecompiledRules = &ir.File{ DocAfter: "t.UnixMilli()", Rules: []ir.Rule{ { - Line: 647, - SyntaxPatterns: []ir.PatternString{{Line: 647, Value: "$t.Unix() / 1000"}}, + Line: 645, + SyntaxPatterns: []ir.PatternString{{Line: 645, Value: "$t.Unix() / 1000"}}, ReportTemplate: "use $t.UnixMilli() instead of $$", SuggestTemplate: "$t.UnixMilli()", WhereExpr: ir.FilterExpr{ - Line: 648, + Line: 646, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 648, + Line: 646, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, { - Line: 648, + Line: 646, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 648, + Line: 646, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 642, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 648, + Line: 646, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 642, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2017,39 +2034,39 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 652, - SyntaxPatterns: []ir.PatternString{{Line: 652, Value: "$t.UnixNano() * 1000"}}, + Line: 650, + SyntaxPatterns: []ir.PatternString{{Line: 650, Value: "$t.UnixNano() * 1000"}}, ReportTemplate: "use $t.UnixMicro() instead of $$", SuggestTemplate: "$t.UnixMicro()", WhereExpr: ir.FilterExpr{ - Line: 653, + Line: 651, Op: ir.FilterAndOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\") && isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 653, + Line: 651, Op: ir.FilterGoVersionGreaterEqThanOp, Src: "m.GoVersion().GreaterEqThan(\"1.17\")", Value: "1.17", }, { - Line: 653, + Line: 651, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 653, + Line: 651, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 642, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 653, + Line: 651, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 644, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 642, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2059,7 +2076,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 662, + Line: 660, Name: "timeCmpSimplify", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2068,55 +2085,55 @@ var PrecompiledRules = &ir.File{ DocAfter: "t.After(tt)", Rules: []ir.Rule{ { - Line: 667, - SyntaxPatterns: []ir.PatternString{{Line: 667, Value: "!$t.Before($tt)"}}, + Line: 665, + SyntaxPatterns: []ir.PatternString{{Line: 665, Value: "!$t.Before($tt)"}}, ReportTemplate: "suggestion: $t.After($tt)", SuggestTemplate: "$t.After($tt)", WhereExpr: ir.FilterExpr{ - Line: 668, + Line: 666, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 668, + Line: 666, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 662, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 668, + Line: 666, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 662, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, }, { - Line: 671, - SyntaxPatterns: []ir.PatternString{{Line: 671, Value: "!$t.After($tt)"}}, + Line: 669, + SyntaxPatterns: []ir.PatternString{{Line: 669, Value: "!$t.After($tt)"}}, ReportTemplate: "suggestion: $t.Before($tt)", SuggestTemplate: "$t.Before($tt)", WhereExpr: ir.FilterExpr{ - Line: 672, + Line: 670, Op: ir.FilterOrOp, Src: "isTime(m[\"t\"])", Args: []ir.FilterExpr{ { - Line: 672, + Line: 670, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, + Args: []ir.FilterExpr{{Line: 662, Op: ir.FilterStringOp, Src: "`time.Time`", Value: "time.Time"}}, }, { - Line: 672, + Line: 670, Op: ir.FilterVarTypeIsOp, Src: "m[\"t\"].Type.Is(`*time.Time`)", Value: "t", - Args: []ir.FilterExpr{{Line: 664, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, + Args: []ir.FilterExpr{{Line: 662, Op: ir.FilterStringOp, Src: "`*time.Time`", Value: "*time.Time"}}, }, }, }, @@ -2124,7 +2141,7 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 680, + Line: 678, Name: "exposedSyncMutex", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2133,57 +2150,57 @@ var PrecompiledRules = &ir.File{ DocAfter: "type Foo struct{ ...; mu sync.Mutex; ... }", Rules: []ir.Rule{ { - Line: 685, - SyntaxPatterns: []ir.PatternString{{Line: 685, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}}, + Line: 683, + SyntaxPatterns: []ir.PatternString{{Line: 683, Value: "type $x struct { $*_; sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 686, + Line: 684, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 682, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 680, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 689, - SyntaxPatterns: []ir.PatternString{{Line: 689, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}}, + Line: 687, + SyntaxPatterns: []ir.PatternString{{Line: 687, Value: "type $x struct { $*_; *sync.Mutex; $*_ }"}}, ReportTemplate: "don't embed *sync.Mutex", WhereExpr: ir.FilterExpr{ - Line: 690, + Line: 688, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 682, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 680, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 693, - SyntaxPatterns: []ir.PatternString{{Line: 693, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}}, + Line: 691, + SyntaxPatterns: []ir.PatternString{{Line: 691, Value: "type $x struct { $*_; sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 694, + Line: 692, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 682, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 680, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, { - Line: 697, - SyntaxPatterns: []ir.PatternString{{Line: 697, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}}, + Line: 695, + SyntaxPatterns: []ir.PatternString{{Line: 695, Value: "type $x struct { $*_; *sync.RWMutex; $*_ }"}}, ReportTemplate: "don't embed *sync.RWMutex", WhereExpr: ir.FilterExpr{ - Line: 698, + Line: 696, Op: ir.FilterVarTextMatchesOp, Src: "isExported(m[\"x\"])", Value: "x", - Args: []ir.FilterExpr{{Line: 682, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, + Args: []ir.FilterExpr{{Line: 680, Op: ir.FilterStringOp, Src: "`^\\p{Lu}`", Value: "^\\p{Lu}"}}, }, }, }, }, { - Line: 706, + Line: 704, Name: "badSorting", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2192,48 +2209,48 @@ var PrecompiledRules = &ir.File{ DocAfter: "sort.Strings(xs)", Rules: []ir.Rule{ { - Line: 707, - SyntaxPatterns: []ir.PatternString{{Line: 707, Value: "$x = sort.IntSlice($x)"}}, + Line: 705, + SyntaxPatterns: []ir.PatternString{{Line: 705, Value: "$x = sort.IntSlice($x)"}}, ReportTemplate: "suspicious sort.IntSlice usage, maybe sort.Ints was intended?", SuggestTemplate: "sort.Ints($x)", WhereExpr: ir.FilterExpr{ - Line: 708, + Line: 706, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]int`)", Value: "x", - Args: []ir.FilterExpr{{Line: 708, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}}, + Args: []ir.FilterExpr{{Line: 706, Op: ir.FilterStringOp, Src: "`[]int`", Value: "[]int"}}, }, }, { - Line: 712, - SyntaxPatterns: []ir.PatternString{{Line: 712, Value: "$x = sort.Float64Slice($x)"}}, + Line: 710, + SyntaxPatterns: []ir.PatternString{{Line: 710, Value: "$x = sort.Float64Slice($x)"}}, ReportTemplate: "suspicious sort.Float64s usage, maybe sort.Float64s was intended?", SuggestTemplate: "sort.Float64s($x)", WhereExpr: ir.FilterExpr{ - Line: 713, + Line: 711, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]float64`)", Value: "x", - Args: []ir.FilterExpr{{Line: 713, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}}, + Args: []ir.FilterExpr{{Line: 711, Op: ir.FilterStringOp, Src: "`[]float64`", Value: "[]float64"}}, }, }, { - Line: 717, - SyntaxPatterns: []ir.PatternString{{Line: 717, Value: "$x = sort.StringSlice($x)"}}, + Line: 715, + SyntaxPatterns: []ir.PatternString{{Line: 715, Value: "$x = sort.StringSlice($x)"}}, ReportTemplate: "suspicious sort.StringSlice usage, maybe sort.Strings was intended?", SuggestTemplate: "sort.Strings($x)", WhereExpr: ir.FilterExpr{ - Line: 718, + Line: 716, Op: ir.FilterVarTypeIsOp, Src: "m[\"x\"].Type.Is(`[]string`)", Value: "x", - Args: []ir.FilterExpr{{Line: 718, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}}, + Args: []ir.FilterExpr{{Line: 716, Op: ir.FilterStringOp, Src: "`[]string`", Value: "[]string"}}, }, }, }, }, { - Line: 727, + Line: 725, Name: "externalErrorReassign", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2241,34 +2258,34 @@ var PrecompiledRules = &ir.File{ DocBefore: "io.EOF = nil", DocAfter: "/* don't do it */", Rules: []ir.Rule{{ - Line: 728, - SyntaxPatterns: []ir.PatternString{{Line: 728, Value: "$pkg.$err = $x"}}, + Line: 726, + SyntaxPatterns: []ir.PatternString{{Line: 726, Value: "$pkg.$err = $x"}}, ReportTemplate: "suspicious reassigment of error from another package", WhereExpr: ir.FilterExpr{ - Line: 729, + Line: 727, Op: ir.FilterAndOp, Src: "m[\"err\"].Type.Is(`error`) && m[\"pkg\"].Object.Is(`PkgName`)", Args: []ir.FilterExpr{ { - Line: 729, + Line: 727, Op: ir.FilterVarTypeIsOp, Src: "m[\"err\"].Type.Is(`error`)", Value: "err", - Args: []ir.FilterExpr{{Line: 729, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, + Args: []ir.FilterExpr{{Line: 727, Op: ir.FilterStringOp, Src: "`error`", Value: "error"}}, }, { - Line: 729, + Line: 727, Op: ir.FilterVarObjectIsOp, Src: "m[\"pkg\"].Object.Is(`PkgName`)", Value: "pkg", - Args: []ir.FilterExpr{{Line: 729, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, + Args: []ir.FilterExpr{{Line: 727, Op: ir.FilterStringOp, Src: "`PkgName`", Value: "PkgName"}}, }, }, }, }}, }, { - Line: 737, + Line: 735, Name: "emptyDecl", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2277,24 +2294,24 @@ var PrecompiledRules = &ir.File{ DocAfter: "/* nothing */", Rules: []ir.Rule{ { - Line: 738, - SyntaxPatterns: []ir.PatternString{{Line: 738, Value: "var()"}}, + Line: 736, + SyntaxPatterns: []ir.PatternString{{Line: 736, Value: "var()"}}, ReportTemplate: "empty var() block", }, { - Line: 739, - SyntaxPatterns: []ir.PatternString{{Line: 739, Value: "const()"}}, + Line: 737, + SyntaxPatterns: []ir.PatternString{{Line: 737, Value: "const()"}}, ReportTemplate: "empty const() block", }, { - Line: 740, - SyntaxPatterns: []ir.PatternString{{Line: 740, Value: "type()"}}, + Line: 738, + SyntaxPatterns: []ir.PatternString{{Line: 738, Value: "type()"}}, ReportTemplate: "empty type() block", }, }, }, { - Line: 747, + Line: 745, Name: "dynamicFmtString", MatcherName: "m", DocTags: []string{"diagnostic", "experimental"}, @@ -2303,16 +2320,16 @@ var PrecompiledRules = &ir.File{ DocAfter: "fmt.Errorf(\"%s\", msg)", Rules: []ir.Rule{ { - Line: 748, - SyntaxPatterns: []ir.PatternString{{Line: 748, Value: "fmt.Errorf($f)"}}, + Line: 746, + SyntaxPatterns: []ir.PatternString{{Line: 746, Value: "fmt.Errorf($f)"}}, ReportTemplate: "use errors.New($f) or fmt.Errorf(\"%s\", $f) instead", SuggestTemplate: "errors.New($f)", WhereExpr: ir.FilterExpr{ - Line: 749, + Line: 747, Op: ir.FilterNotOp, Src: "!m[\"f\"].Const", Args: []ir.FilterExpr{{ - Line: 749, + Line: 747, Op: ir.FilterVarConstOp, Src: "m[\"f\"].Const", Value: "f", @@ -2320,15 +2337,15 @@ var PrecompiledRules = &ir.File{ }, }, { - Line: 753, - SyntaxPatterns: []ir.PatternString{{Line: 753, Value: "fmt.Errorf($f($*args))"}}, + Line: 751, + SyntaxPatterns: []ir.PatternString{{Line: 751, Value: "fmt.Errorf($f($*args))"}}, ReportTemplate: "use errors.New($f($*args)) or fmt.Errorf(\"%s\", $f($*args)) instead", SuggestTemplate: "errors.New($f($*args))", }, }, }, { - Line: 762, + Line: 760, Name: "stringsCompare", MatcherName: "m", DocTags: []string{"style", "experimental"}, @@ -2337,25 +2354,25 @@ var PrecompiledRules = &ir.File{ DocAfter: "x < y", Rules: []ir.Rule{ { - Line: 763, - SyntaxPatterns: []ir.PatternString{{Line: 763, Value: "strings.Compare($s1, $s2) == 0"}}, + Line: 761, + SyntaxPatterns: []ir.PatternString{{Line: 761, Value: "strings.Compare($s1, $s2) == 0"}}, ReportTemplate: "suggestion: $s1 == $s2", SuggestTemplate: "$s1 == $s2", }, { - Line: 766, + Line: 764, SyntaxPatterns: []ir.PatternString{ - {Line: 766, Value: "strings.Compare($s1, $s2) == -1"}, - {Line: 767, Value: "strings.Compare($s1, $s2) < 0"}, + {Line: 764, Value: "strings.Compare($s1, $s2) == -1"}, + {Line: 765, Value: "strings.Compare($s1, $s2) < 0"}, }, ReportTemplate: "suggestion: $s1 < $s2", SuggestTemplate: "$s1 < $s2", }, { - Line: 770, + Line: 768, SyntaxPatterns: []ir.PatternString{ - {Line: 770, Value: "strings.Compare($s1, $s2) == 1"}, - {Line: 771, Value: "strings.Compare($s1, $s2) > 0"}, + {Line: 768, Value: "strings.Compare($s1, $s2) == 1"}, + {Line: 769, Value: "strings.Compare($s1, $s2) > 0"}, }, ReportTemplate: "suggestion: $s1 > $s2", SuggestTemplate: "$s1 > $s2", diff --git a/tools/vendor/github.com/go-toolsmith/astcopy/astcopy.go b/tools/vendor/github.com/go-toolsmith/astcopy/astcopy.go index 393c5cab..91e1f310 100644 --- a/tools/vendor/github.com/go-toolsmith/astcopy/astcopy.go +++ b/tools/vendor/github.com/go-toolsmith/astcopy/astcopy.go @@ -196,6 +196,18 @@ func IndexExpr(x *ast.IndexExpr) *ast.IndexExpr { return &cp } +// IndexListExpr returns x deep copy. +// Copy of nil argument is nil. +func IndexListExpr(x *typeparams.IndexListExpr) *typeparams.IndexListExpr { + if x == nil { + return nil + } + cp := *x + cp.X = copyExpr(x.X) + cp.Indices = ExprList(x.Indices) + return &cp +} + // SliceExpr returns x deep copy. // Copy of nil argument is nil. func SliceExpr(x *ast.SliceExpr) *ast.SliceExpr { @@ -858,6 +870,8 @@ func copyExpr(x ast.Expr) ast.Expr { return SelectorExpr(x) case *ast.IndexExpr: return IndexExpr(x) + case *typeparams.IndexListExpr: + return IndexListExpr(x) case *ast.SliceExpr: return SliceExpr(x) case *ast.TypeAssertExpr: diff --git a/tools/vendor/github.com/go-toolsmith/astequal/astequal.go b/tools/vendor/github.com/go-toolsmith/astequal/astequal.go index b2ab0e64..3d8db4af 100644 --- a/tools/vendor/github.com/go-toolsmith/astequal/astequal.go +++ b/tools/vendor/github.com/go-toolsmith/astequal/astequal.go @@ -109,6 +109,10 @@ func astExprEq(x, y ast.Expr) bool { y, ok := y.(*ast.IndexExpr) return ok && astIndexExprEq(x, y) + case *typeparams.IndexListExpr: + y, ok := y.(*typeparams.IndexListExpr) + return ok && astIndexListExprEq(x, y) + case *ast.SliceExpr: y, ok := y.(*ast.SliceExpr) return ok && astSliceExprEq(x, y) @@ -374,6 +378,13 @@ func astIndexExprEq(x, y *ast.IndexExpr) bool { return astExprEq(x.X, y.X) && astExprEq(x.Index, y.Index) } +func astIndexListExprEq(x, y *typeparams.IndexListExpr) bool { + if x == nil || y == nil { + return x == y + } + return astExprEq(x.X, y.X) && astExprSliceEq(x.Indices, y.Indices) +} + func astSliceExprEq(x, y *ast.SliceExpr) bool { if x == nil || y == nil { return x == y diff --git a/tools/vendor/github.com/golangci/gofmt/gofmt/gofmt.go b/tools/vendor/github.com/golangci/gofmt/gofmt/gofmt.go index fb9c8cb3..e7612afa 100644 --- a/tools/vendor/github.com/golangci/gofmt/gofmt/gofmt.go +++ b/tools/vendor/github.com/golangci/gofmt/gofmt/gofmt.go @@ -6,6 +6,7 @@ package gofmt import ( "bytes" + "context" "flag" "fmt" "go/ast" @@ -14,14 +15,15 @@ import ( "go/scanner" "go/token" "io" - "io/ioutil" + "io/fs" "os" - "os/exec" "path/filepath" "runtime" "runtime/pprof" "strings" - "sync" + + "github.com/golangci/gofmt/gofmt/internal/diff" + "golang.org/x/sync/semaphore" ) var ( @@ -37,76 +39,211 @@ var ( cpuprofile = flag.String("gofmt.cpuprofile", "", "write cpu profile to this file") ) +// Keep these in sync with go/format/format.go. const ( tabWidth = 8 - printerMode = printer.UseSpaces | printer.TabIndent + printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers + + // printerNormalizeNumbers means to canonicalize number literal prefixes + // and exponents while printing. See https://golang.org/doc/go1.13#gofmt. + // + // This value is defined in go/printer specifically for go/format and cmd/gofmt. + printerNormalizeNumbers = 1 << 30 ) +// fdSem guards the number of concurrently-open file descriptors. +// +// For now, this is arbitrarily set to 200, based on the observation that many +// platforms default to a kernel limit of 256. Ideally, perhaps we should derive +// it from rlimit on platforms that support that system call. +// +// File descriptors opened from outside of this package are not tracked, +// so this limit may be approximate. +var fdSem = make(chan bool, 200) + var ( - fileSet = token.NewFileSet() // per process FileSet - exitCode = 0 - rewrite func(*ast.File) *ast.File - parserMode parser.Mode - parserModeInitOnce sync.Once + rewrite func(*token.FileSet, *ast.File) *ast.File + parserMode parser.Mode ) -func report(err error) { - scanner.PrintError(os.Stderr, err) - exitCode = 2 -} - func usage() { fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n") flag.PrintDefaults() } func initParserMode() { - parserModeInitOnce.Do(func() { - parserMode = parser.ParseComments - if *allErrors { - parserMode |= parser.AllErrors - } - }) + parserMode = parser.ParseComments + if *allErrors { + parserMode |= parser.AllErrors + } } -func isGoFile(f os.FileInfo) bool { +func isGoFile(f fs.DirEntry) bool { // ignore non-Go files name := f.Name() - return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") + return !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && !f.IsDir() } -// If in == nil, the source is the contents of the file with the given filename. -func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error { - var perm os.FileMode = 0644 - if in == nil { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - fi, err := f.Stat() - if err != nil { - return err +// A sequencer performs concurrent tasks that may write output, but emits that +// output in a deterministic order. +type sequencer struct { + maxWeight int64 + sem *semaphore.Weighted // weighted by input bytes (an approximate proxy for memory overhead) + prev <-chan *reporterState // 1-buffered +} + +// newSequencer returns a sequencer that allows concurrent tasks up to maxWeight +// and writes tasks' output to out and err. +func newSequencer(maxWeight int64, out, err io.Writer) *sequencer { + sem := semaphore.NewWeighted(maxWeight) + prev := make(chan *reporterState, 1) + prev <- &reporterState{out: out, err: err} + return &sequencer{ + maxWeight: maxWeight, + sem: sem, + prev: prev, + } +} + +// exclusive is a weight that can be passed to a sequencer to cause +// a task to be executed without any other concurrent tasks. +const exclusive = -1 + +// Add blocks until the sequencer has enough weight to spare, then adds f as a +// task to be executed concurrently. +// +// If the weight is either negative or larger than the sequencer's maximum +// weight, Add blocks until all other tasks have completed, then the task +// executes exclusively (blocking all other calls to Add until it completes). +// +// f may run concurrently in a goroutine, but its output to the passed-in +// reporter will be sequential relative to the other tasks in the sequencer. +// +// If f invokes a method on the reporter, execution of that method may block +// until the previous task has finished. (To maximize concurrency, f should +// avoid invoking the reporter until it has finished any parallelizable work.) +// +// If f returns a non-nil error, that error will be reported after f's output +// (if any) and will cause a nonzero final exit code. +func (s *sequencer) Add(weight int64, f func(*reporter) error) { + if weight < 0 || weight > s.maxWeight { + weight = s.maxWeight + } + if err := s.sem.Acquire(context.TODO(), weight); err != nil { + // Change the task from "execute f" to "report err". + weight = 0 + f = func(*reporter) error { return err } + } + + r := &reporter{prev: s.prev} + next := make(chan *reporterState, 1) + s.prev = next + + // Start f in parallel: it can run until it invokes a method on r, at which + // point it will block until the previous task releases the output state. + go func() { + if err := f(r); err != nil { + r.Report(err) } - in = f - perm = fi.Mode().Perm() + next <- r.getState() // Release the next task. + s.sem.Release(weight) + }() +} + +// AddReport prints an error to s after the output of any previously-added +// tasks, causing the final exit code to be nonzero. +func (s *sequencer) AddReport(err error) { + s.Add(0, func(*reporter) error { return err }) +} + +// GetExitCode waits for all previously-added tasks to complete, then returns an +// exit code for the sequence suitable for passing to os.Exit. +func (s *sequencer) GetExitCode() int { + c := make(chan int, 1) + s.Add(0, func(r *reporter) error { + c <- r.ExitCode() + return nil + }) + return <-c +} + +// A reporter reports output, warnings, and errors. +type reporter struct { + prev <-chan *reporterState + state *reporterState +} + +// reporterState carries the state of a reporter instance. +// +// Only one reporter at a time may have access to a reporterState. +type reporterState struct { + out, err io.Writer + exitCode int +} + +// getState blocks until any prior reporters are finished with the reporter +// state, then returns the state for manipulation. +func (r *reporter) getState() *reporterState { + if r.state == nil { + r.state = <-r.prev + } + return r.state +} + +// Warnf emits a warning message to the reporter's error stream, +// without changing its exit code. +func (r *reporter) Warnf(format string, args ...any) { + fmt.Fprintf(r.getState().err, format, args...) +} + +// Write emits a slice to the reporter's output stream. +// +// Any error is returned to the caller, and does not otherwise affect the +// reporter's exit code. +func (r *reporter) Write(p []byte) (int, error) { + return r.getState().out.Write(p) +} + +// Report emits a non-nil error to the reporter's error stream, +// changing its exit code to a nonzero value. +func (r *reporter) Report(err error) { + if err == nil { + panic("Report with nil error") } + st := r.getState() + scanner.PrintError(st.err, err) + st.exitCode = 2 +} - src, err := ioutil.ReadAll(in) +func (r *reporter) ExitCode() int { + return r.getState().exitCode +} + +// If info == nil, we are formatting stdin instead of a file. +// If in == nil, the source is the contents of the file with the given filename. +func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) error { + src, err := readFile(filename, info, in) if err != nil { return err } - file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) + fileSet := token.NewFileSet() + fragmentOk := false + if info == nil { + // If we are formatting stdin, we accept a program fragment in lieu of a + // complete source file. + fragmentOk = true + } + file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, fragmentOk) if err != nil { return err } if rewrite != nil { if sourceAdj == nil { - file = rewrite(file) + file = rewrite(fileSet, file) } else { - fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n") + r.Warnf("warning: rewrite ignored for incomplete programs\n") } } @@ -124,15 +261,21 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error if !bytes.Equal(src, res) { // formatting has changed if *list { - fmt.Fprintln(out, filename) + fmt.Fprintln(r, filename) } if *write { + if info == nil { + panic("-w should not have been allowed with stdin") + } // make a temporary backup before overwriting original + perm := info.Mode().Perm() bakname, err := backupFile(filename+".", src, perm) if err != nil { return err } - err = ioutil.WriteFile(filename, res, perm) + fdSem <- true + err = os.WriteFile(filename, res, perm) + <-fdSem if err != nil { os.Rename(bakname, filename) return err @@ -143,50 +286,112 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error } } if *doDiff { - data, err := diff(src, res, filename) + data, err := diffWithReplaceTempFile(src, res, filename) if err != nil { return fmt.Errorf("computing diff: %s", err) } - fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) - out.Write(data) + fmt.Fprintf(r, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) + r.Write(data) } } if !*list && !*write && !*doDiff { - _, err = out.Write(res) + _, err = r.Write(res) } return err } -func visitFile(path string, f os.FileInfo, err error) error { - if err == nil && isGoFile(f) { - err = processFile(path, nil, os.Stdout, false) +// readFile reads the contents of filename, described by info. +// If in is non-nil, readFile reads directly from it. +// Otherwise, readFile opens and reads the file itself, +// with the number of concurrently-open files limited by fdSem. +func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) { + if in == nil { + fdSem <- true + var err error + f, err := os.Open(filename) + if err != nil { + return nil, err + } + in = f + defer func() { + f.Close() + <-fdSem + }() + } + + // Compute the file's size and read its contents with minimal allocations. + // + // If we have the FileInfo from filepath.WalkDir, use it to make + // a buffer of the right size and avoid ReadAll's reallocations. + // + // If the size is unknown (or bogus, or overflows an int), fall back to + // a size-independent ReadAll. + size := -1 + if info != nil && info.Mode().IsRegular() && int64(int(info.Size())) == info.Size() { + size = int(info.Size()) + } + if size+1 <= 0 { + // The file is not known to be regular, so we don't have a reliable size for it. + var err error + src, err := io.ReadAll(in) + if err != nil { + return nil, err + } + return src, nil + } + + // We try to read size+1 bytes so that we can detect modifications: if we + // read more than size bytes, then the file was modified concurrently. + // (If that happens, we could, say, append to src to finish the read, or + // proceed with a truncated buffer — but the fact that it changed at all + // indicates a possible race with someone editing the file, so we prefer to + // stop to avoid corrupting it.) + src := make([]byte, size+1) + n, err := io.ReadFull(in, src) + if err != nil && err != io.ErrUnexpectedEOF { + return nil, err } - // Don't complain if a file was deleted in the meantime (i.e. - // the directory changed concurrently while running gofmt). - if err != nil && !os.IsNotExist(err) { - report(err) + if n < size { + return nil, fmt.Errorf("error: size of %s changed during reading (from %d to %d bytes)", filename, size, n) + } else if n > size { + return nil, fmt.Errorf("error: size of %s changed during reading (from %d to >=%d bytes)", filename, size, len(src)) } - return nil + return src[:n], nil } -func walkDir(path string) { - filepath.Walk(path, visitFile) +func main() { + // Arbitrarily limit in-flight work to 2MiB times the number of threads. + // + // The actual overhead for the parse tree and output will depend on the + // specifics of the file, but this at least keeps the footprint of the process + // roughly proportional to GOMAXPROCS. + maxWeight := (2 << 20) * int64(runtime.GOMAXPROCS(0)) + s := newSequencer(maxWeight, os.Stdout, os.Stderr) + + // call gofmtMain in a separate function + // so that it can use defer and have them + // run before the exit. + gofmtMain(s) + os.Exit(s.GetExitCode()) } -func gofmtMain() { +func gofmtMain(s *sequencer) { flag.Usage = usage flag.Parse() if *cpuprofile != "" { + fdSem <- true f, err := os.Create(*cpuprofile) if err != nil { - fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err) - exitCode = 2 + s.AddReport(fmt.Errorf("creating cpu profile: %s", err)) return } - defer f.Close() + defer func() { + f.Close() + <-fdSem + }() pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } @@ -194,74 +399,76 @@ func gofmtMain() { initParserMode() initRewrite() - if flag.NArg() == 0 { + args := flag.Args() + if len(args) == 0 { if *write { - fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") - exitCode = 2 + s.AddReport(fmt.Errorf("error: cannot use -w with standard input")) return } - if err := processFile("", os.Stdin, os.Stdout, true); err != nil { - report(err) - } + s.Add(0, func(r *reporter) error { + return processFile("", nil, os.Stdin, r) + }) return } - for i := 0; i < flag.NArg(); i++ { - path := flag.Arg(i) - switch dir, err := os.Stat(path); { + for _, arg := range args { + switch info, err := os.Stat(arg); { case err != nil: - report(err) - case dir.IsDir(): - walkDir(path) + s.AddReport(err) + case !info.IsDir(): + // Non-directory arguments are always formatted. + arg := arg + s.Add(fileWeight(arg, info), func(r *reporter) error { + return processFile(arg, info, nil, r) + }) default: - if err := processFile(path, nil, os.Stdout, false); err != nil { - report(err) + // Directories are walked, ignoring non-Go files. + err := filepath.WalkDir(arg, func(path string, f fs.DirEntry, err error) error { + if err != nil || !isGoFile(f) { + return err + } + info, err := f.Info() + if err != nil { + s.AddReport(err) + return nil + } + s.Add(fileWeight(path, info), func(r *reporter) error { + return processFile(path, info, nil, r) + }) + return nil + }) + if err != nil { + s.AddReport(err) } } } } -func writeTempFile(dir, prefix string, data []byte) (string, error) { - file, err := ioutil.TempFile(dir, prefix) - if err != nil { - return "", err +func fileWeight(path string, info fs.FileInfo) int64 { + if info == nil { + return exclusive } - _, err = file.Write(data) - if err1 := file.Close(); err == nil { - err = err1 + if info.Mode().Type() == fs.ModeSymlink { + var err error + info, err = os.Stat(path) + if err != nil { + return exclusive + } } - if err != nil { - os.Remove(file.Name()) - return "", err + if !info.Mode().IsRegular() { + // For non-regular files, FileInfo.Size is system-dependent and thus not a + // reliable indicator of weight. + return exclusive } - return file.Name(), nil + return info.Size() } -func diff(b1, b2 []byte, filename string) (data []byte, err error) { - f1, err := writeTempFile("", "gofmt", b1) - if err != nil { - return - } - defer os.Remove(f1) - - f2, err := writeTempFile("", "gofmt", b2) - if err != nil { - return - } - defer os.Remove(f2) - - cmd := "diff" - if runtime.GOOS == "plan9" { - cmd = "/bin/ape/diff" - } - - data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput() +func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) { + data, err := diff.Diff("gofmt", b1, b2) 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. return replaceTempFilename(data, filename) } - return + return data, err } // replaceTempFilename replaces temporary filenames in diff with actual one. @@ -298,9 +505,12 @@ const chmodSupported = runtime.GOOS != "windows" // backupFile writes data to a new file named filename with permissions perm, // with 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 + } + + // 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: + // + // 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:] + } + } + + return data, err +} + +func writeTempFile(prefix string, data []byte) (string, error) { + file, err := ioutil.TempFile("", prefix) + if err != nil { + return "", err + } + _, err = file.Write(data) + if err1 := file.Close(); err == nil { + err = err1 + } + if err != nil { + os.Remove(file.Name()) + return "", err + } + return file.Name(), nil +} diff --git a/tools/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go b/tools/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go new file mode 100644 index 00000000..9a05d971 --- /dev/null +++ b/tools/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go @@ -0,0 +1,70 @@ +// 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/tools/vendor/github.com/golangci/gofmt/gofmt/readme.md b/tools/vendor/github.com/golangci/gofmt/gofmt/readme.md new file mode 100644 index 00000000..36a716d8 --- /dev/null +++ b/tools/vendor/github.com/golangci/gofmt/gofmt/readme.md @@ -0,0 +1,3 @@ +# Hard Fork of gofmt + +2022-08-31: Sync with go1.18.5 diff --git a/tools/vendor/github.com/golangci/gofmt/gofmt/rewrite.go b/tools/vendor/github.com/golangci/gofmt/gofmt/rewrite.go index 73741e0a..f1299a42 100644 --- a/tools/vendor/github.com/golangci/gofmt/gofmt/rewrite.go +++ b/tools/vendor/github.com/golangci/gofmt/gofmt/rewrite.go @@ -28,7 +28,9 @@ func initRewrite() { } pattern := parseExpr(f[0], "pattern") replace := parseExpr(f[1], "replacement") - rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) } + rewrite = func(fset *token.FileSet, p *ast.File) *ast.File { + return rewriteFile(fset, pattern, replace, p) + } } // parseExpr parses s as an expression. @@ -54,7 +56,7 @@ func dump(msg string, val reflect.Value) { */ // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file. -func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File { +func rewriteFile(fileSet *token.FileSet, pattern, replace ast.Expr, p *ast.File) *ast.File { cmap := ast.NewCommentMap(fileSet, p, p.Comments) m := make(map[string]reflect.Value) pat := reflect.ValueOf(pattern) @@ -271,6 +273,12 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) // Otherwise copy. switch p := pattern; p.Kind() { case reflect.Slice: + if p.IsNil() { + // Do not turn nil slices into empty slices. go/ast + // guarantees that certain lists will be nil if not + // populated. + return reflect.Zero(p.Type()) + } v := reflect.MakeSlice(p.Type(), p.Len(), p.Len()) for i := 0; i < p.Len(); i++ { v.Index(i).Set(subst(m, p.Index(i), pos)) @@ -284,7 +292,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) } return v - case reflect.Ptr: + case reflect.Pointer: v := reflect.New(p.Type()).Elem() if elem := p.Elem(); elem.IsValid() { v.Set(subst(m, elem, pos).Addr()) diff --git a/tools/vendor/github.com/golangci/gofmt/goimports/goimports.go b/tools/vendor/github.com/golangci/gofmt/goimports/goimports.go index 8878b700..1fa3328f 100644 --- a/tools/vendor/github.com/golangci/gofmt/goimports/goimports.go +++ b/tools/vendor/github.com/golangci/gofmt/goimports/goimports.go @@ -5,273 +5,16 @@ package goimports import ( - "bufio" "bytes" - "errors" - "flag" "fmt" - "go/scanner" - "io" "io/ioutil" - "log" "os" "os/exec" "path/filepath" "runtime" - "runtime/pprof" - "strings" - - "golang.org/x/tools/imports" -) - -var ( - // main operation modes - list = flag.Bool("goimports.l", false, "list files whose formatting differs from goimport's") - write = flag.Bool("goimports.w", false, "write result to (source) file instead of stdout") - doDiff = flag.Bool("goimports.d", false, "display diffs instead of rewriting files") - srcdir = flag.String("goimports.srcdir", "", "choose imports as if source code is from `dir`. When operating on a single file, dir may instead be the complete file name.") - verbose bool // verbose logging - - cpuProfile = flag.String("goimports.cpuprofile", "", "CPU profile output") - memProfile = flag.String("goimports.memprofile", "", "memory profile output") - memProfileRate = flag.Int("goimports.memrate", 0, "if > 0, sets runtime.MemProfileRate") - - options = &imports.Options{ - TabWidth: 8, - TabIndent: true, - Comments: true, - Fragment: true, - } - exitCode = 0 -) - -func init() { - flag.BoolVar(&options.AllErrors, "goimports.e", false, "report all errors (not just the first 10 on different lines)") - flag.StringVar(&imports.LocalPrefix, "goimports.local", "", "put imports beginning with this string after 3rd-party packages; comma-separated list") -} - -func report(err error) { - scanner.PrintError(os.Stderr, err) - exitCode = 2 -} - -func usage() { - fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n") - flag.PrintDefaults() - os.Exit(2) -} - -func isGoFile(f os.FileInfo) bool { - // ignore non-Go files - name := f.Name() - return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") -} - -// argumentType is which mode goimports was invoked as. -type argumentType int - -const ( - // fromStdin means the user is piping their source into goimports. - fromStdin argumentType = iota - - // singleArg is the common case from editors, when goimports is run on - // a single file. - singleArg - - // multipleArg is when the user ran "goimports file1.go file2.go" - // or ran goimports on a directory tree. - multipleArg ) -func processFile(filename string, in io.Reader, out io.Writer, argType argumentType) error { - opt := options - if argType == fromStdin { - nopt := *options - nopt.Fragment = true - opt = &nopt - } - - if in == nil { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - in = f - } - - src, err := ioutil.ReadAll(in) - if err != nil { - return err - } - - target := filename - if *srcdir != "" { - // Determine whether the provided -srcdirc is a directory or file - // and then use it to override the target. - // - // See https://github.com/dominikh/go-mode.el/issues/146 - if isFile(*srcdir) { - if argType == multipleArg { - return errors.New("-srcdir value can't be a file when passing multiple arguments or when walking directories") - } - target = *srcdir - } else if argType == singleArg && strings.HasSuffix(*srcdir, ".go") && !isDir(*srcdir) { - // For a file which doesn't exist on disk yet, but might shortly. - // e.g. user in editor opens $DIR/newfile.go and newfile.go doesn't yet exist on disk. - // The goimports on-save hook writes the buffer to a temp file - // first and runs goimports before the actual save to newfile.go. - // The editor's buffer is named "newfile.go" so that is passed to goimports as: - // goimports -srcdir=/gopath/src/pkg/newfile.go /tmp/gofmtXXXXXXXX.go - // and then the editor reloads the result from the tmp file and writes - // it to newfile.go. - target = *srcdir - } else { - // Pretend that file is from *srcdir in order to decide - // visible imports correctly. - target = filepath.Join(*srcdir, filepath.Base(filename)) - } - } - - res, err := imports.Process(target, src, opt) - if err != nil { - return err - } - - if !bytes.Equal(src, res) { - // formatting has changed - if *list { - fmt.Fprintln(out, filename) - } - if *write { - if argType == fromStdin { - // filename is "" - return errors.New("can't use -w on stdin") - } - err = ioutil.WriteFile(filename, res, 0) - if err != nil { - return err - } - } - if *doDiff { - if argType == fromStdin { - filename = "stdin.go" // because .orig looks silly - } - data, err := diff(src, res, filename) - if err != nil { - return fmt.Errorf("computing diff: %s", err) - } - fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) - out.Write(data) - } - } - - if !*list && !*write && !*doDiff { - _, err = out.Write(res) - } - - return err -} - -func visitFile(path string, f os.FileInfo, err error) error { - if err == nil && isGoFile(f) { - err = processFile(path, nil, os.Stdout, multipleArg) - } - if err != nil { - report(err) - } - return nil -} - -func walkDir(path string) { - filepath.Walk(path, visitFile) -} - -// parseFlags parses command line flags and returns the paths to process. -// It's a var so that custom implementations can replace it in other files. -var parseFlags = func() []string { - flag.BoolVar(&verbose, "v", false, "verbose logging") - - flag.Parse() - return flag.Args() -} - -func bufferedFileWriter(dest string) (w io.Writer, close func()) { - f, err := os.Create(dest) - if err != nil { - log.Fatal(err) - } - bw := bufio.NewWriter(f) - return bw, func() { - if err := bw.Flush(); err != nil { - log.Fatalf("error flushing %v: %v", dest, err) - } - if err := f.Close(); err != nil { - log.Fatal(err) - } - } -} - -func gofmtMain() { - flag.Usage = usage - paths := parseFlags() - - if *cpuProfile != "" { - bw, flush := bufferedFileWriter(*cpuProfile) - pprof.StartCPUProfile(bw) - defer flush() - defer pprof.StopCPUProfile() - } - // doTrace is a conditionally compiled wrapper around runtime/trace. It is - // used to allow goimports to compile under gccgo, which does not support - // runtime/trace. See https://golang.org/issue/15544. - if *memProfileRate > 0 { - runtime.MemProfileRate = *memProfileRate - bw, flush := bufferedFileWriter(*memProfile) - defer func() { - runtime.GC() // materialize all statistics - if err := pprof.WriteHeapProfile(bw); err != nil { - log.Fatal(err) - } - flush() - }() - } - - if verbose { - log.SetFlags(log.LstdFlags | log.Lmicroseconds) - imports.Debug = true - } - if options.TabWidth < 0 { - fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth) - exitCode = 2 - return - } - - if len(paths) == 0 { - if err := processFile("", os.Stdin, os.Stdout, fromStdin); err != nil { - report(err) - } - return - } - - argType := singleArg - if len(paths) > 1 { - argType = multipleArg - } - - for _, path := range paths { - switch dir, err := os.Stat(path); { - case err != nil: - report(err) - case dir.IsDir(): - walkDir(path) - default: - if err := processFile(path, nil, os.Stdout, argType); err != nil { - report(err) - } - } - } -} +// Extracted from golang.org/x/tools@v0.1.12/cmd/goimports/goimports.go func writeTempFile(dir, prefix string, data []byte) (string, error) { file, err := ioutil.TempFile(dir, prefix) @@ -344,15 +87,3 @@ func replaceTempFilename(diff []byte, filename string) ([]byte, error) { bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) return bytes.Join(bs, []byte{'\n'}), nil } - -// isFile reports whether name is a file. -func isFile(name string) bool { - fi, err := os.Stat(name) - return err == nil && fi.Mode().IsRegular() -} - -// isDir reports whether name is a directory. -func isDir(name string) bool { - fi, err := os.Stat(name) - return err == nil && fi.IsDir() -} diff --git a/tools/vendor/github.com/golangci/gofmt/goimports/golangci.go b/tools/vendor/github.com/golangci/gofmt/goimports/golangci.go index e9d013d5..7edc3793 100644 --- a/tools/vendor/github.com/golangci/gofmt/goimports/golangci.go +++ b/tools/vendor/github.com/golangci/gofmt/goimports/golangci.go @@ -8,13 +8,15 @@ import ( "golang.org/x/tools/imports" ) +// 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) if err != nil { return nil, err } - res, err := imports.Process(filename, src, options) + res, err := imports.Process(filename, src, nil) if err != nil { return nil, err } diff --git a/tools/vendor/github.com/golangci/gofmt/goimports/readme.md b/tools/vendor/github.com/golangci/gofmt/goimports/readme.md new file mode 100644 index 00000000..6c793eb7 --- /dev/null +++ b/tools/vendor/github.com/golangci/gofmt/goimports/readme.md @@ -0,0 +1,3 @@ +# Hard Fork of goimports + +2022-08-31: Sync with golang.org/x/tools v0.1.12 diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go index fefb3998..e9638c8e 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go @@ -51,7 +51,6 @@ type Cache struct { // to share a cache directory (for example, if the directory were stored // in a network file system). File locking is notoriously unreliable in // network file systems and may not suffice to protect the cache. -// func Open(dir string) (*Cache, error) { info, err := os.Stat(dir) if err != nil { @@ -159,7 +158,7 @@ func (c *Cache) get(id ActionID) (Entry, error) { defer f.Close() entry := make([]byte, entrySize+1) // +1 to detect whether f is too long if n, readErr := io.ReadFull(f, entry); n != entrySize || readErr != io.ErrUnexpectedEOF { - return failed(fmt.Errorf("read %d/%d bytes from %s with error %s", n, entrySize, fileName, readErr)) + return failed(fmt.Errorf("read %d/%d bytes from %s with error %w", n, entrySize, fileName, readErr)) } if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' { return failed(fmt.Errorf("bad data in %s", fileName)) @@ -181,7 +180,7 @@ func (c *Cache) get(id ActionID) (Entry, error) { } size, err := strconv.ParseInt(string(esize[i:]), 10, 64) if err != nil || size < 0 { - return failed(fmt.Errorf("failed to parse esize int from %s with error %s", fileName, err)) + return failed(fmt.Errorf("failed to parse esize int from %s with error %w", fileName, err)) } i = 0 for i < len(etime) && etime[i] == ' ' { @@ -189,7 +188,7 @@ func (c *Cache) get(id ActionID) (Entry, error) { } tm, err := strconv.ParseInt(string(etime[i:]), 10, 64) if err != nil || tm < 0 { - return failed(fmt.Errorf("failed to parse etime int from %s with error %s", fileName, err)) + return failed(fmt.Errorf("failed to parse etime int from %s with error %w", fileName, err)) } if err = c.used(fileName); err != nil { @@ -498,7 +497,7 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error { return err } if n, wErr := h.Write(buf); n != len(buf) { - return fmt.Errorf("wrote to hash %d/%d bytes with error %s", n, len(buf), wErr) + return fmt.Errorf("wrote to hash %d/%d bytes with error %w", n, len(buf), wErr) } sum := h.Sum(nil) diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/cache/default.go b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/default.go index 4558fb26..399cc84c 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/cache/default.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/default.go @@ -5,7 +5,6 @@ package cache import ( - "errors" "fmt" "log" "os" @@ -13,6 +12,8 @@ import ( "sync" ) +const envGolangciLintCache = "GOLANGCI_LINT_CACHE" + // Default returns the default cache to use. func Default() (*Cache, error) { defaultOnce.Do(initDefaultCache) @@ -65,19 +66,19 @@ func DefaultDir() string { // otherwise distinguish between an explicit "off" and a UserCacheDir error. defaultDirOnce.Do(func() { - defaultDir = os.Getenv("GOLANGCI_LINT_CACHE") + defaultDir = os.Getenv(envGolangciLintCache) if filepath.IsAbs(defaultDir) { return } if defaultDir != "" { - defaultDirErr = errors.New("GOLANGCI_LINT_CACHE is not an absolute path") + defaultDirErr = fmt.Errorf("%s is not an absolute path", envGolangciLintCache) return } // Compute default location. dir, err := os.UserCacheDir() if err != nil { - defaultDirErr = fmt.Errorf("GOLANGCI_LINT_CACHE is not defined and %v", err) + defaultDirErr = fmt.Errorf("%s is not defined and %w", envGolangciLintCache, err) return } defaultDir = filepath.Join(dir, "golangci-lint") diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/cache/readme.md b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/readme.md new file mode 100644 index 00000000..b469711e --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/cache/readme.md @@ -0,0 +1,18 @@ +# cache + +Extracted from go/src/cmd/go/internal/cache/ +I don't know what version of Go this package was pulled from. + +Adapted for golangci-lint: +- https://github.com/golangci/golangci-lint/pull/699 +- https://github.com/golangci/golangci-lint/pull/779 +- https://github.com/golangci/golangci-lint/pull/788 +- https://github.com/golangci/golangci-lint/pull/808 +- https://github.com/golangci/golangci-lint/pull/1063 +- https://github.com/golangci/golangci-lint/pull/1070 +- https://github.com/golangci/golangci-lint/pull/1162 +- https://github.com/golangci/golangci-lint/pull/2318 +- https://github.com/golangci/golangci-lint/pull/2352 +- https://github.com/golangci/golangci-lint/pull/3012 +- https://github.com/golangci/golangci-lint/pull/3096 +- https://github.com/golangci/golangci-lint/pull/3204 diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md b/tools/vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md new file mode 100644 index 00000000..36ec6ed4 --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md @@ -0,0 +1,10 @@ +# renameio + +Extracted from go/src/cmd/go/internal/renameio/ +I don't know what version of Go this package was pulled from. + +Adapted for golangci-lint: +- https://github.com/golangci/golangci-lint/pull/699 +- https://github.com/golangci/golangci-lint/pull/808 +- https://github.com/golangci/golangci-lint/pull/1063 +- https://github.com/golangci/golangci-lint/pull/3204 diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md new file mode 100644 index 00000000..7c7ba048 --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md @@ -0,0 +1,6 @@ +# robustio + +Extracted from go1.19.1/src/cmd/go/internal/robustio + +There is only one modification: +- ERROR_SHARING_VIOLATION extracted from go1.19.1/src/internal/syscall/windows/syscall_windows.go to remove the dependencies to `internal/syscall/windows` diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go index ce3dbbde..15b33773 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go @@ -42,9 +42,9 @@ func RemoveAll(path string) error { // in this package attempt to mitigate. // // Errors considered ephemeral include: -// - syscall.ERROR_ACCESS_DENIED -// - syscall.ERROR_FILE_NOT_FOUND -// - internal/syscall/windows.ERROR_SHARING_VIOLATION +// - syscall.ERROR_ACCESS_DENIED +// - syscall.ERROR_FILE_NOT_FOUND +// - internal/syscall/windows.ERROR_SHARING_VIOLATION // // This set may be expanded in the future; programs must not rely on the // non-ephemerality of any given error. diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go index 1ac0d10d..99fd8ebc 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go @@ -5,7 +5,7 @@ package robustio import ( - "os" + "errors" "syscall" ) @@ -13,16 +13,8 @@ const errFileNotFound = syscall.ENOENT // isEphemeralError returns true if err may be resolved by waiting. func isEphemeralError(err error) bool { - switch werr := err.(type) { - case *os.PathError: - err = werr.Err - case *os.LinkError: - err = werr.Err - case *os.SyscallError: - err = werr.Err - - } - if errno, ok := err.(syscall.Errno); ok { + var errno syscall.Errno + if errors.As(err, &errno) { return errno == errFileNotFound } return false diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go index 6cc2f03d..c56e36ca 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go @@ -2,20 +2,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build windows darwin +//go:build windows || darwin package robustio import ( + "errors" "math/rand" "os" "syscall" "time" ) -const arbitraryTimeout = 500 * time.Millisecond - -const ERROR_SHARING_VIOLATION = 32 +const arbitraryTimeout = 2000 * time.Millisecond // retry retries ephemeral errors from f up to an arbitrary timeout // to work around filesystem flakiness on Windows and Darwin. @@ -32,7 +31,8 @@ func retry(f func() (err error, mayRetry bool)) error { return err } - if errno, ok := err.(syscall.Errno); ok && (lowestErrno == 0 || errno < lowestErrno) { + var errno syscall.Errno + if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) { bestErr = err lowestErrno = errno } else if bestErr == nil { @@ -78,8 +78,7 @@ func readFile(filename string) ([]byte, error) { // Unlike in rename, we do not retry errFileNotFound here: it can occur // as a spurious error, but the file may also genuinely not exist, so the // increase in robustness is probably not worth the extra latency. - - return err, isEphemeralError(err) && err != errFileNotFound + return err, isEphemeralError(err) && !errors.Is(err, errFileNotFound) }) return b, err } diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go index b7d01b34..da9a46e4 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//+build !windows,!darwin +//go:build !windows && !darwin package robustio diff --git a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go index a35237d4..fe172895 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go +++ b/tools/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go @@ -5,23 +5,20 @@ package robustio import ( - "os" + "errors" "syscall" ) const errFileNotFound = syscall.ERROR_FILE_NOT_FOUND +// ERROR_SHARING_VIOLATION (ldez) extract from go1.19.1/src/internal/syscall/windows/syscall_windows.go. +// This is the only modification of this file. +const ERROR_SHARING_VIOLATION syscall.Errno = 32 + // isEphemeralError returns true if err may be resolved by waiting. func isEphemeralError(err error) bool { - switch werr := err.(type) { - case *os.PathError: - err = werr.Err - case *os.LinkError: - err = werr.Err - case *os.SyscallError: - err = werr.Err - } - if errno, ok := err.(syscall.Errno); ok { + var errno syscall.Errno + if errors.As(err, &errno) { switch errno { case syscall.ERROR_ACCESS_DENIED, syscall.ERROR_FILE_NOT_FOUND, diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go index 2723f5c0..6dc3b74b 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go @@ -64,11 +64,11 @@ func NewExecutor(version, commit, date string) *Executor { commit: commit, date: date, DBManager: lintersdb.NewManager(nil, nil), - debugf: logutils.Debug("exec"), + debugf: logutils.Debug(logutils.DebugKeyExec), } e.debugf("Starting execution...") - e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData) + e.log = report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &e.reportData) // to setup log level early we need to parse config from command line extra time to // find `-v` option @@ -105,7 +105,7 @@ func NewExecutor(version, commit, date string) *Executor { // like the default ones. It will overwrite them only if the same option // is found in command-line: it's ok, command-line has higher priority. - r := config.NewFileReader(e.cfg, commandLineCfg, e.log.Child("config_reader")) + r := config.NewFileReader(e.cfg, commandLineCfg, e.log.Child(logutils.DebugKeyConfigReader)) if err = r.Read(); err != nil { e.log.Fatalf("Can't read config: %s", err) } @@ -122,18 +122,18 @@ func NewExecutor(version, commit, date string) *Executor { fixSlicesFlags(e.lintersCmd.Flags()) e.EnabledLintersSet = lintersdb.NewEnabledSet(e.DBManager, - lintersdb.NewValidator(e.DBManager), e.log.Child("lintersdb"), e.cfg) - e.goenv = goutil.NewEnv(e.log.Child("goenv")) + lintersdb.NewValidator(e.DBManager), e.log.Child(logutils.DebugKeyLintersDB), e.cfg) + e.goenv = goutil.NewEnv(e.log.Child(logutils.DebugKeyGoEnv)) e.fileCache = fsutils.NewFileCache() e.lineCache = fsutils.NewLineCache(e.fileCache) - e.sw = timeutils.NewStopwatch("pkgcache", e.log.Child("stopwatch")) - e.pkgCache, err = pkgcache.NewCache(e.sw, e.log.Child("pkgcache")) + e.sw = timeutils.NewStopwatch("pkgcache", e.log.Child(logutils.DebugKeyStopwatch)) + e.pkgCache, err = pkgcache.NewCache(e.sw, e.log.Child(logutils.DebugKeyPkgCache)) if err != nil { e.log.Fatalf("Failed to build packages cache: %s", err) } e.loadGuard = load.NewGuard() - e.contextLoader = lint.NewContextLoader(e.cfg, e.log.Child("loader"), e.goenv, + e.contextLoader = lint.NewContextLoader(e.cfg, e.log.Child(logutils.DebugKeyLoader), e.goenv, e.lineCache, e.fileCache, e.pkgCache, e.loadGuard) if err = e.initHashSalt(version); err != nil { e.log.Fatalf("Failed to init hash salt: %s", err) @@ -169,7 +169,7 @@ func computeBinarySalt(version string) ([]byte, error) { return []byte(version), nil } - if logutils.HaveDebugTag("bin_salt") { + if logutils.HaveDebugTag(logutils.DebugKeyBinSalt) { return []byte("debug"), nil } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go index cc5a78dd..0fdcccff 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go @@ -16,6 +16,12 @@ import ( "github.com/golangci/golangci-lint/pkg/logutils" ) +const ( + // envHelpRun value: "1". + envHelpRun = "HELP_RUN" + envMemProfileRate = "GL_MEM_PROFILE_RATE" +) + func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) error { if e.cfg.Run.PrintVersion { _, _ = fmt.Fprintf(logutils.StdOut, "golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) @@ -35,7 +41,7 @@ func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) error { } if e.cfg.Run.MemProfilePath != "" { - if rate := os.Getenv("GL_MEMPROFILE_RATE"); rate != "" { + if rate := os.Getenv(envMemProfileRate); rate != "" { runtime.MemProfileRate, _ = strconv.Atoi(rate) } } @@ -112,7 +118,7 @@ func formatMemory(memBytes uint64) string { } func getDefaultConcurrency() int { - if os.Getenv("HELP_RUN") == "1" { + if os.Getenv(envHelpRun) == "1" { // Make stable concurrency for README help generating builds. const prettyConcurrency = 8 return prettyConcurrency @@ -125,7 +131,7 @@ func (e *Executor) initRoot() { rootCmd := &cobra.Command{ Use: "golangci-lint", Short: "golangci-lint is a smart linters runner.", - Long: `Smart, fast linters runner. Run it in cloud for every GitHub pull request on https://golangci.com`, + Long: `Smart, fast linters runner.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Help() diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go index 9f9d5ea4..8106dbdb 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go @@ -28,6 +28,13 @@ import ( const defaultFileMode = 0644 +const ( + // envFailOnWarnings value: "1" + envFailOnWarnings = "FAIL_ON_WARNINGS" + // envMemLogEvery value: "1" + envMemLogEvery = "GL_MEM_LOG_EVERY" +) + func getDefaultIssueExcludeHelp() string { parts := []string{"Use or not use default excludes:"} for _, ep := range config.DefaultExcludePatterns { @@ -350,9 +357,9 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) ([]result.Iss if err != nil { return nil, errors.Wrap(err, "context loading failed") } - lintCtx.Log = e.log.Child("linters context") + lintCtx.Log = e.log.Child(logutils.DebugKeyLintersContext) - runner, err := lint.NewRunner(e.cfg, e.log.Child("runner"), + runner, err := lint.NewRunner(e.cfg, e.log.Child(logutils.DebugKeyRunner), e.goenv, e.EnabledLintersSet, e.lineCache, e.DBManager, lintCtx.Packages) if err != nil { return nil, err @@ -390,7 +397,7 @@ func (e *Executor) runAndPrint(ctx context.Context, args []string) error { e.log.Warnf("Failed to discover go env: %s", err) } - if !logutils.HaveDebugTag("linters_output") { + if !logutils.HaveDebugTag(logutils.DebugKeyLintersOutput) { // Don't allow linters and loader to print anything log.SetOutput(io.Discard) savedStdout, savedStderr := e.setOutputToDevNull() @@ -474,9 +481,9 @@ func (e *Executor) createPrinter(format string, w io.Writer) (printers.Printer, case config.OutFormatColoredLineNumber, config.OutFormatLineNumber: p = printers.NewText(e.cfg.Output.PrintIssuedLine, format == config.OutFormatColoredLineNumber, e.cfg.Output.PrintLinterName, - e.log.Child("text_printer"), w) + e.log.Child(logutils.DebugKeyTextPrinter), w) case config.OutFormatTab: - p = printers.NewTab(e.cfg.Output.PrintLinterName, e.log.Child("tab_printer"), w) + p = printers.NewTab(e.cfg.Output.PrintLinterName, e.log.Child(logutils.DebugKeyTabPrinter), w) case config.OutFormatCheckstyle: p = printers.NewCheckstyle(w) case config.OutFormatCodeClimate: @@ -545,7 +552,7 @@ func (e *Executor) setupExitCode(ctx context.Context) { return } - needFailOnWarnings := os.Getenv("GL_TEST_RUN") == "1" || os.Getenv("FAIL_ON_WARNINGS") == "1" + needFailOnWarnings := os.Getenv(lintersdb.EnvTestRun) == "1" || os.Getenv(envFailOnWarnings) == "1" if needFailOnWarnings && len(e.reportData.Warnings) != 0 { e.exitCode = exitcodes.WarningInTest return @@ -569,7 +576,7 @@ func watchResources(ctx context.Context, done chan struct{}, logger logutils.Log ticker := time.NewTicker(intervalMS * time.Millisecond) defer ticker.Stop() - logEveryRecord := os.Getenv("GL_MEM_LOG_EVERY") == "1" + logEveryRecord := os.Getenv(envMemLogEvery) == "1" const MB = 1024 * 1024 track := func() { diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go index f1c36c38..12ffde21 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go @@ -25,10 +25,13 @@ var defaultLintersSettings = LintersSettings{ Comparison: true, }, Exhaustive: ExhaustiveSettings{ + Check: []string{"switch"}, CheckGenerated: false, DefaultSignifiesExhaustive: false, IgnoreEnumMembers: "", PackageScopeOnly: false, + ExplicitExhaustiveMap: false, + ExplicitExhaustiveSwitch: false, }, Forbidigo: ForbidigoSettings{ ExcludeGodocExamples: true, @@ -62,10 +65,22 @@ var defaultLintersSettings = LintersSettings{ MaxDeclLines: 1, MaxDeclChars: 30, }, + InterfaceBloat: InterfaceBloatSettings{ + Max: 10, + }, Lll: LllSettings{ LineLength: 120, TabWidth: 1, }, + LoggerCheck: LoggerCheckSettings{ + Kitlog: true, + Klog: true, + Logr: true, + Zap: true, + RequireStringKey: false, + NoPrintfLike: false, + Rules: nil, + }, MaintIdx: MaintIdxSettings{ Under: 20, }, @@ -105,12 +120,15 @@ var defaultLintersSettings = LintersSettings{ AllowAssignAndCallCuddle: true, AllowAssignAndAnythingCuddle: false, AllowMultiLineAssignCuddle: true, - AllowCuddleDeclaration: false, + ForceCaseTrailingWhitespaceLimit: 0, AllowTrailingComment: false, AllowSeparatedLeadingComment: false, + AllowCuddleDeclaration: false, + AllowCuddleWithCalls: []string{"Lock", "RLock"}, + AllowCuddleWithRHS: []string{"Unlock", "RUnlock"}, ForceCuddleErrCheckAndAssign: false, + ErrorVariableNames: []string{"err"}, ForceExclusiveShortDeclarations: false, - ForceCaseTrailingWhitespaceLimit: 0, }, } @@ -122,6 +140,7 @@ type LintersSettings struct { Depguard DepGuardSettings Dogsled DogsledSettings Dupl DuplSettings + DupWord DupWordSettings Errcheck ErrcheckSettings ErrChkJSON ErrChkJSONSettings ErrorLint ErrorLintSettings @@ -154,6 +173,7 @@ type LintersSettings struct { InterfaceBloat InterfaceBloatSettings Ireturn IreturnSettings Lll LllSettings + LoggerCheck LoggerCheckSettings MaintIdx MaintIdxSettings Makezero MakezeroSettings Maligned MalignedSettings @@ -238,6 +258,10 @@ type DuplSettings struct { Threshold int } +type DupWordSettings struct { + Keywords []string `mapstructure:"keywords"` +} + type ErrcheckSettings struct { DisableDefaultExclusions bool `mapstructure:"disable-default-exclusions"` CheckTypeAssertions bool `mapstructure:"check-type-assertions"` @@ -261,10 +285,13 @@ type ErrorLintSettings struct { } type ExhaustiveSettings struct { - CheckGenerated bool `mapstructure:"check-generated"` - DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"` - IgnoreEnumMembers string `mapstructure:"ignore-enum-members"` - PackageScopeOnly bool `mapstructure:"package-scope-only"` + Check []string `mapstructure:"check"` + CheckGenerated bool `mapstructure:"check-generated"` + DefaultSignifiesExhaustive bool `mapstructure:"default-signifies-exhaustive"` + IgnoreEnumMembers string `mapstructure:"ignore-enum-members"` + PackageScopeOnly bool `mapstructure:"package-scope-only"` + ExplicitExhaustiveMap bool `mapstructure:"explicit-exhaustive-map"` + ExplicitExhaustiveSwitch bool `mapstructure:"explicit-exhaustive-switch"` } type ExhaustiveStructSettings struct { @@ -337,7 +364,13 @@ type GodoxSettings struct { } type GoFmtSettings struct { - Simplify bool + Simplify bool + RewriteRules []GoFmtRewriteRule `mapstructure:"rewrite-rules"` +} + +type GoFmtRewriteRule struct { + Pattern string + Replacement string } type GofumptSettings struct { @@ -470,6 +503,16 @@ type LllSettings struct { TabWidth int `mapstructure:"tab-width"` } +type LoggerCheckSettings struct { + Kitlog bool `mapstructure:"kitlog"` + Klog bool `mapstructure:"klog"` + Logr bool `mapstructure:"logr"` + Zap bool `mapstructure:"zap"` + RequireStringKey bool `mapstructure:"require-string-key"` + NoPrintfLike bool `mapstructure:"no-printf-like"` + Rules []string `mapstructure:"rules"` +} + type MaintIdxSettings struct { Under int `mapstructure:"under"` } @@ -609,13 +652,17 @@ type TenvSettings struct { } type UseStdlibVarsSettings struct { - HTTPMethod bool `mapstructure:"http-method"` - HTTPStatusCode bool `mapstructure:"http-status-code"` - TimeWeekday bool `mapstructure:"time-weekday"` - TimeMonth bool `mapstructure:"time-month"` - TimeLayout bool `mapstructure:"time-layout"` - CryptoHash bool `mapstructure:"crypto-hash"` - DefaultRPCPathFlag bool `mapstructure:"default-rpc-path"` + HTTPMethod bool `mapstructure:"http-method"` + HTTPStatusCode bool `mapstructure:"http-status-code"` + TimeWeekday bool `mapstructure:"time-weekday"` + TimeMonth bool `mapstructure:"time-month"` + TimeLayout bool `mapstructure:"time-layout"` + CryptoHash bool `mapstructure:"crypto-hash"` + DefaultRPCPathFlag bool `mapstructure:"default-rpc-path"` + OSDevNullFlag bool `mapstructure:"os-dev-null-flag"` + SQLIsolationLevelFlag bool `mapstructure:"sql-isolation-level-flag"` + TLSSignatureSchemeFlag bool `mapstructure:"tls-signature-scheme-flag"` + ConstantKind bool `mapstructure:"constant-kind"` } type UnparamSettings struct { @@ -654,16 +701,19 @@ type WrapcheckSettings struct { } type WSLSettings struct { - StrictAppend bool `mapstructure:"strict-append"` - AllowAssignAndCallCuddle bool `mapstructure:"allow-assign-and-call"` - AllowAssignAndAnythingCuddle bool `mapstructure:"allow-assign-and-anything"` - AllowMultiLineAssignCuddle bool `mapstructure:"allow-multiline-assign"` - AllowCuddleDeclaration bool `mapstructure:"allow-cuddle-declarations"` - AllowTrailingComment bool `mapstructure:"allow-trailing-comment"` - AllowSeparatedLeadingComment bool `mapstructure:"allow-separated-leading-comment"` - ForceCuddleErrCheckAndAssign bool `mapstructure:"force-err-cuddling"` - ForceExclusiveShortDeclarations bool `mapstructure:"force-short-decl-cuddling"` - ForceCaseTrailingWhitespaceLimit int `mapstructure:"force-case-trailing-whitespace"` + StrictAppend bool `mapstructure:"strict-append"` + AllowAssignAndCallCuddle bool `mapstructure:"allow-assign-and-call"` + AllowAssignAndAnythingCuddle bool `mapstructure:"allow-assign-and-anything"` + AllowMultiLineAssignCuddle bool `mapstructure:"allow-multiline-assign"` + ForceCaseTrailingWhitespaceLimit int `mapstructure:"force-case-trailing-whitespace"` + AllowTrailingComment bool `mapstructure:"allow-trailing-comment"` + AllowSeparatedLeadingComment bool `mapstructure:"allow-separated-leading-comment"` + AllowCuddleDeclaration bool `mapstructure:"allow-cuddle-declarations"` + AllowCuddleWithCalls []string `mapstructure:"allow-cuddle-with-calls"` + AllowCuddleWithRHS []string `mapstructure:"allow-cuddle-with-rhs"` + ForceCuddleErrCheckAndAssign bool `mapstructure:"enforce-err-cuddling"` + ErrorVariableNames []string `mapstructure:"error-variable-names"` + ForceExclusiveShortDeclarations bool `mapstructure:"force-short-decl-cuddling"` } // CustomLinterSettings encapsulates the meta-data of a private linter. diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go index a4c3913f..3b40e59b 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go @@ -3,4 +3,4 @@ package golinters import "github.com/golangci/golangci-lint/pkg/logutils" // linterLogger must be use only when the context logger is not available. -var linterLogger = logutils.NewStderrLog("linter") +var linterLogger = logutils.NewStderrLog(logutils.DebugKeyLinter) diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go index 9ec35796..f54192a1 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go @@ -1,7 +1,7 @@ package golinters import ( - "github.com/sylvia7788/contextcheck" + "github.com/kkHAIKE/contextcheck" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go index b9241d18..3e0171f5 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go @@ -2,6 +2,8 @@ package golinters import ( "fmt" + "path/filepath" + "regexp" "strings" "sync" @@ -104,16 +106,31 @@ func (d depGuard) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { return resIssues, nil } +var separatorToReplace = regexp.QuoteMeta(string(filepath.Separator)) + +// normalizePathInRegex normalizes path in regular expressions. +// noop on Unix. +// This replacing should be safe because "/" are disallowed in Windows +// https://docs.microsoft.com/windows/win32/fileio/naming-a-file +func normalizePathInRegex(path string) string { + return strings.ReplaceAll(path, "/", separatorToReplace) +} + type guardian struct { *depguard.Depguard pkgsWithErrorMessage map[string]string } func newGuardian(settings *config.DepGuardSettings) (*guardian, error) { + var ignoreFileRules []string + for _, rule := range settings.IgnoreFileRules { + ignoreFileRules = append(ignoreFileRules, normalizePathInRegex(rule)) + } + dg := &depguard.Depguard{ Packages: settings.Packages, IncludeGoRoot: settings.IncludeGoRoot, - IgnoreFileRules: settings.IgnoreFileRules, + IgnoreFileRules: ignoreFileRules, } var err error diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go new file mode 100644 index 00000000..ae85a6d0 --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go @@ -0,0 +1,29 @@ +package golinters + +import ( + "strings" + + "github.com/Abirdcfly/dupword" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewDupWord(setting *config.DupWordSettings) *goanalysis.Linter { + a := dupword.NewAnalyzer() + + cfgMap := map[string]map[string]interface{}{} + if setting != nil { + cfgMap[a.Name] = map[string]interface{}{ + "keyword": strings.Join(setting.Keywords, ","), + } + } + + return goanalysis.NewLinter( + a.Name, + "checks for duplicate words in the source code", + []*analysis.Analyzer{a}, + cfgMap, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go index 778dc004..e6f983ba 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go @@ -15,10 +15,13 @@ func NewExhaustive(settings *config.ExhaustiveSettings) *goanalysis.Linter { if settings != nil { cfg = map[string]map[string]interface{}{ a.Name: { + exhaustive.CheckFlag: settings.Check, exhaustive.CheckGeneratedFlag: settings.CheckGenerated, exhaustive.DefaultSignifiesExhaustiveFlag: settings.DefaultSignifiesExhaustive, exhaustive.IgnoreEnumMembersFlag: settings.IgnoreEnumMembers, exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, + exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, + exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, }, } } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go index c52998fb..4a52c110 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go @@ -28,17 +28,17 @@ import ( ) var ( - debugf = logutils.Debug("goanalysis") + debugf = logutils.Debug(logutils.DebugKeyGoAnalysis) - analyzeDebugf = logutils.Debug("goanalysis/analyze") - isMemoryDebug = logutils.HaveDebugTag("goanalysis/memory") - issuesCacheDebugf = logutils.Debug("goanalysis/issues/cache") + analyzeDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisAnalyze) + isMemoryDebug = logutils.HaveDebugTag(logutils.DebugKeyGoAnalysisMemory) + issuesCacheDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisIssuesCache) - factsDebugf = logutils.Debug("goanalysis/facts") - factsCacheDebugf = logutils.Debug("goanalysis/facts/cache") - factsInheritDebugf = logutils.Debug("goanalysis/facts/inherit") - factsExportDebugf = logutils.Debug("goanalysis/facts") - isFactsExportDebug = logutils.HaveDebugTag("goanalysis/facts/export") + factsDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisFacts) + factsCacheDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisFactsCache) + factsInheritDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisFactsInherit) + factsExportDebugf = logutils.Debug(logutils.DebugKeyGoAnalysisFacts) + isFactsExportDebug = logutils.HaveDebugTag(logutils.DebugKeyGoAnalysisFactsExport) ) type Diagnostic struct { diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go index 50ea64c5..d6f40a0c 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go @@ -3,6 +3,7 @@ package goanalysis import ( "fmt" "go/types" + "io" "reflect" "runtime/debug" "time" @@ -331,7 +332,7 @@ func (act *action) loadPersistedFacts() bool { var facts []Fact key := fmt.Sprintf("%s/facts", act.a.Name) if err := act.r.pkgCache.Get(act.pkg, pkgcache.HashModeNeedAllDeps, key, &facts); err != nil { - if err != pkgcache.ErrMissing { + if !errors.Is(err, pkgcache.ErrMissing) && !errors.Is(err, io.EOF) { act.r.log.Warnf("Failed to get persisted facts: %s", err) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go index 7e4cf902..559fb139 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go @@ -14,6 +14,7 @@ import ( "github.com/golangci/golangci-lint/internal/pkgcache" "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/result" "github.com/golangci/golangci-lint/pkg/timeutils" ) @@ -28,7 +29,7 @@ type runAnalyzersConfig interface { } func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) { - log := lintCtx.Log.Child("goanalysis") + log := lintCtx.Log.Child(logutils.DebugKeyGoAnalysis) sw := timeutils.NewStopwatch("analyzers", log) const stagesToPrint = 10 diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go index d15dabc6..0b4af06a 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go @@ -25,11 +25,9 @@ import ( const goCriticName = "gocritic" -const goCriticDebugKey = "gocritic" - var ( - goCriticDebugf = logutils.Debug(goCriticDebugKey) - isGoCriticDebug = logutils.HaveDebugTag(goCriticDebugKey) + goCriticDebugf = logutils.Debug(logutils.DebugKeyGoCritic) + isGoCriticDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic) ) func NewGoCritic(settings *config.GoCriticSettings, cfg *config.Config) *goanalysis.Linter { @@ -37,9 +35,8 @@ func NewGoCritic(settings *config.GoCriticSettings, cfg *config.Config) *goanaly var resIssues []goanalysis.Issue wrapper := &goCriticWrapper{ - settings: settings, - cfg: cfg, - sizes: types.SizesFor("gc", runtime.GOARCH), + cfg: cfg, + sizes: types.SizesFor("gc", runtime.GOARCH), } analyzer := &analysis.Analyzer{ @@ -72,7 +69,7 @@ Dynamic rules are written declaratively with AST patterns, filters, report messa nil, ). WithContextSetter(func(context *linter.Context) { - wrapper.init() + wrapper.init(settings, context.Log) }). WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { return resIssues @@ -80,33 +77,33 @@ Dynamic rules are written declaratively with AST patterns, filters, report messa } type goCriticWrapper struct { - settings *config.GoCriticSettings settingsWrapper *goCriticSettingsWrapper cfg *config.Config sizes types.Sizes once sync.Once } -func (w *goCriticWrapper) init() { - if w.settings != nil { - // the 'defer' is here to catch the panic from checkers.InitEmbeddedRules() - defer func() { - if err := recover(); err != nil { - linterLogger.Fatalf("%s: %v: setting an explicit GOROOT can fix this problem.", goCriticName, err) - return - } - }() - w.once.Do(checkers.InitEmbeddedRules) - - settingsWrapper := newGoCriticSettingsWrapper(w.settings) +func (w *goCriticWrapper) init(settings *config.GoCriticSettings, logger logutils.Log) { + if settings == nil { + return + } - settingsWrapper.inferEnabledChecks(linterLogger) - if err := settingsWrapper.validate(linterLogger); err != nil { - linterLogger.Fatalf("%s: invalid settings: %s", goCriticName, err) + w.once.Do(func() { + err := checkers.InitEmbeddedRules() + if err != nil { + logger.Fatalf("%s: %v: setting an explicit GOROOT can fix this problem.", goCriticName, err) } + }) + + settingsWrapper := newGoCriticSettingsWrapper(settings, logger) + + settingsWrapper.inferEnabledChecks() - w.settingsWrapper = settingsWrapper + if err := settingsWrapper.validate(); err != nil { + logger.Fatalf("%s: invalid settings: %s", goCriticName, err) } + + w.settingsWrapper = settingsWrapper } func (w *goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { @@ -268,13 +265,15 @@ func (w *goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} type goCriticSettingsWrapper struct { *config.GoCriticSettings + logger logutils.Log + allCheckers []*gocriticlinter.CheckerInfo allCheckerMap map[string]*gocriticlinter.CheckerInfo inferredEnabledChecks map[string]bool } -func newGoCriticSettingsWrapper(settings *config.GoCriticSettings) *goCriticSettingsWrapper { +func newGoCriticSettingsWrapper(settings *config.GoCriticSettings, logger logutils.Log) *goCriticSettingsWrapper { allCheckers := gocriticlinter.GetCheckersInfo() allCheckerMap := make(map[string]*gocriticlinter.CheckerInfo) @@ -284,6 +283,7 @@ func newGoCriticSettingsWrapper(settings *config.GoCriticSettings) *goCriticSett return &goCriticSettingsWrapper{ GoCriticSettings: settings, + logger: logger, allCheckers: allCheckers, allCheckerMap: allCheckerMap, inferredEnabledChecks: map[string]bool{}, @@ -343,7 +343,7 @@ func (s *goCriticSettingsWrapper) disabledCheckersDebugf() { } } -func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) { +func (s *goCriticSettingsWrapper) inferEnabledChecks() { s.checkerTagsDebugf() enabledByDefaultChecks := s.getDefaultEnabledCheckersNames() @@ -371,7 +371,7 @@ func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) { // DisabledTags if len(s.DisabledTags) != 0 { - enabledChecks = s.filterByDisableTags(enabledChecks, s.DisabledTags, log) + enabledChecks = s.filterByDisableTags(enabledChecks, s.DisabledTags) } // EnabledChecks @@ -381,7 +381,7 @@ func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) { alreadyEnabledChecksSet := stringsSliceToSet(enabledChecks) for _, enabledCheck := range s.EnabledChecks { if alreadyEnabledChecksSet[enabledCheck] { - log.Warnf("No need to enable check %q: it's already enabled", enabledCheck) + s.logger.Warnf("%s: no need to enable check %q: it's already enabled", goCriticName, enabledCheck) continue } enabledChecks = append(enabledChecks, enabledCheck) @@ -395,8 +395,8 @@ func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) { enabledChecksSet := stringsSliceToSet(enabledChecks) for _, disabledCheck := range s.DisabledChecks { if !enabledChecksSet[disabledCheck] { - log.Warnf("Gocritic check %q was explicitly disabled via config. However, as this check "+ - "is disabled by default, there is no need to explicitly disable it via config.", disabledCheck) + s.logger.Warnf("%s: check %q was explicitly disabled via config. However, as this check "+ + "is disabled by default, there is no need to explicitly disable it via config.", goCriticName, disabledCheck) continue } delete(enabledChecksSet, disabledCheck) @@ -418,7 +418,7 @@ func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) { s.disabledCheckersDebugf() } -func (s *goCriticSettingsWrapper) validate(log logutils.Log) error { +func (s *goCriticSettingsWrapper) validate() error { if len(s.EnabledTags) == 0 { if len(s.EnabledChecks) != 0 && len(s.DisabledChecks) != 0 { return errors.New("both enabled and disabled check aren't allowed for gocritic") @@ -454,7 +454,7 @@ func (s *goCriticSettingsWrapper) validate(log logutils.Log) error { return errors.Wrap(err, "validate disabled checks") } - if err := s.validateCheckerNames(log); err != nil { + if err := s.validateCheckerNames(); err != nil { return errors.Wrap(err, "validation failed") } @@ -502,7 +502,7 @@ func (s *goCriticSettingsWrapper) getDefaultDisabledCheckersNames() []string { return disabled } -func (s *goCriticSettingsWrapper) validateCheckerNames(log logutils.Log) error { +func (s *goCriticSettingsWrapper) validateCheckerNames() error { allowedNames := s.getAllCheckerNames() for _, name := range s.EnabledChecks { @@ -526,7 +526,7 @@ func (s *goCriticSettingsWrapper) validateCheckerNames(log logutils.Log) error { } if !s.isCheckEnabled(checkName) { - log.Warnf("%s: settings were provided for not enabled check %q", goCriticName, checkName) + s.logger.Warnf("%s: settings were provided for not enabled check %q", goCriticName, checkName) } } @@ -543,13 +543,13 @@ func (s *goCriticSettingsWrapper) getLowerCasedParams() map[string]config.GoCrit return ret } -func (s *goCriticSettingsWrapper) filterByDisableTags(enabledChecks, disableTags []string, log logutils.Log) []string { +func (s *goCriticSettingsWrapper) filterByDisableTags(enabledChecks, disableTags []string) []string { enabledChecksSet := stringsSliceToSet(enabledChecks) for _, enabledCheck := range enabledChecks { checkInfo, checkInfoExists := s.allCheckerMap[enabledCheck] if !checkInfoExists { - log.Warnf("%s: check %q was not exists via filtering disabled tags", goCriticName, enabledCheck) + s.logger.Warnf("%s: check %q was not exists via filtering disabled tags", goCriticName, enabledCheck) continue } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go index e8c02411..112f422f 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go @@ -55,10 +55,15 @@ func NewGofmt(settings *config.GoFmtSettings) *goanalysis.Linter { func runGofmt(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoFmtSettings) ([]goanalysis.Issue, error) { fileNames := getFileNames(pass) + var rewriteRules []gofmtAPI.RewriteRule + for _, rule := range settings.RewriteRules { + rewriteRules = append(rewriteRules, gofmtAPI.RewriteRule(rule)) + } + var issues []goanalysis.Issue for _, f := range fileNames { - diff, err := gofmtAPI.Run(f, settings.Simplify) + diff, err := gofmtAPI.RunRewrite(f, settings.Simplify, rewriteRules) if err != nil { // TODO: skip return nil, err } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go index e9241742..f8d8751f 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go @@ -223,6 +223,9 @@ func getErrorTextForLinter(settings *config.LintersSettings, linterName string) if settings.Gofmt.Simplify { text += " with `-s`" } + for _, rule := range settings.Gofmt.RewriteRules { + text += fmt.Sprintf(" `-r '%s -> %s'`", rule.Pattern, rule.Replacement) + } case goimportsName: text = "File is not `goimports`-ed" if settings.Goimports.LocalPrefixes != "" { diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go index 42aa69b4..355fa8aa 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go @@ -34,7 +34,7 @@ func NewGoimports(settings *config.GoImportsSettings) *goanalysis.Linter { imports.LocalPrefix = settings.LocalPrefixes analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { - issues, err := runGoiImports(lintCtx, pass) + issues, err := runGoImports(lintCtx, pass) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func NewGoimports(settings *config.GoImportsSettings) *goanalysis.Linter { }).WithLoadMode(goanalysis.LoadModeSyntax) } -func runGoiImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { +func runGoImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { fileNames := getFileNames(pass) var issues []goanalysis.Issue diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go index f9cf81c8..044c96f3 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go @@ -11,10 +11,12 @@ import ( func NewInterfaceBloat(settings *config.InterfaceBloatSettings) *goanalysis.Linter { a := analyzer.New() - cfgMap := make(map[string]map[string]interface{}) + var cfg map[string]map[string]interface{} if settings != nil { - cfgMap[a.Name] = map[string]interface{}{ - analyzer.InterfaceMaxMethodsFlag: settings.Max, + cfg = map[string]map[string]interface{}{ + a.Name: { + analyzer.InterfaceMaxMethodsFlag: settings.Max, + }, } } @@ -22,6 +24,6 @@ func NewInterfaceBloat(settings *config.InterfaceBloatSettings) *goanalysis.Lint a.Name, a.Doc, []*analysis.Analyzer{a}, - nil, + cfg, ).WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go new file mode 100644 index 00000000..fc29127c --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go @@ -0,0 +1,44 @@ +package golinters + +import ( + "github.com/timonwong/loggercheck" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewLoggerCheck(settings *config.LoggerCheckSettings) *goanalysis.Linter { + var opts []loggercheck.Option + + if settings != nil { + var disable []string + if !settings.Kitlog { + disable = append(disable, "kitlog") + } + if !settings.Klog { + disable = append(disable, "klog") + } + if !settings.Logr { + disable = append(disable, "logr") + } + if !settings.Zap { + disable = append(disable, "zap") + } + + opts = []loggercheck.Option{ + loggercheck.WithDisable(disable), + loggercheck.WithRequireStringKey(settings.RequireStringKey), + loggercheck.WithRules(settings.Rules), + loggercheck.WithNoPrintfLike(settings.NoPrintfLike), + } + } + + analyzer := loggercheck.NewAnalyzer(opts...) + return goanalysis.NewLinter( + analyzer.Name, + analyzer.Doc, + []*analysis.Analyzer{analyzer}, + nil, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go index 5f50a394..55af7350 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go @@ -23,7 +23,7 @@ func NewParallelTest(settings *config.ParallelTestSettings) *goanalysis.Linter { return goanalysis.NewLinter( "paralleltest", "paralleltest detects missing usage of t.Parallel() method in your Go test", - []*analysis.Analyzer{paralleltest.Analyzer}, + []*analysis.Analyzer{a}, cfg, ).WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go index a9ff67ee..bc1b93a5 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go @@ -28,5 +28,5 @@ func NewReassign(settings *config.ReassignSettings) *goanalysis.Linter { a.Doc, []*analysis.Analyzer{a}, cfg, - ).WithLoadMode(goanalysis.LoadModeSyntax) + ).WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go index 5c160665..faa9e024 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go @@ -25,7 +25,7 @@ import ( const reviveName = "revive" -var reviveDebugf = logutils.Debug("revive") +var reviveDebugf = logutils.Debug(logutils.DebugKeyRevive) // jsonObject defines a JSON object of a failure type jsonObject struct { diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go index b421d30c..0eb21ec9 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go @@ -12,7 +12,7 @@ import ( "github.com/golangci/golangci-lint/pkg/logutils" ) -var debugf = logutils.Debug("megacheck") +var debugf = logutils.Debug(logutils.DebugKeyMegacheck) func getGoVersion(settings *config.StaticCheckSettings) string { var goVersion string diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/logrlint.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go similarity index 53% rename from tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/logrlint.go rename to tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go index 9899808c..3333593a 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/logrlint.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go @@ -1,19 +1,19 @@ package golinters import ( - "github.com/timonwong/logrlint" + "github.com/maratori/testableexamples/pkg/testableexamples" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" ) -func NewLogrLint() *goanalysis.Linter { - a := logrlint.Analyzer +func NewTestableexamples() *goanalysis.Linter { + a := testableexamples.NewAnalyzer() return goanalysis.NewLinter( a.Name, a.Doc, []*analysis.Analyzer{a}, nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + ).WithLoadMode(goanalysis.LoadModeSyntax) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go index dbb6d953..8c4858d8 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go @@ -14,13 +14,17 @@ func NewUseStdlibVars(cfg *config.UseStdlibVarsSettings) *goanalysis.Linter { cfgMap := make(map[string]map[string]interface{}) if cfg != nil { cfgMap[a.Name] = map[string]interface{}{ - analyzer.HTTPMethodFlag: cfg.HTTPMethod, - analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode, - analyzer.TimeWeekdayFlag: cfg.TimeWeekday, - analyzer.TimeMonthFlag: cfg.TimeMonth, - analyzer.TimeLayoutFlag: cfg.TimeLayout, - analyzer.CryptoHashFlag: cfg.CryptoHash, - analyzer.DefaultRPCPathFlag: cfg.DefaultRPCPathFlag, + analyzer.ConstantKindFlag: cfg.ConstantKind, + analyzer.CryptoHashFlag: cfg.CryptoHash, + analyzer.HTTPMethodFlag: cfg.HTTPMethod, + analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode, + analyzer.OSDevNullFlag: cfg.OSDevNullFlag, + analyzer.RPCDefaultPathFlag: cfg.DefaultRPCPathFlag, + analyzer.SQLIsolationLevelFlag: cfg.SQLIsolationLevelFlag, + analyzer.TimeLayoutFlag: cfg.TimeLayout, + analyzer.TimeMonthFlag: cfg.TimeMonth, + analyzer.TimeWeekdayFlag: cfg.TimeWeekday, + analyzer.TLSSignatureSchemeFlag: cfg.TLSSignatureSchemeFlag, } } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go index 9d7060b0..1d595622 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go @@ -19,30 +19,26 @@ func NewWSL(settings *config.WSLSettings) *goanalysis.Linter { var mu sync.Mutex var resIssues []goanalysis.Issue - conf := &wsl.Configuration{ - AllowCuddleWithCalls: []string{"Lock", "RLock"}, - AllowCuddleWithRHS: []string{"Unlock", "RUnlock"}, - ErrorVariableNames: []string{"err"}, - } + conf := wsl.DefaultConfig() if settings != nil { conf.StrictAppend = settings.StrictAppend conf.AllowAssignAndCallCuddle = settings.AllowAssignAndCallCuddle conf.AllowAssignAndAnythingCuddle = settings.AllowAssignAndAnythingCuddle conf.AllowMultiLineAssignCuddle = settings.AllowMultiLineAssignCuddle - conf.AllowCuddleDeclaration = settings.AllowCuddleDeclaration + conf.ForceCaseTrailingWhitespaceLimit = settings.ForceCaseTrailingWhitespaceLimit conf.AllowTrailingComment = settings.AllowTrailingComment conf.AllowSeparatedLeadingComment = settings.AllowSeparatedLeadingComment - conf.ForceCuddleErrCheckAndAssign = settings.ForceCuddleErrCheckAndAssign - conf.ForceCaseTrailingWhitespaceLimit = settings.ForceCaseTrailingWhitespaceLimit - conf.ForceExclusiveShortDeclarations = settings.ForceExclusiveShortDeclarations + conf.AllowCuddleDeclaration = settings.AllowCuddleDeclaration + conf.AllowCuddleWithCalls = settings.AllowCuddleWithCalls + conf.AllowCuddleWithRHS = settings.AllowCuddleWithRHS } analyzer := &analysis.Analyzer{ Name: goanalysis.TheOnlyAnalyzerName, Doc: goanalysis.TheOnlyanalyzerDoc, Run: func(pass *analysis.Pass) (interface{}, error) { - issues := runWSL(pass, conf) + issues := runWSL(pass, &conf) if len(issues) == 0 { return nil, nil diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go index 1c05b980..4873f3f9 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go @@ -30,7 +30,7 @@ func NewEnv(log logutils.Log) *Env { return &Env{ vars: map[string]string{}, log: log, - debugf: logutils.Debug("env"), + debugf: logutils.Debug(logutils.DebugKeyEnv), } } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go index 907c1c4d..92615b57 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go @@ -10,6 +10,9 @@ import ( "github.com/golangci/golangci-lint/pkg/logutils" ) +// EnvTestRun value: "1" +const EnvTestRun = "GL_TEST_RUN" + type EnabledSet struct { m *Manager v *Validator @@ -24,7 +27,7 @@ func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Confi v: v, log: log, cfg: cfg, - debugf: logutils.Debug("enabled_linters"), + debugf: logutils.Debug(logutils.DebugKeyEnabledLinters), } } @@ -84,7 +87,7 @@ func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) { } enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters()) - if os.Getenv("GL_TEST_RUN") == "1" { + if os.Getenv(EnvTestRun) == "1" { es.verbosePrintLintersStatus(enabledLinters) } return enabledLinters, nil diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go index b17ce3be..3867025f 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go @@ -38,7 +38,7 @@ func NewManager(cfg *config.Config, log logutils.Log) *Manager { // WithCustomLinters loads private linters that are specified in the golangci config file. func (m *Manager) WithCustomLinters() *Manager { if m.log == nil { - m.log = report.NewLogWrapper(logutils.NewStderrLog(""), &report.Data{}) + m.log = report.NewLogWrapper(logutils.NewStderrLog(logutils.DebugKeyEmpty), &report.Data{}) } if m.cfg != nil { for name, settings := range m.cfg.LintersSettings.Custom { @@ -108,6 +108,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { depGuardCfg *config.DepGuardSettings dogsledCfg *config.DogsledSettings duplCfg *config.DuplSettings + dupwordCfg *config.DupWordSettings errcheckCfg *config.ErrcheckSettings errchkjsonCfg *config.ErrChkJSONSettings errorlintCfg *config.ErrorLintSettings @@ -140,6 +141,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { interfaceBloatCfg *config.InterfaceBloatSettings ireturnCfg *config.IreturnSettings lllCfg *config.LllSettings + loggerCheckCfg *config.LoggerCheckSettings maintIdxCfg *config.MaintIdxSettings makezeroCfg *config.MakezeroSettings malignedCfg *config.MalignedSettings @@ -182,6 +184,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { depGuardCfg = &m.cfg.LintersSettings.Depguard dogsledCfg = &m.cfg.LintersSettings.Dogsled duplCfg = &m.cfg.LintersSettings.Dupl + dupwordCfg = &m.cfg.LintersSettings.DupWord errcheckCfg = &m.cfg.LintersSettings.Errcheck errchkjsonCfg = &m.cfg.LintersSettings.ErrChkJSON errorlintCfg = &m.cfg.LintersSettings.ErrorLint @@ -214,6 +217,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { interfaceBloatCfg = &m.cfg.LintersSettings.InterfaceBloat ireturnCfg = &m.cfg.LintersSettings.Ireturn lllCfg = &m.cfg.LintersSettings.Lll + loggerCheckCfg = &m.cfg.LintersSettings.LoggerCheck maintIdxCfg = &m.cfg.LintersSettings.MaintIdx makezeroCfg = &m.cfg.LintersSettings.Makezero malignedCfg = &m.cfg.LintersSettings.Maligned @@ -304,7 +308,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.43.0"). WithPresets(linter.PresetBugs). WithLoadForGoAnalysis(). - WithURL("https://github.com/sylvia7788/contextcheck"), + WithURL("https://github.com/kkHAIKE/contextcheck"), linter.NewConfig(golinters.NewCyclop(cyclopCfg)). WithSince("v1.37.0"). @@ -339,6 +343,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithURL("https://github.com/mibk/dupl"), + linter.NewConfig(golinters.NewDupWord(dupwordCfg)). + WithSince("1.50.0"). + WithPresets(linter.PresetComment). + WithAutoFix(). + WithURL("https://github.com/Abirdcfly/dupword"), + linter.NewConfig(golinters.NewDurationCheck()). WithSince("v1.37.0"). WithPresets(linter.PresetBugs). @@ -583,11 +593,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.8.0"). WithPresets(linter.PresetStyle), - linter.NewConfig(golinters.NewLogrLint()). + linter.NewConfig(golinters.NewLoggerCheck(loggerCheckCfg)). WithSince("v1.49.0"). WithLoadForGoAnalysis(). - WithPresets(linter.PresetBugs). - WithURL("https://github.com/timonwong/logrlint"), + WithPresets(linter.PresetStyle, linter.PresetBugs). + WithAlternativeNames("logrlint"). + WithURL("https://github.com/timonwong/loggercheck"), linter.NewConfig(golinters.NewMaintIdx(maintIdxCfg)). WithSince("v1.44.0"). @@ -687,6 +698,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewReassign(reassignCfg)). WithSince("1.49.0"). WithPresets(linter.PresetBugs). + WithLoadForGoAnalysis(). WithURL("https://github.com/curioswitch/go-reassign"), linter.NewConfig(golinters.NewRevive(reviveCfg)). @@ -747,6 +759,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithLoadForGoAnalysis(). WithURL("https://github.com/sivchari/tenv"), + linter.NewConfig(golinters.NewTestableexamples()). + WithSince("v1.50.0"). + WithPresets(linter.PresetTest). + WithURL("https://github.com/maratori/testableexamples"), + linter.NewConfig(golinters.NewTestpackage(testpackageCfg)). WithSince("v1.25.0"). WithPresets(linter.PresetStyle, linter.PresetTest). diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go index 8935134e..0bac1062 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go @@ -41,7 +41,7 @@ func NewContextLoader(cfg *config.Config, log logutils.Log, goenv *goutil.Env, return &ContextLoader{ cfg: cfg, log: log, - debugf: logutils.Debug("loader"), + debugf: logutils.Debug(logutils.DebugKeyLoader), goenv: goenv, pkgTestIDRe: regexp.MustCompile(`^(.*) \[(.*)\.test\]`), lineCache: lineCache, @@ -59,7 +59,7 @@ func (cl *ContextLoader) prepareBuildContext() { return } - os.Setenv("GOROOT", goroot) + os.Setenv(string(goutil.EnvGoRoot), goroot) build.Default.GOROOT = goroot build.Default.BuildTags = cl.cfg.Run.BuildTags } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go index e1a77c7d..b21635f0 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go @@ -39,7 +39,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint if cfg.Run.UseDefaultSkipDirs { skipDirs = append(skipDirs, packages.StdExcludeDirRegexps...) } - skipDirsProcessor, err := processors.NewSkipDirs(skipDirs, log.Child("skip dirs"), cfg.Run.Args) + skipDirsProcessor, err := processors.NewSkipDirs(skipDirs, log.Child(logutils.DebugKeySkipDirs), cfg.Run.Args) if err != nil { return nil, err } @@ -70,7 +70,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint processors.NewCgo(goenv), // Must go after Cgo. - processors.NewFilenameUnadjuster(pkgs, log.Child("filename_unadjuster")), + processors.NewFilenameUnadjuster(pkgs, log.Child(logutils.DebugKeyFilenameUnadjuster)), // Must be before diff, nolint and exclude autogenerated processor at least. processors.NewPathPrettifier(), @@ -84,14 +84,14 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint getExcludeProcessor(&cfg.Issues), getExcludeRulesProcessor(&cfg.Issues, log, lineCache), - processors.NewNolint(log.Child("nolint"), dbManager, enabledLinters), + processors.NewNolint(log.Child(logutils.DebugKeyNolint), dbManager, enabledLinters), processors.NewUniqByLine(cfg), processors.NewDiff(cfg.Issues.Diff, cfg.Issues.DiffFromRevision, cfg.Issues.DiffPatchFilePath, cfg.Issues.WholeFiles), processors.NewMaxPerFileFromLinter(cfg), - processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child("max_same_issues"), cfg), - processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child("max_from_linter"), cfg), - processors.NewSourceCode(lineCache, log.Child("source_code")), + processors.NewMaxSameIssues(cfg.Issues.MaxSameIssues, log.Child(logutils.DebugKeyMaxSameIssues), cfg), + processors.NewMaxFromLinter(cfg.Issues.MaxIssuesPerLinter, log.Child(logutils.DebugKeyMaxFromLinter), cfg), + processors.NewSourceCode(lineCache, log.Child(logutils.DebugKeySourceCode)), processors.NewPathShortener(), getSeverityRulesProcessor(&cfg.Severity, log, lineCache), processors.NewPathPrefixer(cfg.Output.PathPrefix), @@ -288,13 +288,13 @@ func getExcludeRulesProcessor(cfg *config.Issues, log logutils.Log, lineCache *f excludeRulesProcessor = processors.NewExcludeRulesCaseSensitive( excludeRules, lineCache, - log.Child("exclude_rules"), + log.Child(logutils.DebugKeyExcludeRules), ) } else { excludeRulesProcessor = processors.NewExcludeRules( excludeRules, lineCache, - log.Child("exclude_rules"), + log.Child(logutils.DebugKeyExcludeRules), ) } @@ -321,14 +321,14 @@ func getSeverityRulesProcessor(cfg *config.Severity, log logutils.Log, lineCache cfg.Default, severityRules, lineCache, - log.Child("severity_rules"), + log.Child(logutils.DebugKeySeverityRules), ) } else { severityRulesProcessor = processors.NewSeverityRules( cfg.Default, severityRules, lineCache, - log.Child("severity_rules"), + log.Child(logutils.DebugKeySeverityRules), ) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go index 57c35c78..2c9609d8 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go @@ -14,18 +14,18 @@ type Log interface { type LogLevel int const ( - // Debug messages, write to debug logs only by logutils.Debug. + // LogLevelDebug Debug messages, write to debug logs only by logutils.Debug. LogLevelDebug LogLevel = 0 - // Information messages, don't write too many messages, + // LogLevelInfo Information messages, don't write too many messages, // only useful ones: they are shown when running with -v. LogLevelInfo LogLevel = 1 - // Hidden errors: non-critical errors: work can be continued, no need to fail whole program; + // LogLevelWarn Hidden errors: non-critical errors: work can be continued, no need to fail whole program; // tests will crash if any warning occurred. LogLevelWarn LogLevel = 2 - // Only not hidden from user errors: whole program failing, usually + // LogLevelError Only not hidden from user errors: whole program failing, usually // error logging happens in 1-2 places: in the "main" function. LogLevelError LogLevel = 3 ) diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go index 93c9873d..710f084a 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go @@ -5,9 +5,65 @@ import ( "strings" ) +// envDebug value: one or several debug keys. +// examples: +// - Remove output to `/dev/null`: `GL_DEBUG=linters_output ./golangci-lint run` +// - Show linters configuration: `GL_DEBUG=enabled_linters golangci-lint run` +// - Some analysis details: `GL_DEBUG=goanalysis/analyze,goanalysis/facts golangci-lint run` +const envDebug = "GL_DEBUG" + +const ( + DebugKeyAutogenExclude = "autogen_exclude" + DebugKeyBinSalt = "bin_salt" + DebugKeyConfigReader = "config_reader" + DebugKeyEmpty = "" + DebugKeyEnabledLinters = "enabled_linters" + DebugKeyEnv = "env" + DebugKeyExcludeRules = "exclude_rules" + DebugKeyExec = "exec" + DebugKeyFilenameUnadjuster = "filename_unadjuster" + DebugKeyGoEnv = "goenv" + DebugKeyLinter = "linter" + DebugKeyLintersContext = "linters_context" + DebugKeyLintersDB = "lintersdb" + DebugKeyLintersOutput = "linters_output" + DebugKeyLoader = "loader" + DebugKeyMaxFromLinter = "max_from_linter" + DebugKeyMaxSameIssues = "max_same_issues" + DebugKeyPkgCache = "pkgcache" + DebugKeyRunner = "runner" + DebugKeySeverityRules = "severity_rules" + DebugKeySkipDirs = "skip_dirs" + DebugKeySourceCode = "source_code" + DebugKeyStopwatch = "stopwatch" + DebugKeyTabPrinter = "tab_printer" + DebugKeyTest = "test" + DebugKeyTextPrinter = "text_printer" +) + +const ( + DebugKeyGoAnalysis = "goanalysis" + + DebugKeyGoAnalysisAnalyze = DebugKeyGoAnalysis + "/analyze" + DebugKeyGoAnalysisIssuesCache = DebugKeyGoAnalysis + "/issues/cache" + DebugKeyGoAnalysisMemory = DebugKeyGoAnalysis + "/memory" + + DebugKeyGoAnalysisFacts = DebugKeyGoAnalysis + "/facts" + DebugKeyGoAnalysisFactsCache = DebugKeyGoAnalysisFacts + "/cache" + DebugKeyGoAnalysisFactsExport = DebugKeyGoAnalysisFacts + "/export" + DebugKeyGoAnalysisFactsInherit = DebugKeyGoAnalysisFacts + "/inherit" +) + +const ( + DebugKeyGoCritic = "gocritic" + DebugKeyMegacheck = "megacheck" + DebugKeyNolint = "nolint" + DebugKeyRevive = "revive" +) + func getEnabledDebugs() map[string]bool { ret := map[string]bool{} - debugVar := os.Getenv("GL_DEBUG") + debugVar := os.Getenv(envDebug) if debugVar == "" { return ret } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go index b87060d6..a68215e7 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go @@ -10,13 +10,20 @@ import ( "github.com/golangci/golangci-lint/pkg/exitcodes" ) +const ( + // envLogLevel values: "error", "err", "warning", "warn","info" + envLogLevel = "LOG_LEVEL" + // envLogTimestamp value: "1" + envLogTimestamp = "LOG_TIMESTAMP" +) + type StderrLog struct { name string logger *logrus.Logger level LogLevel } -var _ Log = NewStderrLog("") +var _ Log = NewStderrLog(DebugKeyEmpty) func NewStderrLog(name string) *StderrLog { sl := &StderrLog{ @@ -25,7 +32,7 @@ func NewStderrLog(name string) *StderrLog { level: LogLevelWarn, } - switch os.Getenv("LOG_LEVEL") { + switch os.Getenv(envLogLevel) { case "error", "err": sl.logger.SetLevel(logrus.ErrorLevel) case "warning", "warn": @@ -41,7 +48,7 @@ func NewStderrLog(name string) *StderrLog { DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` EnvironmentOverrideColors: true, } - if os.Getenv("LOG_TIMESTAMP") == "1" { + if os.Getenv(envLogTimestamp) == "1" { formatter.DisableTimestamp = false formatter.FullTimestamp = true formatter.TimestampFormat = time.StampMilli diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go index a11b68f7..f75ebaf5 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go @@ -12,7 +12,7 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) -var autogenDebugf = logutils.Debug("autogen_exclude") +var autogenDebugf = logutils.Debug(logutils.DebugKeyAutogenExclude) type ageFileSummary struct { isGenerated bool diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go index 65e01785..67104bab 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go @@ -12,6 +12,8 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) +const envGolangciDiffProcessorPatch = "GOLANGCI_DIFF_PROCESSOR_PATCH" + type Diff struct { onlyNew bool fromRev string @@ -28,7 +30,7 @@ func NewDiff(onlyNew bool, fromRev, patchFilePath string, wholeFiles bool) *Diff fromRev: fromRev, patchFilePath: patchFilePath, wholeFiles: wholeFiles, - patch: os.Getenv("GOLANGCI_DIFF_PROCESSOR_PATCH"), + patch: os.Getenv(envGolangciDiffProcessorPatch), } } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go index d4d6569f..e9f474b9 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go @@ -44,7 +44,8 @@ func createRules(rules []ExcludeRule, prefix string) []excludeRule { parsedRule.source = regexp.MustCompile(prefix + rule.Source) } if rule.Path != "" { - parsedRule.path = regexp.MustCompile(rule.Path) + path := normalizePathInRegex(rule.Path) + parsedRule.path = regexp.MustCompile(path) } parsedRules = append(parsedRules, parsedRule) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go index 17f519e3..d125e157 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" + "github.com/golangci/golangci-lint/internal/robustio" "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/logutils" @@ -104,13 +105,13 @@ func (f Fixer) fixIssuesInFile(filePath string, issues []result.Issue) error { if err = f.writeFixedFile(origFileLines, issues, tmpOutFile); err != nil { tmpOutFile.Close() - os.Remove(tmpOutFile.Name()) + _ = robustio.RemoveAll(tmpOutFile.Name()) return err } tmpOutFile.Close() - if err = os.Rename(tmpOutFile.Name(), filePath); err != nil { - os.Remove(tmpOutFile.Name()) + if err = robustio.Rename(tmpOutFile.Name(), filePath); err != nil { + _ = robustio.RemoveAll(tmpOutFile.Name()) return errors.Wrapf(err, "failed to rename %s -> %s", tmpOutFile.Name(), filePath) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go similarity index 72% rename from tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go rename to tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go index 7108fd3b..8bc3d847 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go @@ -1,10 +1,6 @@ package processors import ( - "path/filepath" - "regexp" - "strings" - "github.com/pkg/errors" "github.com/golangci/golangci-lint/pkg/result" @@ -48,15 +44,3 @@ func transformIssues(issues []result.Issue, transform func(i *result.Issue) *res return retIssues } - -var separatorToReplace = regexp.QuoteMeta(string(filepath.Separator)) - -func normalizePathInRegex(path string) string { - if filepath.Separator == '/' { - return path - } - - // This replacing should be safe because "/" are disallowed in Windows - // https://docs.microsoft.com/ru-ru/windows/win32/fileio/naming-a-file - return strings.ReplaceAll(path, "/", separatorToReplace) -} diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go index 96104eab..492dfd72 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go @@ -16,7 +16,7 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) -var nolintDebugf = logutils.Debug("nolint") +var nolintDebugf = logutils.Debug(logutils.DebugKeyNolint) var nolintRe = regexp.MustCompile(`^nolint( |:|$)`) type ignoredRange struct { diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go index 5ce940b3..04ed8312 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go @@ -1,7 +1,7 @@ package processors import ( - "path" + "path/filepath" "github.com/golangci/golangci-lint/pkg/result" ) @@ -27,7 +27,7 @@ func (*PathPrefixer) Name() string { func (p *PathPrefixer) Process(issues []result.Issue) ([]result.Issue, error) { if p.prefix != "" { for i := range issues { - issues[i].Pos.Filename = path.Join(p.prefix, issues[i].Pos.Filename) + issues[i].Pos.Filename = filepath.Join(p.prefix, issues[i].Pos.Filename) } } return issues, nil diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_unix.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_unix.go new file mode 100644 index 00000000..b0c7c338 --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_unix.go @@ -0,0 +1,8 @@ +//go:build !windows + +package processors + +// normalizePathInRegex it's a noop function on Unix. +func normalizePathInRegex(path string) string { + return path +} diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_windows.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_windows.go new file mode 100644 index 00000000..7f3e3622 --- /dev/null +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_windows.go @@ -0,0 +1,19 @@ +//go:build windows + +package processors + +import ( + "path/filepath" + "regexp" + "strings" +) + +var separatorToReplace = regexp.QuoteMeta(string(filepath.Separator)) + +// normalizePathInRegex normalizes path in regular expressions. +// noop on Unix. +// This replacing should be safe because "/" are disallowed in Windows +// https://docs.microsoft.com/windows/win32/fileio/naming-a-file +func normalizePathInRegex(path string) string { + return strings.ReplaceAll(path, "/", separatorToReplace) +} diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go index 7c9a4c1d..4077b340 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go @@ -49,7 +49,8 @@ func createSeverityRules(rules []SeverityRule, prefix string) []severityRule { parsedRule.source = regexp.MustCompile(prefix + rule.Source) } if rule.Path != "" { - parsedRule.path = regexp.MustCompile(rule.Path) + path := normalizePathInRegex(rule.Path) + parsedRule.path = regexp.MustCompile(path) } parsedRules = append(parsedRules, parsedRule) } diff --git a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go index f9305959..740c4fa8 100644 --- a/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go +++ b/tools/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go @@ -90,10 +90,8 @@ var ( type ByName struct{ next comparator } -//nolint:golint func (cmp ByName) Next() comparator { return cmp.next } -//nolint:golint func (cmp ByName) Compare(a, b *result.Issue) compareResult { var res compareResult @@ -110,10 +108,8 @@ func (cmp ByName) Compare(a, b *result.Issue) compareResult { type ByLine struct{ next comparator } -//nolint:golint func (cmp ByLine) Next() comparator { return cmp.next } -//nolint:golint func (cmp ByLine) Compare(a, b *result.Issue) compareResult { var res compareResult @@ -130,10 +126,8 @@ func (cmp ByLine) Compare(a, b *result.Issue) compareResult { type ByColumn struct{ next comparator } -//nolint:golint func (cmp ByColumn) Next() comparator { return cmp.next } -//nolint:golint func (cmp ByColumn) Compare(a, b *result.Issue) compareResult { var res compareResult diff --git a/tools/vendor/github.com/google/go-cmp/cmp/compare.go b/tools/vendor/github.com/google/go-cmp/cmp/compare.go index fd2b3a42..087320da 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/compare.go @@ -13,21 +13,21 @@ // // The primary features of cmp are: // -// • When the default behavior of equality does not suit the needs of the test, -// custom equality functions can override the equality operation. -// For example, an equality function may report floats as equal so long as they -// are within some tolerance of each other. +// - When the default behavior of equality does not suit the test's needs, +// custom equality functions can override the equality operation. +// For example, an equality function may report floats as equal so long as +// they are within some tolerance of each other. // -// • Types that have an Equal method may use that method to determine equality. -// This allows package authors to determine the equality operation for the types -// that they define. +// - Types with an Equal method may use that method to determine equality. +// This allows package authors to determine the equality operation +// for the types that they define. // -// • If no custom equality functions are used and no Equal method is defined, -// equality is determined by recursively comparing the primitive kinds on both -// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported -// fields are not compared by default; they result in panics unless suppressed -// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly -// compared using the Exporter option. +// - If no custom equality functions are used and no Equal method is defined, +// equality is determined by recursively comparing the primitive kinds on +// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, +// unexported fields are not compared by default; they result in panics +// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) +// or explicitly compared using the Exporter option. package cmp import ( @@ -45,25 +45,25 @@ import ( // Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // -// • Let S be the set of all Ignore, Transformer, and Comparer options that -// remain after applying all path filters, value filters, and type filters. -// If at least one Ignore exists in S, then the comparison is ignored. -// If the number of Transformer and Comparer options in S is greater than one, -// then Equal panics because it is ambiguous which option to use. -// If S contains a single Transformer, then use that to transform the current -// values and recursively call Equal on the output values. -// If S contains a single Comparer, then use that to compare the current values. -// Otherwise, evaluation proceeds to the next rule. +// - Let S be the set of all Ignore, Transformer, and Comparer options that +// remain after applying all path filters, value filters, and type filters. +// If at least one Ignore exists in S, then the comparison is ignored. +// If the number of Transformer and Comparer options in S is non-zero, +// then Equal panics because it is ambiguous which option to use. +// If S contains a single Transformer, then use that to transform +// the current values and recursively call Equal on the output values. +// If S contains a single Comparer, then use that to compare the current values. +// Otherwise, evaluation proceeds to the next rule. // -// • If the values have an Equal method of the form "(T) Equal(T) bool" or -// "(T) Equal(I) bool" where T is assignable to I, then use the result of -// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and -// evaluation proceeds to the next rule. +// - If the values have an Equal method of the form "(T) Equal(T) bool" or +// "(T) Equal(I) bool" where T is assignable to I, then use the result of +// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and +// evaluation proceeds to the next rule. // -// • Lastly, try to compare x and y based on their basic kinds. -// Simple kinds like booleans, integers, floats, complex numbers, strings, and -// channels are compared using the equivalent of the == operator in Go. -// Functions are only equal if they are both nil, otherwise they are unequal. +// - Lastly, try to compare x and y based on their basic kinds. +// Simple kinds like booleans, integers, floats, complex numbers, strings, +// and channels are compared using the equivalent of the == operator in Go. +// Functions are only equal if they are both nil, otherwise they are unequal. // // Structs are equal if recursively calling Equal on all fields report equal. // If a struct contains unexported fields, Equal panics unless an Ignore option @@ -144,7 +144,7 @@ func rootStep(x, y interface{}) PathStep { // so that they have the same parent type. var t reflect.Type if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { - t = reflect.TypeOf((*interface{})(nil)).Elem() + t = anyType if vx.IsValid() { vvx := reflect.New(t).Elem() vvx.Set(vx) @@ -639,7 +639,9 @@ type dynChecker struct{ curr, next int } // Next increments the state and reports whether a check should be performed. // // Checks occur every Nth function call, where N is a triangular number: +// // 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... +// // See https://en.wikipedia.org/wiki/Triangular_number // // This sequence ensures that the cost of checks drops significantly as diff --git a/tools/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/tools/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go index bc196b16..a248e543 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -127,9 +127,9 @@ var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 // This function returns an edit-script, which is a sequence of operations // needed to convert one list into the other. The following invariants for // the edit-script are maintained: -// • eq == (es.Dist()==0) -// • nx == es.LenX() -// • ny == es.LenY() +// - eq == (es.Dist()==0) +// - nx == es.LenX() +// - ny == es.LenY() // // This algorithm is not guaranteed to be an optimal solution (i.e., one that // produces an edit-script with a minimal Levenshtein distance). This algorithm @@ -169,12 +169,13 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { // A diagonal edge is equivalent to a matching symbol between both X and Y. // Invariants: - // • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx - // • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny + // - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx + // - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny // // In general: - // • fwdFrontier.X < revFrontier.X - // • fwdFrontier.Y < revFrontier.Y + // - fwdFrontier.X < revFrontier.X + // - fwdFrontier.Y < revFrontier.Y + // // Unless, it is time for the algorithm to terminate. fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} revPath := path{-1, point{nx, ny}, make(EditScript, 0)} @@ -195,19 +196,21 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { // computing sub-optimal edit-scripts between two lists. // // The algorithm is approximately as follows: - // • Searching for differences switches back-and-forth between - // a search that starts at the beginning (the top-left corner), and - // a search that starts at the end (the bottom-right corner). The goal of - // the search is connect with the search from the opposite corner. - // • As we search, we build a path in a greedy manner, where the first - // match seen is added to the path (this is sub-optimal, but provides a - // decent result in practice). When matches are found, we try the next pair - // of symbols in the lists and follow all matches as far as possible. - // • When searching for matches, we search along a diagonal going through - // through the "frontier" point. If no matches are found, we advance the - // frontier towards the opposite corner. - // • This algorithm terminates when either the X coordinates or the - // Y coordinates of the forward and reverse frontier points ever intersect. + // - Searching for differences switches back-and-forth between + // a search that starts at the beginning (the top-left corner), and + // a search that starts at the end (the bottom-right corner). + // The goal of the search is connect with the search + // from the opposite corner. + // - As we search, we build a path in a greedy manner, + // where the first match seen is added to the path (this is sub-optimal, + // but provides a decent result in practice). When matches are found, + // we try the next pair of symbols in the lists and follow all matches + // as far as possible. + // - When searching for matches, we search along a diagonal going through + // through the "frontier" point. If no matches are found, + // we advance the frontier towards the opposite corner. + // - This algorithm terminates when either the X coordinates or the + // Y coordinates of the forward and reverse frontier points ever intersect. // This algorithm is correct even if searching only in the forward direction // or in the reverse direction. We do both because it is commonly observed @@ -389,6 +392,7 @@ type point struct{ X, Y int } func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } // zigzag maps a consecutive sequence of integers to a zig-zag sequence. +// // [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] func zigzag(x int) int { if x&1 != 0 { diff --git a/tools/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/tools/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go deleted file mode 100644 index 9147a299..00000000 --- a/tools/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017, 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 value - -import ( - "math" - "reflect" -) - -// IsZero reports whether v is the zero value. -// This does not rely on Interface and so can be used on unexported fields. -func IsZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return v.Bool() == false - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return math.Float64bits(v.Float()) == 0 - case reflect.Complex64, reflect.Complex128: - return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0 - case reflect.String: - return v.String() == "" - case reflect.UnsafePointer: - return v.Pointer() == 0 - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - return v.IsNil() - case reflect.Array: - for i := 0; i < v.Len(); i++ { - if !IsZero(v.Index(i)) { - return false - } - } - return true - case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - if !IsZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/tools/vendor/github.com/google/go-cmp/cmp/options.go b/tools/vendor/github.com/google/go-cmp/cmp/options.go index e57b9eb5..1f9ca9c4 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/options.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/options.go @@ -33,6 +33,7 @@ type Option interface { } // applicableOption represents the following types: +// // Fundamental: ignore | validator | *comparer | *transformer // Grouping: Options type applicableOption interface { @@ -43,6 +44,7 @@ type applicableOption interface { } // coreOption represents the following types: +// // Fundamental: ignore | validator | *comparer | *transformer // Filters: *pathFilter | *valuesFilter type coreOption interface { @@ -336,9 +338,9 @@ func (tr transformer) String() string { // both implement T. // // The equality function must be: -// • Symmetric: equal(x, y) == equal(y, x) -// • Deterministic: equal(x, y) == equal(x, y) -// • Pure: equal(x, y) does not modify x or y +// - Symmetric: equal(x, y) == equal(y, x) +// - Deterministic: equal(x, y) == equal(x, y) +// - Pure: equal(x, y) does not modify x or y func Comparer(f interface{}) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.Equal) || v.IsNil() { @@ -430,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option { } // Result represents the comparison result for a single node and -// is provided by cmp when calling Result (see Reporter). +// is provided by cmp when calling Report (see Reporter). type Result struct { _ [0]func() // Make Result incomparable flags resultFlags diff --git a/tools/vendor/github.com/google/go-cmp/cmp/path.go b/tools/vendor/github.com/google/go-cmp/cmp/path.go index c7100346..a0a58850 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/path.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/path.go @@ -41,13 +41,13 @@ type PathStep interface { // The type of each valid value is guaranteed to be identical to Type. // // In some cases, one or both may be invalid or have restrictions: - // • For StructField, both are not interface-able if the current field - // is unexported and the struct type is not explicitly permitted by - // an Exporter to traverse unexported fields. - // • For SliceIndex, one may be invalid if an element is missing from - // either the x or y slice. - // • For MapIndex, one may be invalid if an entry is missing from - // either the x or y map. + // - For StructField, both are not interface-able if the current field + // is unexported and the struct type is not explicitly permitted by + // an Exporter to traverse unexported fields. + // - For SliceIndex, one may be invalid if an element is missing from + // either the x or y slice. + // - For MapIndex, one may be invalid if an entry is missing from + // either the x or y map. // // The provided values must not be mutated. Values() (vx, vy reflect.Value) @@ -94,6 +94,7 @@ func (pa Path) Index(i int) PathStep { // The simplified path only contains struct field accesses. // // For example: +// // MyMap.MySlices.MyField func (pa Path) String() string { var ss []string @@ -108,6 +109,7 @@ func (pa Path) String() string { // GoString returns the path to a specific node using Go syntax. // // For example: +// // (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField func (pa Path) GoString() string { var ssPre, ssPost []string @@ -159,7 +161,7 @@ func (ps pathStep) String() string { if ps.typ == nil { return "" } - s := ps.typ.String() + s := value.TypeString(ps.typ, false) if s == "" || strings.ContainsAny(s, "{}\n") { return "root" // Type too simple or complex to print } @@ -282,7 +284,7 @@ type typeAssertion struct { func (ta TypeAssertion) Type() reflect.Type { return ta.typ } func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } -func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) } +func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } // Transform is a transformation from the parent type to the current type. type Transform struct{ *transform } diff --git a/tools/vendor/github.com/google/go-cmp/cmp/report_compare.go b/tools/vendor/github.com/google/go-cmp/cmp/report_compare.go index 1ef65ac1..2050bf6b 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -7,8 +7,6 @@ package cmp import ( "fmt" "reflect" - - "github.com/google/go-cmp/cmp/internal/value" ) // numContextRecords is the number of surrounding equal records to print. @@ -117,7 +115,7 @@ func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out // For leaf nodes, format the value based on the reflect.Values alone. // As a special case, treat equal []byte as a leaf nodes. - isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == reflect.TypeOf(byte(0)) + isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0 if v.MaxDepth == 0 || isEqualBytes { switch opts.DiffMode { @@ -248,11 +246,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, pt var isZero bool switch opts.DiffMode { case diffIdentical: - isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY) + isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero() case diffRemoved: - isZero = value.IsZero(r.Value.ValueX) + isZero = r.Value.ValueX.IsZero() case diffInserted: - isZero = value.IsZero(r.Value.ValueY) + isZero = r.Value.ValueY.IsZero() } if isZero { continue diff --git a/tools/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/tools/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 287b8935..2ab41fad 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -16,6 +16,13 @@ import ( "github.com/google/go-cmp/cmp/internal/value" ) +var ( + anyType = reflect.TypeOf((*interface{})(nil)).Elem() + stringType = reflect.TypeOf((*string)(nil)).Elem() + bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() + byteType = reflect.TypeOf((*byte)(nil)).Elem() +) + type formatValueOptions struct { // AvoidStringer controls whether to avoid calling custom stringer // methods like error.Error or fmt.Stringer.String. @@ -184,7 +191,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, } for i := 0; i < v.NumField(); i++ { vv := v.Field(i) - if value.IsZero(vv) { + if vv.IsZero() { continue // Elide fields with zero values } if len(list) == maxLen { @@ -205,7 +212,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, } // Check whether this is a []byte of text data. - if t.Elem() == reflect.TypeOf(byte(0)) { + if t.Elem() == byteType { b := v.Bytes() isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) } if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 { diff --git a/tools/vendor/github.com/google/go-cmp/cmp/report_slices.go b/tools/vendor/github.com/google/go-cmp/cmp/report_slices.go index 68b5c1ae..23e444f6 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -104,7 +104,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { case t.Kind() == reflect.String: sx, sy = vx.String(), vy.String() isString = true - case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): + case t.Kind() == reflect.Slice && t.Elem() == byteType: sx, sy = string(vx.Bytes()), string(vy.Bytes()) isString = true case t.Kind() == reflect.Array: @@ -147,7 +147,10 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { }) efficiencyLines := float64(esLines.Dist()) / float64(len(esLines)) efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes)) - isPureLinedText = efficiencyLines < 4*efficiencyBytes + quotedLength := len(strconv.Quote(sx + sy)) + unquotedLength := len(sx) + len(sy) + escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength) + isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1 } } @@ -171,12 +174,13 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { // differences in a string literal. This format is more readable, // but has edge-cases where differences are visually indistinguishable. // This format is avoided under the following conditions: - // • A line starts with `"""` - // • A line starts with "..." - // • A line contains non-printable characters - // • Adjacent different lines differ only by whitespace + // - A line starts with `"""` + // - A line starts with "..." + // - A line contains non-printable characters + // - Adjacent different lines differ only by whitespace // // For example: + // // """ // ... // 3 identical lines // foo @@ -231,7 +235,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"} switch t.Kind() { case reflect.String: - if t != reflect.TypeOf(string("")) { + if t != stringType { out = opts.FormatType(t, out) } case reflect.Slice: @@ -326,12 +330,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { switch t.Kind() { case reflect.String: out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf(string("")) { + if t != stringType { out = opts.FormatType(t, out) } case reflect.Slice: out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf([]byte(nil)) { + if t != bytesType { out = opts.FormatType(t, out) } } @@ -446,7 +450,6 @@ func (opts formatOptions) formatDiffSlice( // {NumIdentical: 3}, // {NumInserted: 1}, // ] -// func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { var prevMode byte lastStats := func(mode byte) *diffStats { @@ -503,7 +506,6 @@ func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) // {NumIdentical: 8, NumRemoved: 12, NumInserted: 3}, // {NumIdentical: 63}, // ] -// func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { groups, groupsOrig := groups[:0], groups for i, ds := range groupsOrig { @@ -548,7 +550,6 @@ func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStat // {NumRemoved: 9}, // {NumIdentical: 64}, // incremented by 10 // ] -// func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats { var ix, iy int // indexes into sequence x and y for i, ds := range groups { diff --git a/tools/vendor/github.com/google/go-cmp/cmp/report_text.go b/tools/vendor/github.com/google/go-cmp/cmp/report_text.go index 0fd46d7f..388fcf57 100644 --- a/tools/vendor/github.com/google/go-cmp/cmp/report_text.go +++ b/tools/vendor/github.com/google/go-cmp/cmp/report_text.go @@ -393,6 +393,7 @@ func (s diffStats) Append(ds diffStats) diffStats { // String prints a humanly-readable summary of coalesced records. // // Example: +// // diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" func (s diffStats) String() string { var ss []string diff --git a/tools/vendor/github.com/sylvia7788/contextcheck/.gitignore b/tools/vendor/github.com/kkHAIKE/contextcheck/.gitignore similarity index 100% rename from tools/vendor/github.com/sylvia7788/contextcheck/.gitignore rename to tools/vendor/github.com/kkHAIKE/contextcheck/.gitignore diff --git a/tools/vendor/github.com/sylvia7788/contextcheck/LICENSE b/tools/vendor/github.com/kkHAIKE/contextcheck/LICENSE similarity index 100% rename from tools/vendor/github.com/sylvia7788/contextcheck/LICENSE rename to tools/vendor/github.com/kkHAIKE/contextcheck/LICENSE diff --git a/tools/vendor/github.com/sylvia7788/contextcheck/Makefile b/tools/vendor/github.com/kkHAIKE/contextcheck/Makefile similarity index 100% rename from tools/vendor/github.com/sylvia7788/contextcheck/Makefile rename to tools/vendor/github.com/kkHAIKE/contextcheck/Makefile diff --git a/tools/vendor/github.com/sylvia7788/contextcheck/README.md b/tools/vendor/github.com/kkHAIKE/contextcheck/README.md similarity index 72% rename from tools/vendor/github.com/sylvia7788/contextcheck/README.md rename to tools/vendor/github.com/kkHAIKE/contextcheck/README.md index c6bb9895..a383228a 100644 --- a/tools/vendor/github.com/sylvia7788/contextcheck/README.md +++ b/tools/vendor/github.com/kkHAIKE/contextcheck/README.md @@ -71,8 +71,8 @@ func call8() { ``` ## Tips - -You can break ctx inheritance by this way, eg: [issue](https://github.com/sylvia7788/contextcheck/issues/2). +### need break ctx inheritance +eg: [issue](https://github.com/kkHAIKE/contextcheck/issues/2). ```go func call1(ctx context.Context) { @@ -94,12 +94,49 @@ func NoInheritCancel(_ context.Context) (context.Context,context.CancelFunc) { } ``` +### skip check specify function +You can add `// nolint: contextcheck` in function decl doc comment, to skip this linter in some false-positive case. + +```go +// nolint: contextcheck +func call1() { + doSomeThing(context.Background()) // add nolint will no issuss for that +} + +func call2(ctx context.Context) { + call1() +} + +func call3() { + call2(context.Background()) +} +``` + +### force mark specify function have server-side http.Request parameter +default behavior is mark http.HandlerFunc or a function use r.Context(). + +```go +// @contextcheck(req_has_ctx) +func writeErr(w http.ResponseWriter, r *http.Request, err error) { + doSomeThing(r.Context()) +} + +func handler(w http.ResponseWriter, r *http.Request) { + ... + if err != nil { + writeErr(w, r, err) + return + } + ... +} +``` + ## Installation You can get `contextcheck` by `go get` command. ```bash -$ go get -u github.com/sylvia7788/contextcheck +$ go get -u github.com/kkHAIKE/contextcheck ``` or build yourself. diff --git a/tools/vendor/github.com/sylvia7788/contextcheck/contextcheck.go b/tools/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go similarity index 81% rename from tools/vendor/github.com/sylvia7788/contextcheck/contextcheck.go rename to tools/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go index 6352191a..e4a79b0d 100644 --- a/tools/vendor/github.com/sylvia7788/contextcheck/contextcheck.go +++ b/tools/vendor/github.com/kkHAIKE/contextcheck/contextcheck.go @@ -3,6 +3,7 @@ package contextcheck import ( "go/ast" "go/types" + "regexp" "strconv" "strings" "sync" @@ -18,6 +19,8 @@ type Configuration struct { DisableFact bool } +var pkgprefix string + func NewAnalyzer(cfg Configuration) *analysis.Analyzer { analyzer := &analysis.Analyzer{ Name: "contextcheck", @@ -27,6 +30,7 @@ func NewAnalyzer(cfg Configuration) *analysis.Analyzer { buildssa.Analyzer, }, } + analyzer.Flags.StringVar(&pkgprefix, "pkgprefix", "", "filter init pkgs (only for cmd)") if !cfg.DisableFact { analyzer.FactTypes = append(analyzer.FactTypes, (*ctxFact)(nil)) @@ -54,6 +58,7 @@ type entryType int const ( EntryNone entryType = iota + EntryNormal // without ctx in EntryWithCtx // has ctx in EntryWithHttpHandler // is http handler ) @@ -66,6 +71,12 @@ var ( type resInfo struct { Valid bool Funcs []string + + // reuse for doc + ReqCtx bool + Skip bool + + EntryType entryType } type ctxFact map[string]resInfo @@ -93,7 +104,10 @@ func NewRun(pkgs []*packages.Package, disableFact bool) func(pass *analysis.Pass } return func(pass *analysis.Pass) (interface{}, error) { // skip different repo - if !m[strings.Split(pass.Pkg.Path(), "/")[0]] { + if len(m) > 0 && !m[strings.Split(pass.Pkg.Path(), "/")[0]] { + return nil, nil + } + if len(m) == 0 && pkgprefix != "" && !strings.HasPrefix(pass.Pkg.Path(), pkgprefix) { return nil, nil } @@ -133,13 +147,16 @@ func (r *runner) run(pass *analysis.Pass) { continue } - if entryType := r.checkIsEntry(f); entryType == EntryNone { + if entryType := r.checkIsEntry(f); entryType == EntryNormal { + if _, ok := r.getValue(key, f); ok { + continue + } // record the result of nomal function checkingMap := make(map[string]bool) checkingMap[key] = true r.setFact(key, r.checkFuncWithoutCtx(f, checkingMap), f.Name()) continue - } else { + } else if entryType == EntryWithCtx || entryType == EntryWithHttpHandler { tmpFuncs = append(tmpFuncs, entryInfo{f: f, tp: entryType}) } } @@ -177,14 +194,14 @@ func (r *runner) getRequiedType(pssa *buildssa.SSA, path, name string) (obj *typ } func (r *runner) collectHttpTyps(pssa *buildssa.SSA) { - objRes, pobjRes, ok := r.getRequiedType(pssa, httpPkg, httpRes) + objRes, _, ok := r.getRequiedType(pssa, httpPkg, httpRes) if ok { - r.httpResTyps = append(r.httpResTyps, objRes, pobjRes) + r.httpResTyps = append(r.httpResTyps, objRes) } - objReq, pobjReq, ok := r.getRequiedType(pssa, httpPkg, httpReq) + _, pobjReq, ok := r.getRequiedType(pssa, httpPkg, httpReq) if ok { - r.httpReqTyps = append(r.httpReqTyps, objReq, pobjReq, types.NewPointer(pobjReq)) + r.httpReqTyps = append(r.httpReqTyps, pobjReq) } } @@ -219,10 +236,18 @@ func (r *runner) noImportedContextAndHttp(f *ssa.Function) (ret bool) { return true } -func (r *runner) checkIsEntry(f *ssa.Function) entryType { - if r.noImportedContextAndHttp(f) { - return EntryNone +func (r *runner) checkIsEntry(f *ssa.Function) (ret entryType) { + // if r.noImportedContextAndHttp(f) { + // return EntryNormal + // } + key := "entry:" + f.RelString(nil) + res, ok := r.getValue(key, f) + if ok { + return res.EntryType } + defer func() { + r.currentFact[key] = resInfo{EntryType: ret} + }() ctxIn, ctxOut := r.checkIsCtx(f) if ctxOut { @@ -233,12 +258,52 @@ func (r *runner) checkIsEntry(f *ssa.Function) entryType { return EntryWithCtx } + reqctx, skip := r.docFlag(f) + // check is `func handler(w http.ResponseWriter, r *http.Request) {}` - if r.checkIsHttpHandler(f) { + // or use '// @contextcheck(req_has_ctx)' + if r.checkIsHttpHandler(f, reqctx) { return EntryWithHttpHandler } - return EntryNone + if skip { + return EntryNone + } + + return EntryNormal +} + +func (r *runner) docFlag(f *ssa.Function) (reqctx, skip bool) { + for _, v := range r.getDocFromFunc(f) { + if len(nolintRe.FindString(v.Text)) > 0 && strings.Contains(v.Text, "contextcheck") { + skip = true + } else if strings.HasPrefix(v.Text, "// @contextcheck(req_has_ctx)") { + reqctx = true + } + } + return +} + +var nolintRe = regexp.MustCompile(`^//\s?nolint:`) + +func (r *runner) getDocFromFunc(f *ssa.Function) []*ast.Comment { + file := analysisutil.File(r.pass, f.Pos()) + if file == nil { + return nil + } + + // only support FuncDecl comment + var fd *ast.FuncDecl + for _, v := range file.Decls { + if tmp, ok := v.(*ast.FuncDecl); ok && tmp.Name.Pos() == f.Pos() { + fd = tmp + break + } + } + if fd == nil || fd.Doc == nil || len(fd.Doc.List) == 0 { + return nil + } + return fd.Doc.List } func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) { @@ -270,18 +335,30 @@ func (r *runner) checkIsCtx(f *ssa.Function) (in, out bool) { return } -func (r *runner) checkIsHttpHandler(f *ssa.Function) bool { - // must has no result - if f.Signature.Results().Len() > 0 { +func (r *runner) checkIsHttpHandler(f *ssa.Function, reqctx bool) bool { + var hasReq bool + tuple := f.Signature.Params() + for i := 0; i < tuple.Len(); i++ { + if r.isHttpReqType(tuple.At(i).Type()) { + hasReq = true + break + } + } + if !hasReq { return false } + if reqctx { + return true + } // must be `func f(w http.ResponseWriter, r *http.Request) {}` - tuple := f.Signature.Params() - if tuple.Len() != 2 { - return false + if f.Signature.Results().Len() == 0 && tuple.Len() == 2 && + r.isHttpResType(tuple.At(0).Type()) && r.isHttpReqType(tuple.At(1).Type()) { + return true } - return r.isHttpResType(tuple.At(0).Type()) && r.isHttpReqType(tuple.At(1).Type()) + + // check if use r.Context() + return f.Blocks != nil && len(r.getHttpReqCtx(f, true)) > 0 } func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[ssa.Instruction]bool, ok bool) { @@ -349,7 +426,7 @@ func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[ } if isHttpHandler { - for _, v := range r.getHttpReqCtx(f) { + for _, v := range r.getHttpReqCtx(f, false) { checkRefs(v, false) } } else { @@ -385,7 +462,7 @@ func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[ return } -func (r *runner) getHttpReqCtx(f *ssa.Function) (rets []ssa.Value) { +func (r *runner) getHttpReqCtx(f *ssa.Function, least1 bool) (rets []ssa.Value) { checkedRefMap := make(map[ssa.Value]bool) var checkRefs func(val ssa.Value, fromAddr bool) @@ -427,6 +504,9 @@ func (r *runner) getHttpReqCtx(f *ssa.Function) (rets []ssa.Value) { if f.Signature.Recv() != nil { // collect the return of r.Context rets = append(rets, i.Value()) + if least1 { + return + } } case *ssa.Store: if !fromAddr { @@ -445,7 +525,6 @@ func (r *runner) getHttpReqCtx(f *ssa.Function) (rets []ssa.Value) { for _, param := range f.Params { if r.isHttpReqType(param.Type()) { checkRefs(param, false) - break } } @@ -500,6 +579,7 @@ func (r *runner) checkFuncWithCtx(f *ssa.Function, tp entryType) { func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]bool) (ret bool) { ret = true orgKey := f.RelString(nil) + var seted bool for _, b := range f.Blocks { for _, instr := range b.Instrs { tp, ok := r.getCtxType(instr) @@ -530,7 +610,10 @@ func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]boo ret = false // save the call link - r.setFact(orgKey, res.Valid, res.Funcs...) + if !seted { + seted = true + r.setFact(orgKey, res.Valid, res.Funcs...) + } } continue } @@ -540,7 +623,7 @@ func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]boo continue } - if entryType := r.checkIsEntry(ff); entryType == EntryNone { + if entryType := r.checkIsEntry(ff); entryType == EntryNormal { // cannot get info from fact, skip if ff.Blocks == nil { continue @@ -553,7 +636,11 @@ func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]boo checkingMap[key] = true valid := r.checkFuncWithoutCtx(ff, checkingMap) - r.setFact(orgKey, valid, ff.Name()) + r.setFact(key, valid, ff.Name()) + if res, ok := r.getValue(key, ff); ok && !valid && !seted { + seted = true + r.setFact(orgKey, valid, res.Funcs...) + } if !valid { ret = false } @@ -698,9 +785,13 @@ func (r *runner) getValue(key string, f *ssa.Function) (res resInfo, ok bool) { } func (r *runner) setFact(key string, valid bool, funcs ...string) { + var names []string + if !valid { + names = append(r.currentFact[key].Funcs, funcs...) + } r.currentFact[key] = resInfo{ Valid: valid, - Funcs: append(r.currentFact[key].Funcs, funcs...), + Funcs: names, } } diff --git a/tools/vendor/github.com/maratori/testableexamples/LICENSE b/tools/vendor/github.com/maratori/testableexamples/LICENSE new file mode 100644 index 00000000..e8b68be3 --- /dev/null +++ b/tools/vendor/github.com/maratori/testableexamples/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Marat Reymers + +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/tools/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go b/tools/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go new file mode 100644 index 00000000..26d22c70 --- /dev/null +++ b/tools/vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go @@ -0,0 +1,34 @@ +package testableexamples + +import ( + "go/ast" + "go/doc" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// NewAnalyzer returns Analyzer that checks if examples are testable. +func NewAnalyzer() *analysis.Analyzer { + return &analysis.Analyzer{ + Name: "testableexamples", + Doc: "linter checks if examples are testable (have an expected output)", + Run: func(pass *analysis.Pass) (interface{}, error) { + testFiles := make([]*ast.File, 0, len(pass.Files)) + for _, file := range pass.Files { + fileName := pass.Fset.File(file.Pos()).Name() + if strings.HasSuffix(fileName, "_test.go") { + testFiles = append(testFiles, file) + } + } + + for _, example := range doc.Examples(testFiles...) { + if example.Output == "" && !example.EmptyOutput { + pass.Reportf(example.Code.Pos(), "missing output for example, go test can't validate it") + } + } + + return nil, nil + }, + } +} diff --git a/tools/vendor/github.com/mgechev/revive/rule/empty-lines.go b/tools/vendor/github.com/mgechev/revive/rule/empty-lines.go index 12866072..2710a897 100644 --- a/tools/vendor/github.com/mgechev/revive/rule/empty-lines.go +++ b/tools/vendor/github.com/mgechev/revive/rule/empty-lines.go @@ -51,7 +51,7 @@ func (w lintEmptyLines) checkStart(block *ast.BlockStmt) { firstNode := block.List[0] firstStmt := w.position(firstNode.Pos()) - firstBlockLineIsStmt := firstStmt.Line-(blockStart.Line+1) == 0 + firstBlockLineIsStmt := firstStmt.Line-(blockStart.Line+1) <= 0 _, firstBlockLineIsComment := w.cmap[blockStart.Line+1] if firstBlockLineIsStmt || firstBlockLineIsComment { return @@ -70,7 +70,7 @@ func (w lintEmptyLines) checkEnd(block *ast.BlockStmt) { lastNode := block.List[len(block.List)-1] lastStmt := w.position(lastNode.End()) - lastBlockLineIsStmt := (blockEnd.Line-1)-lastStmt.Line == 0 + lastBlockLineIsStmt := (blockEnd.Line-1)-lastStmt.Line <= 0 _, lastBlockLineIsComment := w.cmap[blockEnd.Line-1] if lastBlockLineIsStmt || lastBlockLineIsComment { return diff --git a/tools/vendor/github.com/mgechev/revive/rule/function-length.go b/tools/vendor/github.com/mgechev/revive/rule/function-length.go index 717ddbf7..d600d7a2 100644 --- a/tools/vendor/github.com/mgechev/revive/rule/function-length.go +++ b/tools/vendor/github.com/mgechev/revive/rule/function-length.go @@ -11,17 +11,19 @@ import ( // FunctionLength lint. type FunctionLength struct { - maxStmt int - maxLines int + maxStmt int + maxLines int + configured bool sync.Mutex } func (r *FunctionLength) configure(arguments lint.Arguments) { r.Lock() - if r.maxLines == 0 { + if !r.configured { maxStmt, maxLines := r.parseArguments(arguments) r.maxStmt = int(maxStmt) r.maxLines = int(maxLines) + r.configured = true } r.Unlock() } diff --git a/tools/vendor/github.com/mgechev/revive/rule/nested-structs.go b/tools/vendor/github.com/mgechev/revive/rule/nested-structs.go index b4f7352d..968511f2 100644 --- a/tools/vendor/github.com/mgechev/revive/rule/nested-structs.go +++ b/tools/vendor/github.com/mgechev/revive/rule/nested-structs.go @@ -43,6 +43,11 @@ func (l *lintNestedStructs) Visit(n ast.Node) ast.Visitor { } return nil case *ast.Field: + _, isChannelField := v.Type.(*ast.ChanType) + if isChannelField { + return nil + } + filter := func(n ast.Node) bool { switch n.(type) { case *ast.StructType: diff --git a/tools/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go b/tools/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go index f0e83b0c..bad90753 100644 --- a/tools/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go +++ b/tools/vendor/github.com/mgechev/revive/rule/unconditional-recursion.go @@ -28,12 +28,12 @@ func (*UnconditionalRecursionRule) Name() string { } type funcDesc struct { - reciverID *ast.Ident - id *ast.Ident + receiverID *ast.Ident + id *ast.Ident } func (fd *funcDesc) equal(other *funcDesc) bool { - receiversAreEqual := (fd.reciverID == nil && other.reciverID == nil) || fd.reciverID != nil && other.reciverID != nil && fd.reciverID.Name == other.reciverID.Name + receiversAreEqual := (fd.receiverID == nil && other.receiverID == nil) || fd.receiverID != nil && other.receiverID != nil && fd.receiverID.Name == other.receiverID.Name idsAreEqual := (fd.id == nil && other.id == nil) || fd.id.Name == other.id.Name return receiversAreEqual && idsAreEqual diff --git a/tools/vendor/github.com/nishanths/exhaustive/README.md b/tools/vendor/github.com/nishanths/exhaustive/README.md index 3992704a..a65d9de2 100644 --- a/tools/vendor/github.com/nishanths/exhaustive/README.md +++ b/tools/vendor/github.com/nishanths/exhaustive/README.md @@ -1,6 +1,6 @@ ## exhaustive [![Godoc][2]][1] -Check exhaustiveness of enum switch statements in Go source code. +Check exhaustiveness of enum switch statements and map literals in Go source code. ``` go install github.com/nishanths/exhaustive/cmd/exhaustive@latest @@ -39,7 +39,7 @@ const ( ) ``` -and the switch statement +and the code ```go package calc @@ -54,12 +54,21 @@ func f(t token.Token) { default: } } + +func g(t token.Token) string { + return map[token.Token]string{ + token.Add: "add", + token.Subtract: "subtract", + token.Multiply: "multiply", + }[t] +} ``` running exhaustive will print ``` calc.go:6:2: missing cases in switch of type token.Token: Quotient, Remainder +calc.go:15:9: missing map keys of type token.Token: Quotient, Remainder ``` ## Contributing diff --git a/tools/vendor/github.com/nishanths/exhaustive/comment.go b/tools/vendor/github.com/nishanths/exhaustive/comment.go index cae8c64d..1232df11 100644 --- a/tools/vendor/github.com/nishanths/exhaustive/comment.go +++ b/tools/vendor/github.com/nishanths/exhaustive/comment.go @@ -2,6 +2,7 @@ package exhaustive import ( "go/ast" + "go/token" "regexp" "strings" ) @@ -50,10 +51,28 @@ func isGeneratedFileComment(s string) bool { return generatedCodeRe.MatchString(s) } +type generatedCache map[*ast.File]bool + +func (c generatedCache) IsGenerated(file *ast.File) bool { + if _, ok := c[file]; !ok { + c[file] = isGeneratedFile(file) + } + return c[file] +} + // ignoreDirective is used to exclude checking of specific switch statements. const ignoreDirective = "//exhaustive:ignore" const enforceDirective = "//exhaustive:enforce" +type commentsCache map[*ast.File]ast.CommentMap + +func (c commentsCache) GetComments(file *ast.File, set *token.FileSet) ast.CommentMap { + if _, ok := c[file]; !ok { + c[file] = ast.NewCommentMap(set, file, file.Comments) + } + return c[file] +} + func containsDirective(comments []*ast.CommentGroup, directive string) bool { for _, c := range comments { for _, cc := range c.List { diff --git a/tools/vendor/github.com/nishanths/exhaustive/exhaustive.go b/tools/vendor/github.com/nishanths/exhaustive/exhaustive.go index e852df75..8ec80e06 100644 --- a/tools/vendor/github.com/nishanths/exhaustive/exhaustive.go +++ b/tools/vendor/github.com/nishanths/exhaustive/exhaustive.go @@ -1,24 +1,24 @@ /* Package exhaustive provides an analyzer that checks exhaustiveness of enum -switch statements in Go source code. +switch statements and map literals in Go source code. -Definition of enum +# Definition of enum The Go language spec does not provide an explicit definition for an enum. For the purpose of this analyzer, an enum type is any named type (a.k.a. defined -type) whose underlying type is an integer (includes byte and rune), a float, or -a string type. An enum type has associated with it constants of this named type; -these constants constitute the enum members. +type) whose underlying type is an integer (includes byte and rune), a float, +or a string type. An enum type has associated with it constants of this named +type; these constants constitute the enum members. In the example below, Biome is an enum type with 3 members. - type Biome int + type Biome int - const ( - Tundra Biome = 1 - Savanna Biome = 2 - Desert Biome = 3 - ) + const ( + Tundra Biome = 1 + Savanna Biome = 2 + Desert Biome = 3 + ) For a constant to be an enum member for an enum type, the constant must be declared in the same scope as the enum type. Note that the scope requirement @@ -31,10 +31,10 @@ using explicit values, or by any means of declaring a valid Go const. It is allowed for multiple enum member constants for a given enum type to have the same constant value. -Definition of exhaustiveness +# Definition of exhaustiveness -A switch statement that switches on a value of an enum type is exhaustive if all -of the enum type's members are listed in the switch statement's cases. If +A switch statement that switches on a value of an enum type is exhaustive if +all of the enum type's members are listed in the switch statement's cases. If multiple enum member constants have the same constant value, it is sufficient for any one of these same-valued members to be listed. @@ -44,40 +44,46 @@ For an enum type defined in an external package, it is sufficient that only exported enum members are listed. Only identifiers denoting constants (e.g. Tundra) and qualified identifiers -denoting constants (e.g. somepkg.Grassland) listed in a switch statement's cases -can contribute towards satisfying exhaustiveness. Literal values, struct fields, -re-assignable variables, etc. will not. +denoting constants (e.g. somepkg.Grassland) listed in a switch statement's +cases can contribute towards satisfying exhaustiveness. Literal values, struct +fields, re-assignable variables, etc. will not. The analyzer will produce a diagnostic about unhandled enum members if the required memebers are not listed in a switch statement's cases (this applies even if the switch statement has a 'default' case). -Type aliases +# Map literals + +All of the above also applies to map literals in which the key type is an enum +type. Empty map literals are never checked. The -check flag must include +"map" for map literals to be checked. + +# Type aliases The analyzer handles type aliases for an enum type in the following manner. Consider the example below. T2 is a enum type, and T1 is an alias for T2. Note that we don't term T1 itself an enum type; it is only an alias for an enum type. - package pkg - type T1 = newpkg.T2 - const ( - A = newpkg.A - B = newpkg.B - ) - - package newpkg - type T2 int - const ( - A T2 = 1 - B T2 = 2 - ) - -Then a switch statement that switches on a value of type T1 (which, in reality, -is just an alternate spelling for type T2) is exhaustive if all of T2's enum -members are listed in the switch statement's cases. The same conditions -described in the previous section for same-valued enum members and for -exported/unexported enum members apply here too. + package pkg + type T1 = newpkg.T2 + const ( + A = newpkg.A + B = newpkg.B + ) + + package newpkg + type T2 int + const ( + A T2 = 1 + B T2 = 2 + ) + +Then a switch statement that switches on a value of type T1 (which, in +reality, is just an alternate spelling for type T2) is exhaustive if all of +T2's enum members are listed in the switch statement's cases. The same +conditions described in the previous section for same-valued enum members and +for exported/unexported enum members apply here too. It is worth noting that, though T1 and T2 are identical types, only constants declared in the same scope as type T2's scope can be T2's enum members. In the @@ -88,44 +94,54 @@ newpkg.T2) will never result in new diagnostics from the analyzer, as long as the set of enum member constant values of the new RHS type (newpkg.T2) is a subset of the set of enum member constant values of the old LHS type (T1). -Advanced notes - -Non-enum member constants in a switch statement's cases: Recall from an earlier -section that a constant must be declared in the same scope as the enum type to -be an enum member. It is valid, however, both to the Go type checker and to this -analyzer, for any constant of the right type to be listed in the cases of an -enum switch statement (it does not necessarily have to be an enum member -constant declared in the same scope/package as the enum type's scope/package). -This is particularly useful when a type alias is involved: A forwarding constant -declaration (such as pkg.A, in type T1's package) can take the place of the -actual enum member constant (newpkg.A, in type T2's package) in the switch -statement's cases to satisfy exhaustiveness. - - var v pkg.T1 = pkg.ReturnsT1() // v is effectively of type newpkg.T2 due to alias - switch v { - case pkg.A: // valid substitute for newpkg.A (same constant value) - case pkg.B: // valid substitute for newpkg.B (same constant value) - } +# Advanced notes + +Non-enum member constants in a switch statement's cases: Recall from an +earlier section that a constant must be declared in the same scope as the enum +type to be an enum member. It is valid, however, both to the Go type checker +and to this analyzer, for any constant of the right type to be listed in the +cases of an enum switch statement (it does not necessarily have to be an enum +member constant declared in the same scope/package as the enum type's +scope/package). This is particularly useful when a type alias is involved: A +forwarding constant declaration (such as pkg.A, in type T1's package) can take +the place of the actual enum member constant (newpkg.A, in type T2's package) +in the switch statement's cases to satisfy exhaustiveness. + + var v pkg.T1 = pkg.ReturnsT1() // v is effectively of type newpkg.T2 due to alias + switch v { + case pkg.A: // valid substitute for newpkg.A (same constant value) + case pkg.B: // valid substitute for newpkg.B (same constant value) + } -Flags +# Flags Notable flags supported by the analyzer are described below. All of these flags are optional. - flag type default value + flag type default value - -explicit-exhaustive-switch bool false - -check-generated bool false - -default-signifies-exhaustive bool false - -ignore-enum-members string (none) - -package-scope-only bool false + -check string switch + -explicit-exhaustive-switch bool false + -explicit-exhaustive-map bool false + -check-generated bool false + -default-signifies-exhaustive bool false + -ignore-enum-members string (none) + -package-scope-only bool false +The -check flag specifies the program elements that should be checked for +exhaustiveness. By default, only switch statements are checked. Specify +-check=switch,map to also check map literals. If the -explicit-exhaustive-switch flag is enabled, the analyzer only runs on switch statements explicitly marked with the comment text ("exhaustive:enforce"). Otherwise, it runs on every enum switch statement not marked with the comment text ("exhaustive:ignore"). +If the -explicit-exhaustive-map flag is enabled, the analyzer only runs on +map literals explicitly marked with the comment text +("exhaustive:enforce"). Otherwise, it runs on every enum map literal not +marked with the comment text ("exhaustive:ignore"). + If the -check-generated flag is enabled, switch statements in generated Go source files are also checked. Otherwise, by default, switch statements in generated files are not checked. See https://golang.org/s/generatedcode for the @@ -150,22 +166,22 @@ on package-scoped enums will be checked for exhaustiveness. By default, the analyzer finds enums defined in all scopes, and checks switch statements that switch on all these enums. -Skip analysis +# Skip analysis In implicitly exhaustive switch mode (-explicit-exhaustive-switch=false), skip checking of a specific switch statement by associating the comment shown in the example below with the switch statement. Note the lack of whitespace between the comment marker ("//") and the comment text ("exhaustive:ignore"). - //exhaustive:ignore - switch v { ... } + //exhaustive:ignore + switch v { ... } In explicitly exhaustive switch mode (-explicit-exhaustive-switch=true), run exhaustiveness checks on a specific switch statement by associating the comment shown in the example below with the switch statement. - //exhaustive:enforce - switch v { ... } + //exhaustive:enforce + switch v { ... } To ignore specific enum members, see the -ignore-enum-members flag. @@ -176,7 +192,9 @@ package exhaustive import ( "flag" + "go/ast" "regexp" + "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -214,7 +232,9 @@ func (v *regexpFlag) Set(expr string) error { func (v *regexpFlag) value() *regexp.Regexp { return v.r } func init() { + Analyzer.Flags.StringVar(&fCheck, CheckFlag, checkSwitch, "program elements to check for exhaustiveness") Analyzer.Flags.BoolVar(&fExplicitExhaustiveSwitch, ExplicitExhaustiveSwitchFlag, false, "only run exhaustive check on switches with \"//exhaustive:enforce\" comment") + Analyzer.Flags.BoolVar(&fExplicitExhaustiveMap, ExplicitExhaustiveMapFlag, false, "only run exhaustive check on map literals with \"//exhaustive:enforce\" comment") Analyzer.Flags.BoolVar(&fCheckGenerated, CheckGeneratedFlag, false, "check switch statements in generated files") Analyzer.Flags.BoolVar(&fDefaultSignifiesExhaustive, DefaultSignifiesExhaustiveFlag, false, "presence of \"default\" case in switch statements satisfies exhaustiveness, even if all enum members are not listed") Analyzer.Flags.Var(&fIgnoreEnumMembers, IgnoreEnumMembersFlag, "enum members matching `regex` do not have to be listed in switch statements to satisfy exhaustiveness") @@ -228,7 +248,9 @@ func init() { // Flag names used by the analyzer. They are exported for use by analyzer // driver programs. const ( + CheckFlag = "check" ExplicitExhaustiveSwitchFlag = "explicit-exhaustive-switch" + ExplicitExhaustiveMapFlag = "explicit-exhaustive-map" CheckGeneratedFlag = "check-generated" DefaultSignifiesExhaustiveFlag = "default-signifies-exhaustive" IgnoreEnumMembersFlag = "ignore-enum-members" @@ -239,17 +261,26 @@ const ( ) var ( + fCheck string fExplicitExhaustiveSwitch bool + fExplicitExhaustiveMap bool fCheckGenerated bool fDefaultSignifiesExhaustive bool fIgnoreEnumMembers regexpFlag fPackageScopeOnly bool ) +const ( + checkSwitch = "switch" + checkMap = "map" +) + // resetFlags resets the flag variables to their default values. // Useful in tests. func resetFlags() { + fCheck = checkSwitch fExplicitExhaustiveSwitch = false + fExplicitExhaustiveMap = false fCheckGenerated = false fDefaultSignifiesExhaustive = false fIgnoreEnumMembers = regexpFlag{} @@ -258,24 +289,79 @@ func resetFlags() { var Analyzer = &analysis.Analyzer{ Name: "exhaustive", - Doc: "check exhaustiveness of enum switch statements", + Doc: "check exhaustiveness of enum switch statements and map literals", Run: run, Requires: []*analysis.Analyzer{inspect.Analyzer}, FactTypes: []analysis.Fact{&enumMembersFact{}}, } func run(pass *analysis.Pass) (interface{}, error) { + checks := make(map[string]bool) + for _, v := range strings.Split(fCheck, ",") { + v = strings.TrimSpace(v) + switch v { + case checkSwitch: + checks[checkSwitch] = true + case checkMap: + checks[checkMap] = true + } + } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - for typ, members := range findEnums(fPackageScopeOnly, pass.Pkg, inspect, pass.TypesInfo) { + for typ, members := range findEnums( + fPackageScopeOnly, + pass.Pkg, + inspect, + pass.TypesInfo, + ) { exportFact(pass, typ, members) } - checkSwitchStatements(pass, inspect, config{ - explicitExhaustiveSwitch: fExplicitExhaustiveSwitch, - defaultSignifiesExhaustive: fDefaultSignifiesExhaustive, - checkGeneratedFiles: fCheckGenerated, - ignoreEnumMembers: fIgnoreEnumMembers.value(), + generated := make(generatedCache) + comments := make(commentsCache) + + swChecker := switchChecker( + pass, + switchConfig{ + explicitExhaustiveSwitch: fExplicitExhaustiveSwitch, + defaultSignifiesExhaustive: fDefaultSignifiesExhaustive, + checkGeneratedFiles: fCheckGenerated, + ignoreEnumMembers: fIgnoreEnumMembers.value(), + }, + generated, + comments, + ) + + mapChecker := mapChecker( + pass, + mapConfig{ + explicitExhaustiveMap: fExplicitExhaustiveMap, + checkGeneratedFiles: fCheckGenerated, + ignoreEnumMembers: fIgnoreEnumMembers.value(), + }, + generated, + comments, + ) + + var types []ast.Node + if checks[checkSwitch] { + types = append(types, &ast.SwitchStmt{}) + } + if checks[checkMap] { + types = append(types, &ast.CompositeLit{}) + } + + inspect.WithStack(types, func(n ast.Node, push bool, stack []ast.Node) bool { + var proceed bool + switch n.(type) { + case *ast.SwitchStmt: + proceed, _ = swChecker(n, push, stack) + case *ast.CompositeLit: + proceed, _ = mapChecker(n, push, stack) + } + return proceed }) + return nil, nil } diff --git a/tools/vendor/github.com/nishanths/exhaustive/map.go b/tools/vendor/github.com/nishanths/exhaustive/map.go new file mode 100644 index 00000000..1b86fe5b --- /dev/null +++ b/tools/vendor/github.com/nishanths/exhaustive/map.go @@ -0,0 +1,148 @@ +package exhaustive + +import ( + "fmt" + "go/ast" + "go/types" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" +) + +// mapConfig is configuration for mapChecker. +type mapConfig struct { + explicitExhaustiveMap bool + checkGeneratedFiles bool + ignoreEnumMembers *regexp.Regexp // can be nil +} + +// mapChecker returns a node visitor that checks exhaustiveness +// of enum keys in map literal for the supplied pass, and reports diagnostics if non-exhaustive. +// It expects to only see *ast.CompositeLit nodes. +func mapChecker(pass *analysis.Pass, cfg mapConfig, generated generatedCache, comments commentsCache) nodeVisitor { + return func(n ast.Node, push bool, stack []ast.Node) (bool, string) { + if !push { + // The proceed return value should not matter; it is ignored by + // inspector package for pop calls. + // Nevertheless, return true to be on the safe side for the future. + return true, resultNotPush + } + + file := stack[0].(*ast.File) + + if !cfg.checkGeneratedFiles && generated.IsGenerated(file) { + // Don't check this file. + // Return false because the children nodes of node `n` don't have to be checked. + return false, resultGeneratedFile + } + + lit := n.(*ast.CompositeLit) + + mapType, ok := pass.TypesInfo.Types[lit.Type].Type.(*types.Map) + if !ok { + namedType, ok2 := pass.TypesInfo.Types[lit.Type].Type.(*types.Named) + if !ok2 { + return true, resultNotMapLiteral + } + + mapType, ok = namedType.Underlying().(*types.Map) + if !ok { + return true, resultNotMapLiteral + } + } + + if len(lit.Elts) == 0 { + // because it may be used as an alternative for make(map[...]...) + return false, resultEmptyMapLiteral + } + + keyType, ok := mapType.Key().(*types.Named) + if !ok { + return true, resultMapKeyIsNotNamedType + } + + fileComments := comments.GetComments(file, pass.Fset) + var relatedComments []*ast.CommentGroup + for i := range stack { + // iterate over stack in the reverse order (from bottom to top) + node := stack[len(stack)-1-i] + switch node.(type) { + // need to check comments associated with following nodes, + // because logic of ast package doesn't allow to associate comment with *ast.CompositeLit + case *ast.CompositeLit, // stack[len(stack)-1] + *ast.ReturnStmt, // return ... + *ast.IndexExpr, // map[enum]...{...}[key] + *ast.CallExpr, // myfunc(map...) + *ast.UnaryExpr, // &map... + *ast.AssignStmt, // variable assignment (without var keyword) + *ast.DeclStmt, // var declaration, parent of *ast.GenDecl + *ast.GenDecl, // var declaration, parent of *ast.ValueSpec + *ast.ValueSpec: // var declaration + relatedComments = append(relatedComments, fileComments[node]...) + continue + } + // stop iteration on the first inappropriate node + break + } + + if !cfg.explicitExhaustiveMap && containsIgnoreDirective(relatedComments) { + // Skip checking of this map literal due to ignore directive comment. + // Still return true because there may be nested map literals + // that are not to be ignored. + return true, resultMapIgnoreComment + } + if cfg.explicitExhaustiveMap && !containsEnforceDirective(relatedComments) { + // Skip checking of this map literal due to missing enforce directive comment. + return true, resultMapNoEnforceComment + } + + keyPkg := keyType.Obj().Pkg() + if keyPkg == nil { + // The Go documentation says: nil for labels and objects in the Universe scope. + // This happens for the `error` type, for example. + return true, resultNilMapKeyTypePkg + } + + enumTyp := enumType{keyType.Obj()} + members, ok := importFact(pass, enumTyp) + if !ok { + return true, resultMapKeyNotEnum + } + + samePkg := keyPkg == pass.Pkg // do the map literal and the map key type (i.e. enum type) live in the same package? + checkUnexported := samePkg // we want to include unexported members in the exhaustiveness check only if we're in the same package + checklist := makeChecklist(members, keyPkg, checkUnexported, cfg.ignoreEnumMembers) + + for _, e := range lit.Elts { + expr, ok := e.(*ast.KeyValueExpr) + if !ok { + continue // is it possible for valid map literal? + } + analyzeCaseClauseExpr(expr.Key, pass.TypesInfo, checklist.found) + } + + if len(checklist.remaining()) == 0 { + // All enum members accounted for. + // Nothing to report. + return true, resultEnumMembersAccounted + } + + pass.Report(makeMapDiagnostic(lit, samePkg, enumTyp, members, checklist.remaining())) + return true, resultReportedDiagnostic + } +} + +// Makes a "missing map keys" diagnostic. +// samePkg should be true if the enum type and the map literal are defined in the same package. +func makeMapDiagnostic(lit *ast.CompositeLit, samePkg bool, enumTyp enumType, allMembers enumMembers, missingMembers map[string]struct{}) analysis.Diagnostic { + message := fmt.Sprintf("missing map keys of type %s: %s", + diagnosticEnumTypeName(enumTyp.TypeName, samePkg), + strings.Join(diagnosticMissingMembers(missingMembers, allMembers), ", ")) + + return analysis.Diagnostic{ + Pos: lit.Pos(), + End: lit.End(), + Message: message, + } +} diff --git a/tools/vendor/github.com/nishanths/exhaustive/switch.go b/tools/vendor/github.com/nishanths/exhaustive/switch.go index dcf3b6d0..115c317e 100644 --- a/tools/vendor/github.com/nishanths/exhaustive/switch.go +++ b/tools/vendor/github.com/nishanths/exhaustive/switch.go @@ -5,12 +5,10 @@ import ( "go/ast" "go/types" "regexp" - "sort" "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/ast/astutil" - "golang.org/x/tools/go/ast/inspector" ) // nodeVisitor is like the visitor function used by Inspector.WithStack, @@ -21,11 +19,18 @@ import ( // that the nodeVisitor function took the expected code path. type nodeVisitor func(n ast.Node, push bool, stack []ast.Node) (proceed bool, result string) -// Result values returned by a node visitor constructed via switchStmtChecker. +// Result values returned by a node visitor constructed via switchChecker. const ( resultNotPush = "not push" resultGeneratedFile = "generated file" resultNoSwitchTag = "no switch tag" + resultEmptyMapLiteral = "empty map literal" + resultNotMapLiteral = "not map literal" + resultMapKeyIsNotNamedType = "map key is not named type" + resultNilMapKeyTypePkg = "nil map key type package" + resultMapKeyNotEnum = "map key not known enum type" + resultMapIgnoreComment = "map literal has ignore comment" + resultMapNoEnforceComment = "map literal has no enforce comment" resultTagNotValue = "switch tag not value type" resultTagNotNamed = "switch tag not named type" resultTagNoPkg = "switch tag does not belong to regular package" @@ -37,14 +42,11 @@ const ( resultReportedDiagnostic = "reported diagnostic" ) -// switchStmtChecker returns a node visitor that checks exhaustiveness +// switchChecker returns a node visitor that checks exhaustiveness // of enum switch statements for the supplied pass, and reports diagnostics for // switch statements that are non-exhaustive. // It expects to only see *ast.SwitchStmt nodes. -func switchStmtChecker(pass *analysis.Pass, cfg config) nodeVisitor { - generated := make(map[*ast.File]bool) // cached results - comments := make(map[*ast.File]ast.CommentMap) // cached results - +func switchChecker(pass *analysis.Pass, cfg switchConfig, generated generatedCache, comments commentsCache) nodeVisitor { return func(n ast.Node, push bool, stack []ast.Node) (bool, string) { if !push { // The proceed return value should not matter; it is ignored by @@ -55,12 +57,7 @@ func switchStmtChecker(pass *analysis.Pass, cfg config) nodeVisitor { file := stack[0].(*ast.File) - // Determine if the file is a generated file, and save the result. - // If it is a generated file, don't check the file. - if _, ok := generated[file]; !ok { - generated[file] = isGeneratedFile(file) - } - if generated[file] && !cfg.checkGeneratedFiles { + if !cfg.checkGeneratedFiles && generated.IsGenerated(file) { // Don't check this file. // Return false because the children nodes of node `n` don't have to be checked. return false, resultGeneratedFile @@ -68,10 +65,7 @@ func switchStmtChecker(pass *analysis.Pass, cfg config) nodeVisitor { sw := n.(*ast.SwitchStmt) - if _, ok := comments[file]; !ok { - comments[file] = ast.NewCommentMap(pass.Fset, file, file.Comments) - } - switchComments := comments[file][sw] + switchComments := comments.GetComments(file, pass.Fset)[sw] if !cfg.explicitExhaustiveSwitch && containsIgnoreDirective(switchComments) { // Skip checking of this switch statement due to ignore directive comment. // Still return true because there may be nested switch statements @@ -115,9 +109,7 @@ func switchStmtChecker(pass *analysis.Pass, cfg config) nodeVisitor { checkUnexported := samePkg // we want to include unexported members in the exhaustiveness check only if we're in the same package checklist := makeChecklist(members, tagPkg, checkUnexported, cfg.ignoreEnumMembers) - hasDefaultCase := analyzeSwitchClauses(sw, pass.TypesInfo, func(val constantValue) { - checklist.found(val) - }) + hasDefaultCase := analyzeSwitchClauses(sw, pass.TypesInfo, checklist.found) if len(checklist.remaining()) == 0 { // All enum members accounted for. @@ -130,30 +122,19 @@ func switchStmtChecker(pass *analysis.Pass, cfg config) nodeVisitor { // So don't report. return true, resultDefaultCaseSuffices } - pass.Report(makeDiagnostic(sw, samePkg, enumTyp, members, checklist.remaining())) + pass.Report(makeSwitchDiagnostic(sw, samePkg, enumTyp, members, checklist.remaining())) return true, resultReportedDiagnostic } } -// config is configuration for checkSwitchStatements. -type config struct { +// switchConfig is configuration for switchChecker. +type switchConfig struct { explicitExhaustiveSwitch bool defaultSignifiesExhaustive bool checkGeneratedFiles bool ignoreEnumMembers *regexp.Regexp // can be nil } -// checkSwitchStatements checks exhaustiveness of enum switch statements for the supplied -// pass. It reports switch statements that are not exhaustive via pass.Report. -func checkSwitchStatements(pass *analysis.Pass, inspect *inspector.Inspector, cfg config) { - f := switchStmtChecker(pass, cfg) - - inspect.WithStack([]ast.Node{&ast.SwitchStmt{}}, func(n ast.Node, push bool, stack []ast.Node) bool { - proceed, _ := f(n, push, stack) - return proceed - }) -} - func isDefaultCase(c *ast.CaseClause) bool { return c.List == nil // see doc comment on List field } @@ -262,19 +243,30 @@ func analyzeCaseClauseExpr(e ast.Expr, info *types.Info, found func(val constant // diagnosticMissingMembers constructs the list of missing enum members, // suitable for use in a reported diagnostic message. +// Order is the same as in enumMembers.Names. func diagnosticMissingMembers(missingMembers map[string]struct{}, em enumMembers) []string { - missingByConstVal := make(map[constantValue][]string) // missing members, keyed by constant value. - for m := range missingMembers { - val := em.NameToValue[m] - missingByConstVal[val] = append(missingByConstVal[val], m) + missingNamesGroupedByValue := make([][]string, len(em.Names)) // empty groups will be filtered out later + firstIndex := make(map[constantValue]int, len(em.ValueToNames)) + for i, name := range em.Names { + value := em.NameToValue[name] + j, ok := firstIndex[value] + if !ok { + firstIndex[value] = i + j = i + } + + if _, missing := missingMembers[name]; missing { + missingNamesGroupedByValue[j] = append(missingNamesGroupedByValue[j], name) + } } - var out []string - for _, names := range missingByConstVal { - sort.Strings(names) + out := make([]string, 0, len(missingMembers)) + for _, names := range missingNamesGroupedByValue { + if len(names) == 0 { + continue + } out = append(out, strings.Join(names, "|")) } - sort.Strings(out) return out } @@ -290,7 +282,7 @@ func diagnosticEnumTypeName(enumType *types.TypeName, samePkg bool) string { // Makes a "missing cases in switch" diagnostic. // samePkg should be true if the enum type and the switch statement are defined // in the same package. -func makeDiagnostic(sw *ast.SwitchStmt, samePkg bool, enumTyp enumType, allMembers enumMembers, missingMembers map[string]struct{}) analysis.Diagnostic { +func makeSwitchDiagnostic(sw *ast.SwitchStmt, samePkg bool, enumTyp enumType, allMembers enumMembers, missingMembers map[string]struct{}) analysis.Diagnostic { message := fmt.Sprintf("missing cases in switch of type %s: %s", diagnosticEnumTypeName(enumTyp.TypeName, samePkg), strings.Join(diagnosticMissingMembers(missingMembers, allMembers), ", ")) @@ -310,7 +302,6 @@ func makeDiagnostic(sw *ast.SwitchStmt, samePkg bool, enumTyp enumType, allMembe // statement's cases. // // The remaining method returns the member names not accounted for. -// type checklist struct { em enumMembers checkl map[string]struct{} diff --git a/tools/vendor/github.com/pelletier/go-toml/v2/errors.go b/tools/vendor/github.com/pelletier/go-toml/v2/errors.go index 5e6635c3..2e7f0ffd 100644 --- a/tools/vendor/github.com/pelletier/go-toml/v2/errors.go +++ b/tools/vendor/github.com/pelletier/go-toml/v2/errors.go @@ -103,6 +103,7 @@ func (e *DecodeError) Key() Key { // // The function copies all bytes used in DecodeError, so that document and // highlight can be freely deallocated. +// //nolint:funlen func wrapDecodeError(document []byte, de *decodeError) *DecodeError { offset := danger.SubsliceOffset(document, de.highlight) diff --git a/tools/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go b/tools/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go index 33c7f915..9dec2e00 100644 --- a/tools/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go +++ b/tools/vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go @@ -11,10 +11,10 @@ import ( // // For example: // -// it := n.Children() -// for it.Next() { -// it.Node() -// } +// it := n.Children() +// for it.Next() { +// it.Node() +// } type Iterator struct { started bool node *Node diff --git a/tools/vendor/github.com/pelletier/go-toml/v2/marshaler.go b/tools/vendor/github.com/pelletier/go-toml/v2/marshaler.go index 4eb526bb..acb28831 100644 --- a/tools/vendor/github.com/pelletier/go-toml/v2/marshaler.go +++ b/tools/vendor/github.com/pelletier/go-toml/v2/marshaler.go @@ -54,7 +54,7 @@ func NewEncoder(w io.Writer) *Encoder { // This behavior can be controlled on an individual struct field basis with the // inline tag: // -// MyField `inline:"true"` +// MyField `toml:",inline"` func (enc *Encoder) SetTablesInline(inline bool) *Encoder { enc.tablesInline = inline return enc @@ -65,7 +65,7 @@ func (enc *Encoder) SetTablesInline(inline bool) *Encoder { // // This behavior can be controlled on an individual struct field basis with the multiline tag: // -// MyField `multiline:"true"` +// MyField `multiline:"true"` func (enc *Encoder) SetArraysMultiline(multiline bool) *Encoder { enc.arraysMultiline = multiline return enc @@ -89,7 +89,7 @@ func (enc *Encoder) SetIndentTables(indent bool) *Encoder { // // If v cannot be represented to TOML it returns an error. // -// Encoding rules +// # Encoding rules // // A top level slice containing only maps or structs is encoded as [[table // array]]. @@ -117,7 +117,20 @@ func (enc *Encoder) SetIndentTables(indent bool) *Encoder { // When encoding structs, fields are encoded in order of definition, with their // exact name. // -// Struct tags +// Tables and array tables are separated by empty lines. However, consecutive +// subtables definitions are not. For example: +// +// [top1] +// +// [top2] +// [top2.child1] +// +// [[array]] +// +// [[array]] +// [array.child2] +// +// # Struct tags // // The encoding of each public struct field can be customized by the format // string in the "toml" key of the struct field's tag. This follows @@ -333,13 +346,13 @@ func isNil(v reflect.Value) bool { } } +func shouldOmitEmpty(options valueOptions, v reflect.Value) bool { + return options.omitempty && isEmptyValue(v) +} + func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) { var err error - if (ctx.options.omitempty || options.omitempty) && isEmptyValue(v) { - return b, nil - } - if !ctx.inline { b = enc.encodeComment(ctx.indent, options.comment, b) } @@ -365,6 +378,8 @@ func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v r func isEmptyValue(v reflect.Value) bool { switch v.Kind() { + case reflect.Struct: + return isEmptyStruct(v) case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: @@ -381,6 +396,34 @@ func isEmptyValue(v reflect.Value) bool { return false } +func isEmptyStruct(v reflect.Value) bool { + // TODO: merge with walkStruct and cache. + typ := v.Type() + for i := 0; i < typ.NumField(); i++ { + fieldType := typ.Field(i) + + // only consider exported fields + if fieldType.PkgPath != "" { + continue + } + + tag := fieldType.Tag.Get("toml") + + // special field name to skip field + if tag == "-" { + continue + } + + f := v.Field(i) + + if !isEmptyValue(f) { + return false + } + } + + return true +} + const literalQuote = '\'' func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byte { @@ -410,7 +453,6 @@ func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte { return b } -//nolint:cyclop func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byte { stringQuote := `"` @@ -757,7 +799,13 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro } ctx.skipTableHeader = false + hasNonEmptyKV := false for _, kv := range t.kvs { + if shouldOmitEmpty(kv.Options, kv.Value) { + continue + } + hasNonEmptyKV = true + ctx.setKey(kv.Key) b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value) @@ -768,7 +816,20 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro b = append(b, '\n') } + first := true for _, table := range t.tables { + if shouldOmitEmpty(table.Options, table.Value) { + continue + } + if first { + first = false + if hasNonEmptyKV { + b = append(b, '\n') + } + } else { + b = append(b, "\n"...) + } + ctx.setKey(table.Key) ctx.options = table.Options @@ -777,8 +838,6 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro if err != nil { return nil, err } - - b = append(b, '\n') } return b, nil @@ -791,6 +850,10 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte first := true for _, kv := range t.kvs { + if shouldOmitEmpty(kv.Options, kv.Value) { + continue + } + if first { first = false } else { @@ -806,7 +869,7 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte } if len(t.tables) > 0 { - panic("inline table cannot contain nested tables, online key-values") + panic("inline table cannot contain nested tables, only key-values") } b = append(b, "}"...) @@ -905,6 +968,10 @@ func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect. b = enc.encodeComment(ctx.indent, ctx.options.comment, b) for i := 0; i < v.Len(); i++ { + if i != 0 { + b = append(b, "\n"...) + } + b = append(b, scratch...) var err error diff --git a/tools/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go b/tools/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go index b3596f6d..d0d7a72d 100644 --- a/tools/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go +++ b/tools/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go @@ -79,22 +79,22 @@ func (d *Decoder) DisallowUnknownFields() *Decoder { // strict mode and a field is missing, a `toml.StrictMissingError` is // returned. In any other case, this function returns a standard Go error. // -// Type mapping +// # Type mapping // // List of supported TOML types and their associated accepted Go types: // -// String -> string -// Integer -> uint*, int*, depending on size -// Float -> float*, depending on size -// Boolean -> bool -// Offset Date-Time -> time.Time -// Local Date-time -> LocalDateTime, time.Time -// Local Date -> LocalDate, time.Time -// Local Time -> LocalTime, time.Time -// Array -> slice and array, depending on elements types -// Table -> map and struct -// Inline Table -> same as Table -// Array of Tables -> same as Array and Table +// String -> string +// Integer -> uint*, int*, depending on size +// Float -> float*, depending on size +// Boolean -> bool +// Offset Date-Time -> time.Time +// Local Date-time -> LocalDateTime, time.Time +// Local Date -> LocalDate, time.Time +// Local Time -> LocalTime, time.Time +// Array -> slice and array, depending on elements types +// Table -> map and struct +// Inline Table -> same as Table +// Array of Tables -> same as Array and Table func (d *Decoder) Decode(v interface{}) error { b, err := ioutil.ReadAll(d.r) if err != nil { @@ -123,7 +123,7 @@ type decoder struct { stashedExpr bool // Skip expressions until a table is found. This is set to true when a - // table could not be create (missing field in map), so all KV expressions + // table could not be created (missing field in map), so all KV expressions // need to be skipped. skipUntilTable bool @@ -344,9 +344,9 @@ func (d *decoder) handleArrayTableCollectionLast(key ast.Iterator, v reflect.Val elem := v.Index(idx) _, err := d.handleArrayTable(key, elem) return v, err + default: + return reflect.Value{}, fmt.Errorf("toml: cannot decode array table into a %s", v.Type()) } - - return d.handleArrayTable(key, v) } // When parsing an array table expression, each part of the key needs to be @@ -483,7 +483,7 @@ func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handle d.errorContext.Struct = t d.errorContext.Field = path - f := v.FieldByIndex(path) + f := fieldByIndex(v, path) x, err := nextFn(key, f) if err != nil || d.skipUntilTable { return reflect.Value{}, err @@ -1071,7 +1071,7 @@ func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflec d.errorContext.Struct = t d.errorContext.Field = path - f := v.FieldByIndex(path) + f := fieldByIndex(v, path) x, err := d.handleKeyValueInner(key, value, f) if err != nil { return reflect.Value{}, err @@ -1135,6 +1135,21 @@ func initAndDereferencePointer(v reflect.Value) reflect.Value { return elem } +// Same as reflect.Value.FieldByIndex, but creates pointers if needed. +func fieldByIndex(v reflect.Value, path []int) reflect.Value { + for i, x := range path { + v = v.Field(x) + + if i < len(path)-1 && v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + } + return v +} + type fieldPathsMap = map[string][]int var globalFieldPathsCache atomic.Value // map[danger.TypeID]fieldPathsMap @@ -1192,7 +1207,14 @@ func forEachField(t reflect.Type, path []int, do func(name string, path []int)) } if f.Anonymous && name == "" { - forEachField(f.Type, fieldPath, do) + t2 := f.Type + if t2.Kind() == reflect.Ptr { + t2 = t2.Elem() + } + + if t2.Kind() == reflect.Struct { + forEachField(t2, fieldPath, do) + } continue } diff --git a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go index 58ddb263..ab02136f 100644 --- a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go +++ b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/analysis.go @@ -57,7 +57,7 @@ func run(pass *analysis.Pass) (interface{}, error) { type TypesInfoExt struct { types.Info - // Maps AST nodes back to the node they are contain within. + // Maps AST nodes back to the node they are contained within. NodeParent map[ast.Node]ast.Node // Maps an object back to all identifiers to refer to it. @@ -97,3 +97,15 @@ func newTypesInfoExt(info *types.Info) *TypesInfoExt { IdentifiersForObject: identifiersForObject, } } + +func (info *TypesInfoExt) ContainingFuncDecl(node ast.Node) *ast.FuncDecl { + for parent := info.NodeParent[node]; ; parent = info.NodeParent[parent] { + if _, ok := parent.(*ast.File); ok { + break + } + if fun, ok := parent.(*ast.FuncDecl); ok { + return fun + } + } + return nil +} diff --git a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go index 5301a3f2..fb065ced 100644 --- a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go +++ b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/lint.go @@ -156,10 +156,14 @@ func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []Lint { if !isErrorComparison(info.Info, binExpr) { continue } - + // Some errors that are returned from some functions are exempt. if isAllowedErrorComparison(info, binExpr) { continue } + // Comparisons that happen in `func (type) Is(error) bool` are okay. + if isNodeInErrorIsFunc(info, binExpr) { + continue + } lints = append(lints, Lint{ Message: fmt.Sprintf("comparing with %s will fail on wrapped errors. Use errors.Is to check for a specific error", binExpr.Op), @@ -181,11 +185,17 @@ func LintErrorComparisons(fset *token.FileSet, info *TypesInfoExt) []Lint { if tagType.Type.String() != "error" { continue } + if isNodeInErrorIsFunc(info, switchStmt) { + continue + } + + if switchComparesNonNil(switchStmt) { + lints = append(lints, Lint{ + Message: "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors", + Pos: switchStmt.Pos(), + }) + } - lints = append(lints, Lint{ - Message: "switch on an error will fail on wrapped errors. Use errors.Is to check for specific errors", - Pos: switchStmt.Pos(), - }) } return lints @@ -207,6 +217,55 @@ func isErrorComparison(info types.Info, binExpr *ast.BinaryExpr) bool { return tx.Type.String() == "error" || ty.Type.String() == "error" } +func isNodeInErrorIsFunc(info *TypesInfoExt, node ast.Node) bool { + funcDecl := info.ContainingFuncDecl(node) + if funcDecl == nil { + return false + } + + if funcDecl.Name.Name != "Is" { + return false + } + if funcDecl.Recv == nil { + return false + } + // There should be 1 argument of type error. + if ii := funcDecl.Type.Params.List; len(ii) != 1 || info.Types[ii[0].Type].Type.String() != "error" { + return false + } + // The return type should be bool. + if ii := funcDecl.Type.Results.List; len(ii) != 1 || info.Types[ii[0].Type].Type.String() != "bool" { + return false + } + + return true +} + +// switchComparesNonNil returns true if one of its clauses compares by value. +func switchComparesNonNil(switchStmt *ast.SwitchStmt) bool { + for _, caseBlock := range switchStmt.Body.List { + caseClause, ok := caseBlock.(*ast.CaseClause) + if !ok { + continue + } + for _, clause := range caseClause.List { + switch clause := clause.(type) { + case nil: + // default label is safe + continue + case *ast.Ident: + // `case nil` is safe + if clause.Name == "nil" { + continue + } + } + // anything else (including an Ident other than nil) isn't safe + return true + } + } + return false +} + func LintErrorTypeAssertions(fset *token.FileSet, info types.Info) []Lint { lints := []Lint{} diff --git a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go index f3d81b57..d9a935ff 100644 --- a/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go +++ b/tools/vendor/github.com/polyfloyd/go-errorlint/errorlint/printf.go @@ -14,6 +14,9 @@ func verbOrder(verbs []verb, numArgs int) [][]verb { if v.index != -1 { i = v.index - 1 } + if i >= len(orderedVerbs) { + continue + } orderedVerbs[i] = append(orderedVerbs[i], v) verbs = verbs[1:] i++ diff --git a/tools/vendor/github.com/quasilyte/go-ruleguard/internal/xtypes/xtypes.go b/tools/vendor/github.com/quasilyte/go-ruleguard/internal/xtypes/xtypes.go index 028a5f14..4c5c2a2a 100644 --- a/tools/vendor/github.com/quasilyte/go-ruleguard/internal/xtypes/xtypes.go +++ b/tools/vendor/github.com/quasilyte/go-ruleguard/internal/xtypes/xtypes.go @@ -2,6 +2,8 @@ package xtypes import ( "go/types" + + "golang.org/x/exp/typeparams" ) // Implements reports whether type v implements iface. @@ -63,9 +65,6 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { } switch x := x.(type) { - case nil: - return false - case *types.Basic: // Basic types are singletons except for the rune and byte // aliases, thus we cannot solely rely on the x == y check @@ -142,6 +141,11 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { typeIdentical(x.Results(), y.Results(), p) } + case *typeparams.Union: + // TODO(quasilyte): do we want to match generic union types too? + // It would require copying a lot of code from the go/types. + return false + case *types.Interface: // Two interface types are identical if they have the same set of methods with // the same names and identical function types. Lower-case method names from @@ -214,6 +218,12 @@ func typeIdentical(x, y types.Type, p *ifacePair) bool { } return sameID(x.Obj(), y.Obj().Pkg(), y.Obj().Name()) + case *typeparams.TypeParam: + // nothing to do (x and y being equal is caught in the very beginning of this function) + + case nil: + // avoid a crash in case of nil type + default: panic("unreachable") } diff --git a/tools/vendor/github.com/quasilyte/gogrep/Makefile b/tools/vendor/github.com/quasilyte/gogrep/Makefile index d05331f4..01dd2192 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/Makefile +++ b/tools/vendor/github.com/quasilyte/gogrep/Makefile @@ -6,9 +6,9 @@ test: @echo "everything is OK" ci-lint: - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.43.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH_DIR)/bin v1.45.2 $(GOPATH_DIR)/bin/golangci-lint run ./... - go install github.com/quasilyte/go-consistent@latest + go install github.com/quasilyte/go-consistent@master $(GOPATH_DIR)/bin/go-consistent . ./internal/... ./nodetag/... ./filters/... @echo "everything is OK" diff --git a/tools/vendor/github.com/quasilyte/gogrep/compile.go b/tools/vendor/github.com/quasilyte/gogrep/compile.go index cc60c05a..a00a39cc 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/compile.go +++ b/tools/vendor/github.com/quasilyte/gogrep/compile.go @@ -6,6 +6,7 @@ import ( "go/token" "github.com/quasilyte/gogrep/internal/stdinfo" + "golang.org/x/exp/typeparams" ) type compileError string @@ -211,7 +212,7 @@ func (c *compiler) compileField(n *ast.Field) { } c.emitInstOp(opEnd) } - c.compileExpr(n.Type) + c.compileTypeExpr(n.Type) } func (c *compiler) compileValueSpec(spec *ast.ValueSpec) { @@ -234,7 +235,7 @@ func (c *compiler) compileValueSpec(spec *ast.ValueSpec) { } c.emitInstOp(opEnd) if spec.Type != nil { - c.compileOptExpr(spec.Type) + c.compileOptTypeExpr(spec.Type) } if len(spec.Values) != 0 { for _, v := range spec.Values { @@ -245,9 +246,26 @@ func (c *compiler) compileValueSpec(spec *ast.ValueSpec) { } func (c *compiler) compileTypeSpec(spec *ast.TypeSpec) { + // Generic types can't have aliases, so we use that fact here. + typeParams := typeparams.ForTypeSpec(spec) + if !spec.Assign.IsValid() && !isWildName(spec.Name.Name) && typeParams == nil { + c.emitInst(instruction{ + op: opSimpleTypeSpec, + valueIndex: c.internString(spec.Name, spec.Name.Name), + }) + c.compileTypeExpr(spec.Type) + return + } + if typeParams != nil { + c.emitInstOp(opGenericTypeSpec) + c.compileIdent(spec.Name) + c.compileFieldList(typeParams) + c.compileTypeExpr(spec.Type) + return + } c.emitInstOp(pickOp(spec.Assign.IsValid(), opTypeAliasSpec, opTypeSpec)) c.compileIdent(spec.Name) - c.compileExpr(spec.Type) + c.compileTypeExpr(spec.Type) } func (c *compiler) compileFile(n *ast.File) { @@ -274,6 +292,16 @@ func (c *compiler) compileDecl(n ast.Decl) { func (c *compiler) compileFuncDecl(n *ast.FuncDecl) { if n.Recv == nil { + if !isWildName(n.Name.Name) && typeparams.ForFuncType(n.Type) == nil && n.Body != nil { + // Generic functions can't live without body, so there is no generic proto decls. + c.emitInst(instruction{ + op: opSimpleFuncDecl, + valueIndex: c.internString(n.Name, n.Name.Name), + }) + c.compileFuncType(n.Type) + c.compileBlockStmt(n.Body) + return + } c.emitInstOp(pickOp(n.Body == nil, opFuncProtoDecl, opFuncDecl)) } else { c.emitInstOp(pickOp(n.Body == nil, opMethodProtoDecl, opMethodDecl)) @@ -313,6 +341,22 @@ func (c *compiler) compileGenDecl(n *ast.GenDecl) { } } +func (c *compiler) compileTypeExpr(n ast.Expr) { + if ident, ok := n.(*ast.Ident); ok && ident.Name == "any" && !c.config.Strict && typeparams.Enabled() { + c.emitInstOp(opEfaceType) + return + } + c.compileExpr(n) +} + +func (c *compiler) compileOptTypeExpr(n ast.Expr) { + if ident, ok := n.(*ast.Ident); ok && isWildName(ident.Name) { + c.compileWildIdent(ident, true) + return + } + c.compileTypeExpr(n) +} + func (c *compiler) compileExpr(n ast.Expr) { switch n := n.(type) { case *ast.BasicLit: @@ -321,6 +365,8 @@ func (c *compiler) compileExpr(n ast.Expr) { c.compileBinaryExpr(n) case *ast.IndexExpr: c.compileIndexExpr(n) + case *typeparams.IndexListExpr: + c.compileIndexListExpr(n) case *ast.Ident: c.compileIdent(n) case *ast.CallExpr: @@ -408,6 +454,15 @@ func (c *compiler) compileIndexExpr(n *ast.IndexExpr) { c.compileExpr(n.Index) } +func (c *compiler) compileIndexListExpr(n *typeparams.IndexListExpr) { + c.emitInstOp(opIndexListExpr) + c.compileExpr(n.X) + for _, x := range n.Indices { + c.compileExpr(x) + } + c.emitInstOp(opEnd) +} + func (c *compiler) compileWildIdent(n *ast.Ident, optional bool) { info := decodeWildName(n.Name) var inst instruction @@ -467,25 +522,41 @@ func (c *compiler) compileExprMembers(list []ast.Expr) { } func (c *compiler) compileCallExpr(n *ast.CallExpr) { - canBeVariadic := func(n *ast.CallExpr) bool { + variadicOperation := func(n *ast.CallExpr) (operation, uint8) { if len(n.Args) == 0 { - return false + return opNonVariadicCallExpr, 0 } lastArg, ok := n.Args[len(n.Args)-1].(*ast.Ident) if !ok { - return false + return opNonVariadicCallExpr, 0 } - return isWildName(lastArg.Name) && decodeWildName(lastArg.Name).Seq + if !isWildName(lastArg.Name) || !decodeWildName(lastArg.Name).Seq { + return opNonVariadicCallExpr, 0 + } + if len(n.Args) == 1 { + return opCallExpr, 0 + } + // If there is any seq op before the lastArg, we emit opCallExpr too. + for i := 0; i < len(n.Args)-1; i++ { + if decodeWildNode(n.Args[i]).Seq { + return opCallExpr, 0 + } + } + return opMaybeVariadicCallExpr, c.toUint8(n, len(n.Args)-1) } - op := opNonVariadicCallExpr + var value uint8 + var op operation if n.Ellipsis.IsValid() { op = opVariadicCallExpr - } else if canBeVariadic(n) { - op = opCallExpr + } else { + op, value = variadicOperation(n) } - c.emitInstOp(op) + c.prog.insts = append(c.prog.insts, instruction{ + op: op, + value: value, + }) c.compileSymbol(n.Fun) c.compileExprMembers(n.Args) } @@ -592,16 +663,32 @@ func (c *compiler) compileStructType(n *ast.StructType) { } func (c *compiler) compileInterfaceType(n *ast.InterfaceType) { + if len(n.Methods.List) == 0 && !c.config.Strict { + c.emitInstOp(opEfaceType) + return + } c.emitInstOp(opInterfaceType) c.compileOptFieldList(n.Methods) } func (c *compiler) compileFuncType(n *ast.FuncType) { void := n.Results == nil || len(n.Results.List) == 0 + typeParams := typeparams.ForFuncType(n) if void { - c.emitInstOp(opVoidFuncType) + if typeParams == nil { + c.emitInstOp(opVoidFuncType) + } else { + c.emitInstOp(opGenericVoidFuncType) + } } else { - c.emitInstOp(opFuncType) + if typeParams == nil { + c.emitInstOp(opFuncType) + } else { + c.emitInstOp(opGenericFuncType) + } + } + if typeParams != nil { + c.compileOptFieldList(typeParams) } c.compileOptFieldList(n.Params) if !void { @@ -612,18 +699,18 @@ func (c *compiler) compileFuncType(n *ast.FuncType) { func (c *compiler) compileArrayType(n *ast.ArrayType) { if n.Len == nil { c.emitInstOp(opSliceType) - c.compileExpr(n.Elt) + c.compileTypeExpr(n.Elt) } else { c.emitInstOp(opArrayType) c.compileExpr(n.Len) - c.compileExpr(n.Elt) + c.compileTypeExpr(n.Elt) } } func (c *compiler) compileMapType(n *ast.MapType) { c.emitInstOp(opMapType) - c.compileExpr(n.Key) - c.compileExpr(n.Value) + c.compileTypeExpr(n.Key) + c.compileTypeExpr(n.Value) } func (c *compiler) compileChanType(n *ast.ChanType) { @@ -631,7 +718,7 @@ func (c *compiler) compileChanType(n *ast.ChanType) { op: opChanType, value: c.toUint8(n, int(n.Dir)), }) - c.compileExpr(n.Value) + c.compileTypeExpr(n.Value) } func (c *compiler) compileCompositeLit(n *ast.CompositeLit) { @@ -639,7 +726,7 @@ func (c *compiler) compileCompositeLit(n *ast.CompositeLit) { c.emitInstOp(opCompositeLit) } else { c.emitInstOp(opTypedCompositeLit) - c.compileExpr(n.Type) + c.compileTypeExpr(n.Type) } for _, elt := range n.Elts { c.compileExpr(elt) @@ -687,7 +774,7 @@ func (c *compiler) compileTypeAssertExpr(n *ast.TypeAssertExpr) { if n.Type != nil { c.emitInstOp(opTypeAssertExpr) c.compileExpr(n.X) - c.compileExpr(n.Type) + c.compileTypeExpr(n.Type) } else { c.emitInstOp(opTypeSwitchAssertExpr) c.compileExpr(n.X) diff --git a/tools/vendor/github.com/quasilyte/gogrep/gen_operations.go b/tools/vendor/github.com/quasilyte/gogrep/gen_operations.go index 8de59980..fd803577 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/gen_operations.go +++ b/tools/vendor/github.com/quasilyte/gogrep/gen_operations.go @@ -42,6 +42,8 @@ var opPrototypes = []operationProto{ {name: "IndexExpr", tag: "IndexExpr", args: "x expr"}, + {name: "IndexListExpr", tag: "IndexListExpr", args: "x exprs..."}, + {name: "SliceExpr", tag: "SliceExpr", args: "x"}, {name: "SliceFromExpr", tag: "SliceExpr", args: "x from", example: "x[from:]"}, {name: "SliceToExpr", tag: "SliceExpr", args: "x to", example: "x[:to]"}, @@ -60,9 +62,12 @@ var opPrototypes = []operationProto{ {name: "TypeSwitchAssertExpr", tag: "TypeAssertExpr", args: "x"}, {name: "StructType", tag: "StructType", args: "fields"}, - {name: "InterfaceType", tag: "StructType", args: "fields"}, + {name: "InterfaceType", tag: "InterfaceType", args: "fields"}, + {name: "EfaceType", tag: "InterfaceType"}, {name: "VoidFuncType", tag: "FuncType", args: "params"}, + {name: "GenericVoidFuncType", tag: "FuncType", args: "typeparams params"}, {name: "FuncType", tag: "FuncType", args: "params results"}, + {name: "GenericFuncType", tag: "FuncType", args: "typeparams params results"}, {name: "ArrayType", tag: "ArrayType", args: "length elem"}, {name: "SliceType", tag: "ArrayType", args: "elem"}, {name: "MapType", tag: "MapType", args: "key value"}, @@ -92,6 +97,7 @@ var opPrototypes = []operationProto{ {name: "VariadicCallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs...)"}, {name: "NonVariadicCallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs)"}, + {name: "MaybeVariadicCallExpr", tag: "CallExpr", args: "fn args", value: "int | can be variadic if len(args)>value", example: "f(1, xs) or f(1, xs...)"}, {name: "CallExpr", tag: "CallExpr", args: "fn args", example: "f(1, xs) or f(1, xs...)"}, {name: "AssignStmt", tag: "AssignStmt", args: "lhs rhs", value: "token.Token | ':=' or '='", example: "lhs := rhs()"}, @@ -167,9 +173,12 @@ var opPrototypes = []operationProto{ {name: "TypedValueInitSpec", tag: "ValueSpec", args: "lhs... type rhs...", example: "lhs typ = rhs"}, {name: "TypedValueSpec", tag: "ValueSpec", args: "lhs... type", example: "lhs typ"}, + {name: "SimpleTypeSpec", tag: "TypeSpec", args: "type", valueIndex: "strings | type name", example: "name type"}, {name: "TypeSpec", tag: "TypeSpec", args: "name type", example: "name type"}, + {name: "GenericTypeSpec", tag: "TypeSpec", args: "name typeparasm type", example: "name[typeparams] type"}, {name: "TypeAliasSpec", tag: "TypeSpec", args: "name type", example: "name = type"}, + {name: "SimpleFuncDecl", tag: "FuncDecl", args: "type block", valueIndex: "strings | field name"}, {name: "FuncDecl", tag: "FuncDecl", args: "name type block"}, {name: "MethodDecl", tag: "FuncDecl", args: "recv name type block"}, {name: "FuncProtoDecl", tag: "FuncDecl", args: "name type"}, diff --git a/tools/vendor/github.com/quasilyte/gogrep/match.go b/tools/vendor/github.com/quasilyte/gogrep/match.go index d927beff..d4e3243a 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/match.go +++ b/tools/vendor/github.com/quasilyte/gogrep/match.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/go-toolsmith/astequal" + "golang.org/x/exp/typeparams" ) type matcher struct { @@ -232,6 +233,15 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast case opNonVariadicCallExpr: n, ok := n.(*ast.CallExpr) return ok && !n.Ellipsis.IsValid() && m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args) + case opMaybeVariadicCallExpr: + n, ok := n.(*ast.CallExpr) + if !ok { + return false + } + if n.Ellipsis.IsValid() && len(n.Args) <= int(inst.value) { + return false + } + return m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args) case opCallExpr: n, ok := n.(*ast.CallExpr) return ok && m.matchNode(state, n.Fun) && m.matchArgList(state, n.Args) @@ -277,6 +287,10 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast n, ok := n.(*ast.IndexExpr) return ok && m.matchNode(state, n.X) && m.matchNode(state, n.Index) + case opIndexListExpr: + n, ok := n.(*typeparams.IndexListExpr) + return ok && m.matchNode(state, n.X) && m.matchExprSlice(state, n.Indices) + case opKeyValueExpr: n, ok := n.(*ast.KeyValueExpr) return ok && m.matchNode(state, n.Key) && m.matchNode(state, n.Value) @@ -307,15 +321,30 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast case opVoidFuncType: n, ok := n.(*ast.FuncType) return ok && n.Results == nil && m.matchNode(state, n.Params) + case opGenericVoidFuncType: + n, ok := n.(*ast.FuncType) + return ok && n.Results == nil && m.matchNode(state, typeparams.ForFuncType(n)) && m.matchNode(state, n.Params) case opFuncType: n, ok := n.(*ast.FuncType) return ok && m.matchNode(state, n.Params) && m.matchNode(state, n.Results) + case opGenericFuncType: + n, ok := n.(*ast.FuncType) + return ok && m.matchNode(state, typeparams.ForFuncType(n)) && m.matchNode(state, n.Params) && m.matchNode(state, n.Results) case opStructType: n, ok := n.(*ast.StructType) return ok && m.matchNode(state, n.Fields) case opInterfaceType: n, ok := n.(*ast.InterfaceType) return ok && m.matchNode(state, n.Methods) + case opEfaceType: + switch n := n.(type) { + case *ast.InterfaceType: + return len(n.Methods.List) == 0 + case *ast.Ident: + return n.Name == "any" + default: + return false + } case opCompositeLit: n, ok := n.(*ast.CompositeLit) @@ -511,13 +540,17 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast _, ok := n.(*ast.EmptyStmt) return ok + case opSimpleFuncDecl: + n, ok := n.(*ast.FuncDecl) + return ok && n.Recv == nil && n.Body != nil && typeparams.ForFuncType(n.Type) == nil && + n.Name.Name == m.stringValue(inst) && m.matchNode(state, n.Type) && m.matchNode(state, n.Body) case opFuncDecl: n, ok := n.(*ast.FuncDecl) return ok && n.Recv == nil && n.Body != nil && m.matchNode(state, n.Name) && m.matchNode(state, n.Type) && m.matchNode(state, n.Body) case opFuncProtoDecl: n, ok := n.(*ast.FuncDecl) - return ok && n.Recv == nil && n.Body == nil && + return ok && n.Recv == nil && n.Body == nil && typeparams.ForFuncType(n.Type) == nil && m.matchNode(state, n.Name) && m.matchNode(state, n.Type) case opMethodDecl: n, ok := n.(*ast.FuncDecl) @@ -545,9 +578,15 @@ func (m *matcher) matchNodeWithInst(state *MatcherState, inst instruction, n ast return ok && len(n.Values) != 0 && m.matchIdentSlice(state, n.Names) && m.matchNode(state, n.Type) && m.matchExprSlice(state, n.Values) + case opSimpleTypeSpec: + n, ok := n.(*ast.TypeSpec) + return ok && !n.Assign.IsValid() && typeparams.ForTypeSpec(n) == nil && n.Name.Name == m.stringValue(inst) && m.matchNode(state, n.Type) case opTypeSpec: n, ok := n.(*ast.TypeSpec) return ok && !n.Assign.IsValid() && m.matchNode(state, n.Name) && m.matchNode(state, n.Type) + case opGenericTypeSpec: + n, ok := n.(*ast.TypeSpec) + return ok && !n.Assign.IsValid() && m.matchNode(state, n.Name) && m.matchNode(state, typeparams.ForTypeSpec(n)) && m.matchNode(state, n.Type) case opTypeAliasSpec: n, ok := n.(*ast.TypeSpec) return ok && n.Assign.IsValid() && m.matchNode(state, n.Name) && m.matchNode(state, n.Type) diff --git a/tools/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go b/tools/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go index a4cc2ff8..8060e0ec 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go +++ b/tools/vendor/github.com/quasilyte/gogrep/nodetag/nodetag.go @@ -2,6 +2,8 @@ package nodetag import ( "go/ast" + + "golang.org/x/exp/typeparams" ) type Value int @@ -37,6 +39,7 @@ const ( ImportSpec IncDecStmt IndexExpr + IndexListExpr InterfaceType KeyValueExpr LabeledStmt @@ -126,6 +129,8 @@ func FromNode(n ast.Node) Value { return IncDecStmt case *ast.IndexExpr: return IndexExpr + case *typeparams.IndexListExpr: + return IndexListExpr case *ast.InterfaceType: return InterfaceType case *ast.KeyValueExpr: @@ -236,6 +241,8 @@ func FromString(s string) Value { return IncDecStmt case "IndexExpr": return IndexExpr + case "IndexListExpr": + return IndexListExpr case "InterfaceType": return InterfaceType case "KeyValueExpr": diff --git a/tools/vendor/github.com/quasilyte/gogrep/operation_string.go b/tools/vendor/github.com/quasilyte/gogrep/operation_string.go index fa093266..23eb2006 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/operation_string.go +++ b/tools/vendor/github.com/quasilyte/gogrep/operation_string.go @@ -30,113 +30,121 @@ func _() { _ = x[opIdent-19] _ = x[opPkg-20] _ = x[opIndexExpr-21] - _ = x[opSliceExpr-22] - _ = x[opSliceFromExpr-23] - _ = x[opSliceToExpr-24] - _ = x[opSliceFromToExpr-25] - _ = x[opSliceToCapExpr-26] - _ = x[opSliceFromToCapExpr-27] - _ = x[opFuncLit-28] - _ = x[opCompositeLit-29] - _ = x[opTypedCompositeLit-30] - _ = x[opSimpleSelectorExpr-31] - _ = x[opSelectorExpr-32] - _ = x[opTypeAssertExpr-33] - _ = x[opTypeSwitchAssertExpr-34] - _ = x[opStructType-35] - _ = x[opInterfaceType-36] - _ = x[opVoidFuncType-37] - _ = x[opFuncType-38] - _ = x[opArrayType-39] - _ = x[opSliceType-40] - _ = x[opMapType-41] - _ = x[opChanType-42] - _ = x[opKeyValueExpr-43] - _ = x[opEllipsis-44] - _ = x[opTypedEllipsis-45] - _ = x[opStarExpr-46] - _ = x[opUnaryExpr-47] - _ = x[opBinaryExpr-48] - _ = x[opParenExpr-49] - _ = x[opArgList-50] - _ = x[opSimpleArgList-51] - _ = x[opVariadicCallExpr-52] - _ = x[opNonVariadicCallExpr-53] - _ = x[opCallExpr-54] - _ = x[opAssignStmt-55] - _ = x[opMultiAssignStmt-56] - _ = x[opBranchStmt-57] - _ = x[opSimpleLabeledBranchStmt-58] - _ = x[opLabeledBranchStmt-59] - _ = x[opSimpleLabeledStmt-60] - _ = x[opLabeledStmt-61] - _ = x[opBlockStmt-62] - _ = x[opExprStmt-63] - _ = x[opGoStmt-64] - _ = x[opDeferStmt-65] - _ = x[opSendStmt-66] - _ = x[opEmptyStmt-67] - _ = x[opIncDecStmt-68] - _ = x[opReturnStmt-69] - _ = x[opIfStmt-70] - _ = x[opIfInitStmt-71] - _ = x[opIfElseStmt-72] - _ = x[opIfInitElseStmt-73] - _ = x[opIfNamedOptStmt-74] - _ = x[opIfNamedOptElseStmt-75] - _ = x[opSwitchStmt-76] - _ = x[opSwitchTagStmt-77] - _ = x[opSwitchInitStmt-78] - _ = x[opSwitchInitTagStmt-79] - _ = x[opSelectStmt-80] - _ = x[opTypeSwitchStmt-81] - _ = x[opTypeSwitchInitStmt-82] - _ = x[opCaseClause-83] - _ = x[opDefaultCaseClause-84] - _ = x[opCommClause-85] - _ = x[opDefaultCommClause-86] - _ = x[opForStmt-87] - _ = x[opForPostStmt-88] - _ = x[opForCondStmt-89] - _ = x[opForCondPostStmt-90] - _ = x[opForInitStmt-91] - _ = x[opForInitPostStmt-92] - _ = x[opForInitCondStmt-93] - _ = x[opForInitCondPostStmt-94] - _ = x[opRangeStmt-95] - _ = x[opRangeKeyStmt-96] - _ = x[opRangeKeyValueStmt-97] - _ = x[opRangeClause-98] - _ = x[opRangeHeader-99] - _ = x[opRangeKeyHeader-100] - _ = x[opRangeKeyValueHeader-101] - _ = x[opFieldList-102] - _ = x[opUnnamedField-103] - _ = x[opSimpleField-104] - _ = x[opField-105] - _ = x[opMultiField-106] - _ = x[opValueSpec-107] - _ = x[opValueInitSpec-108] - _ = x[opTypedValueInitSpec-109] - _ = x[opTypedValueSpec-110] - _ = x[opTypeSpec-111] - _ = x[opTypeAliasSpec-112] - _ = x[opFuncDecl-113] - _ = x[opMethodDecl-114] - _ = x[opFuncProtoDecl-115] - _ = x[opMethodProtoDecl-116] - _ = x[opDeclStmt-117] - _ = x[opConstDecl-118] - _ = x[opVarDecl-119] - _ = x[opTypeDecl-120] - _ = x[opAnyImportDecl-121] - _ = x[opImportDecl-122] - _ = x[opEmptyPackage-123] + _ = x[opIndexListExpr-22] + _ = x[opSliceExpr-23] + _ = x[opSliceFromExpr-24] + _ = x[opSliceToExpr-25] + _ = x[opSliceFromToExpr-26] + _ = x[opSliceToCapExpr-27] + _ = x[opSliceFromToCapExpr-28] + _ = x[opFuncLit-29] + _ = x[opCompositeLit-30] + _ = x[opTypedCompositeLit-31] + _ = x[opSimpleSelectorExpr-32] + _ = x[opSelectorExpr-33] + _ = x[opTypeAssertExpr-34] + _ = x[opTypeSwitchAssertExpr-35] + _ = x[opStructType-36] + _ = x[opInterfaceType-37] + _ = x[opEfaceType-38] + _ = x[opVoidFuncType-39] + _ = x[opGenericVoidFuncType-40] + _ = x[opFuncType-41] + _ = x[opGenericFuncType-42] + _ = x[opArrayType-43] + _ = x[opSliceType-44] + _ = x[opMapType-45] + _ = x[opChanType-46] + _ = x[opKeyValueExpr-47] + _ = x[opEllipsis-48] + _ = x[opTypedEllipsis-49] + _ = x[opStarExpr-50] + _ = x[opUnaryExpr-51] + _ = x[opBinaryExpr-52] + _ = x[opParenExpr-53] + _ = x[opArgList-54] + _ = x[opSimpleArgList-55] + _ = x[opVariadicCallExpr-56] + _ = x[opNonVariadicCallExpr-57] + _ = x[opMaybeVariadicCallExpr-58] + _ = x[opCallExpr-59] + _ = x[opAssignStmt-60] + _ = x[opMultiAssignStmt-61] + _ = x[opBranchStmt-62] + _ = x[opSimpleLabeledBranchStmt-63] + _ = x[opLabeledBranchStmt-64] + _ = x[opSimpleLabeledStmt-65] + _ = x[opLabeledStmt-66] + _ = x[opBlockStmt-67] + _ = x[opExprStmt-68] + _ = x[opGoStmt-69] + _ = x[opDeferStmt-70] + _ = x[opSendStmt-71] + _ = x[opEmptyStmt-72] + _ = x[opIncDecStmt-73] + _ = x[opReturnStmt-74] + _ = x[opIfStmt-75] + _ = x[opIfInitStmt-76] + _ = x[opIfElseStmt-77] + _ = x[opIfInitElseStmt-78] + _ = x[opIfNamedOptStmt-79] + _ = x[opIfNamedOptElseStmt-80] + _ = x[opSwitchStmt-81] + _ = x[opSwitchTagStmt-82] + _ = x[opSwitchInitStmt-83] + _ = x[opSwitchInitTagStmt-84] + _ = x[opSelectStmt-85] + _ = x[opTypeSwitchStmt-86] + _ = x[opTypeSwitchInitStmt-87] + _ = x[opCaseClause-88] + _ = x[opDefaultCaseClause-89] + _ = x[opCommClause-90] + _ = x[opDefaultCommClause-91] + _ = x[opForStmt-92] + _ = x[opForPostStmt-93] + _ = x[opForCondStmt-94] + _ = x[opForCondPostStmt-95] + _ = x[opForInitStmt-96] + _ = x[opForInitPostStmt-97] + _ = x[opForInitCondStmt-98] + _ = x[opForInitCondPostStmt-99] + _ = x[opRangeStmt-100] + _ = x[opRangeKeyStmt-101] + _ = x[opRangeKeyValueStmt-102] + _ = x[opRangeClause-103] + _ = x[opRangeHeader-104] + _ = x[opRangeKeyHeader-105] + _ = x[opRangeKeyValueHeader-106] + _ = x[opFieldList-107] + _ = x[opUnnamedField-108] + _ = x[opSimpleField-109] + _ = x[opField-110] + _ = x[opMultiField-111] + _ = x[opValueSpec-112] + _ = x[opValueInitSpec-113] + _ = x[opTypedValueInitSpec-114] + _ = x[opTypedValueSpec-115] + _ = x[opSimpleTypeSpec-116] + _ = x[opTypeSpec-117] + _ = x[opGenericTypeSpec-118] + _ = x[opTypeAliasSpec-119] + _ = x[opSimpleFuncDecl-120] + _ = x[opFuncDecl-121] + _ = x[opMethodDecl-122] + _ = x[opFuncProtoDecl-123] + _ = x[opMethodProtoDecl-124] + _ = x[opDeclStmt-125] + _ = x[opConstDecl-126] + _ = x[opVarDecl-127] + _ = x[opTypeDecl-128] + _ = x[opAnyImportDecl-129] + _ = x[opImportDecl-130] + _ = x[opEmptyPackage-131] } -const _operation_name = "InvalidNodeNamedNodeNodeSeqNamedNodeSeqOptNodeNamedOptNodeFieldNodeNamedFieldNodeMultiStmtMultiExprMultiDeclEndBasicLitStrictIntLitStrictFloatLitStrictCharLitStrictStringLitStrictComplexLitIdentPkgIndexExprSliceExprSliceFromExprSliceToExprSliceFromToExprSliceToCapExprSliceFromToCapExprFuncLitCompositeLitTypedCompositeLitSimpleSelectorExprSelectorExprTypeAssertExprTypeSwitchAssertExprStructTypeInterfaceTypeVoidFuncTypeFuncTypeArrayTypeSliceTypeMapTypeChanTypeKeyValueExprEllipsisTypedEllipsisStarExprUnaryExprBinaryExprParenExprArgListSimpleArgListVariadicCallExprNonVariadicCallExprCallExprAssignStmtMultiAssignStmtBranchStmtSimpleLabeledBranchStmtLabeledBranchStmtSimpleLabeledStmtLabeledStmtBlockStmtExprStmtGoStmtDeferStmtSendStmtEmptyStmtIncDecStmtReturnStmtIfStmtIfInitStmtIfElseStmtIfInitElseStmtIfNamedOptStmtIfNamedOptElseStmtSwitchStmtSwitchTagStmtSwitchInitStmtSwitchInitTagStmtSelectStmtTypeSwitchStmtTypeSwitchInitStmtCaseClauseDefaultCaseClauseCommClauseDefaultCommClauseForStmtForPostStmtForCondStmtForCondPostStmtForInitStmtForInitPostStmtForInitCondStmtForInitCondPostStmtRangeStmtRangeKeyStmtRangeKeyValueStmtRangeClauseRangeHeaderRangeKeyHeaderRangeKeyValueHeaderFieldListUnnamedFieldSimpleFieldFieldMultiFieldValueSpecValueInitSpecTypedValueInitSpecTypedValueSpecTypeSpecTypeAliasSpecFuncDeclMethodDeclFuncProtoDeclMethodProtoDeclDeclStmtConstDeclVarDeclTypeDeclAnyImportDeclImportDeclEmptyPackage" +const _operation_name = "InvalidNodeNamedNodeNodeSeqNamedNodeSeqOptNodeNamedOptNodeFieldNodeNamedFieldNodeMultiStmtMultiExprMultiDeclEndBasicLitStrictIntLitStrictFloatLitStrictCharLitStrictStringLitStrictComplexLitIdentPkgIndexExprIndexListExprSliceExprSliceFromExprSliceToExprSliceFromToExprSliceToCapExprSliceFromToCapExprFuncLitCompositeLitTypedCompositeLitSimpleSelectorExprSelectorExprTypeAssertExprTypeSwitchAssertExprStructTypeInterfaceTypeEfaceTypeVoidFuncTypeGenericVoidFuncTypeFuncTypeGenericFuncTypeArrayTypeSliceTypeMapTypeChanTypeKeyValueExprEllipsisTypedEllipsisStarExprUnaryExprBinaryExprParenExprArgListSimpleArgListVariadicCallExprNonVariadicCallExprMaybeVariadicCallExprCallExprAssignStmtMultiAssignStmtBranchStmtSimpleLabeledBranchStmtLabeledBranchStmtSimpleLabeledStmtLabeledStmtBlockStmtExprStmtGoStmtDeferStmtSendStmtEmptyStmtIncDecStmtReturnStmtIfStmtIfInitStmtIfElseStmtIfInitElseStmtIfNamedOptStmtIfNamedOptElseStmtSwitchStmtSwitchTagStmtSwitchInitStmtSwitchInitTagStmtSelectStmtTypeSwitchStmtTypeSwitchInitStmtCaseClauseDefaultCaseClauseCommClauseDefaultCommClauseForStmtForPostStmtForCondStmtForCondPostStmtForInitStmtForInitPostStmtForInitCondStmtForInitCondPostStmtRangeStmtRangeKeyStmtRangeKeyValueStmtRangeClauseRangeHeaderRangeKeyHeaderRangeKeyValueHeaderFieldListUnnamedFieldSimpleFieldFieldMultiFieldValueSpecValueInitSpecTypedValueInitSpecTypedValueSpecSimpleTypeSpecTypeSpecGenericTypeSpecTypeAliasSpecSimpleFuncDeclFuncDeclMethodDeclFuncProtoDeclMethodProtoDeclDeclStmtConstDeclVarDeclTypeDeclAnyImportDeclImportDeclEmptyPackage" -var _operation_index = [...]uint16{0, 7, 11, 20, 27, 39, 46, 58, 67, 81, 90, 99, 108, 111, 119, 131, 145, 158, 173, 189, 194, 197, 206, 215, 228, 239, 254, 268, 286, 293, 305, 322, 340, 352, 366, 386, 396, 409, 421, 429, 438, 447, 454, 462, 474, 482, 495, 503, 512, 522, 531, 538, 551, 567, 586, 594, 604, 619, 629, 652, 669, 686, 697, 706, 714, 720, 729, 737, 746, 756, 766, 772, 782, 792, 806, 820, 838, 848, 861, 875, 892, 902, 916, 934, 944, 961, 971, 988, 995, 1006, 1017, 1032, 1043, 1058, 1073, 1092, 1101, 1113, 1130, 1141, 1152, 1166, 1185, 1194, 1206, 1217, 1222, 1232, 1241, 1254, 1272, 1286, 1294, 1307, 1315, 1325, 1338, 1353, 1361, 1370, 1377, 1385, 1398, 1408, 1420} +var _operation_index = [...]uint16{0, 7, 11, 20, 27, 39, 46, 58, 67, 81, 90, 99, 108, 111, 119, 131, 145, 158, 173, 189, 194, 197, 206, 219, 228, 241, 252, 267, 281, 299, 306, 318, 335, 353, 365, 379, 399, 409, 422, 431, 443, 462, 470, 485, 494, 503, 510, 518, 530, 538, 551, 559, 568, 578, 587, 594, 607, 623, 642, 663, 671, 681, 696, 706, 729, 746, 763, 774, 783, 791, 797, 806, 814, 823, 833, 843, 849, 859, 869, 883, 897, 915, 925, 938, 952, 969, 979, 993, 1011, 1021, 1038, 1048, 1065, 1072, 1083, 1094, 1109, 1120, 1135, 1150, 1169, 1178, 1190, 1207, 1218, 1229, 1243, 1262, 1271, 1283, 1294, 1299, 1309, 1318, 1331, 1349, 1363, 1377, 1385, 1400, 1413, 1427, 1435, 1445, 1458, 1473, 1481, 1490, 1497, 1505, 1518, 1528, 1540} func (i operation) String() string { if i >= operation(len(_operation_index)-1) { diff --git a/tools/vendor/github.com/quasilyte/gogrep/operations.gen.go b/tools/vendor/github.com/quasilyte/gogrep/operations.gen.go index 8ff1fbeb..9af838ab 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/operations.gen.go +++ b/tools/vendor/github.com/quasilyte/gogrep/operations.gen.go @@ -94,481 +94,518 @@ const ( // Args: x expr opIndexExpr operation = 21 + // Tag: IndexListExpr + // Args: x exprs... + opIndexListExpr operation = 22 + // Tag: SliceExpr // Args: x - opSliceExpr operation = 22 + opSliceExpr operation = 23 // Tag: SliceExpr // Args: x from // Example: x[from:] - opSliceFromExpr operation = 23 + opSliceFromExpr operation = 24 // Tag: SliceExpr // Args: x to // Example: x[:to] - opSliceToExpr operation = 24 + opSliceToExpr operation = 25 // Tag: SliceExpr // Args: x from to // Example: x[from:to] - opSliceFromToExpr operation = 25 + opSliceFromToExpr operation = 26 // Tag: SliceExpr // Args: x from cap // Example: x[:from:cap] - opSliceToCapExpr operation = 26 + opSliceToCapExpr operation = 27 // Tag: SliceExpr // Args: x from to cap // Example: x[from:to:cap] - opSliceFromToCapExpr operation = 27 + opSliceFromToCapExpr operation = 28 // Tag: FuncLit // Args: type block - opFuncLit operation = 28 + opFuncLit operation = 29 // Tag: CompositeLit // Args: elts... // Example: {elts...} - opCompositeLit operation = 29 + opCompositeLit operation = 30 // Tag: CompositeLit // Args: typ elts... // Example: typ{elts...} - opTypedCompositeLit operation = 30 + opTypedCompositeLit operation = 31 // Tag: SelectorExpr // Args: x // ValueIndex: strings | selector name - opSimpleSelectorExpr operation = 31 + opSimpleSelectorExpr operation = 32 // Tag: SelectorExpr // Args: x sel - opSelectorExpr operation = 32 + opSelectorExpr operation = 33 // Tag: TypeAssertExpr // Args: x typ - opTypeAssertExpr operation = 33 + opTypeAssertExpr operation = 34 // Tag: TypeAssertExpr // Args: x - opTypeSwitchAssertExpr operation = 34 + opTypeSwitchAssertExpr operation = 35 // Tag: StructType // Args: fields - opStructType operation = 35 + opStructType operation = 36 - // Tag: StructType + // Tag: InterfaceType // Args: fields - opInterfaceType operation = 36 + opInterfaceType operation = 37 + + // Tag: InterfaceType + opEfaceType operation = 38 // Tag: FuncType // Args: params - opVoidFuncType operation = 37 + opVoidFuncType operation = 39 + + // Tag: FuncType + // Args: typeparams params + opGenericVoidFuncType operation = 40 // Tag: FuncType // Args: params results - opFuncType operation = 38 + opFuncType operation = 41 + + // Tag: FuncType + // Args: typeparams params results + opGenericFuncType operation = 42 // Tag: ArrayType // Args: length elem - opArrayType operation = 39 + opArrayType operation = 43 // Tag: ArrayType // Args: elem - opSliceType operation = 40 + opSliceType operation = 44 // Tag: MapType // Args: key value - opMapType operation = 41 + opMapType operation = 45 // Tag: ChanType // Args: value // Value: ast.ChanDir | channel direction - opChanType operation = 42 + opChanType operation = 46 // Tag: KeyValueExpr // Args: key value - opKeyValueExpr operation = 43 + opKeyValueExpr operation = 47 // Tag: Ellipsis - opEllipsis operation = 44 + opEllipsis operation = 48 // Tag: Ellipsis // Args: type - opTypedEllipsis operation = 45 + opTypedEllipsis operation = 49 // Tag: StarExpr // Args: x - opStarExpr operation = 46 + opStarExpr operation = 50 // Tag: UnaryExpr // Args: x // Value: token.Token | unary operator - opUnaryExpr operation = 47 + opUnaryExpr operation = 51 // Tag: BinaryExpr // Args: x y // Value: token.Token | binary operator - opBinaryExpr operation = 48 + opBinaryExpr operation = 52 // Tag: ParenExpr // Args: x - opParenExpr operation = 49 + opParenExpr operation = 53 // Tag: Unknown // Args: exprs... // Example: 1, 2, 3 - opArgList operation = 50 + opArgList operation = 54 // Tag: Unknown // Like ArgList, but pattern contains no $* // Args: exprs[] // Example: 1, 2, 3 // Value: int | slice len - opSimpleArgList operation = 51 + opSimpleArgList operation = 55 // Tag: CallExpr // Args: fn args // Example: f(1, xs...) - opVariadicCallExpr operation = 52 + opVariadicCallExpr operation = 56 // Tag: CallExpr // Args: fn args // Example: f(1, xs) - opNonVariadicCallExpr operation = 53 + opNonVariadicCallExpr operation = 57 // Tag: CallExpr // Args: fn args // Example: f(1, xs) or f(1, xs...) - opCallExpr operation = 54 + // Value: int | can be variadic if len(args)>value + opMaybeVariadicCallExpr operation = 58 + + // Tag: CallExpr + // Args: fn args + // Example: f(1, xs) or f(1, xs...) + opCallExpr operation = 59 // Tag: AssignStmt // Args: lhs rhs // Example: lhs := rhs() // Value: token.Token | ':=' or '=' - opAssignStmt operation = 55 + opAssignStmt operation = 60 // Tag: AssignStmt // Args: lhs... rhs... // Example: lhs1, lhs2 := rhs() // Value: token.Token | ':=' or '=' - opMultiAssignStmt operation = 56 + opMultiAssignStmt operation = 61 // Tag: BranchStmt // Args: x // Value: token.Token | branch kind - opBranchStmt operation = 57 + opBranchStmt operation = 62 // Tag: BranchStmt // Args: x // Value: token.Token | branch kind // ValueIndex: strings | label name - opSimpleLabeledBranchStmt operation = 58 + opSimpleLabeledBranchStmt operation = 63 // Tag: BranchStmt // Args: label x // Value: token.Token | branch kind - opLabeledBranchStmt operation = 59 + opLabeledBranchStmt operation = 64 // Tag: LabeledStmt // Args: x // ValueIndex: strings | label name - opSimpleLabeledStmt operation = 60 + opSimpleLabeledStmt operation = 65 // Tag: LabeledStmt // Args: label x - opLabeledStmt operation = 61 + opLabeledStmt operation = 66 // Tag: BlockStmt // Args: body... - opBlockStmt operation = 62 + opBlockStmt operation = 67 // Tag: ExprStmt // Args: x - opExprStmt operation = 63 + opExprStmt operation = 68 // Tag: GoStmt // Args: x - opGoStmt operation = 64 + opGoStmt operation = 69 // Tag: DeferStmt // Args: x - opDeferStmt operation = 65 + opDeferStmt operation = 70 // Tag: SendStmt // Args: ch value - opSendStmt operation = 66 + opSendStmt operation = 71 // Tag: EmptyStmt - opEmptyStmt operation = 67 + opEmptyStmt operation = 72 // Tag: IncDecStmt // Args: x // Value: token.Token | '++' or '--' - opIncDecStmt operation = 68 + opIncDecStmt operation = 73 // Tag: ReturnStmt // Args: results... - opReturnStmt operation = 69 + opReturnStmt operation = 74 // Tag: IfStmt // Args: cond block // Example: if cond {} - opIfStmt operation = 70 + opIfStmt operation = 75 // Tag: IfStmt // Args: init cond block // Example: if init; cond {} - opIfInitStmt operation = 71 + opIfInitStmt operation = 76 // Tag: IfStmt // Args: cond block else // Example: if cond {} else ... - opIfElseStmt operation = 72 + opIfElseStmt operation = 77 // Tag: IfStmt // Args: init cond block else // Example: if init; cond {} else ... - opIfInitElseStmt operation = 73 + opIfInitElseStmt operation = 78 // Tag: IfStmt // Args: block // Example: if $*x {} // ValueIndex: strings | wildcard name - opIfNamedOptStmt operation = 74 + opIfNamedOptStmt operation = 79 // Tag: IfStmt // Args: block else // Example: if $*x {} else ... // ValueIndex: strings | wildcard name - opIfNamedOptElseStmt operation = 75 + opIfNamedOptElseStmt operation = 80 // Tag: SwitchStmt // Args: body... // Example: switch {} - opSwitchStmt operation = 76 + opSwitchStmt operation = 81 // Tag: SwitchStmt // Args: tag body... // Example: switch tag {} - opSwitchTagStmt operation = 77 + opSwitchTagStmt operation = 82 // Tag: SwitchStmt // Args: init body... // Example: switch init; {} - opSwitchInitStmt operation = 78 + opSwitchInitStmt operation = 83 // Tag: SwitchStmt // Args: init tag body... // Example: switch init; tag {} - opSwitchInitTagStmt operation = 79 + opSwitchInitTagStmt operation = 84 // Tag: SelectStmt // Args: body... - opSelectStmt operation = 80 + opSelectStmt operation = 85 // Tag: TypeSwitchStmt // Args: x block // Example: switch x.(type) {} - opTypeSwitchStmt operation = 81 + opTypeSwitchStmt operation = 86 // Tag: TypeSwitchStmt // Args: init x block // Example: switch init; x.(type) {} - opTypeSwitchInitStmt operation = 82 + opTypeSwitchInitStmt operation = 87 // Tag: CaseClause // Args: values... body... - opCaseClause operation = 83 + opCaseClause operation = 88 // Tag: CaseClause // Args: body... - opDefaultCaseClause operation = 84 + opDefaultCaseClause operation = 89 // Tag: CommClause // Args: comm body... - opCommClause operation = 85 + opCommClause operation = 90 // Tag: CommClause // Args: body... - opDefaultCommClause operation = 86 + opDefaultCommClause operation = 91 // Tag: ForStmt // Args: blocl // Example: for {} - opForStmt operation = 87 + opForStmt operation = 92 // Tag: ForStmt // Args: post block // Example: for ; ; post {} - opForPostStmt operation = 88 + opForPostStmt operation = 93 // Tag: ForStmt // Args: cond block // Example: for ; cond; {} - opForCondStmt operation = 89 + opForCondStmt operation = 94 // Tag: ForStmt // Args: cond post block // Example: for ; cond; post {} - opForCondPostStmt operation = 90 + opForCondPostStmt operation = 95 // Tag: ForStmt // Args: init block // Example: for init; ; {} - opForInitStmt operation = 91 + opForInitStmt operation = 96 // Tag: ForStmt // Args: init post block // Example: for init; ; post {} - opForInitPostStmt operation = 92 + opForInitPostStmt operation = 97 // Tag: ForStmt // Args: init cond block // Example: for init; cond; {} - opForInitCondStmt operation = 93 + opForInitCondStmt operation = 98 // Tag: ForStmt // Args: init cond post block // Example: for init; cond; post {} - opForInitCondPostStmt operation = 94 + opForInitCondPostStmt operation = 99 // Tag: RangeStmt // Args: x block // Example: for range x {} - opRangeStmt operation = 95 + opRangeStmt operation = 100 // Tag: RangeStmt // Args: key x block // Example: for key := range x {} // Value: token.Token | ':=' or '=' - opRangeKeyStmt operation = 96 + opRangeKeyStmt operation = 101 // Tag: RangeStmt // Args: key value x block // Example: for key, value := range x {} // Value: token.Token | ':=' or '=' - opRangeKeyValueStmt operation = 97 + opRangeKeyValueStmt operation = 102 // Tag: RangeStmt // Args: x // Example: range x - opRangeClause operation = 98 + opRangeClause operation = 103 // Tag: RangeStmt // Args: x // Example: for range x - opRangeHeader operation = 99 + opRangeHeader operation = 104 // Tag: RangeStmt // Args: key x // Example: for key := range x // Value: token.Token | ':=' or '=' - opRangeKeyHeader operation = 100 + opRangeKeyHeader operation = 105 // Tag: RangeStmt // Args: key value x // Example: for key, value := range x // Value: token.Token | ':=' or '=' - opRangeKeyValueHeader operation = 101 + opRangeKeyValueHeader operation = 106 // Tag: Unknown // Args: fields... - opFieldList operation = 102 + opFieldList operation = 107 // Tag: Unknown // Args: typ // Example: type - opUnnamedField operation = 103 + opUnnamedField operation = 108 // Tag: Unknown // Args: typ // Example: name type // ValueIndex: strings | field name - opSimpleField operation = 104 + opSimpleField operation = 109 // Tag: Unknown // Args: name typ // Example: $name type - opField operation = 105 + opField operation = 110 // Tag: Unknown // Args: names... typ // Example: name1, name2 type - opMultiField operation = 106 + opMultiField operation = 111 // Tag: ValueSpec // Args: value - opValueSpec operation = 107 + opValueSpec operation = 112 // Tag: ValueSpec // Args: lhs... rhs... // Example: lhs = rhs - opValueInitSpec operation = 108 + opValueInitSpec operation = 113 // Tag: ValueSpec // Args: lhs... type rhs... // Example: lhs typ = rhs - opTypedValueInitSpec operation = 109 + opTypedValueInitSpec operation = 114 // Tag: ValueSpec // Args: lhs... type // Example: lhs typ - opTypedValueSpec operation = 110 + opTypedValueSpec operation = 115 + + // Tag: TypeSpec + // Args: type + // Example: name type + // ValueIndex: strings | type name + opSimpleTypeSpec operation = 116 // Tag: TypeSpec // Args: name type // Example: name type - opTypeSpec operation = 111 + opTypeSpec operation = 117 + + // Tag: TypeSpec + // Args: name typeparasm type + // Example: name[typeparams] type + opGenericTypeSpec operation = 118 // Tag: TypeSpec // Args: name type // Example: name = type - opTypeAliasSpec operation = 112 + opTypeAliasSpec operation = 119 + + // Tag: FuncDecl + // Args: type block + // ValueIndex: strings | field name + opSimpleFuncDecl operation = 120 // Tag: FuncDecl // Args: name type block - opFuncDecl operation = 113 + opFuncDecl operation = 121 // Tag: FuncDecl // Args: recv name type block - opMethodDecl operation = 114 + opMethodDecl operation = 122 // Tag: FuncDecl // Args: name type - opFuncProtoDecl operation = 115 + opFuncProtoDecl operation = 123 // Tag: FuncDecl // Args: recv name type - opMethodProtoDecl operation = 116 + opMethodProtoDecl operation = 124 // Tag: DeclStmt // Args: decl - opDeclStmt operation = 117 + opDeclStmt operation = 125 // Tag: GenDecl // Args: valuespecs... - opConstDecl operation = 118 + opConstDecl operation = 126 // Tag: GenDecl // Args: valuespecs... - opVarDecl operation = 119 + opVarDecl operation = 127 // Tag: GenDecl // Args: typespecs... - opTypeDecl operation = 120 + opTypeDecl operation = 128 // Tag: GenDecl - opAnyImportDecl operation = 121 + opAnyImportDecl operation = 129 // Tag: GenDecl // Args: importspecs... - opImportDecl operation = 122 + opImportDecl operation = 130 // Tag: File // Args: name - opEmptyPackage operation = 123 + opEmptyPackage operation = 131 ) type operationInfo struct { @@ -751,6 +788,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opIndexListExpr: { + Tag: nodetag.IndexListExpr, + NumArgs: 2, + ValueKind: emptyValue, + ExtraValueKind: emptyValue, + VariadicMap: 2, // 10 + SliceIndex: -1, + }, opSliceExpr: { Tag: nodetag.SliceExpr, NumArgs: 1, @@ -864,13 +909,21 @@ var operationInfoTable = [256]operationInfo{ SliceIndex: -1, }, opInterfaceType: { - Tag: nodetag.StructType, + Tag: nodetag.InterfaceType, NumArgs: 1, ValueKind: emptyValue, ExtraValueKind: emptyValue, VariadicMap: 0, // 0 SliceIndex: -1, }, + opEfaceType: { + Tag: nodetag.InterfaceType, + NumArgs: 0, + ValueKind: emptyValue, + ExtraValueKind: emptyValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opVoidFuncType: { Tag: nodetag.FuncType, NumArgs: 1, @@ -879,6 +932,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opGenericVoidFuncType: { + Tag: nodetag.FuncType, + NumArgs: 2, + ValueKind: emptyValue, + ExtraValueKind: emptyValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opFuncType: { Tag: nodetag.FuncType, NumArgs: 2, @@ -887,6 +948,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opGenericFuncType: { + Tag: nodetag.FuncType, + NumArgs: 3, + ValueKind: emptyValue, + ExtraValueKind: emptyValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opArrayType: { Tag: nodetag.ArrayType, NumArgs: 2, @@ -1007,6 +1076,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opMaybeVariadicCallExpr: { + Tag: nodetag.CallExpr, + NumArgs: 2, + ValueKind: intValue, + ExtraValueKind: emptyValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opCallExpr: { Tag: nodetag.CallExpr, NumArgs: 2, @@ -1463,6 +1540,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 1, // 1 SliceIndex: -1, }, + opSimpleTypeSpec: { + Tag: nodetag.TypeSpec, + NumArgs: 1, + ValueKind: emptyValue, + ExtraValueKind: stringValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opTypeSpec: { Tag: nodetag.TypeSpec, NumArgs: 2, @@ -1471,6 +1556,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opGenericTypeSpec: { + Tag: nodetag.TypeSpec, + NumArgs: 3, + ValueKind: emptyValue, + ExtraValueKind: emptyValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opTypeAliasSpec: { Tag: nodetag.TypeSpec, NumArgs: 2, @@ -1479,6 +1572,14 @@ var operationInfoTable = [256]operationInfo{ VariadicMap: 0, // 0 SliceIndex: -1, }, + opSimpleFuncDecl: { + Tag: nodetag.FuncDecl, + NumArgs: 2, + ValueKind: emptyValue, + ExtraValueKind: stringValue, + VariadicMap: 0, // 0 + SliceIndex: -1, + }, opFuncDecl: { Tag: nodetag.FuncDecl, NumArgs: 3, diff --git a/tools/vendor/github.com/quasilyte/gogrep/parse.go b/tools/vendor/github.com/quasilyte/gogrep/parse.go index f70c4a8f..aa5ffbf9 100644 --- a/tools/vendor/github.com/quasilyte/gogrep/parse.go +++ b/tools/vendor/github.com/quasilyte/gogrep/parse.go @@ -146,7 +146,7 @@ func parseDetectingNode(fset *token.FileSet, src string) (ast.Node, error) { } if strings.HasPrefix(src, "for ") && !strings.HasSuffix(src, "}") { asStmts := execTmpl(tmplStmts, src+"{}") - f, err := parser.ParseFile(fset, "", asStmts, 0) + f, err := parser.ParseFile(fset, "", asStmts, parser.SkipObjectResolution) if err == nil && noBadNodes(f) { bl := f.Decls[0].(*ast.FuncDecl).Body if len(bl.List) == 1 { @@ -156,9 +156,9 @@ func parseDetectingNode(fset *token.FileSet, src string) (ast.Node, error) { } // try as a block; otherwise blocks might be mistaken for composite - // literals further below + // literals further below\ asBlock := execTmpl(tmplBlock, src) - if f, err := parser.ParseFile(fset, "", asBlock, 0); err == nil && noBadNodes(f) { + if f, err := parser.ParseFile(fset, "", asBlock, parser.SkipObjectResolution); err == nil && noBadNodes(f) { bl := f.Decls[0].(*ast.FuncDecl).Body if len(bl.List) == 1 { ifs := bl.List[0].(*ast.IfStmt) @@ -168,7 +168,7 @@ func parseDetectingNode(fset *token.FileSet, src string) (ast.Node, error) { // then as value expressions asExprs := execTmpl(tmplExprs, src) - if f, err := parser.ParseFile(fset, "", asExprs, 0); err == nil && noBadNodes(f) { + if f, err := parser.ParseFile(fset, "", asExprs, parser.SkipObjectResolution); err == nil && noBadNodes(f) { vs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec) cl := vs.Values[0].(*ast.CompositeLit) if len(cl.Elts) == 1 { @@ -179,7 +179,7 @@ func parseDetectingNode(fset *token.FileSet, src string) (ast.Node, error) { // then try as statements asStmts := execTmpl(tmplStmts, src) - f, err := parser.ParseFile(fset, "", asStmts, 0) + f, err := parser.ParseFile(fset, "", asStmts, parser.SkipObjectResolution) if err == nil && noBadNodes(f) { bl := f.Decls[0].(*ast.FuncDecl).Body if len(bl.List) == 1 { diff --git a/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/analyzer.go b/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/analyzer.go index 63c2f716..b55a10be 100644 --- a/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/analyzer.go +++ b/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/analyzer.go @@ -14,13 +14,17 @@ import ( ) const ( - TimeWeekdayFlag = "time-weekday" - TimeMonthFlag = "time-month" - TimeLayoutFlag = "time-layout" - CryptoHashFlag = "crypto-hash" - HTTPMethodFlag = "http-method" - HTTPStatusCodeFlag = "http-status-code" - DefaultRPCPathFlag = "default-rpc-path" + TimeWeekdayFlag = "time-weekday" + TimeMonthFlag = "time-month" + TimeLayoutFlag = "time-layout" + CryptoHashFlag = "crypto-hash" + HTTPMethodFlag = "http-method" + HTTPStatusCodeFlag = "http-status-code" + RPCDefaultPathFlag = "rpc-default-path" + OSDevNullFlag = "os-dev-null" + SQLIsolationLevelFlag = "sql-isolation-level" + TLSSignatureSchemeFlag = "tls-signature-scheme" + ConstantKindFlag = "constant-kind" ) // New returns new usestdlibvars analyzer. @@ -38,234 +42,338 @@ func flags() flag.FlagSet { flags := flag.NewFlagSet("", flag.ExitOnError) flags.Bool(HTTPMethodFlag, true, "suggest the use of http.MethodXX") flags.Bool(HTTPStatusCodeFlag, true, "suggest the use of http.StatusXX") - flags.Bool(TimeWeekdayFlag, false, "suggest the use of time.Weekday") - flags.Bool(TimeMonthFlag, false, "suggest the use of time.Month") + flags.Bool(TimeWeekdayFlag, false, "suggest the use of time.Weekday.String()") + flags.Bool(TimeMonthFlag, false, "suggest the use of time.Month.String()") flags.Bool(TimeLayoutFlag, false, "suggest the use of time.Layout") - flags.Bool(CryptoHashFlag, false, "suggest the use of crypto.Hash") - flags.Bool(DefaultRPCPathFlag, false, "suggest the use of rpc.DefaultXXPath") + flags.Bool(CryptoHashFlag, false, "suggest the use of crypto.Hash.String()") + flags.Bool(RPCDefaultPathFlag, false, "suggest the use of rpc.DefaultXXPath") + flags.Bool(OSDevNullFlag, false, "suggest the use of os.DevNull") + flags.Bool(SQLIsolationLevelFlag, false, "suggest the use of sql.LevelXX.String()") + flags.Bool(TLSSignatureSchemeFlag, false, "suggest the use of tls.SignatureScheme.String()") + flags.Bool(ConstantKindFlag, false, "suggest the use of constant.Kind.String()") return *flags } func run(pass *analysis.Pass) (interface{}, error) { insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - filter := []ast.Node{ + types := []ast.Node{ (*ast.CallExpr)(nil), (*ast.BasicLit)(nil), (*ast.CompositeLit)(nil), (*ast.IfStmt)(nil), (*ast.SwitchStmt)(nil), + (*ast.ForStmt)(nil), } - insp.Preorder(filter, func(node ast.Node) { + insp.Preorder(types, func(node ast.Node) { switch n := node.(type) { case *ast.CallExpr: - selectorExpr, ok := n.Fun.(*ast.SelectorExpr) + fun, ok := n.Fun.(*ast.SelectorExpr) if !ok { return } - ident, ok := selectorExpr.X.(*ast.Ident) + x, ok := fun.X.(*ast.Ident) if !ok { return } - switch ident.Name { - case "http": - switch selectorExpr.Sel.Name { - case "NewRequest": - if !lookupFlag(pass, HTTPMethodFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 3, 0, token.STRING); basicLit != nil { - checkHTTPMethod(pass, basicLit) - } - - case "NewRequestWithContext": - if !lookupFlag(pass, HTTPMethodFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 4, 1, token.STRING); basicLit != nil { - checkHTTPMethod(pass, basicLit) - } - - case "Error": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 3, 2, token.INT); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } - - case "StatusText": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 1, 0, token.INT); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } - - case "Redirect": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 4, 3, token.INT); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } - - case "RedirectHandler": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 2, 1, token.INT); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } - } - default: - if selectorExpr.Sel.Name == "WriteHeader" { - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - - if basicLit := getBasicLitFromArgs(n.Args, 1, 0, token.INT); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } + funArgs(pass, x, fun, n.Args) + + case *ast.BasicLit: + for _, c := range []struct { + flag string + checkFunc func(pass *analysis.Pass, basicLit *ast.BasicLit) + }{ + {flag: TimeWeekdayFlag, checkFunc: checkTimeWeekday}, + {flag: TimeMonthFlag, checkFunc: checkTimeMonth}, + {flag: TimeLayoutFlag, checkFunc: checkTimeLayout}, + {flag: CryptoHashFlag, checkFunc: checkCryptoHash}, + {flag: RPCDefaultPathFlag, checkFunc: checkRPCDefaultPath}, + {flag: OSDevNullFlag, checkFunc: checkOSDevNull}, + {flag: SQLIsolationLevelFlag, checkFunc: checkSQLIsolationLevel}, + {flag: TLSSignatureSchemeFlag, checkFunc: checkTLSSignatureScheme}, + {flag: ConstantKindFlag, checkFunc: checkConstantKind}, + } { + if lookupFlag(pass, c.flag) { + c.checkFunc(pass, n) } } - case *ast.BasicLit: - currentVal := getBasicLitValue(n) + case *ast.CompositeLit: + typ, ok := n.Type.(*ast.SelectorExpr) + if !ok { + return + } - if lookupFlag(pass, TimeWeekdayFlag) { - checkTimeWeekday(pass, n.Pos(), currentVal) + x, ok := typ.X.(*ast.Ident) + if !ok { + return } - if lookupFlag(pass, TimeMonthFlag) { - checkTimeMonth(pass, n.Pos(), currentVal) + typeElts(pass, x, typ, n.Elts) + + case *ast.IfStmt: + cond, ok := n.Cond.(*ast.BinaryExpr) + if !ok { + return } - if lookupFlag(pass, TimeLayoutFlag) { - checkTimeLayout(pass, n.Pos(), currentVal) + x, ok := cond.X.(*ast.SelectorExpr) + if !ok { + return } - if lookupFlag(pass, CryptoHashFlag) { - checkCryptoHash(pass, n.Pos(), currentVal) + y, ok := cond.Y.(*ast.BasicLit) + if !ok { + return } - if lookupFlag(pass, DefaultRPCPathFlag) { - checkDefaultRPCPath(pass, n.Pos(), currentVal) + ifElseStmt(pass, x, y) + + case *ast.SwitchStmt: + x, ok := n.Tag.(*ast.SelectorExpr) + if ok { + switchStmt(pass, x, n.Body.List) + } else { + switchStmtAsIfElseStmt(pass, n.Body.List) } - case *ast.CompositeLit: - selectorExpr, ok := n.Type.(*ast.SelectorExpr) + case *ast.ForStmt: + cond, ok := n.Cond.(*ast.BinaryExpr) + if !ok { + return + } + + x, ok := cond.X.(*ast.SelectorExpr) if !ok { return } - ident, ok := selectorExpr.X.(*ast.Ident) + y, ok := cond.Y.(*ast.BasicLit) if !ok { return } - if ident.Name == "http" { - switch selectorExpr.Sel.Name { - case "Request": - if !lookupFlag(pass, HTTPMethodFlag) { - return - } + ifElseStmt(pass, x, y) + } + }) - if basicLit := getBasicLitFromElts(n.Elts, "Method"); basicLit != nil { - checkHTTPMethod(pass, basicLit) - } + return nil, nil +} - case "Response": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } +// funArgs checks arguments of function or method. +func funArgs(pass *analysis.Pass, x *ast.Ident, fun *ast.SelectorExpr, args []ast.Expr) { + switch x.Name { + case "http": + switch fun.Sel.Name { + // http.NewRequest(http.MethodGet, "localhost", http.NoBody) + case "NewRequest": + if !lookupFlag(pass, HTTPMethodFlag) { + return + } - if basicLit := getBasicLitFromElts(n.Elts, "StatusCode"); basicLit != nil { - checkHTTPStatusCode(pass, basicLit) - } - } + if basicLit := getBasicLitFromArgs(args, 3, 0, token.STRING); basicLit != nil { + checkHTTPMethod(pass, basicLit) } - case *ast.IfStmt: - binaryExpr, ok := n.Cond.(*ast.BinaryExpr) - if !ok { + // http.NewRequestWithContext(context.Background(), http.MethodGet, "localhost", http.NoBody) + case "NewRequestWithContext": + if !lookupFlag(pass, HTTPMethodFlag) { return } - selectorExpr, ok := binaryExpr.X.(*ast.SelectorExpr) - if !ok { + if basicLit := getBasicLitFromArgs(args, 4, 1, token.STRING); basicLit != nil { + checkHTTPMethod(pass, basicLit) + } + + // http.Error(w, err, http.StatusInternalServerError) + case "Error": + if !lookupFlag(pass, HTTPStatusCodeFlag) { return } - basicLit, ok := binaryExpr.Y.(*ast.BasicLit) - if !ok { + if basicLit := getBasicLitFromArgs(args, 3, 2, token.INT); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) + } + + // http.StatusText(http.StatusOK) + case "StatusText": + if !lookupFlag(pass, HTTPStatusCodeFlag) { return } - switch selectorExpr.Sel.Name { - case "StatusCode": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } + if basicLit := getBasicLitFromArgs(args, 1, 0, token.INT); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) + } + // http.Redirect(w, r, "localhost", http.StatusMovedPermanently) + case "Redirect": + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } + + if basicLit := getBasicLitFromArgs(args, 4, 3, token.INT); basicLit != nil { checkHTTPStatusCode(pass, basicLit) - case "Method": - if !lookupFlag(pass, HTTPMethodFlag) { - return - } + } + + // http.RedirectHandler("localhost", http.StatusMovedPermanently) + case "RedirectHandler": + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } + if basicLit := getBasicLitFromArgs(args, 2, 1, token.INT); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) + } + } + case "httptest": + if fun.Sel.Name == "NewRequest" { + if !lookupFlag(pass, HTTPMethodFlag) { + return + } + + if basicLit := getBasicLitFromArgs(args, 3, 0, token.STRING); basicLit != nil { checkHTTPMethod(pass, basicLit) } + } + default: + // w.WriteHeader(http.StatusOk) + if fun.Sel.Name == "WriteHeader" { + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } - case *ast.SwitchStmt: - selectorExpr, ok := n.Tag.(*ast.SelectorExpr) - if !ok { + if basicLit := getBasicLitFromArgs(args, 1, 0, token.INT); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) + } + } + } +} + +// typeElts checks elements of type. +func typeElts(pass *analysis.Pass, x *ast.Ident, typ *ast.SelectorExpr, elts []ast.Expr) { + switch x.Name { + case "http": + switch typ.Sel.Name { + // http.Request{Method: http.MethodGet} + case "Request": + if !lookupFlag(pass, HTTPMethodFlag) { return } - var checkFunc func(pass *analysis.Pass, basicLit *ast.BasicLit) + if basicLit := getBasicLitFromElts(elts, "Method"); basicLit != nil { + checkHTTPMethod(pass, basicLit) + } - switch selectorExpr.Sel.Name { - case "StatusCode": - if !lookupFlag(pass, HTTPStatusCodeFlag) { - return - } - checkFunc = checkHTTPStatusCode - case "Method": - if !lookupFlag(pass, HTTPMethodFlag) { - return - } - checkFunc = checkHTTPMethod - default: + // http.Response{StatusCode: http.StatusOK} + case "Response": + if !lookupFlag(pass, HTTPStatusCodeFlag) { return } - for _, stmt := range n.Body.List { - caseClause, ok := stmt.(*ast.CaseClause) - if !ok { - continue - } - for _, expr := range caseClause.List { - basicLit, ok := expr.(*ast.BasicLit) - if !ok { - continue - } - checkFunc(pass, basicLit) - } + if basicLit := getBasicLitFromElts(elts, "StatusCode"); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) } } - }) + case "httptest": + if typ.Sel.Name == "ResponseRecorder" { + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } - return nil, nil + if basicLit := getBasicLitFromElts(elts, "Code"); basicLit != nil { + checkHTTPStatusCode(pass, basicLit) + } + } + } +} + +// ifElseStmt checks X and Y in if-else-statement. +func ifElseStmt(pass *analysis.Pass, x *ast.SelectorExpr, y *ast.BasicLit) { + switch x.Sel.Name { + case "StatusCode": + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } + + checkHTTPStatusCode(pass, y) + + case "Method": + if !lookupFlag(pass, HTTPMethodFlag) { + return + } + + checkHTTPMethod(pass, y) + } +} + +func switchStmt(pass *analysis.Pass, x *ast.SelectorExpr, cases []ast.Stmt) { + var checkFunc func(pass *analysis.Pass, basicLit *ast.BasicLit) + + switch x.Sel.Name { + case "StatusCode": + if !lookupFlag(pass, HTTPStatusCodeFlag) { + return + } + + checkFunc = checkHTTPStatusCode + + case "Method": + if !lookupFlag(pass, HTTPMethodFlag) { + return + } + + checkFunc = checkHTTPMethod + + default: + return + } + + for _, c := range cases { + caseClause, ok := c.(*ast.CaseClause) + if !ok { + continue + } + + for _, expr := range caseClause.List { + basicLit, ok := expr.(*ast.BasicLit) + if !ok { + continue + } + + checkFunc(pass, basicLit) + } + } +} + +func switchStmtAsIfElseStmt(pass *analysis.Pass, cases []ast.Stmt) { + for _, c := range cases { + caseClause, ok := c.(*ast.CaseClause) + if !ok { + continue + } + + for _, expr := range caseClause.List { + binaryExpr, ok := expr.(*ast.BinaryExpr) + if !ok { + continue + } + + x, ok := binaryExpr.X.(*ast.SelectorExpr) + if !ok { + continue + } + + y, ok := binaryExpr.Y.(*ast.BasicLit) + if !ok { + continue + } + + ifElseStmt(pass, x, y) + } + } } func lookupFlag(pass *analysis.Pass, name string) bool { @@ -275,7 +383,9 @@ func lookupFlag(pass *analysis.Pass, name string) bool { func checkHTTPMethod(pass *analysis.Pass, basicLit *ast.BasicLit) { currentVal := getBasicLitValue(basicLit) - if newVal, ok := mapping.HTTPMethod[strings.ToUpper(currentVal)]; ok { + key := strings.ToUpper(currentVal) + + if newVal, ok := mapping.HTTPMethod[key]; ok { report(pass, basicLit.Pos(), currentVal, newVal) } } @@ -288,39 +398,82 @@ func checkHTTPStatusCode(pass *analysis.Pass, basicLit *ast.BasicLit) { } } -func checkTimeWeekday(pass *analysis.Pass, pos token.Pos, currentVal string) { +func checkTimeWeekday(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + if newVal, ok := mapping.TimeWeekday[currentVal]; ok { - report(pass, pos, currentVal, newVal) + report(pass, basicLit.Pos(), currentVal, newVal) } } -func checkTimeMonth(pass *analysis.Pass, pos token.Pos, currentVal string) { +func checkTimeMonth(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + if newVal, ok := mapping.TimeMonth[currentVal]; ok { - report(pass, pos, currentVal, newVal) + report(pass, basicLit.Pos(), currentVal, newVal) } } -func checkTimeLayout(pass *analysis.Pass, pos token.Pos, currentVal string) { +func checkTimeLayout(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + if newVal, ok := mapping.TimeLayout[currentVal]; ok { - report(pass, pos, currentVal, newVal) + report(pass, basicLit.Pos(), currentVal, newVal) } } -func checkCryptoHash(pass *analysis.Pass, pos token.Pos, currentVal string) { +func checkCryptoHash(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + if newVal, ok := mapping.CryptoHash[currentVal]; ok { - report(pass, pos, currentVal, newVal) + report(pass, basicLit.Pos(), currentVal, newVal) } } -func checkDefaultRPCPath(pass *analysis.Pass, pos token.Pos, currentVal string) { - if newVal, ok := mapping.DefaultRPCPath[currentVal]; ok { - report(pass, pos, currentVal, newVal) +func checkRPCDefaultPath(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + + if newVal, ok := mapping.RPCDefaultPath[currentVal]; ok { + report(pass, basicLit.Pos(), currentVal, newVal) + } +} + +func checkOSDevNull(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + + if newVal, ok := mapping.OSDevNull[currentVal]; ok { + report(pass, basicLit.Pos(), currentVal, newVal) + } +} + +func checkSQLIsolationLevel(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + + if newVal, ok := mapping.SQLIsolationLevel[currentVal]; ok { + report(pass, basicLit.Pos(), currentVal, newVal) + } +} + +func checkTLSSignatureScheme(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + + if newVal, ok := mapping.TLSSignatureScheme[currentVal]; ok { + report(pass, basicLit.Pos(), currentVal, newVal) + } +} + +func checkConstantKind(pass *analysis.Pass, basicLit *ast.BasicLit) { + currentVal := getBasicLitValue(basicLit) + + if newVal, ok := mapping.ConstantKind[currentVal]; ok { + report(pass, basicLit.Pos(), currentVal, newVal) } } // getBasicLitFromArgs gets the *ast.BasicLit of a function argument. // // Arguments: +// - args - slice of function arguments // - count - expected number of argument in function // - idx - index of the argument to get the *ast.BasicLit // - typ - argument type @@ -329,6 +482,10 @@ func getBasicLitFromArgs(args []ast.Expr, count, idx int, typ token.Token) *ast. return nil } + if idx > count-1 { + return nil + } + basicLit, ok := args[idx].(*ast.BasicLit) if !ok { return nil @@ -344,32 +501,45 @@ func getBasicLitFromArgs(args []ast.Expr, count, idx int, typ token.Token) *ast. // getBasicLitFromElts gets the *ast.BasicLit of a struct elements. // // Arguments: -// - key: name of key in struct +// - elts - slice of a struct elements +// - key - name of key in struct func getBasicLitFromElts(elts []ast.Expr, key string) *ast.BasicLit { for _, e := range elts { - expr, ok := e.(*ast.KeyValueExpr) + keyValueExpr, ok := e.(*ast.KeyValueExpr) if !ok { continue } - ident, ok := expr.Key.(*ast.Ident) + + ident, ok := keyValueExpr.Key.(*ast.Ident) if !ok { continue } + if ident.Name != key { continue } - if basicLit, ok := expr.Value.(*ast.BasicLit); ok { + + if basicLit, ok := keyValueExpr.Value.(*ast.BasicLit); ok { return basicLit } } + return nil } -// getBasicLitValue returns BasicLit value as string without quotes +// getBasicLitValue returns BasicLit value as string without quotes. func getBasicLitValue(basicLit *ast.BasicLit) string { - return strings.Trim(basicLit.Value, "\"") + var val strings.Builder + for _, r := range basicLit.Value { + if r == '"' { + continue + } else { + val.WriteRune(r) + } + } + return val.String() } func report(pass *analysis.Pass, pos token.Pos, currentVal, newVal string) { - pass.Reportf(pos, `%q can be replaced by %s`, currentVal, newVal) + pass.Reportf(pos, "%q can be replaced by %s", currentVal, newVal) } diff --git a/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping/mapping.go b/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping/mapping.go index 56fae1bf..506166b5 100644 --- a/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping/mapping.go +++ b/tools/vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping/mapping.go @@ -2,8 +2,12 @@ package mapping import ( "crypto" + "crypto/tls" + "database/sql" + "go/constant" "net/http" "net/rpc" + "os" "strconv" "time" ) @@ -111,7 +115,7 @@ var HTTPStatusCode = map[string]string{ strconv.Itoa(http.StatusNetworkAuthenticationRequired): "http.StatusNetworkAuthenticationRequired", } -var DefaultRPCPath = map[string]string{ +var RPCDefaultPath = map[string]string{ rpc.DefaultRPCPath: "rpc.DefaultRPCPath", rpc.DefaultDebugPath: "rpc.DefaultDebugPath", } @@ -159,3 +163,42 @@ var TimeLayout = map[string]string{ time.StampMicro: "time.StampMicro", time.StampNano: "time.StampNano", } + +var OSDevNull = map[string]string{ + os.DevNull: "os.DevNull", +} + +var SQLIsolationLevel = map[string]string{ + // sql.LevelDefault.String(): "sql.LevelDefault.String()", + sql.LevelReadUncommitted.String(): "sql.LevelReadUncommitted.String()", + sql.LevelReadCommitted.String(): "sql.LevelReadCommitted.String()", + sql.LevelWriteCommitted.String(): "sql.LevelWriteCommitted.String()", + sql.LevelRepeatableRead.String(): "sql.LevelRepeatableRead.String()", + // sql.LevelSnapshot.String(): "sql.LevelSnapshot.String()", + // sql.LevelSerializable.String(): "sql.LevelSerializable.String()", + // sql.LevelLinearizable.String(): "sql.LevelLinearizable.String()", +} + +var TLSSignatureScheme = map[string]string{ + tls.PSSWithSHA256.String(): "tls.PSSWithSHA256.String()", + tls.ECDSAWithP256AndSHA256.String(): "tls.ECDSAWithP256AndSHA256.String()", + tls.Ed25519.String(): "tls.Ed25519.String()", + tls.PSSWithSHA384.String(): "tls.PSSWithSHA384.String()", + tls.PSSWithSHA512.String(): "tls.PSSWithSHA512.String()", + tls.PKCS1WithSHA256.String(): "tls.PKCS1WithSHA256.String()", + tls.PKCS1WithSHA384.String(): "tls.PKCS1WithSHA384.String()", + tls.PKCS1WithSHA512.String(): "tls.PKCS1WithSHA512.String()", + tls.ECDSAWithP384AndSHA384.String(): "tls.ECDSAWithP384AndSHA384.String()", + tls.ECDSAWithP521AndSHA512.String(): "tls.ECDSAWithP521AndSHA512.String()", + tls.PKCS1WithSHA1.String(): "tls.PKCS1WithSHA1.String()", + tls.ECDSAWithSHA1.String(): "tls.ECDSAWithSHA1.String()", +} + +var ConstantKind = map[string]string{ + // constant.Unknown.String(): "constant.Unknown.String()", + constant.Bool.String(): "constant.Bool.String()", + constant.String.String(): "constant.String.String()", + constant.Int.String(): "constant.Int.String()", + constant.Float.String(): "constant.Float.String()", + constant.Complex.String(): "constant.Complex.String()", +} diff --git a/tools/vendor/github.com/spf13/viper/Makefile b/tools/vendor/github.com/spf13/viper/Makefile index 02d3e371..130c427e 100644 --- a/tools/vendor/github.com/spf13/viper/Makefile +++ b/tools/vendor/github.com/spf13/viper/Makefile @@ -16,7 +16,7 @@ endif # Dependency versions GOTESTSUM_VERSION = 1.8.0 -GOLANGCI_VERSION = 1.45.2 +GOLANGCI_VERSION = 1.49.0 # Add the ability to override some variables # Use with care @@ -48,7 +48,7 @@ bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION} @ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint bin/golangci-lint-${GOLANGCI_VERSION}: @mkdir -p bin - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ./bin/ v${GOLANGCI_VERSION} + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b ./bin/ v${GOLANGCI_VERSION} @mv bin/golangci-lint "$@" .PHONY: lint diff --git a/tools/vendor/github.com/spf13/viper/README.md b/tools/vendor/github.com/spf13/viper/README.md index c14e8927..5701422c 100644 --- a/tools/vendor/github.com/spf13/viper/README.md +++ b/tools/vendor/github.com/spf13/viper/README.md @@ -119,7 +119,7 @@ viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search viper.AddConfigPath(".") // optionally look for config in the working directory err := viper.ReadInConfig() // Find and read the config file if err != nil { // Handle errors reading the config file - panic(fmt.Errorf("Fatal error config file: %w \n", err)) + panic(fmt.Errorf("fatal error config file: %w", err)) } ``` @@ -447,6 +447,13 @@ viper.SetConfigType("json") // because there is no file extension in a stream of err := viper.ReadRemoteConfig() ``` +#### etcd3 +```go +viper.AddRemoteProvider("etcd3", "http://127.0.0.1:4001","/config/hugo.json") +viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" +err := viper.ReadRemoteConfig() +``` + #### Consul You need to set a key to Consul key/value storage with JSON value containing your desired config. For example, create a Consul key/value store key `MY_CONSUL_KEY` with value: @@ -594,7 +601,7 @@ configuration level. Viper can access array indices by using numbers in the path. For example: -```json +```jsonc { "host": { "address": "localhost", @@ -622,7 +629,7 @@ GetInt("host.ports.1") // returns 6029 Lastly, if there exists a key that matches the delimited key path, its value will be returned instead. E.g. -```json +```jsonc { "datastore.metric.host": "0.0.0.0", "host": { diff --git a/tools/vendor/github.com/spf13/viper/logger.go b/tools/vendor/github.com/spf13/viper/logger.go index 0115067a..a64e1446 100644 --- a/tools/vendor/github.com/spf13/viper/logger.go +++ b/tools/vendor/github.com/spf13/viper/logger.go @@ -7,8 +7,8 @@ import ( ) // Logger is a unified interface for various logging use cases and practices, including: -// - leveled logging -// - structured logging +// - leveled logging +// - structured logging type Logger interface { // Trace logs a Trace event. // diff --git a/tools/vendor/github.com/spf13/viper/util.go b/tools/vendor/github.com/spf13/viper/util.go index ee7a86d9..64e65750 100644 --- a/tools/vendor/github.com/spf13/viper/util.go +++ b/tools/vendor/github.com/spf13/viper/util.go @@ -64,18 +64,25 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { return nm } +func insensitiviseVal(val interface{}) interface{} { + switch val.(type) { + case map[interface{}]interface{}: + // nested map: cast and recursively insensitivise + val = cast.ToStringMap(val) + insensitiviseMap(val.(map[string]interface{})) + case map[string]interface{}: + // nested map: recursively insensitivise + insensitiviseMap(val.(map[string]interface{})) + case []interface{}: + // nested array: recursively insensitivise + insensitiveArray(val.([]interface{})) + } + return val +} + func insensitiviseMap(m map[string]interface{}) { for key, val := range m { - switch val.(type) { - case map[interface{}]interface{}: - // nested map: cast and recursively insensitivise - val = cast.ToStringMap(val) - insensitiviseMap(val.(map[string]interface{})) - case map[string]interface{}: - // nested map: recursively insensitivise - insensitiviseMap(val.(map[string]interface{})) - } - + val = insensitiviseVal(val) lower := strings.ToLower(key) if key != lower { // remove old key (not lower-cased) @@ -86,6 +93,12 @@ func insensitiviseMap(m map[string]interface{}) { } } +func insensitiveArray(a []interface{}) { + for i, val := range a { + a[i] = insensitiviseVal(val) + } +} + func absPathify(logger Logger, inPath string) string { logger.Info("trying to resolve absolute path", "path", inPath) diff --git a/tools/vendor/github.com/spf13/viper/viper.go b/tools/vendor/github.com/spf13/viper/viper.go index a3812e92..5f76cc09 100644 --- a/tools/vendor/github.com/spf13/viper/viper.go +++ b/tools/vendor/github.com/spf13/viper/viper.go @@ -132,10 +132,10 @@ type DecoderConfigOption func(*mapstructure.DecoderConfig) // DecodeHook returns a DecoderConfigOption which overrides the default // DecoderConfig.DecodeHook value, the default is: // -// mapstructure.ComposeDecodeHookFunc( -// mapstructure.StringToTimeDurationHookFunc(), -// mapstructure.StringToSliceHookFunc(","), -// ) +// mapstructure.ComposeDecodeHookFunc( +// mapstructure.StringToTimeDurationHookFunc(), +// mapstructure.StringToSliceHookFunc(","), +// ) func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption { return func(c *mapstructure.DecoderConfig) { c.DecodeHook = hook @@ -156,18 +156,18 @@ func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption { // // For example, if values from the following sources were loaded: // -// Defaults : { -// "secret": "", -// "user": "default", -// "endpoint": "https://localhost" -// } -// Config : { -// "user": "root" -// "secret": "defaultsecret" -// } -// Env : { -// "secret": "somesecretkey" -// } +// Defaults : { +// "secret": "", +// "user": "default", +// "endpoint": "https://localhost" +// } +// Config : { +// "user": "root" +// "secret": "defaultsecret" +// } +// Env : { +// "secret": "somesecretkey" +// } // // The resulting config will have the following values: // @@ -300,7 +300,7 @@ func NewWithOptions(opts ...Option) *Viper { func Reset() { v = New() SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"} - SupportedRemoteProviders = []string{"etcd", "consul", "firestore"} + SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"} } // TODO: make this lazy initialization instead @@ -419,7 +419,7 @@ type RemoteProvider interface { var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"} // SupportedRemoteProviders are universally supported remote providers. -var SupportedRemoteProviders = []string{"etcd", "consul", "firestore"} +var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"} func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { @@ -573,7 +573,7 @@ func (v *Viper) AddConfigPath(in string) { // AddRemoteProvider adds a remote configuration source. // Remote Providers are searched in the order they are added. -// provider is a string value: "etcd", "consul" or "firestore" are currently supported. +// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported. // endpoint is the url. etcd requires http://ip:port consul requires ip:port // path is the path in the k/v store to retrieve configuration // To retrieve a config file called myapp.json from /configs/myapp.json @@ -604,7 +604,7 @@ func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { // AddSecureRemoteProvider adds a remote configuration source. // Secure Remote Providers are searched in the order they are added. -// provider is a string value: "etcd", "consul" or "firestore" are currently supported. +// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported. // endpoint is the url. etcd requires http://ip:port consul requires ip:port // secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg // path is the path in the k/v store to retrieve configuration @@ -785,7 +785,8 @@ func (v *Viper) searchMapWithPathPrefixes( // isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere // on its path in the map. // e.g., if "foo.bar" has a value in the given map, it “shadows” -// "foo.bar.baz" in a lower-priority map +// +// "foo.bar.baz" in a lower-priority map func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { var parentVal interface{} for i := 1; i < len(path); i++ { @@ -810,7 +811,8 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) // isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere // in a sub-path of the map. // e.g., if "foo.bar" has a value in the given map, it “shadows” -// "foo.bar.baz" in a lower-priority map +// +// "foo.bar.baz" in a lower-priority map func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { // unify input map var m map[string]interface{} @@ -835,7 +837,8 @@ func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { // isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere // in the environment, when automatic env is on. // e.g., if "foo.bar" has a value in the environment, it “shadows” -// "foo.bar.baz" in a lower-priority map +// +// "foo.bar.baz" in a lower-priority map func (v *Viper) isPathShadowedInAutoEnv(path []string) string { var parentKey string for i := 1; i < len(path); i++ { @@ -856,11 +859,11 @@ func (v *Viper) isPathShadowedInAutoEnv(path []string) string { // would return a string slice for the key if the key's type is inferred by // the default value and the Get function would return: // -// []string {"a", "b", "c"} +// []string {"a", "b", "c"} // // Otherwise the Get function would return: // -// "a b c" +// "a b c" func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } func (v *Viper) SetTypeByDefaultValue(enable bool) { @@ -988,6 +991,13 @@ func (v *Viper) GetUint(key string) uint { return cast.ToUint(v.Get(key)) } +// GetUint16 returns the value associated with the key as an unsigned integer. +func GetUint16(key string) uint16 { return v.GetUint16(key) } + +func (v *Viper) GetUint16(key string) uint16 { + return cast.ToUint16(v.Get(key)) +} + // GetUint32 returns the value associated with the key as an unsigned integer. func GetUint32(key string) uint32 { return v.GetUint32(key) } @@ -1137,9 +1147,8 @@ func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { // BindPFlag binds a specific key to a pflag (as used by cobra). // Example (where serverCmd is a Cobra instance): // -// serverCmd.Flags().Int("port", 1138, "Port to run Application server on") -// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) -// +// serverCmd.Flags().Int("port", 1138, "Port to run Application server on") +// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { @@ -1870,6 +1879,10 @@ func (v *Viper) getKeyValueConfig() error { return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") } + if len(v.remoteProviders) == 0 { + return RemoteConfigError("No Remote Providers") + } + for _, rp := range v.remoteProviders { val, err := v.getRemoteConfig(rp) if err != nil { @@ -1896,6 +1909,10 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{} // Retrieve the first found remote configuration. func (v *Viper) watchKeyValueConfigOnChannel() error { + if len(v.remoteProviders) == 0 { + return RemoteConfigError("No Remote Providers") + } + for _, rp := range v.remoteProviders { respc, _ := RemoteConfig.WatchChannel(rp) // Todo: Add quit channel @@ -1913,9 +1930,15 @@ func (v *Viper) watchKeyValueConfigOnChannel() error { // Retrieve the first found remote configuration. func (v *Viper) watchKeyValueConfig() error { + if len(v.remoteProviders) == 0 { + return RemoteConfigError("No Remote Providers") + } + for _, rp := range v.remoteProviders { val, err := v.watchRemoteConfig(rp) if err != nil { + v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error()) + continue } v.kvstore = val @@ -1958,9 +1981,10 @@ func (v *Viper) AllKeys() []string { // flattenAndMergeMap recursively flattens the given map into a map[string]bool // of key paths (used as a set, easier to manipulate than a []string): -// - each path is merged into a single key string, delimited with v.keyDelim -// - if a path is shadowed by an earlier value in the initial shadow map, -// it is skipped. +// - each path is merged into a single key string, delimited with v.keyDelim +// - if a path is shadowed by an earlier value in the initial shadow map, +// it is skipped. +// // The resulting set of paths is merged to the given shadow set at the same time. func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { if shadow != nil && prefix != "" && shadow[prefix] { @@ -2111,14 +2135,17 @@ func (v *Viper) getConfigFile() (string, error) { // Debug prints all configuration registries for debugging // purposes. -func Debug() { v.Debug() } - -func (v *Viper) Debug() { - fmt.Printf("Aliases:\n%#v\n", v.aliases) - fmt.Printf("Override:\n%#v\n", v.override) - fmt.Printf("PFlags:\n%#v\n", v.pflags) - fmt.Printf("Env:\n%#v\n", v.env) - fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore) - fmt.Printf("Config:\n%#v\n", v.config) - fmt.Printf("Defaults:\n%#v\n", v.defaults) +func Debug() { v.Debug() } +func DebugTo(w io.Writer) { v.DebugTo(w) } + +func (v *Viper) Debug() { v.DebugTo(os.Stdout) } + +func (v *Viper) DebugTo(w io.Writer) { + fmt.Fprintf(w, "Aliases:\n%#v\n", v.aliases) + fmt.Fprintf(w, "Override:\n%#v\n", v.override) + fmt.Fprintf(w, "PFlags:\n%#v\n", v.pflags) + fmt.Fprintf(w, "Env:\n%#v\n", v.env) + fmt.Fprintf(w, "Key/Value Store:\n%#v\n", v.kvstore) + fmt.Fprintf(w, "Config:\n%#v\n", v.config) + fmt.Fprintf(w, "Defaults:\n%#v\n", v.defaults) } diff --git a/tools/vendor/github.com/subosito/gotenv/gotenv.go b/tools/vendor/github.com/subosito/gotenv/gotenv.go index b7a83be2..7b1186e1 100644 --- a/tools/vendor/github.com/subosito/gotenv/gotenv.go +++ b/tools/vendor/github.com/subosito/gotenv/gotenv.go @@ -124,6 +124,7 @@ func Read(filename string) (Env, error) { if err != nil { return nil, err } + defer f.Close() return strictParse(f, false) } diff --git a/tools/vendor/github.com/timonwong/loggercheck/.codecov.yml b/tools/vendor/github.com/timonwong/loggercheck/.codecov.yml new file mode 100644 index 00000000..ef90457c --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/.codecov.yml @@ -0,0 +1,16 @@ +coverage: + range: 70..90 # green if 90+, red if 70- + status: + patch: + # coverage status for pull request diff + default: + threshold: 1% # allow a little drop + project: + # coverage status for whole project + default: + target: auto # use coverage of base commit as target + threshold: 1% # allow a little drop + +ignore: + - "plugin/**" + - "cmd/**" diff --git a/tools/vendor/github.com/timonwong/logrlint/.gitignore b/tools/vendor/github.com/timonwong/loggercheck/.gitignore similarity index 62% rename from tools/vendor/github.com/timonwong/logrlint/.gitignore rename to tools/vendor/github.com/timonwong/loggercheck/.gitignore index 955e8064..33df0df9 100644 --- a/tools/vendor/github.com/timonwong/logrlint/.gitignore +++ b/tools/vendor/github.com/timonwong/loggercheck/.gitignore @@ -3,3 +3,7 @@ bin/ vendor/ + +dist/ + +cover.out diff --git a/tools/vendor/github.com/timonwong/loggercheck/.golangci.yml b/tools/vendor/github.com/timonwong/loggercheck/.golangci.yml new file mode 100644 index 00000000..28732789 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/.golangci.yml @@ -0,0 +1,94 @@ +linters-settings: + dupl: + threshold: 100 + funlen: + lines: 100 + statements: 50 + goconst: + min-len: 2 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - whyNoLint + gocyclo: + min-complexity: 15 + goimports: + local-prefixes: github.com/timonwong/loggercheck + gomnd: + # don't include the "operation" and "assign" + checks: + - argument + - case + - condition + - return + ignored-numbers: + - '0' + - '1' + - '2' + - '3' + ignored-functions: + - strings.SplitN + - strconv.ParseInt + govet: + check-shadowing: true + lll: + line-length: 140 + misspell: + locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped +linters: + disable-all: true + enable: + - bodyclose + - dogsled + - dupl + - errcheck + - exportloopref + - funlen + - gochecknoinits + - goconst + - gocritic + - gocyclo + - gofumpt + - goimports + - gomnd + - goprintffuncname + - gosec + - gosimple + - govet + - ineffassign + - lll + - misspell + - nakedret + - noctx + - nolintlint + - revive + - staticcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - whitespace + +issues: + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - path: _test\.go + linters: + - gomnd + +run: + timeout: 5m + go: '1.17' + skip-dirs: + - testdata \ No newline at end of file diff --git a/tools/vendor/github.com/timonwong/loggercheck/.goreleaser.yml b/tools/vendor/github.com/timonwong/loggercheck/.goreleaser.yml new file mode 100644 index 00000000..55ffe7ea --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/.goreleaser.yml @@ -0,0 +1,59 @@ +--- +project_name: loggercheck + +release: + github: + owner: timonwong + name: loggercheck + +builds: + - binary: loggercheck + goos: + - darwin + - windows + - linux + goarch: + - '386' + - amd64 + - arm + - arm64 + goarm: + - '7' + env: + - CGO_ENABLED=0 + ignore: + - goos: darwin + goarch: '386' + main: ./cmd/loggercheck/ + flags: + - -trimpath + ldflags: -s -w + +archives: + - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + format_overrides: + - goos: windows + format: zip + files: + - LICENSE + - README.md + +snapshot: + name_template: '{{ incpatch .Version }}-next' + +checksum: + name_template: 'checksums.txt' + +changelog: + sort: asc + filters: + exclude: + - '(?i)^docs?:' + - '(?i)^docs\([^:]+\):' + - '(?i)^docs\[[^:]+\]:' + - '^tests?:' + - '(?i)^dev:' + - '^build\(deps\): bump .* in /docs \(#\d+\)' + - '^build\(deps\): bump .* in /\.github/peril \(#\d+\)' + - Merge pull request + - Merge branch diff --git a/tools/vendor/github.com/timonwong/logrlint/LICENSE b/tools/vendor/github.com/timonwong/loggercheck/LICENSE similarity index 100% rename from tools/vendor/github.com/timonwong/logrlint/LICENSE rename to tools/vendor/github.com/timonwong/loggercheck/LICENSE diff --git a/tools/vendor/github.com/timonwong/loggercheck/Makefile b/tools/vendor/github.com/timonwong/loggercheck/Makefile new file mode 100644 index 00000000..37bf8720 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/Makefile @@ -0,0 +1,22 @@ +.PHONY: lint +lint: + golangci-lint run ./... + +.PHONY: test-deps +test-deps: + cd testdata/src/a && go mod vendor + +.PHONY: test +test: test-deps + go test -v -covermode=atomic -coverprofile=cover.out -coverpkg ./... ./... + +.PHONY: build +build: + go build -o bin/loggercheck ./cmd/loggercheck + +.PHONY: build-plugin +build-plugin: + CGO_ENABLED=1 go build -o bin/loggercheck.so -buildmode=plugin ./plugin + +.PHONY: build-all +build-all: build build-plugin diff --git a/tools/vendor/github.com/timonwong/loggercheck/README.md b/tools/vendor/github.com/timonwong/loggercheck/README.md new file mode 100644 index 00000000..36fe887d --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/README.md @@ -0,0 +1,103 @@ +# loggercheck + +## Description + +A linter checks the odd number of key and value pairs for common logger libraries: +- [kitlog](https://github.com/go-kit/log) +- [klog](https://github.com/kubernetes/klog) +- [logr](https://github.com/go-logr/logr) +- [zap](https://github.com/uber-go/zap) + +## Badges + +![Build Status](https://github.com/timonwong/loggercheck/workflows/CI/badge.svg) +[![Coverage](https://img.shields.io/codecov/c/github/timonwong/loggercheck?token=Nutf41gwoG)](https://app.codecov.io/gh/timonwong/loggercheck) +[![License](https://img.shields.io/github/license/timonwong/loggercheck.svg)](/LICENSE) +[![Release](https://img.shields.io/github/release/timonwong/loggercheck.svg)](https://github.com/timonwong/loggercheck/releases/latest) + +## Install + +```shel +go install github.com/timonwong/loggercheck/cmd/loggercheck +``` + +## Usage + +``` +loggercheck: Checks key valur pairs for common logger libraries (kitlog,logr,klog,zap). + +Usage: loggercheck [-flag] [package] + + +Flags: + -V print version and exit + -all + no effect (deprecated) + -c int + display offending line with this many lines of context (default -1) + -cpuprofile string + write CPU profile to this file + -debug string + debug flags, any subset of "fpstv" + -disable value + comma-separated list of disabled logger checker (kitlog,klog,logr,zap) (default kitlog) + -fix + apply all suggested fixes + -flags + print analyzer flags in JSON + -json + emit JSON output + -memprofile string + write memory profile to this file + -noprintflike + require printf-like format specifier not present in args + -requirestringkey + require all logging keys to be inlined constant strings + -rulefile string + path to a file contains a list of rules + -source + no effect (deprecated) + -tags string + no effect (deprecated) + -test + indicates whether test files should be analyzed, too (default true) + -trace string + write trace log to this file + -v no effect (deprecated) +``` + +## Example + +```go +package a + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" +) + +func Example() { + log := logr.Discard() + log = log.WithValues("key") + log.Info("message", "key1", "value1", "key2", "value2", "key3") + log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2") + log.Error(fmt.Errorf("error"), "message", "key1", "value1", "key2", "value2") + + var log2 logr.Logger + log2 = log + log2.Info("message", "key1") + + log3 := logr.FromContextOrDiscard(context.TODO()) + log3.Error(fmt.Errorf("error"), "message", "key1") +} +``` + +``` +a.go:12:23: odd number of arguments passed as key-value pairs for logging +a.go:13:22: odd number of arguments passed as key-value pairs for logging +a.go:14:44: odd number of arguments passed as key-value pairs for logging +a.go:19:23: odd number of arguments passed as key-value pairs for logging +a.go:22:45: odd number of arguments passed as key-value pairs for logging +``` \ No newline at end of file diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/bytebufferpool/pool.go b/tools/vendor/github.com/timonwong/loggercheck/internal/bytebufferpool/pool.go new file mode 100644 index 00000000..9d88d21c --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/bytebufferpool/pool.go @@ -0,0 +1,22 @@ +package bytebufferpool + +import ( + "bytes" + "sync" +) + +var pool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + +func Get() *bytes.Buffer { + buf := pool.Get().(*bytes.Buffer) + buf.Reset() + return buf +} + +func Put(buf *bytes.Buffer) { + pool.Put(buf) +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/checker.go b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/checker.go new file mode 100644 index 00000000..5615636e --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/checker.go @@ -0,0 +1,59 @@ +package checkers + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" +) + +type Config struct { + RequireStringKey bool + NoPrintfLike bool +} + +type CallContext struct { + Expr *ast.CallExpr + Func *types.Func + Signature *types.Signature +} + +type Checker interface { + FilterKeyAndValues(pass *analysis.Pass, keyAndValues []ast.Expr) []ast.Expr + CheckLoggingKey(pass *analysis.Pass, keyAndValues []ast.Expr) + CheckPrintfLikeSpecifier(pass *analysis.Pass, args []ast.Expr) +} + +func ExecuteChecker(c Checker, pass *analysis.Pass, call CallContext, cfg Config) { + params := call.Signature.Params() + nparams := params.Len() // variadic => nonzero + startIndex := nparams - 1 + + lastArg := params.At(nparams - 1) + iface, ok := lastArg.Type().(*types.Slice).Elem().(*types.Interface) + if !ok || !iface.Empty() { + return // final (args) param is not ...interface{} + } + + keyValuesArgs := c.FilterKeyAndValues(pass, call.Expr.Args[startIndex:]) + + if len(keyValuesArgs)%2 != 0 { + firstArg := keyValuesArgs[0] + lastArg := keyValuesArgs[len(keyValuesArgs)-1] + pass.Report(analysis.Diagnostic{ + Pos: firstArg.Pos(), + End: lastArg.End(), + Category: DiagnosticCategory, + Message: "odd number of arguments passed as key-value pairs for logging", + }) + } + + if cfg.RequireStringKey { + c.CheckLoggingKey(pass, keyValuesArgs) + } + + if cfg.NoPrintfLike { + // Check all args + c.CheckPrintfLikeSpecifier(pass, call.Expr.Args) + } +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/common.go b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/common.go new file mode 100644 index 00000000..259be96c --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/common.go @@ -0,0 +1,60 @@ +package checkers + +import ( + "go/ast" + "go/constant" + "go/printer" + "go/token" + "go/types" + "strconv" + "unicode/utf8" + + "golang.org/x/tools/go/analysis" + + "github.com/timonwong/loggercheck/internal/bytebufferpool" +) + +const ( + DiagnosticCategory = "logging" +) + +// extractValueFromStringArg returns true if the argument is string literal or string constant. +func extractValueFromStringArg(pass *analysis.Pass, arg ast.Expr) (value string, ok bool) { + switch arg := arg.(type) { + case *ast.BasicLit: // literals, string literals specifically + if arg.Kind == token.STRING { + if val, err := strconv.Unquote(arg.Value); err == nil { + return val, true + } + } + case *ast.Ident: // identifiers, string constants specifically + if arg.Obj != nil && arg.Obj.Kind == ast.Con { + typeAndValue := pass.TypesInfo.Types[arg] + if typ, ok := typeAndValue.Type.(*types.Basic); ok && typ.Kind() == types.String { + return constant.StringVal(typeAndValue.Value), true + } + } + } + + return "", false +} + +func renderNodeEllipsis(fset *token.FileSet, v interface{}) string { + const maxLen = 20 + + buf := bytebufferpool.Get() + defer bytebufferpool.Put(buf) + + _ = printer.Fprint(buf, fset, v) + s := buf.String() + if utf8.RuneCountInString(s) > maxLen { + // Copied from go/constant/value.go + i := 0 + for n := 0; n < maxLen-3; n++ { + _, size := utf8.DecodeRuneInString(s[i:]) + i += size + } + s = s[:i] + "..." + } + return s +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/general.go b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/general.go new file mode 100644 index 00000000..6512cce3 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/general.go @@ -0,0 +1,68 @@ +package checkers + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/go/analysis" + + "github.com/timonwong/loggercheck/internal/checkers/printf" + "github.com/timonwong/loggercheck/internal/stringutil" +) + +type General struct{} + +func (g General) FilterKeyAndValues(_ *analysis.Pass, keyAndValues []ast.Expr) []ast.Expr { + return keyAndValues +} + +func (g General) CheckLoggingKey(pass *analysis.Pass, keyAndValues []ast.Expr) { + for i := 0; i < len(keyAndValues); i += 2 { + arg := keyAndValues[i] + if value, ok := extractValueFromStringArg(pass, arg); ok { + if stringutil.IsASCII(value) { + continue + } + + pass.Report(analysis.Diagnostic{ + Pos: arg.Pos(), + End: arg.End(), + Category: DiagnosticCategory, + Message: fmt.Sprintf( + "logging keys are expected to be alphanumeric strings, please remove any non-latin characters from %q", + value), + }) + } else { + pass.Report(analysis.Diagnostic{ + Pos: arg.Pos(), + End: arg.End(), + Category: DiagnosticCategory, + Message: fmt.Sprintf( + "logging keys are expected to be inlined constant strings, please replace %q provided with string", + renderNodeEllipsis(pass.Fset, arg)), + }) + } + } +} + +func (g General) CheckPrintfLikeSpecifier(pass *analysis.Pass, args []ast.Expr) { + for _, arg := range args { + format, ok := extractValueFromStringArg(pass, arg) + if !ok { + continue + } + + if specifier, ok := printf.IsPrintfLike(format); ok { + pass.Report(analysis.Diagnostic{ + Pos: arg.Pos(), + End: arg.End(), + Category: DiagnosticCategory, + Message: fmt.Sprintf("logging message should not use format specifier %q", specifier), + }) + + return // One error diagnostic is enough + } + } +} + +var _ Checker = (*General)(nil) diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/printf/printf.go b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/printf/printf.go new file mode 100644 index 00000000..b38f46f2 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/printf/printf.go @@ -0,0 +1,252 @@ +package printf + +import ( + "strconv" + "strings" + "unicode/utf8" +) + +// Copied from golang.org/x/tools +// Copyright 2010 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. + +type printVerb struct { + verb rune // User may provide verb through Formatter; could be a rune. + flags string // known flags are all ASCII +} + +// Common flag sets for printf verbs. +const ( + noFlag = "" + numFlag = " -+.0" + sharpNumFlag = " -+.0#" + allFlags = " -+.0#" +) + +// printVerbs identifies which flags are known to printf for each verb. +var printVerbs = []printVerb{ + // '-' is a width modifier, always valid. + // '.' is a precision for float, max width for strings. + // '+' is required sign for numbers, Go format for %v. + // '#' is alternate format for several verbs. + // ' ' is spacer for numbers + {'%', noFlag}, + {'b', sharpNumFlag}, + {'c', "-"}, + {'d', numFlag}, + {'e', sharpNumFlag}, + {'E', sharpNumFlag}, + {'f', sharpNumFlag}, + {'F', sharpNumFlag}, + {'g', sharpNumFlag}, + {'G', sharpNumFlag}, + {'o', sharpNumFlag}, + {'O', sharpNumFlag}, + {'p', "-#"}, + {'q', " -+.0#"}, + {'s', " -+.0"}, + {'t', "-"}, + {'T', "-"}, + {'U', "-#"}, + {'v', allFlags}, + {'w', allFlags}, + {'x', sharpNumFlag}, + {'X', sharpNumFlag}, +} + +// formatState holds the parsed representation of a printf directive such as "%3.*[4]d". +// It is constructed by parsePrintfVerb. +type formatState struct { + verb rune // the format verb: 'd' for "%d" + format string // the full format directive from % through verb, "%.3d". + flags []byte // the list of # + etc. + // Used only during parse. + hasIndex bool // Whether the argument is indexed. + indexPending bool // Whether we have an indexed argument that has not resolved. + nbytes int // number of bytes of the format string consumed. +} + +// parseFlags accepts any printf flags. +func (s *formatState) parseFlags() { + for s.nbytes < len(s.format) { + switch c := s.format[s.nbytes]; c { + case '#', '0', '+', '-', ' ': + s.flags = append(s.flags, c) + s.nbytes++ + default: + return + } + } +} + +// scanNum advances through a decimal number if present. +func (s *formatState) scanNum() { + for ; s.nbytes < len(s.format); s.nbytes++ { + c := s.format[s.nbytes] + if c < '0' || '9' < c { + return + } + } +} + +func stringIndexAt(s, substr string, start int) int { + idx := strings.Index(s[start:], substr) + if idx < 0 { + return idx + } + return idx + start +} + +// parseIndex scans an index expression. It returns false if there is a syntax error. +func (s *formatState) parseIndex() bool { + if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { + return true + } + // Argument index present. + s.nbytes++ // skip '[' + start := s.nbytes + s.scanNum() + ok := true + if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { + ok = false + s.nbytes = stringIndexAt(s.format, "]", start) + if s.nbytes < 0 { + return false + } + } + arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) + if err != nil || !ok || arg32 <= 0 { + return false + } + s.nbytes++ // skip ']' + s.hasIndex = true + s.indexPending = true + return true +} + +// parseNum scans a width or precision (or *). +func (s *formatState) parseNum() { + if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { + if s.indexPending { // Absorb it. + s.indexPending = false + } + s.nbytes++ + } else { + s.scanNum() + } +} + +// parsePrecision scans for a precision. It returns false if there's a bad index expression. +func (s *formatState) parsePrecision() bool { + // If there's a period, there may be a precision. + if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { + s.flags = append(s.flags, '.') // Treat precision as a flag. + s.nbytes++ + if !s.parseIndex() { + return false + } + s.parseNum() + } + return true +} + +// parsePrintfVerb looks the formatting directive that begins the format string +// and returns a formatState that encodes what the directive wants, without looking +// at the actual arguments present in the call. The result is nil if there is an error. +func parsePrintfVerb(format string) *formatState { + state := &formatState{ + format: format, + flags: make([]byte, 0, 5), //nolint:gomnd + nbytes: 1, // There's guaranteed to be a percent sign. + } + + // There may be flags. + state.parseFlags() + // There may be an index. + if !state.parseIndex() { + return nil + } + // There may be a width. + state.parseNum() + // There may be a precision. + if !state.parsePrecision() { + return nil + } + // Now a verb, possibly prefixed by an index (which we may already have). + if !state.indexPending && !state.parseIndex() { + return nil + } + if state.nbytes == len(state.format) { + // missing verb at end of string + return nil + } + verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) + state.verb = verb + state.nbytes += w + state.format = state.format[:state.nbytes] + return state +} + +func containsAll(s string, pattern []byte) bool { + for _, c := range pattern { + if !strings.ContainsRune(s, rune(c)) { + return false + } + } + return true +} + +func isPrintfArg(state *formatState) bool { + var v printVerb + found := false + // Linear scan is fast enough for a small list. + for _, v = range printVerbs { + if v.verb == state.verb { + found = true + break + } + } + + if !found { + // unknown verb, just skip + return false + } + + if !containsAll(v.flags, state.flags) { + // unrecognized format flag, just skip + return false + } + + return true +} + +func IsPrintfLike(format string) (firstSpecifier string, ok bool) { + if !strings.Contains(format, "%") { + return "", false + } + + for i, w := 0, 0; i < len(format); i += w { + w = 1 + if format[i] != '%' { + continue + } + + state := parsePrintfVerb(format[i:]) + if state == nil { + return "", false + } + + w = len(state.format) + if !isPrintfArg(state) { + return "", false + } + + if !ok { + firstSpecifier = state.format + ok = true + } + } + + return +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/zap.go b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/zap.go new file mode 100644 index 00000000..2356f834 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/checkers/zap.go @@ -0,0 +1,42 @@ +package checkers + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" +) + +type Zap struct { + General +} + +func (z Zap) FilterKeyAndValues(pass *analysis.Pass, keyAndValues []ast.Expr) []ast.Expr { + // Check the argument count + filtered := make([]ast.Expr, 0, len(keyAndValues)) + for _, arg := range keyAndValues { + // Skip any zapcore.Field we found + switch arg := arg.(type) { + case *ast.CallExpr, *ast.Ident: + typ := pass.TypesInfo.TypeOf(arg) + switch typ := typ.(type) { + case *types.Named: + obj := typ.Obj() + // This is a strongly-typed field. Consume it and move on. + // Actually it's go.uber.org/zap/zapcore.Field, however for simplicity + // we don't check the import path + if obj != nil && obj.Name() == "Field" { + continue + } + default: + // pass + } + } + + filtered = append(filtered, arg) + } + + return filtered +} + +var _ Checker = (*Zap)(nil) diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/rules/rules.go b/tools/vendor/github.com/timonwong/loggercheck/internal/rules/rules.go new file mode 100644 index 00000000..27d6ebb2 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/rules/rules.go @@ -0,0 +1,201 @@ +package rules + +import ( + "bufio" + "errors" + "fmt" + "go/types" + "io" + "strings" + + "github.com/timonwong/loggercheck/internal/bytebufferpool" +) + +var ErrInvalidRule = errors.New("invalid rule format") + +const CustomRulesetName = "custom" + +type Ruleset struct { + Name string + PackageImport string + Rules []FuncRule + + ruleIndicesByFuncName map[string][]int +} + +func (rs *Ruleset) Match(fn *types.Func) bool { + // PackageImport is already checked (by indices), skip checking it here + sig := fn.Type().(*types.Signature) // it's safe since we already checked + + // Fail fast if the function name is not in the rule list. + indices, ok := rs.ruleIndicesByFuncName[fn.Name()] + if !ok { + return false + } + + for _, idx := range indices { + rule := &rs.Rules[idx] + if matchRule(rule, sig) { + return true + } + } + + return false +} + +func receiverTypeOf(recvType types.Type) string { + buf := bytebufferpool.Get() + defer bytebufferpool.Put(buf) + + var recvNamed *types.Named + switch recvType := recvType.(type) { + case *types.Pointer: + buf.WriteByte('*') + if elem, ok := recvType.Elem().(*types.Named); ok { + recvNamed = elem + } + case *types.Named: + recvNamed = recvType + } + + if recvNamed == nil { + // not supported type + return "" + } + + buf.WriteString(recvNamed.Obj().Name()) + typeParams := recvNamed.TypeParams() + if typeParamsLen := typeParams.Len(); typeParamsLen > 0 { + buf.WriteByte('[') + for i := 0; i < typeParamsLen; i++ { + if i > 0 { + // comma as separator + buf.WriteByte(',') + } + p := typeParams.At(i) + buf.WriteString(p.Obj().Name()) + } + buf.WriteByte(']') + } + + return buf.String() +} + +func matchRule(p *FuncRule, sig *types.Signature) bool { + // we do not check package import here since it's already checked in Match() + recv := sig.Recv() + isReceiver := recv != nil + if isReceiver != p.IsReceiver { + return false + } + + if isReceiver { + recvType := recv.Type() + receiverType := receiverTypeOf(recvType) + if receiverType != p.ReceiverType { + return false + } + } + + return true +} + +type FuncRule struct { // package import should be accessed from Rulset + ReceiverType string + FuncName string + IsReceiver bool +} + +func ParseFuncRule(rule string) (packageImport string, pat FuncRule, err error) { + lastDot := strings.LastIndexFunc(rule, func(r rune) bool { + return r == '.' || r == '/' + }) + if lastDot == -1 || rule[lastDot] == '/' { + return "", pat, ErrInvalidRule + } + + importOrReceiver := rule[:lastDot] + pat.FuncName = rule[lastDot+1:] + + if strings.HasPrefix(rule, "(") { // package + if !strings.HasSuffix(importOrReceiver, ")") { + return "", FuncRule{}, ErrInvalidRule + } + + var isPointerReceiver bool + pat.IsReceiver = true + receiver := importOrReceiver[1 : len(importOrReceiver)-1] + if strings.HasPrefix(receiver, "*") { + isPointerReceiver = true + receiver = receiver[1:] + } + + typeDotIdx := strings.LastIndexFunc(receiver, func(r rune) bool { + return r == '.' || r == '/' + }) + if typeDotIdx == -1 || receiver[typeDotIdx] == '/' { + return "", FuncRule{}, ErrInvalidRule + } + receiverType := receiver[typeDotIdx+1:] + if isPointerReceiver { + receiverType = "*" + receiverType + } + pat.ReceiverType = receiverType + packageImport = receiver[:typeDotIdx] + } else { + packageImport = importOrReceiver + } + + return packageImport, pat, nil +} + +func ParseRules(lines []string) (result []Ruleset, err error) { + rulesByImport := make(map[string][]FuncRule) + for i, line := range lines { + if line == "" { + continue + } + + if strings.HasPrefix(line, "#") { // comments + continue + } + + packageImport, pat, err := ParseFuncRule(line) + if err != nil { + return nil, fmt.Errorf("error parse rule at line %d: %w", i+1, err) + } + rulesByImport[packageImport] = append(rulesByImport[packageImport], pat) + } + + for packageImport, rules := range rulesByImport { + ruleIndicesByFuncName := make(map[string][]int, len(rules)) + for idx, rule := range rules { + fnName := rule.FuncName + ruleIndicesByFuncName[fnName] = append(ruleIndicesByFuncName[fnName], idx) + } + + result = append(result, Ruleset{ + Name: CustomRulesetName, // NOTE(timonwong) Always "custom" for custom rule + PackageImport: packageImport, + Rules: rules, + ruleIndicesByFuncName: ruleIndicesByFuncName, + }) + } + return result, nil +} + +func ParseRuleFile(r io.Reader) (result []Ruleset, err error) { + // Rule files are relatively small, so read it into string slice first. + var lines []string + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + lines = append(lines, line) + } + if err := scanner.Err(); err != nil { + return nil, err + } + + return ParseRules(lines) +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/sets/string.go b/tools/vendor/github.com/timonwong/loggercheck/internal/sets/string.go new file mode 100644 index 00000000..daf8d57f --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/sets/string.go @@ -0,0 +1,59 @@ +package sets + +import ( + "sort" + "strings" +) + +type Empty struct{} + +type StringSet map[string]Empty + +func NewString(items ...string) StringSet { + s := make(StringSet) + s.Insert(items...) + return s +} + +func (s StringSet) Insert(items ...string) { + for _, item := range items { + s[item] = Empty{} + } +} + +func (s StringSet) Has(item string) bool { + _, contained := s[item] + return contained +} + +func (s StringSet) List() []string { + if len(s) == 0 { + return nil + } + + res := make([]string, 0, len(s)) + for key := range s { + res = append(res, key) + } + sort.Strings(res) + return res +} + +// Set implements flag.Value interface. +func (s *StringSet) Set(v string) error { + v = strings.TrimSpace(v) + if v == "" { + *s = nil + return nil + } + + parts := strings.Split(v, ",") + set := NewString(parts...) + *s = set + return nil +} + +// String implements flag.Value interface +func (s StringSet) String() string { + return strings.Join(s.List(), ",") +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/internal/stringutil/is.go b/tools/vendor/github.com/timonwong/loggercheck/internal/stringutil/is.go new file mode 100644 index 00000000..a36b742f --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/internal/stringutil/is.go @@ -0,0 +1,15 @@ +package stringutil + +import "unicode/utf8" + +// IsASCII returns true if string are ASCII. +func IsASCII(s string) bool { + for _, r := range s { + if r >= utf8.RuneSelf { + // Not ASCII. + return false + } + } + + return true +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/loggercheck.go b/tools/vendor/github.com/timonwong/loggercheck/loggercheck.go new file mode 100644 index 00000000..704f9678 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/loggercheck.go @@ -0,0 +1,196 @@ +package loggercheck + +import ( + "flag" + "fmt" + "go/ast" + "go/types" + "os" + "strings" + + "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" + + "github.com/timonwong/loggercheck/internal/checkers" + "github.com/timonwong/loggercheck/internal/rules" + "github.com/timonwong/loggercheck/internal/sets" +) + +const Doc = `Checks key valur pairs for common logger libraries (kitlog,klog,logr,zap).` + +func NewAnalyzer(opts ...Option) *analysis.Analyzer { + l := newLoggerCheck(opts...) + a := &analysis.Analyzer{ + Name: "loggercheck", + Doc: Doc, + Flags: *l.fs, + Run: l.run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } + return a +} + +type loggercheck struct { + fs *flag.FlagSet + + disable sets.StringSet // flag -disable + ruleFile string // flag -rulefile + requireStringKey bool // flag -requirestringkey + noPrintfLike bool // flag -noprintflike + + rules []string // used for external integration, for example golangci-lint + rulesetList []rules.Ruleset // populate at runtime + rulesetIndicesByImport map[string][]int // ruleset index, populate at runtime +} + +func newLoggerCheck(opts ...Option) *loggercheck { + fs := flag.NewFlagSet("loggercheck", flag.ExitOnError) + l := &loggercheck{ + fs: fs, + disable: sets.NewString("kitlog"), + rulesetList: append([]rules.Ruleset{}, staticRuleList...), // ensure we make a clone of static rules first + } + + fs.StringVar(&l.ruleFile, "rulefile", "", "path to a file contains a list of rules") + fs.Var(&l.disable, "disable", "comma-separated list of disabled logger checker (kitlog,klog,logr,zap)") + fs.BoolVar(&l.requireStringKey, "requirestringkey", false, "require all logging keys to be inlined constant strings") + fs.BoolVar(&l.noPrintfLike, "noprintflike", false, "require printf-like format specifier not present in args") + + for _, opt := range opts { + opt(l) + } + + return l +} + +func (l *loggercheck) isCheckerDisabled(name string) bool { + return l.disable.Has(name) +} + +// vendorLessPath returns the devendorized version of the import path ipath. +// For example: "a/vendor/github.com/go-logr/logr" will become "github.com/go-logr/logr". +func vendorLessPath(ipath string) string { + if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { + return ipath[i+len("/vendor/"):] + } + return ipath +} + +func (l *loggercheck) getCheckerForFunc(fn *types.Func) checkers.Checker { + pkg := fn.Pkg() + if pkg == nil { + return nil + } + + pkgPath := vendorLessPath(pkg.Path()) + indices := l.rulesetIndicesByImport[pkgPath] + + for _, idx := range indices { + rs := &l.rulesetList[idx] + if l.isCheckerDisabled(rs.Name) { + // Skip ignored logger checker. + continue + } + + if !rs.Match(fn) { + continue + } + + checker := checkerByRulesetName[rs.Name] + if checker == nil { + return checkers.General{} + } + return checker + } + + return nil +} + +func (l *loggercheck) checkLoggerArguments(pass *analysis.Pass, call *ast.CallExpr) { + fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func) + if fn == nil { + return // function pointer is not supported + } + + sig, ok := fn.Type().(*types.Signature) + if !ok || !sig.Variadic() { + return // not variadic + } + + // ellipsis args is hard, just skip + if call.Ellipsis.IsValid() { + return + } + + checker := l.getCheckerForFunc(fn) + if checker == nil { + return + } + + checkers.ExecuteChecker(checker, pass, checkers.CallContext{ + Expr: call, + Func: fn, + Signature: sig, + }, checkers.Config{ + RequireStringKey: l.requireStringKey, + NoPrintfLike: l.noPrintfLike, + }) +} + +func (l *loggercheck) processConfig() error { + if l.ruleFile != "" { // flags takes precedence over configs + f, err := os.Open(l.ruleFile) + if err != nil { + return fmt.Errorf("failed to open rule file: %w", err) + } + defer f.Close() + + custom, err := rules.ParseRuleFile(f) + if err != nil { + return fmt.Errorf("failed to parse rule file: %w", err) + } + l.rulesetList = append(l.rulesetList, custom...) + } else if len(l.rules) > 0 { + custom, err := rules.ParseRules(l.rules) + if err != nil { + return fmt.Errorf("failed to parse rules: %w", err) + } + l.rulesetList = append(l.rulesetList, custom...) + } + + // Build index + indices := make(map[string][]int) + for i, rs := range l.rulesetList { + indices[rs.PackageImport] = append(indices[rs.PackageImport], i) + } + l.rulesetIndicesByImport = indices + + return nil +} + +func (l *loggercheck) run(pass *analysis.Pass) (interface{}, error) { + err := l.processConfig() + if err != nil { + return nil, err + } + + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + } + insp.Preorder(nodeFilter, func(node ast.Node) { + call := node.(*ast.CallExpr) + + typ := pass.TypesInfo.Types[call.Fun].Type + if typ == nil { + // Skip checking functions with unknown type. + return + } + + l.checkLoggerArguments(pass, call) + }) + + return nil, nil +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/options.go b/tools/vendor/github.com/timonwong/loggercheck/options.go new file mode 100644 index 00000000..6b5f00af --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/options.go @@ -0,0 +1,31 @@ +package loggercheck + +import ( + "github.com/timonwong/loggercheck/internal/sets" +) + +type Option func(*loggercheck) + +func WithDisable(disable []string) Option { + return func(l *loggercheck) { + l.disable = sets.NewString(disable...) + } +} + +func WithRules(customRules []string) Option { + return func(l *loggercheck) { + l.rules = customRules + } +} + +func WithRequireStringKey(requireStringKey bool) Option { + return func(l *loggercheck) { + l.requireStringKey = requireStringKey + } +} + +func WithNoPrintfLike(noPrintfLike bool) Option { + return func(l *loggercheck) { + l.noPrintfLike = noPrintfLike + } +} diff --git a/tools/vendor/github.com/timonwong/loggercheck/staticrules.go b/tools/vendor/github.com/timonwong/loggercheck/staticrules.go new file mode 100644 index 00000000..f955b343 --- /dev/null +++ b/tools/vendor/github.com/timonwong/loggercheck/staticrules.go @@ -0,0 +1,68 @@ +package loggercheck + +import ( + "errors" + "fmt" + + "github.com/timonwong/loggercheck/internal/checkers" + "github.com/timonwong/loggercheck/internal/rules" +) + +var ( + staticRuleList = []rules.Ruleset{ + mustNewStaticRuleSet("logr", []string{ + "(github.com/go-logr/logr.Logger).Error", + "(github.com/go-logr/logr.Logger).Info", + "(github.com/go-logr/logr.Logger).WithValues", + }), + mustNewStaticRuleSet("klog", []string{ + "k8s.io/klog/v2.InfoS", + "k8s.io/klog/v2.InfoSDepth", + "k8s.io/klog/v2.ErrorS", + "(k8s.io/klog/v2.Verbose).InfoS", + "(k8s.io/klog/v2.Verbose).InfoSDepth", + "(k8s.io/klog/v2.Verbose).ErrorS", + }), + mustNewStaticRuleSet("zap", []string{ + "(*go.uber.org/zap.SugaredLogger).With", + "(*go.uber.org/zap.SugaredLogger).Debugw", + "(*go.uber.org/zap.SugaredLogger).Infow", + "(*go.uber.org/zap.SugaredLogger).Warnw", + "(*go.uber.org/zap.SugaredLogger).Errorw", + "(*go.uber.org/zap.SugaredLogger).DPanicw", + "(*go.uber.org/zap.SugaredLogger).Panicw", + "(*go.uber.org/zap.SugaredLogger).Fatalw", + }), + mustNewStaticRuleSet("kitlog", []string{ + "github.com/go-kit/log.With", + "github.com/go-kit/log.WithPrefix", + "github.com/go-kit/log.WithSuffix", + "(github.com/go-kit/log.Logger).Log", + }), + } + checkerByRulesetName = map[string]checkers.Checker{ + // by default, checkers.General will be used. + "zap": checkers.Zap{}, + } +) + +// mustNewStaticRuleSet only called at init, catch errors during development. +// In production it will not panic. +func mustNewStaticRuleSet(name string, lines []string) rules.Ruleset { + if len(lines) == 0 { + panic(errors.New("no rules provided")) + } + + rulesetList, err := rules.ParseRules(lines) + if err != nil { + panic(err) + } + + if len(rulesetList) != 1 { + panic(fmt.Errorf("expected 1 ruleset, got %d", len(rulesetList))) + } + + ruleset := rulesetList[0] + ruleset.Name = name + return ruleset +} diff --git a/tools/vendor/github.com/timonwong/logrlint/Makefile b/tools/vendor/github.com/timonwong/logrlint/Makefile deleted file mode 100644 index ad63ec53..00000000 --- a/tools/vendor/github.com/timonwong/logrlint/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -lint: - golangci-lint run ./... - -.PHONY: test-deps -test-deps: - cd testdata/src/a && go mod vendor - -.PHONY: test -test: test-deps - go test ./... - -.PHONY: build -build: - go build -o bin/logrlint ./cmd/logrlint - -.PHONY: build-plugin -build-plugin: - CGO_ENABLED=1 go build -o bin/logrlint.so -buildmode=plugin ./plugin diff --git a/tools/vendor/github.com/timonwong/logrlint/README.md b/tools/vendor/github.com/timonwong/logrlint/README.md deleted file mode 100644 index 6b3f7892..00000000 --- a/tools/vendor/github.com/timonwong/logrlint/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# logrlint - -A linter checks the odd number of key and value pairs for [logr](https://github.com/go-logr/logr) diff --git a/tools/vendor/github.com/timonwong/logrlint/logrlint.go b/tools/vendor/github.com/timonwong/logrlint/logrlint.go deleted file mode 100644 index 5c45903c..00000000 --- a/tools/vendor/github.com/timonwong/logrlint/logrlint.go +++ /dev/null @@ -1,106 +0,0 @@ -package logrlint - -import ( - "fmt" - "go/ast" - "go/types" - - "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" -) - -const Doc = "Check logr arguments." - -var Analyzer = &analysis.Analyzer{ - Name: "logrlint", - Doc: Doc, - Run: run, - Requires: []*analysis.Analyzer{inspect.Analyzer}, -} - -var isValidName = map[string]struct{}{ - "Error": {}, - "Info": {}, - "WithValues": {}, -} - -func isValidPackage(pass *analysis.Pass, fn *types.Func) bool { - // We allow only logr package import path - const packageName = "github.com/go-logr/logr" - - pkg := fn.Pkg() - if pkg == nil { - return false - } - pkgPath := pkg.Path() - // Fast path: for GOPATH or go mod enabled packages - if pkgPath == packageName { - return true - } - - // Special case for vendor - vendorPath := fmt.Sprintf("%s/vendor/%s", pass.Pkg.Name(), packageName) - return pkgPath == vendorPath -} - -func checkEvenArguments(pass *analysis.Pass, call *ast.CallExpr) { - fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func) - if fn == nil { - return // function pointer is not supported - } - - sig, ok := fn.Type().(*types.Signature) - if !ok || !sig.Variadic() { - return // not variadic - } - - if _, ok := isValidName[fn.Name()]; !ok { - return - } - - if !isValidPackage(pass, fn) { - return - } - - params := sig.Params() - nparams := params.Len() // variadic => nonzero - args := params.At(nparams - 1) - iface, ok := args.Type().(*types.Slice).Elem().(*types.Interface) - if !ok || !iface.Empty() { - return // final (args) param is not ...interface{} - } - - startIndex := nparams - 1 - variadicLen := len(call.Args) - (startIndex) - if variadicLen%2 != 0 { - firstArg := call.Args[startIndex] - lastArg := call.Args[len(call.Args)-1] - pass.Report(analysis.Diagnostic{ - Pos: firstArg.Pos(), - End: lastArg.End(), - Category: "logging", - Message: "odd number of arguments passed as key-value pairs for logging"}) - } -} - -func run(pass *analysis.Pass) (interface{}, error) { - insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter := []ast.Node{ - (*ast.CallExpr)(nil), - } - insp.Preorder(nodeFilter, func(node ast.Node) { - call := node.(*ast.CallExpr) - - typ := pass.TypesInfo.Types[call.Fun].Type - if typ == nil { - // Skip checking functions with unknown type. - return - } - - checkEvenArguments(pass, call) - }) - - return nil, nil -} diff --git a/tools/vendor/golang.org/x/sync/errgroup/errgroup.go b/tools/vendor/golang.org/x/sync/errgroup/errgroup.go index 4c0850a4..cbee7a4e 100644 --- a/tools/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/tools/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -61,8 +61,8 @@ func (g *Group) Wait() error { // It blocks until the new goroutine can be added without the number of // active goroutines in the group exceeding the configured limit. // -// The first call to return a non-nil error cancels the group; its error will be -// returned by Wait. +// The first call to return a non-nil error cancels the group's context, if the +// group was created by calling WithContext. The error will be returned by Wait. func (g *Group) Go(f func() error) { if g.sem != nil { g.sem <- token{} diff --git a/tools/vendor/golang.org/x/sync/semaphore/semaphore.go b/tools/vendor/golang.org/x/sync/semaphore/semaphore.go new file mode 100644 index 00000000..30f632c5 --- /dev/null +++ b/tools/vendor/golang.org/x/sync/semaphore/semaphore.go @@ -0,0 +1,136 @@ +// Copyright 2017 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 semaphore provides a weighted semaphore implementation. +package semaphore // import "golang.org/x/sync/semaphore" + +import ( + "container/list" + "context" + "sync" +) + +type waiter struct { + n int64 + ready chan<- struct{} // Closed when semaphore acquired. +} + +// NewWeighted creates a new weighted semaphore with the given +// maximum combined weight for concurrent access. +func NewWeighted(n int64) *Weighted { + w := &Weighted{size: n} + return w +} + +// Weighted provides a way to bound concurrent access to a resource. +// The callers can request access with a given weight. +type Weighted struct { + size int64 + cur int64 + mu sync.Mutex + waiters list.List +} + +// Acquire acquires the semaphore with a weight of n, blocking until resources +// are available or ctx is done. On success, returns nil. On failure, returns +// ctx.Err() and leaves the semaphore unchanged. +// +// If ctx is already done, Acquire may still succeed without blocking. +func (s *Weighted) Acquire(ctx context.Context, n int64) error { + s.mu.Lock() + if s.size-s.cur >= n && s.waiters.Len() == 0 { + s.cur += n + s.mu.Unlock() + return nil + } + + if n > s.size { + // Don't make other Acquire calls block on one that's doomed to fail. + s.mu.Unlock() + <-ctx.Done() + return ctx.Err() + } + + ready := make(chan struct{}) + w := waiter{n: n, ready: ready} + elem := s.waiters.PushBack(w) + s.mu.Unlock() + + select { + case <-ctx.Done(): + err := ctx.Err() + s.mu.Lock() + select { + case <-ready: + // Acquired the semaphore after we were canceled. Rather than trying to + // fix up the queue, just pretend we didn't notice the cancelation. + err = nil + default: + isFront := s.waiters.Front() == elem + s.waiters.Remove(elem) + // If we're at the front and there're extra tokens left, notify other waiters. + if isFront && s.size > s.cur { + s.notifyWaiters() + } + } + s.mu.Unlock() + return err + + case <-ready: + return nil + } +} + +// TryAcquire acquires the semaphore with a weight of n without blocking. +// On success, returns true. On failure, returns false and leaves the semaphore unchanged. +func (s *Weighted) TryAcquire(n int64) bool { + s.mu.Lock() + success := s.size-s.cur >= n && s.waiters.Len() == 0 + if success { + s.cur += n + } + s.mu.Unlock() + return success +} + +// Release releases the semaphore with a weight of n. +func (s *Weighted) Release(n int64) { + s.mu.Lock() + s.cur -= n + if s.cur < 0 { + s.mu.Unlock() + panic("semaphore: released more than held") + } + s.notifyWaiters() + s.mu.Unlock() +} + +func (s *Weighted) notifyWaiters() { + for { + next := s.waiters.Front() + if next == nil { + break // No more waiters blocked. + } + + w := next.Value.(waiter) + if s.size-s.cur < w.n { + // Not enough tokens for the next waiter. We could keep going (to try to + // find a waiter with a smaller request), but under load that could cause + // starvation for large requests; instead, we leave all remaining waiters + // blocked. + // + // Consider a semaphore used as a read-write lock, with N tokens, N + // readers, and one writer. Each reader can Acquire(1) to obtain a read + // lock. The writer can Acquire(N) to obtain a write lock, excluding all + // of the readers. If we allow the readers to jump ahead in the queue, + // the writer will starve — there is always one token available for every + // reader. + break + } + + s.cur += w.n + s.waiters.Remove(next) + close(w.ready) + } +} diff --git a/tools/vendor/golang.org/x/sys/plan9/syscall.go b/tools/vendor/golang.org/x/sys/plan9/syscall.go index ea971285..67e5b011 100644 --- a/tools/vendor/golang.org/x/sys/plan9/syscall.go +++ b/tools/vendor/golang.org/x/sys/plan9/syscall.go @@ -80,8 +80,7 @@ func BytePtrToString(p *byte) string { ptr = unsafe.Pointer(uintptr(ptr) + 1) } - s := unsafe.Slice((*byte)(unsafe.Pointer(p)), n) - return string(s) + return string(unsafe.Slice(p, n)) } // Single-word zero for use when we need a valid pointer to 0 bytes. diff --git a/tools/vendor/golang.org/x/sys/unix/mkall.sh b/tools/vendor/golang.org/x/sys/unix/mkall.sh index 3b2335d5..1b2b424a 100644 --- a/tools/vendor/golang.org/x/sys/unix/mkall.sh +++ b/tools/vendor/golang.org/x/sys/unix/mkall.sh @@ -214,11 +214,6 @@ esac if [ "$GOOSARCH" == "aix_ppc64" ]; then # aix/ppc64 script generates files instead of writing to stdin. echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ; - elif [ "$GOOS" == "darwin" ]; then - # 1.12 and later, syscalls via libSystem - echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; - # 1.13 and later, syscalls via libSystem (including syscallPtr) - echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go"; elif [ "$GOOS" == "illumos" ]; then # illumos code generation requires a --illumos switch echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go"; diff --git a/tools/vendor/golang.org/x/sys/unix/syscall.go b/tools/vendor/golang.org/x/sys/unix/syscall.go index 9916e5e8..63e8c838 100644 --- a/tools/vendor/golang.org/x/sys/unix/syscall.go +++ b/tools/vendor/golang.org/x/sys/unix/syscall.go @@ -80,8 +80,7 @@ func BytePtrToString(p *byte) string { ptr = unsafe.Pointer(uintptr(ptr) + 1) } - s := unsafe.Slice((*byte)(unsafe.Pointer(p)), n) - return string(s) + return string(unsafe.Slice(p, n)) } // Single-word zero for use when we need a valid pointer to 0 bytes. diff --git a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go b/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go deleted file mode 100644 index b0098607..00000000 --- a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && go1.12 && !go1.13 -// +build darwin,go1.12,!go1.13 - -package unix - -import ( - "unsafe" -) - -const _SYS_GETDIRENTRIES64 = 344 - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - // To implement this using libSystem we'd need syscall_syscallPtr for - // fdopendir. However, syscallPtr was only added in Go 1.13, so we fall - // back to raw syscalls for this func on Go 1.12. - var p unsafe.Pointer - if len(buf) > 0 { - p = unsafe.Pointer(&buf[0]) - } else { - p = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0) - n = int(r0) - if e1 != 0 { - return n, errnoErr(e1) - } - return n, nil -} diff --git a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go deleted file mode 100644 index 1259f6df..00000000 --- a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && go1.13 -// +build darwin,go1.13 - -package unix - -import "unsafe" - -//sys closedir(dir uintptr) (err error) -//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) - -func fdopendir(fd int) (dir uintptr, err error) { - r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) - dir = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_fdopendir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - // Simulate Getdirentries using fdopendir/readdir_r/closedir. - // We store the number of entries to skip in the seek - // offset of fd. See issue #31368. - // It's not the full required semantics, but should handle the case - // of calling Getdirentries or ReadDirent repeatedly. - // It won't handle assigning the results of lseek to *basep, or handle - // the directory being edited underfoot. - skip, err := Seek(fd, 0, 1 /* SEEK_CUR */) - if err != nil { - return 0, err - } - - // We need to duplicate the incoming file descriptor - // because the caller expects to retain control of it, but - // fdopendir expects to take control of its argument. - // Just Dup'ing the file descriptor is not enough, as the - // result shares underlying state. Use Openat to make a really - // new file descriptor referring to the same directory. - fd2, err := Openat(fd, ".", O_RDONLY, 0) - if err != nil { - return 0, err - } - d, err := fdopendir(fd2) - if err != nil { - Close(fd2) - return 0, err - } - defer closedir(d) - - var cnt int64 - for { - var entry Dirent - var entryp *Dirent - e := readdir_r(d, &entry, &entryp) - if e != 0 { - return n, errnoErr(e) - } - if entryp == nil { - break - } - if skip > 0 { - skip-- - cnt++ - continue - } - - reclen := int(entry.Reclen) - if reclen > len(buf) { - // Not enough room. Return for now. - // The counter will let us know where we should start up again. - // Note: this strategy for suspending in the middle and - // restarting is O(n^2) in the length of the directory. Oh well. - break - } - - // Copy entry into return buffer. - s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen) - copy(buf, s) - - buf = buf[reclen:] - n += reclen - cnt++ - } - // Set the seek offset of the input fd to record - // how many files we've already returned. - _, err = Seek(fd, cnt, 0 /* SEEK_SET */) - if err != nil { - return n, err - } - - return n, nil -} diff --git a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.go b/tools/vendor/golang.org/x/sys/unix/syscall_darwin.go index 4f87f16e..1f633821 100644 --- a/tools/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/tools/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -19,6 +19,96 @@ import ( "unsafe" ) +//sys closedir(dir uintptr) (err error) +//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) + +func fdopendir(fd int) (dir uintptr, err error) { + r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) + dir = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fdopendir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { + // Simulate Getdirentries using fdopendir/readdir_r/closedir. + // We store the number of entries to skip in the seek + // offset of fd. See issue #31368. + // It's not the full required semantics, but should handle the case + // of calling Getdirentries or ReadDirent repeatedly. + // It won't handle assigning the results of lseek to *basep, or handle + // the directory being edited underfoot. + skip, err := Seek(fd, 0, 1 /* SEEK_CUR */) + if err != nil { + return 0, err + } + + // We need to duplicate the incoming file descriptor + // because the caller expects to retain control of it, but + // fdopendir expects to take control of its argument. + // Just Dup'ing the file descriptor is not enough, as the + // result shares underlying state. Use Openat to make a really + // new file descriptor referring to the same directory. + fd2, err := Openat(fd, ".", O_RDONLY, 0) + if err != nil { + return 0, err + } + d, err := fdopendir(fd2) + if err != nil { + Close(fd2) + return 0, err + } + defer closedir(d) + + var cnt int64 + for { + var entry Dirent + var entryp *Dirent + e := readdir_r(d, &entry, &entryp) + if e != 0 { + return n, errnoErr(e) + } + if entryp == nil { + break + } + if skip > 0 { + skip-- + cnt++ + continue + } + + reclen := int(entry.Reclen) + if reclen > len(buf) { + // Not enough room. Return for now. + // The counter will let us know where we should start up again. + // Note: this strategy for suspending in the middle and + // restarting is O(n^2) in the length of the directory. Oh well. + break + } + + // Copy entry into return buffer. + s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen) + copy(buf, s) + + buf = buf[reclen:] + n += reclen + cnt++ + } + // Set the seek offset of the input fd to record + // how many files we've already returned. + _, err = Seek(fd, cnt, 0 /* SEEK_SET */) + if err != nil { + return n, err + } + + return n, nil +} + // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. type SockaddrDatalink struct { Len uint8 diff --git a/tools/vendor/golang.org/x/sys/unix/xattr_bsd.go b/tools/vendor/golang.org/x/sys/unix/xattr_bsd.go index 25df1e37..663b3779 100644 --- a/tools/vendor/golang.org/x/sys/unix/xattr_bsd.go +++ b/tools/vendor/golang.org/x/sys/unix/xattr_bsd.go @@ -160,13 +160,12 @@ func Lremovexattr(link string, attr string) (err error) { } func Listxattr(file string, dest []byte) (sz int, err error) { - d := initxattrdest(dest, 0) destsiz := len(dest) // FreeBSD won't allow you to list xattrs from multiple namespaces - s := 0 + s, pos := 0, 0 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz) + stmp, e := ListxattrNS(file, nsid, dest[pos:]) /* Errors accessing system attrs are ignored so that * we can implement the Linux-like behavior of omitting errors that @@ -175,66 +174,102 @@ func Listxattr(file string, dest []byte) (sz int, err error) { * Linux will still error if we ask for user attributes on a file that * we don't have read permissions on, so don't ignore those errors */ - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - continue - } else if e != nil { + if e != nil { + if e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } return s, e } s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 + pos = s + if pos > destsiz { + pos = destsiz } - d = initxattrdest(dest, s) } return s, nil } -func Flistxattr(fd int, dest []byte) (sz int, err error) { +func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) { d := initxattrdest(dest, 0) destsiz := len(dest) - s := 0 + s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz) + if e != nil { + return 0, err + } + + return s, nil +} + +func Flistxattr(fd int, dest []byte) (sz int, err error) { + destsiz := len(dest) + + s, pos := 0, 0 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz) - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - continue - } else if e != nil { + stmp, e := FlistxattrNS(fd, nsid, dest[pos:]) + + if e != nil { + if e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } return s, e } s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 + pos = s + if pos > destsiz { + pos = destsiz } - d = initxattrdest(dest, s) } return s, nil } -func Llistxattr(link string, dest []byte) (sz int, err error) { +func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) { d := initxattrdest(dest, 0) destsiz := len(dest) - s := 0 + s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz) + if e != nil { + return 0, err + } + + return s, nil +} + +func Llistxattr(link string, dest []byte) (sz int, err error) { + destsiz := len(dest) + + s, pos := 0, 0 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { - stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz) - if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { - continue - } else if e != nil { + stmp, e := LlistxattrNS(link, nsid, dest[pos:]) + + if e != nil { + if e == EPERM && nsid != EXTATTR_NAMESPACE_USER { + continue + } return s, e } s += stmp - destsiz -= s - if destsiz < 0 { - destsiz = 0 + pos = s + if pos > destsiz { + pos = destsiz } - d = initxattrdest(dest, s) + } + + return s, nil +} + +func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) { + d := initxattrdest(dest, 0) + destsiz := len(dest) + + s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz) + if e != nil { + return 0, err } return s, nil diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go deleted file mode 100644 index a06eb093..00000000 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -tags darwin,amd64,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && amd64 && go1.13 -// +build darwin,amd64,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_closedir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -var libc_readdir_r_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s deleted file mode 100644 index f5bb40ed..00000000 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s +++ /dev/null @@ -1,25 +0,0 @@ -// go run mkasm.go darwin amd64 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" - -TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) - -GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) - -TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) - -GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) - -TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) - -GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 -DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index 467deed7..c2461c49 100644 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -1,8 +1,8 @@ -// go run mksyscall.go -tags darwin,amd64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go +// go run mksyscall.go -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go // Code generated by the command above; see README.md. DO NOT EDIT. -//go:build darwin && amd64 && go1.12 -// +build darwin,amd64,go1.12 +//go:build darwin && amd64 +// +build darwin,amd64 package unix @@ -463,6 +463,32 @@ var libc_munlockall_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func closedir(dir uintptr) (err error) { + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_closedir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + res = Errno(r0) + return +} + +var libc_readdir_r_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]int32) (err error) { _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index b41467a0..95fe4c0e 100644 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -1,11 +1,14 @@ // go run mkasm.go darwin amd64 // Code generated by the command above; DO NOT EDIT. -//go:build go1.12 -// +build go1.12 - #include "textflag.h" +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fdopendir(SB) + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) @@ -174,6 +177,18 @@ TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_closedir(SB) + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) + TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go deleted file mode 100644 index cec595d5..00000000 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go +++ /dev/null @@ -1,40 +0,0 @@ -// go run mksyscall.go -tags darwin,arm64,go1.13 syscall_darwin.1_13.go -// Code generated by the command above; see README.md. DO NOT EDIT. - -//go:build darwin && arm64 && go1.13 -// +build darwin,arm64,go1.13 - -package unix - -import ( - "syscall" - "unsafe" -) - -var _ syscall.Errno - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func closedir(dir uintptr) (err error) { - _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -var libc_closedir_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { - r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) - res = Errno(r0) - return -} - -var libc_readdir_r_trampoline_addr uintptr - -//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s deleted file mode 100644 index 0c3f76bc..00000000 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s +++ /dev/null @@ -1,25 +0,0 @@ -// go run mkasm.go darwin arm64 -// Code generated by the command above; DO NOT EDIT. - -//go:build go1.13 -// +build go1.13 - -#include "textflag.h" - -TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_fdopendir(SB) - -GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) - -TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_closedir(SB) - -GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 -DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) - -TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 - JMP libc_readdir_r(SB) - -GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 -DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 35938d34..26a0fdc5 100644 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -1,8 +1,8 @@ -// go run mksyscall.go -tags darwin,arm64,go1.12 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go +// go run mksyscall.go -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go // Code generated by the command above; see README.md. DO NOT EDIT. -//go:build darwin && arm64 && go1.12 -// +build darwin,arm64,go1.12 +//go:build darwin && arm64 +// +build darwin,arm64 package unix @@ -463,6 +463,32 @@ var libc_munlockall_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func closedir(dir uintptr) (err error) { + _, _, e1 := syscall_syscall(libc_closedir_trampoline_addr, uintptr(dir), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_closedir_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_closedir closedir "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) { + r0, _, _ := syscall_syscall(libc_readdir_r_trampoline_addr, uintptr(dir), uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result))) + res = Errno(r0) + return +} + +var libc_readdir_r_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readdir_r readdir_r "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]int32) (err error) { _, _, e1 := syscall_rawSyscall(libc_pipe_trampoline_addr, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index e1f9204a..efa5b4c9 100644 --- a/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/tools/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -1,11 +1,14 @@ // go run mkasm.go darwin arm64 // Code generated by the command above; DO NOT EDIT. -//go:build go1.12 -// +build go1.12 - #include "textflag.h" +TEXT libc_fdopendir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fdopendir(SB) + +GLOBL ·libc_fdopendir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fdopendir_trampoline_addr(SB)/8, $libc_fdopendir_trampoline<>(SB) + TEXT libc_getgroups_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) @@ -174,6 +177,18 @@ TEXT libc_munlockall_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munlockall_trampoline_addr(SB), RODATA, $8 DATA ·libc_munlockall_trampoline_addr(SB)/8, $libc_munlockall_trampoline<>(SB) +TEXT libc_closedir_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_closedir(SB) + +GLOBL ·libc_closedir_trampoline_addr(SB), RODATA, $8 +DATA ·libc_closedir_trampoline_addr(SB)/8, $libc_closedir_trampoline<>(SB) + +TEXT libc_readdir_r_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readdir_r(SB) + +GLOBL ·libc_readdir_r_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readdir_r_trampoline_addr(SB)/8, $libc_readdir_r_trampoline<>(SB) + TEXT libc_pipe_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) diff --git a/tools/vendor/golang.org/x/sys/windows/syscall.go b/tools/vendor/golang.org/x/sys/windows/syscall.go index 72074d58..8732cdb9 100644 --- a/tools/vendor/golang.org/x/sys/windows/syscall.go +++ b/tools/vendor/golang.org/x/sys/windows/syscall.go @@ -30,8 +30,6 @@ import ( "strings" "syscall" "unsafe" - - "golang.org/x/sys/internal/unsafeheader" ) // ByteSliceFromString returns a NUL-terminated slice of bytes @@ -83,13 +81,7 @@ func BytePtrToString(p *byte) string { ptr = unsafe.Pointer(uintptr(ptr) + 1) } - var s []byte - h := (*unsafeheader.Slice)(unsafe.Pointer(&s)) - h.Data = unsafe.Pointer(p) - h.Len = n - h.Cap = n - - return string(s) + return string(unsafe.Slice(p, n)) } // Single-word zero for use when we need a valid pointer to 0 bytes. diff --git a/tools/vendor/golang.org/x/sys/windows/syscall_windows.go b/tools/vendor/golang.org/x/sys/windows/syscall_windows.go index e2791381..29737b20 100644 --- a/tools/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/tools/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -138,13 +138,7 @@ func UTF16PtrToString(p *uint16) string { ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) } - var s []uint16 - h := (*unsafeheader.Slice)(unsafe.Pointer(&s)) - h.Data = unsafe.Pointer(p) - h.Len = n - h.Cap = n - - return string(utf16.Decode(s)) + return string(utf16.Decode(unsafe.Slice(p, n))) } func Getpagesize() int { return 4096 } @@ -364,6 +358,15 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) //sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) +//sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows +//sys EnumChildWindows(hwnd HWND, enumFunc uintptr, param unsafe.Pointer) = user32.EnumChildWindows +//sys GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, err error) = user32.GetClassNameW +//sys GetDesktopWindow() (hwnd HWND) = user32.GetDesktopWindow +//sys GetForegroundWindow() (hwnd HWND) = user32.GetForegroundWindow +//sys IsWindow(hwnd HWND) (isWindow bool) = user32.IsWindow +//sys IsWindowUnicode(hwnd HWND) (isUnicode bool) = user32.IsWindowUnicode +//sys IsWindowVisible(hwnd HWND) (isVisible bool) = user32.IsWindowVisible +//sys GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) = user32.GetGUIThreadInfo // Volume Management Functions //sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW diff --git a/tools/vendor/golang.org/x/sys/windows/types_windows.go b/tools/vendor/golang.org/x/sys/windows/types_windows.go index f9eaca52..ef489f54 100644 --- a/tools/vendor/golang.org/x/sys/windows/types_windows.go +++ b/tools/vendor/golang.org/x/sys/windows/types_windows.go @@ -3213,3 +3213,22 @@ type ModuleInfo struct { } const ALL_PROCESSOR_GROUPS = 0xFFFF + +type Rect struct { + Left int32 + Top int32 + Right int32 + Bottom int32 +} + +type GUIThreadInfo struct { + Size uint32 + Flags uint32 + Active HWND + Focus HWND + Capture HWND + MenuOwner HWND + MoveSize HWND + CaretHandle HWND + CaretRect Rect +} diff --git a/tools/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/tools/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 52d4742c..6c6f27ba 100644 --- a/tools/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/tools/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -444,9 +444,18 @@ var ( procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") procSHGetKnownFolderPath = modshell32.NewProc("SHGetKnownFolderPath") procShellExecuteW = modshell32.NewProc("ShellExecuteW") + procEnumChildWindows = moduser32.NewProc("EnumChildWindows") + procEnumWindows = moduser32.NewProc("EnumWindows") procExitWindowsEx = moduser32.NewProc("ExitWindowsEx") + procGetClassNameW = moduser32.NewProc("GetClassNameW") + procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow") + procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow") + procGetGUIThreadInfo = moduser32.NewProc("GetGUIThreadInfo") procGetShellWindow = moduser32.NewProc("GetShellWindow") procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId") + procIsWindow = moduser32.NewProc("IsWindow") + procIsWindowUnicode = moduser32.NewProc("IsWindowUnicode") + procIsWindowVisible = moduser32.NewProc("IsWindowVisible") procMessageBoxW = moduser32.NewProc("MessageBoxW") procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") @@ -3802,6 +3811,19 @@ func ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *ui return } +func EnumChildWindows(hwnd HWND, enumFunc uintptr, param unsafe.Pointer) { + syscall.Syscall(procEnumChildWindows.Addr(), 3, uintptr(hwnd), uintptr(enumFunc), uintptr(param)) + return +} + +func EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) { + r1, _, e1 := syscall.Syscall(procEnumWindows.Addr(), 2, uintptr(enumFunc), uintptr(param), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func ExitWindowsEx(flags uint32, reason uint32) (err error) { r1, _, e1 := syscall.Syscall(procExitWindowsEx.Addr(), 2, uintptr(flags), uintptr(reason), 0) if r1 == 0 { @@ -3810,6 +3832,35 @@ func ExitWindowsEx(flags uint32, reason uint32) (err error) { return } +func GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, err error) { + r0, _, e1 := syscall.Syscall(procGetClassNameW.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(className)), uintptr(maxCount)) + copied = int32(r0) + if copied == 0 { + err = errnoErr(e1) + } + return +} + +func GetDesktopWindow() (hwnd HWND) { + r0, _, _ := syscall.Syscall(procGetDesktopWindow.Addr(), 0, 0, 0, 0) + hwnd = HWND(r0) + return +} + +func GetForegroundWindow() (hwnd HWND) { + r0, _, _ := syscall.Syscall(procGetForegroundWindow.Addr(), 0, 0, 0, 0) + hwnd = HWND(r0) + return +} + +func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) { + r1, _, e1 := syscall.Syscall(procGetGUIThreadInfo.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(info)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func GetShellWindow() (shellWindow HWND) { r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0) shellWindow = HWND(r0) @@ -3825,6 +3876,24 @@ func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) { return } +func IsWindow(hwnd HWND) (isWindow bool) { + r0, _, _ := syscall.Syscall(procIsWindow.Addr(), 1, uintptr(hwnd), 0, 0) + isWindow = r0 != 0 + return +} + +func IsWindowUnicode(hwnd HWND) (isUnicode bool) { + r0, _, _ := syscall.Syscall(procIsWindowUnicode.Addr(), 1, uintptr(hwnd), 0, 0) + isUnicode = r0 != 0 + return +} + +func IsWindowVisible(hwnd HWND) (isVisible bool) { + r0, _, _ := syscall.Syscall(procIsWindowVisible.Addr(), 1, uintptr(hwnd), 0, 0) + isVisible = r0 != 0 + return +} + func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) { r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0) ret = int32(r0) diff --git a/tools/vendor/gopkg.in/ini.v1/deprecated.go b/tools/vendor/gopkg.in/ini.v1/deprecated.go index e8bda06e..48b8e66d 100644 --- a/tools/vendor/gopkg.in/ini.v1/deprecated.go +++ b/tools/vendor/gopkg.in/ini.v1/deprecated.go @@ -14,12 +14,9 @@ package ini -const ( +var ( // Deprecated: Use "DefaultSection" instead. DEFAULT_SECTION = DefaultSection -) - -var ( // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. AllCapsUnderscore = SnackCase ) diff --git a/tools/vendor/gopkg.in/ini.v1/ini.go b/tools/vendor/gopkg.in/ini.v1/ini.go index ac2a93a5..99e7f865 100644 --- a/tools/vendor/gopkg.in/ini.v1/ini.go +++ b/tools/vendor/gopkg.in/ini.v1/ini.go @@ -23,15 +23,15 @@ import ( ) const ( - // DefaultSection is the name of default section. You can use this constant or the string literal. - // In most of cases, an empty string is all you need to access the section. - DefaultSection = "DEFAULT" - // Maximum allowed depth when recursively substituing variable names. depthValues = 99 ) var ( + // DefaultSection is the name of default section. You can use this var or the string literal. + // In most of cases, an empty string is all you need to access the section. + DefaultSection = "DEFAULT" + // LineBreak is the delimiter to determine or compose a new line. // This variable will be changed to "\r\n" automatically on Windows at package init time. LineBreak = "\n" diff --git a/tools/vendor/modules.txt b/tools/vendor/modules.txt index ca9e85fe..9789c764 100644 --- a/tools/vendor/modules.txt +++ b/tools/vendor/modules.txt @@ -28,6 +28,9 @@ cloud.google.com/go/storage/internal/apiv2 # code.gitea.io/sdk/gitea v0.15.1 ## explicit; go 1.13 code.gitea.io/sdk/gitea +# github.com/Abirdcfly/dupword v0.0.7 +## explicit; go 1.19 +github.com/Abirdcfly/dupword # github.com/AlekSi/pointer v1.2.0 ## explicit; go 1.18 github.com/AlekSi/pointer @@ -104,7 +107,7 @@ github.com/Masterminds/sprig ## explicit; go 1.12 github.com/Microsoft/go-winio github.com/Microsoft/go-winio/pkg/guid -# github.com/OpenPeeDeeP/depguard v1.1.0 +# github.com/OpenPeeDeeP/depguard v1.1.1 ## explicit; go 1.13 github.com/OpenPeeDeeP/depguard # github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 @@ -380,11 +383,11 @@ github.com/chavacava/garif # github.com/cpuguy83/go-md2man/v2 v2.0.2 ## explicit; go 1.11 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/curioswitch/go-reassign v0.1.2 +# github.com/curioswitch/go-reassign v0.2.0 ## explicit; go 1.18 github.com/curioswitch/go-reassign github.com/curioswitch/go-reassign/internal/analyzer -# github.com/daixiang0/gci v0.6.3 +# github.com/daixiang0/gci v0.8.0 ## explicit; go 1.18 github.com/daixiang0/gci/pkg/config github.com/daixiang0/gci/pkg/format @@ -457,7 +460,7 @@ github.com/fsnotify/fsnotify # github.com/fzipp/gocyclo v0.6.0 ## explicit; go 1.18 github.com/fzipp/gocyclo -# github.com/go-critic/go-critic v0.6.4 +# github.com/go-critic/go-critic v0.6.5 ## explicit; go 1.16 github.com/go-critic/go-critic/checkers github.com/go-critic/go-critic/checkers/internal/astwalk @@ -528,10 +531,10 @@ github.com/go-telegram-bot-api/telegram-bot-api # github.com/go-toolsmith/astcast v1.0.0 ## explicit github.com/go-toolsmith/astcast -# github.com/go-toolsmith/astcopy v1.0.1 +# github.com/go-toolsmith/astcopy v1.0.2 ## explicit; go 1.16 github.com/go-toolsmith/astcopy -# github.com/go-toolsmith/astequal v1.0.2 +# github.com/go-toolsmith/astequal v1.0.3 ## explicit; go 1.16 github.com/go-toolsmith/astequal # github.com/go-toolsmith/astfmt v1.0.0 @@ -591,11 +594,13 @@ 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-20190930125516-244bba706f1a -## explicit +# github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 +## explicit; go 1.18 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.49.0 +# github.com/golangci/golangci-lint v1.50.0 ## explicit; go 1.19 github.com/golangci/golangci-lint/cmd/golangci-lint github.com/golangci/golangci-lint/internal/cache @@ -638,7 +643,7 @@ github.com/golangci/revgrep # github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 ## explicit github.com/golangci/unconvert -# github.com/google/go-cmp v0.5.8 +# github.com/google/go-cmp v0.5.9 ## explicit; go 1.13 github.com/google/go-cmp/cmp github.com/google/go-cmp/cmp/internal/diff @@ -870,6 +875,9 @@ github.com/kisielk/errcheck/errcheck ## explicit github.com/kisielk/gotool github.com/kisielk/gotool/internal/load +# github.com/kkHAIKE/contextcheck v1.1.2 +## explicit; go 1.15 +github.com/kkHAIKE/contextcheck # github.com/klauspost/compress v1.15.1 ## explicit; go 1.15 github.com/klauspost/compress @@ -914,6 +922,9 @@ github.com/lufeee/execinquery # github.com/magiconair/properties v1.8.6 ## explicit; go 1.13 github.com/magiconair/properties +# github.com/maratori/testableexamples v1.0.0 +## explicit; go 1.19 +github.com/maratori/testableexamples/pkg/testableexamples # github.com/maratori/testpackage v1.1.0 ## explicit; go 1.18 github.com/maratori/testpackage/pkg/testpackage @@ -945,7 +956,7 @@ 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.2.3 +# github.com/mgechev/revive v1.2.4 ## explicit; go 1.19 github.com/mgechev/revive/config github.com/mgechev/revive/formatter @@ -1004,7 +1015,7 @@ github.com/nbutton23/zxcvbn-go/match github.com/nbutton23/zxcvbn-go/matching github.com/nbutton23/zxcvbn-go/scoring github.com/nbutton23/zxcvbn-go/utils/math -# github.com/nishanths/exhaustive v0.8.1 +# github.com/nishanths/exhaustive v0.8.3 ## explicit; go 1.14 github.com/nishanths/exhaustive # github.com/nishanths/predeclared v0.2.2 @@ -1023,7 +1034,7 @@ github.com/olekukonko/tablewriter # github.com/pelletier/go-toml v1.9.5 ## explicit; go 1.12 github.com/pelletier/go-toml -# github.com/pelletier/go-toml/v2 v2.0.2 +# github.com/pelletier/go-toml/v2 v2.0.5 ## explicit; go 1.16 github.com/pelletier/go-toml/v2 github.com/pelletier/go-toml/v2/internal/ast @@ -1038,7 +1049,7 @@ github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/polyfloyd/go-errorlint v1.0.2 +# github.com/polyfloyd/go-errorlint v1.0.5 ## explicit; go 1.13 github.com/polyfloyd/go-errorlint/errorlint # github.com/prometheus/client_golang v1.12.1 @@ -1059,7 +1070,7 @@ github.com/prometheus/common/model github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util -# github.com/quasilyte/go-ruleguard v0.3.17 +# github.com/quasilyte/go-ruleguard v0.3.18 ## explicit; go 1.17 github.com/quasilyte/go-ruleguard/internal/goenv github.com/quasilyte/go-ruleguard/internal/golist @@ -1076,7 +1087,7 @@ github.com/quasilyte/go-ruleguard/ruleguard/quasigo/stdlib/qstrconv github.com/quasilyte/go-ruleguard/ruleguard/quasigo/stdlib/qstrings github.com/quasilyte/go-ruleguard/ruleguard/textmatch github.com/quasilyte/go-ruleguard/ruleguard/typematch -# github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 +# github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f ## explicit; go 1.16 github.com/quasilyte/gogrep github.com/quasilyte/gogrep/internal/stdinfo @@ -1108,7 +1119,7 @@ github.com/sasha-s/go-csync # github.com/sashamelentyev/interfacebloat v1.1.0 ## explicit; go 1.18 github.com/sashamelentyev/interfacebloat/pkg/analyzer -# github.com/sashamelentyev/usestdlibvars v1.13.0 +# github.com/sashamelentyev/usestdlibvars v1.20.0 ## explicit; go 1.19 github.com/sashamelentyev/usestdlibvars/pkg/analyzer github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping @@ -1167,7 +1178,7 @@ github.com/spf13/jwalterweatherman # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag -# github.com/spf13/viper v1.12.0 +# github.com/spf13/viper v1.13.0 ## explicit; go 1.17 github.com/spf13/viper github.com/spf13/viper/internal/encoding @@ -1191,12 +1202,9 @@ github.com/stretchr/objx ## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/mock -# github.com/subosito/gotenv v1.4.0 +# github.com/subosito/gotenv v1.4.1 ## explicit; go 1.18 github.com/subosito/gotenv -# github.com/sylvia7788/contextcheck v1.0.6 -## explicit; go 1.15 -github.com/sylvia7788/contextcheck # github.com/tdakkota/asciicheck v0.1.1 ## explicit; go 1.13 github.com/tdakkota/asciicheck @@ -1209,9 +1217,15 @@ github.com/tetafro/godot # github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 ## explicit; go 1.12 github.com/timakin/bodyclose/passes/bodyclose -# github.com/timonwong/logrlint v0.1.0 -## explicit; go 1.16 -github.com/timonwong/logrlint +# github.com/timonwong/loggercheck v0.9.3 +## explicit; go 1.18 +github.com/timonwong/loggercheck +github.com/timonwong/loggercheck/internal/bytebufferpool +github.com/timonwong/loggercheck/internal/checkers +github.com/timonwong/loggercheck/internal/checkers/printf +github.com/timonwong/loggercheck/internal/rules +github.com/timonwong/loggercheck/internal/sets +github.com/timonwong/loggercheck/internal/stringutil # github.com/tomarrell/wrapcheck/v2 v2.6.2 ## explicit; go 1.18 github.com/tomarrell/wrapcheck/v2/wrapcheck @@ -1340,7 +1354,7 @@ golang.org/x/crypto/ssh/knownhosts ## explicit; go 1.18 golang.org/x/exp/constraints golang.org/x/exp/slices -# golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d +# golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 ## explicit; go 1.18 golang.org/x/exp/typeparams # golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 @@ -1371,10 +1385,11 @@ golang.org/x/oauth2/google/internal/externalaccount golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 +# golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde ## explicit golang.org/x/sync/errgroup -# golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 +golang.org/x/sync/semaphore +# golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 ## explicit; go 1.17 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -1628,7 +1643,7 @@ google.golang.org/protobuf/types/known/wrapperspb # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc ## explicit gopkg.in/alexcesaro/quotedprintable.v3 -# gopkg.in/ini.v1 v1.66.6 +# gopkg.in/ini.v1 v1.67.0 ## explicit gopkg.in/ini.v1 # gopkg.in/mail.v2 v2.3.1 @@ -1685,8 +1700,8 @@ honnef.co/go/tools/staticcheck/fakereflect honnef.co/go/tools/staticcheck/fakexml honnef.co/go/tools/stylecheck honnef.co/go/tools/unused -# mvdan.cc/gofumpt v0.3.1 -## explicit; go 1.17 +# mvdan.cc/gofumpt v0.4.0 +## explicit; go 1.18 mvdan.cc/gofumpt/format mvdan.cc/gofumpt/internal/version # mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed diff --git a/tools/vendor/mvdan.cc/gofumpt/format/format.go b/tools/vendor/mvdan.cc/gofumpt/format/format.go index 727acce7..fa4f2fcb 100644 --- a/tools/vendor/mvdan.cc/gofumpt/format/format.go +++ b/tools/vendor/mvdan.cc/gofumpt/format/format.go @@ -68,7 +68,7 @@ func Source(src []byte, opts Options) ([]byte, error) { // to ensure that using token.NoPos+1 will panic. fset.AddFile("gofumpt_base.go", 1, 10) - file, err := parser.ParseFile(fset, "", src, parser.ParseComments) + file, err := parser.ParseFile(fset, "", src, parser.SkipObjectResolution|parser.ParseComments) if err != nil { return nil, err } @@ -297,14 +297,14 @@ func (f *fumpter) lineEnd(line int) token.Pos { // rxCommentDirective covers all common Go comment directives: // -// //go: | standard Go directives, like go:noinline -// //some-words: | similar to the syntax above, like lint:ignore or go-sumtype:decl -// //line | inserted line information for cmd/compile -// //export | to mark cgo funcs for exporting -// //extern | C function declarations for gccgo -// //sys(nb)? | syscall function wrapper prototypes -// //nolint | nolint directive for golangci -// //noinspection | noinspection directive for GoLand and friends +// //go: | standard Go directives, like go:noinline +// //some-words: | similar to the syntax above, like lint:ignore or go-sumtype:decl +// //line | inserted line information for cmd/compile +// //export | to mark cgo funcs for exporting +// //extern | C function declarations for gccgo +// //sys(nb)? | syscall function wrapper prototypes +// //nolint | nolint directive for golangci +// //noinspection | noinspection directive for GoLand and friends // // Note that the "some-words:" matching expects a letter afterward, such as // "go:generate", to prevent matching false positives like "https://site". @@ -316,23 +316,39 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { switch node := c.Node().(type) { case *ast.File: // Join contiguous lone var/const/import lines. - // Abort if there are empty lines or comments in between, - // including a leading comment, which could be a directive. + // Abort if there are empty lines in between, + // including a leading comment if it's a directive. newDecls := make([]ast.Decl, 0, len(node.Decls)) for i := 0; i < len(node.Decls); { newDecls = append(newDecls, node.Decls[i]) start, ok := node.Decls[i].(*ast.GenDecl) - if !ok || isCgoImport(start) || start.Doc != nil { + if !ok || isCgoImport(start) || containsAnyDirective(start.Doc) { i++ continue } lastPos := start.Pos() + contLoop: for i++; i < len(node.Decls); { cont, ok := node.Decls[i].(*ast.GenDecl) - if !ok || cont.Tok != start.Tok || cont.Lparen != token.NoPos || - f.Line(lastPos) < f.Line(cont.Pos())-1 || isCgoImport(cont) { + if !ok || cont.Tok != start.Tok || cont.Lparen != token.NoPos || isCgoImport(cont) { break } + // Are there things between these two declarations? e.g. empty lines, comments, directives + // If so, break the chain on empty lines and directives, continue below for comments. + if f.Line(lastPos) < f.Line(cont.Pos())-1 { + // break on empty line + if cont.Doc == nil { + break + } + // break on directive + for i, comment := range cont.Doc.List { + if f.Line(comment.Slash) != f.Line(lastPos)+1+i || rxCommentDirective.MatchString(strings.TrimPrefix(comment.Text, "//")) { + break contLoop + } + } + // continue below for comments + } + start.Specs = append(start.Specs, cont.Specs...) if c := f.inlineComment(cont.End()); c != nil { // don't move an inline comment outside @@ -361,7 +377,8 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { pos = comments[0].Pos() } - multi := f.Line(pos) < f.Line(decl.End()) + // Note that we want End-1, as End is the character after the node. + multi := f.Line(pos) < f.Line(decl.End()-1) if multi && lastMulti && f.Line(lastEnd)+1 == f.Line(pos) { f.addNewline(lastEnd) } @@ -377,7 +394,9 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { if comment.Text == "//gofumpt:diagnose" || strings.HasPrefix(comment.Text, "//gofumpt:diagnose ") { slc := []string{ "//gofumpt:diagnose", + "version:", version.String(), + "flags:", "-lang=" + f.LangVersion, "-modpath=" + f.ModulePath, } @@ -553,7 +572,7 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { } } handleMultiLine(sign.Params) - if sign.Results != nil { + if sign.Results != nil && len(sign.Results.List) > 0 { lastResultLine := f.Line(sign.Results.List[len(sign.Results.List)-1].End()) isLastResultOnParamClosingLine := sign.Params != nil && lastResultLine == f.Line(sign.Params.Closing) if !isLastResultOnParamClosingLine { @@ -577,7 +596,13 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { // don't move comments break } - if f.printLength(node) > shortLineLimit { + // check the length excluding the body + nodeWithoutBody := &ast.CaseClause{ + Case: node.Case, + List: node.List, + Colon: node.Colon, + } + if f.printLength(nodeWithoutBody) > shortLineLimit { // too long to collapse break } @@ -850,11 +875,11 @@ func identEqual(expr ast.Expr, name string) bool { // isCgoImport returns true if the declaration is simply: // -// import "C" +// import "C" // // or the equivalent: // -// import `C` +// import `C` // // Note that parentheses do not affect the result. func isCgoImport(decl *ast.GenDecl) bool { @@ -1018,3 +1043,16 @@ func setPos(v reflect.Value, pos token.Pos) { } } } + +func containsAnyDirective(group *ast.CommentGroup) bool { + if group == nil { + return false + } + for _, comment := range group.List { + body := strings.TrimPrefix(comment.Text, "//") + if rxCommentDirective.MatchString(body) { + return true + } + } + return false +} diff --git a/tools/vendor/mvdan.cc/gofumpt/format/simplify.go b/tools/vendor/mvdan.cc/gofumpt/format/simplify.go index f2fd4d6b..11764646 100644 --- a/tools/vendor/mvdan.cc/gofumpt/format/simplify.go +++ b/tools/vendor/mvdan.cc/gofumpt/format/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/tools/vendor/mvdan.cc/gofumpt/internal/version/version.go b/tools/vendor/mvdan.cc/gofumpt/internal/version/version.go index 3ec8830d..99293048 100644 --- a/tools/vendor/mvdan.cc/gofumpt/internal/version/version.go +++ b/tools/vendor/mvdan.cc/gofumpt/internal/version/version.go @@ -4,28 +4,99 @@ package version import ( + "encoding/json" "fmt" "os" + "runtime" "runtime/debug" + "time" + + "golang.org/x/mod/module" ) -var version = "(devel)" // to match the default from runtime/debug +// Note that this is not a main package, so a "var version" will not work with +// our go-cross script which uses -ldflags=main.version=xxx. -func String() string { - if testVersion := os.Getenv("GOFUMPT_VERSION_TEST"); testVersion != "" { - return testVersion +const ourModulePath = "mvdan.cc/gofumpt" + +const fallbackVersion = "(devel)" // to match the default from runtime/debug + +func findModule(info *debug.BuildInfo, modulePath string) *debug.Module { + if info.Main.Path == modulePath { + return &info.Main } - // don't overwrite the version if it was set by -ldflags=-X - if info, ok := debug.ReadBuildInfo(); ok && version == "(devel)" { - mod := &info.Main - if mod.Replace != nil { - mod = mod.Replace + for _, dep := range info.Deps { + if dep.Path == modulePath { + return dep } - version = mod.Version } - return version + return nil } -func Print() { - fmt.Println(String()) +func gofumptVersion() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return fallbackVersion // no build info available + } + // Note that gofumpt may be used as a library via the format package, + // so we cannot assume it is the main module in the build. + mod := findModule(info, ourModulePath) + if mod == nil { + return fallbackVersion // not found? + } + if mod.Replace != nil { + mod = mod.Replace + } + + // If we found a meaningful version, we are done. + // If gofumpt is not the main module, stop as well, + // as VCS info is only for the main module. + if mod.Version != "(devel)" || mod != &info.Main { + return mod.Version + } + + // Fall back to trying to use VCS information. + // Until https://github.com/golang/go/issues/50603 is implemented, + // manually construct something like a pseudo-version. + // TODO: remove when this code is dead, hopefully in Go 1.20. + + // For the tests, as we don't want the VCS information to change over time. + if v := os.Getenv("GARBLE_TEST_BUILDSETTINGS"); v != "" { + var extra []debug.BuildSetting + if err := json.Unmarshal([]byte(v), &extra); err != nil { + panic(err) + } + info.Settings = append(info.Settings, extra...) + } + + var vcsTime time.Time + var vcsRevision string + for _, setting := range info.Settings { + switch setting.Key { + case "vcs.time": + // If the format is invalid, we'll print a zero timestamp. + vcsTime, _ = time.Parse(time.RFC3339Nano, setting.Value) + case "vcs.revision": + vcsRevision = setting.Value + if len(vcsRevision) > 12 { + vcsRevision = vcsRevision[:12] + } + } + } + if vcsRevision != "" { + return module.PseudoVersion("", "", vcsTime, vcsRevision) + } + return fallbackVersion +} + +func goVersion() string { + // For the tests, as we don't want the Go version to change over time. + if testVersion := os.Getenv("GO_VERSION_TEST"); testVersion != "" { + return testVersion + } + return runtime.Version() +} + +func String() string { + return fmt.Sprintf("%s (%s)", gofumptVersion(), goVersion()) }