From 4165372ec8fd142475a4e35fd0cf4f8042132208 Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Wed, 22 Feb 2023 22:16:50 +0100 Subject: dependencies: update set go min requirements to 1.19 update dependencies update vendor --- vendor/github.com/Abirdcfly/dupword/.gitignore | 183 + .../github.com/Abirdcfly/dupword/.goreleaser.yml | 72 + vendor/github.com/Abirdcfly/dupword/LICENSE | 21 + vendor/github.com/Abirdcfly/dupword/README.md | 151 + vendor/github.com/Abirdcfly/dupword/dupword.go | 302 + vendor/github.com/Abirdcfly/dupword/version.go | 41 + vendor/github.com/BurntSushi/toml/decode.go | 42 +- vendor/github.com/BurntSushi/toml/decode_go116.go | 4 +- vendor/github.com/BurntSushi/toml/doc.go | 22 +- vendor/github.com/BurntSushi/toml/encode.go | 40 +- vendor/github.com/BurntSushi/toml/error.go | 67 +- vendor/github.com/BurntSushi/toml/go.mod | 3 - vendor/github.com/BurntSushi/toml/lex.go | 2 +- vendor/github.com/BurntSushi/toml/meta.go | 4 +- vendor/github.com/Djarvur/go-err113/go.mod | 5 - vendor/github.com/Djarvur/go-err113/go.sum | 20 - .../go-exhaustruct/v2/pkg/analyzer/analyzer.go | 49 +- .../v2/pkg/analyzer/struct-fields.go | 42 +- vendor/github.com/OpenPeeDeeP/depguard/README.md | 2 +- vendor/github.com/OpenPeeDeeP/depguard/depguard.go | 12 + vendor/github.com/OpenPeeDeeP/depguard/go.mod | 10 - vendor/github.com/OpenPeeDeeP/depguard/go.sum | 16 - vendor/github.com/alingse/asasalint/asasalint.go | 2 +- vendor/github.com/alingse/asasalint/go.mod | 10 - vendor/github.com/alingse/asasalint/go.sum | 6 - .../ashanbrown/forbidigo/forbidigo/forbidigo.go | 190 +- .../ashanbrown/forbidigo/forbidigo/patterns.go | 106 +- vendor/github.com/blizzy78/varnamelen/go.mod | 13 - vendor/github.com/blizzy78/varnamelen/go.sum | 32 - vendor/github.com/bombsimon/wsl/v3/.golangci.yml | 78 + vendor/github.com/bombsimon/wsl/v3/.travis.yml | 25 - vendor/github.com/bombsimon/wsl/v3/README.md | 4 +- vendor/github.com/bombsimon/wsl/v3/go.mod | 12 - vendor/github.com/bombsimon/wsl/v3/go.sum | 25 - vendor/github.com/bombsimon/wsl/v3/wsl.go | 49 +- vendor/github.com/breml/errchkjson/go.mod | 11 - vendor/github.com/breml/errchkjson/go.sum | 30 - vendor/github.com/cespare/xxhash/v2/README.md | 31 +- vendor/github.com/cespare/xxhash/v2/go.mod | 3 - vendor/github.com/cespare/xxhash/v2/go.sum | 0 vendor/github.com/cespare/xxhash/v2/testall.sh | 10 + vendor/github.com/cespare/xxhash/v2/xxhash.go | 47 +- .../github.com/cespare/xxhash/v2/xxhash_amd64.go | 13 - vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s | 336 +- vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s | 183 + vendor/github.com/cespare/xxhash/v2/xxhash_asm.go | 15 + .../github.com/cespare/xxhash/v2/xxhash_other.go | 22 +- vendor/github.com/cespare/xxhash/v2/xxhash_safe.go | 1 + .../github.com/cespare/xxhash/v2/xxhash_unsafe.go | 3 +- vendor/github.com/charithe/durationcheck/go.mod | 5 - vendor/github.com/charithe/durationcheck/go.sum | 26 - vendor/github.com/chavacava/garif/go.mod | 5 - vendor/github.com/chavacava/garif/go.sum | 15 - .../curioswitch/go-reassign/.gitattributes | 2 + .../github.com/curioswitch/go-reassign/.gitignore | 6 + .../curioswitch/go-reassign/.golangci.yml | 38 + .../curioswitch/go-reassign/.goreleaser.yaml | 27 + vendor/github.com/curioswitch/go-reassign/LICENSE | 21 + .../github.com/curioswitch/go-reassign/README.md | 53 + .../github.com/curioswitch/go-reassign/analyzer.go | 13 + .../go-reassign/internal/analyzer/analyzer.go | 84 + vendor/github.com/daixiang0/gci/pkg/gci/gci.go | 40 +- vendor/github.com/daixiang0/gci/pkg/parse/parse.go | 106 +- .../github.com/daixiang0/gci/pkg/section/errors.go | 4 +- .../daixiang0/gci/pkg/section/standard_list.go | 3 +- .../daixiang0/gci/pkg/utils/constants.go | 6 +- vendor/github.com/denis-tingaikin/go-header/go.mod | 13 - vendor/github.com/denis-tingaikin/go-header/go.sum | 12 - .../dvyukov/go-fuzz/go-fuzz-build/cover.go | 2 +- .../dvyukov/go-fuzz/go-fuzz-build/main.go | 40 +- vendor/github.com/ettle/strcase/go.mod | 5 - vendor/github.com/ettle/strcase/go.sum | 11 - vendor/github.com/fatih/color/README.md | 14 +- vendor/github.com/fatih/color/color.go | 46 +- vendor/github.com/fatih/color/doc.go | 137 +- vendor/github.com/fatih/color/go.mod | 8 - vendor/github.com/fatih/color/go.sum | 9 - vendor/github.com/fatih/structtag/go.mod | 3 - vendor/github.com/felixge/httpsnoop/README.md | 3 +- .../felixge/httpsnoop/capture_metrics.go | 24 +- vendor/github.com/felixge/httpsnoop/go.mod | 3 - .../felixge/httpsnoop/wrap_generated_gteq_1.8.go | 115 +- .../felixge/httpsnoop/wrap_generated_lt_1.8.go | 67 +- vendor/github.com/fsnotify/fsnotify/.gitignore | 10 +- vendor/github.com/fsnotify/fsnotify/AUTHORS | 62 - vendor/github.com/fsnotify/fsnotify/CHANGELOG.md | 113 + .../github.com/fsnotify/fsnotify/CONTRIBUTING.md | 72 +- vendor/github.com/fsnotify/fsnotify/LICENSE | 47 +- vendor/github.com/fsnotify/fsnotify/README.md | 205 +- vendor/github.com/fsnotify/fsnotify/backend_fen.go | 162 + .../fsnotify/fsnotify/backend_inotify.go | 459 ++ .../github.com/fsnotify/fsnotify/backend_kqueue.go | 707 ++ .../github.com/fsnotify/fsnotify/backend_other.go | 66 + .../fsnotify/fsnotify/backend_windows.go | 746 ++ vendor/github.com/fsnotify/fsnotify/fen.go | 38 - vendor/github.com/fsnotify/fsnotify/fsnotify.go | 80 +- .../fsnotify/fsnotify/fsnotify_unsupported.go | 36 - vendor/github.com/fsnotify/fsnotify/go.mod | 10 - vendor/github.com/fsnotify/fsnotify/go.sum | 2 - vendor/github.com/fsnotify/fsnotify/inotify.go | 351 - .../github.com/fsnotify/fsnotify/inotify_poller.go | 187 - vendor/github.com/fsnotify/fsnotify/kqueue.go | 535 -- vendor/github.com/fsnotify/fsnotify/mkdoc.zsh | 208 + .../github.com/fsnotify/fsnotify/open_mode_bsd.go | 12 - .../fsnotify/fsnotify/open_mode_darwin.go | 13 - vendor/github.com/fsnotify/fsnotify/system_bsd.go | 8 + .../github.com/fsnotify/fsnotify/system_darwin.go | 9 + vendor/github.com/fsnotify/fsnotify/windows.go | 586 -- vendor/github.com/fzipp/gocyclo/go.mod | 3 - .../go-critic/checkers/badCond_checker.go | 27 +- .../go-critic/checkers/badRegexp_checker.go | 2 +- .../go-critic/checkers/dupBranchBody_checker.go | 2 +- .../go-critic/go-critic/checkers/embedded_rules.go | 6 +- .../go-critic/checkers/hugeParam_checker.go | 4 - .../go-critic/checkers/ifElseChain_checker.go | 23 +- .../checkers/internal/astwalk/local_def_visitor.go | 6 +- .../checkers/internal/astwalk/type_expr_walker.go | 5 +- .../go-critic/checkers/newDeref_checker.go | 5 + .../go-critic/checkers/rangeValCopy_checker.go | 7 +- .../go-critic/checkers/ruleguard_checker.go | 8 +- .../go-critic/checkers/rulesdata/rulesdata.go | 1198 +-- .../go-critic/go-critic/framework/linter/linter.go | 28 +- vendor/github.com/go-toolsmith/astcast/.travis.yml | 9 - vendor/github.com/go-toolsmith/astcast/README.md | 27 +- vendor/github.com/go-toolsmith/astcast/go.mod | 6 - vendor/github.com/go-toolsmith/astcast/go.sum | 4 - vendor/github.com/go-toolsmith/astcopy/.travis.yml | 9 - vendor/github.com/go-toolsmith/astcopy/README.md | 26 +- vendor/github.com/go-toolsmith/astcopy/astcopy.go | 46 +- .../go-toolsmith/astcopy/astcopy_go117.go | 30 + .../go-toolsmith/astcopy/astcopy_go118.go | 36 + vendor/github.com/go-toolsmith/astcopy/go.mod | 9 - vendor/github.com/go-toolsmith/astcopy/go.sum | 6 - .../github.com/go-toolsmith/astequal/.travis.yml | 9 - vendor/github.com/go-toolsmith/astequal/README.md | 27 +- .../github.com/go-toolsmith/astequal/astequal.go | 11 + vendor/github.com/go-toolsmith/astequal/go.mod | 7 - vendor/github.com/go-toolsmith/astequal/go.sum | 4 - vendor/github.com/go-toolsmith/astfmt/.travis.yml | 9 - vendor/github.com/go-toolsmith/astfmt/README.md | 26 +- vendor/github.com/go-toolsmith/astfmt/go.mod | 6 - vendor/github.com/go-toolsmith/astfmt/go.sum | 4 - vendor/github.com/go-toolsmith/astp/.gitignore | 4 - vendor/github.com/go-toolsmith/astp/.travis.yml | 9 - vendor/github.com/go-toolsmith/astp/README.md | 27 +- vendor/github.com/go-toolsmith/astp/go.mod | 6 - vendor/github.com/go-toolsmith/astp/go.sum | 4 - .../github.com/go-toolsmith/strparse/.travis.yml | 9 - vendor/github.com/go-toolsmith/strparse/README.md | 32 +- vendor/github.com/go-toolsmith/strparse/go.mod | 1 - vendor/github.com/go-toolsmith/typep/.travis.yml | 9 - vendor/github.com/go-toolsmith/typep/README.md | 29 +- vendor/github.com/go-toolsmith/typep/go.mod | 1 - vendor/github.com/go-toolsmith/typep/safeExpr.go | 73 - vendor/github.com/go-toolsmith/typep/safe_expr.go | 73 + .../go-toolsmith/typep/simplePredicates.go | 359 - .../go-toolsmith/typep/simple_predicates.go | 359 + vendor/github.com/go-xmlfmt/xmlfmt/README.md | 113 +- vendor/github.com/go-xmlfmt/xmlfmt/xmlfmt.go | 54 +- .../golang/protobuf/ptypes/empty/empty.pb.go | 62 - vendor/github.com/golangci/gofmt/gofmt/gofmt.go | 433 +- vendor/github.com/golangci/gofmt/gofmt/golangci.go | 60 +- vendor/github.com/golangci/gofmt/gofmt/internal.go | 8 +- .../golangci/gofmt/gofmt/internal/diff/diff.go | 79 + .../gofmt/gofmt/internal/execabs/execabs.go | 70 + vendor/github.com/golangci/gofmt/gofmt/readme.md | 3 + vendor/github.com/golangci/gofmt/gofmt/rewrite.go | 14 +- .../golangci/gofmt/goimports/goimports.go | 271 +- .../golangci/gofmt/goimports/golangci.go | 4 +- .../github.com/golangci/gofmt/goimports/readme.md | 3 + .../golangci/golangci-lint/internal/cache/cache.go | 13 +- .../golangci-lint/internal/cache/default.go | 8 +- .../golangci-lint/internal/cache/readme.md | 18 + .../golangci-lint/internal/renameio/readme.md | 10 + .../golangci-lint/internal/robustio/readme.md | 6 + .../golangci-lint/internal/robustio/robustio.go | 6 +- .../internal/robustio/robustio_darwin.go | 14 +- .../internal/robustio/robustio_flaky.go | 13 +- .../internal/robustio/robustio_other.go | 2 +- .../internal/robustio/robustio_windows.go | 17 +- .../golangci/golangci-lint/pkg/commands/cache.go | 48 +- .../golangci/golangci-lint/pkg/commands/config.go | 25 +- .../golangci-lint/pkg/commands/executor.go | 23 +- .../golangci/golangci-lint/pkg/commands/help.go | 28 +- .../golangci/golangci-lint/pkg/commands/linters.go | 22 +- .../golangci/golangci-lint/pkg/commands/root.go | 54 +- .../golangci/golangci-lint/pkg/commands/run.go | 26 +- .../golangci/golangci-lint/pkg/commands/version.go | 18 +- .../golangci/golangci-lint/pkg/config/issues.go | 9 +- .../golangci-lint/pkg/config/linters_settings.go | 142 +- .../pkg/config/linters_settings_gocritic.go | 366 - .../golangci/golangci-lint/pkg/config/reader.go | 6 +- .../golangci-lint/pkg/fsutils/path_unix.go | 8 + .../golangci-lint/pkg/fsutils/path_windows.go | 28 + .../golangci-lint/pkg/golinters/commons.go | 2 +- .../golangci-lint/pkg/golinters/contextcheck.go | 15 +- .../golangci-lint/pkg/golinters/depguard.go | 8 +- .../golangci/golangci-lint/pkg/golinters/dupl.go | 6 +- .../golangci-lint/pkg/golinters/dupword.go | 29 + .../golangci-lint/pkg/golinters/exhaustive.go | 4 + .../golangci-lint/pkg/golinters/forbidigo.go | 2 +- .../golangci/golangci-lint/pkg/golinters/gci.go | 41 +- .../golangci-lint/pkg/golinters/ginkgolinter.go | 29 + .../pkg/golinters/goanalysis/linter.go | 2 +- .../pkg/golinters/goanalysis/runner.go | 18 +- .../pkg/golinters/goanalysis/runner_action.go | 3 +- .../golinters/goanalysis/runner_loadingpackage.go | 11 +- .../goanalysis/runner_loadingpackage_ti.go | 21 - .../goanalysis/runner_loadingpackage_ti_go117.go | 20 - .../pkg/golinters/goanalysis/runners.go | 3 +- .../pkg/golinters/gocheckcompilerdirectives.go | 19 + .../pkg/golinters/gochecknoglobals.go | 2 +- .../golangci-lint/pkg/golinters/gocritic.go | 473 +- .../golangci/golangci-lint/pkg/golinters/godot.go | 2 +- .../golangci/golangci-lint/pkg/golinters/gofmt.go | 11 +- .../golangci-lint/pkg/golinters/gofmt_common.go | 5 +- .../golangci-lint/pkg/golinters/gofumpt.go | 6 +- .../golangci-lint/pkg/golinters/goimports.go | 13 +- .../golangci-lint/pkg/golinters/gomodguard.go | 7 +- .../golangci/golangci-lint/pkg/golinters/govet.go | 10 +- .../golangci-lint/pkg/golinters/importas.go | 4 +- .../golangci-lint/pkg/golinters/interfacebloat.go | 29 + .../golangci/golangci-lint/pkg/golinters/lll.go | 29 +- .../golangci-lint/pkg/golinters/loggercheck.go | 44 + .../golangci-lint/pkg/golinters/misspell.go | 7 +- .../golangci-lint/pkg/golinters/musttag.go | 29 + .../golangci-lint/pkg/golinters/nolintlint.go | 3 - .../pkg/golinters/nolintlint/README.md | 10 +- .../pkg/golinters/nolintlint/nolintlint.go | 13 +- .../golangci-lint/pkg/golinters/paralleltest.go | 2 +- .../golangci-lint/pkg/golinters/reassign.go | 32 + .../golangci/golangci-lint/pkg/golinters/revive.go | 9 +- .../pkg/golinters/staticcheck_common.go | 5 +- .../golangci-lint/pkg/golinters/tagliatelle.go | 5 +- .../pkg/golinters/testableexamples.go | 19 + .../golangci/golangci-lint/pkg/golinters/unused.go | 10 +- .../golangci-lint/pkg/golinters/usestdlibvars.go | 38 + .../golangci/golangci-lint/pkg/golinters/util.go | 17 + .../golangci/golangci-lint/pkg/golinters/wsl.go | 21 +- .../golangci/golangci-lint/pkg/goutil/env.go | 2 +- .../golangci-lint/pkg/lint/linter/linter.go | 4 +- .../pkg/lint/lintersdb/enabled_set.go | 7 +- .../golangci-lint/pkg/lint/lintersdb/manager.go | 124 +- .../golangci-lint/pkg/lint/lintersdb/validator.go | 7 +- .../golangci/golangci-lint/pkg/lint/load.go | 16 +- .../golangci/golangci-lint/pkg/lint/runner.go | 23 +- .../golangci/golangci-lint/pkg/logutils/log.go | 8 +- .../golangci-lint/pkg/logutils/logutils.go | 58 +- .../golangci-lint/pkg/logutils/stderr_log.go | 13 +- .../golangci-lint/pkg/printers/checkstyle.go | 4 +- .../golangci-lint/pkg/printers/codeclimate.go | 9 +- .../golangci/golangci-lint/pkg/printers/tab.go | 4 +- .../golangci/golangci-lint/pkg/printers/text.go | 6 +- .../pkg/result/processors/autogenerated_exclude.go | 11 +- .../pkg/result/processors/base_rule.go | 2 +- .../golangci-lint/pkg/result/processors/diff.go | 4 +- .../pkg/result/processors/exclude_rules.go | 3 +- .../pkg/result/processors/filename_unadjuster.go | 4 +- .../golangci-lint/pkg/result/processors/fixer.go | 7 +- .../golangci-lint/pkg/result/processors/issues.go | 46 + .../pkg/result/processors/max_from_linter.go | 4 +- .../result/processors/max_per_file_from_linter.go | 4 +- .../pkg/result/processors/max_same_issues.go | 4 +- .../golangci-lint/pkg/result/processors/nolint.go | 20 +- .../pkg/result/processors/path_prefixer.go | 4 +- .../pkg/result/processors/path_shortener.go | 4 +- .../pkg/result/processors/severity_rules.go | 3 +- .../pkg/result/processors/skip_dirs.go | 3 +- .../pkg/result/processors/skip_files.go | 3 +- .../pkg/result/processors/sort_results.go | 6 - .../pkg/result/processors/uniq_by_line.go | 4 +- .../golangci-lint/pkg/result/processors/utils.go | 62 - vendor/github.com/golangci/lint-1/go.mod | 3 - vendor/github.com/golangci/lint-1/go.sum | 6 - vendor/github.com/golangci/misspell/.gitignore | 3 + vendor/github.com/golangci/misspell/.golangci.yml | 106 + vendor/github.com/golangci/misspell/.travis.yml | 20 - vendor/github.com/golangci/misspell/Dockerfile | 3 - vendor/github.com/golangci/misspell/Gopkg.lock | 24 - vendor/github.com/golangci/misspell/Gopkg.toml | 34 - vendor/github.com/golangci/misspell/LICENSE | 1 - vendor/github.com/golangci/misspell/Makefile | 27 +- vendor/github.com/golangci/misspell/README.md | 2 +- vendor/github.com/golangci/misspell/ascii.go | 16 +- vendor/github.com/golangci/misspell/case.go | 15 +- vendor/github.com/golangci/misspell/goreleaser.yml | 25 +- vendor/github.com/golangci/misspell/legal.go | 5 +- vendor/github.com/golangci/misspell/mime.go | 65 +- vendor/github.com/golangci/misspell/notwords.go | 16 +- vendor/github.com/golangci/misspell/replace.go | 50 +- .../github.com/golangci/misspell/stringreplacer.go | 151 +- vendor/github.com/golangci/misspell/url.go | 7 +- vendor/github.com/golangci/revgrep/go.mod | 3 - vendor/github.com/golangci/revgrep/go.sum | 0 vendor/github.com/google/go-cmp/cmp/compare.go | 64 +- .../google/go-cmp/cmp/internal/diff/diff.go | 44 +- .../google/go-cmp/cmp/internal/value/zero.go | 48 - vendor/github.com/google/go-cmp/cmp/options.go | 10 +- vendor/github.com/google/go-cmp/cmp/path.go | 20 +- .../github.com/google/go-cmp/cmp/report_compare.go | 10 +- .../github.com/google/go-cmp/cmp/report_reflect.go | 11 +- .../github.com/google/go-cmp/cmp/report_slices.go | 25 +- vendor/github.com/google/go-cmp/cmp/report_text.go | 1 + vendor/github.com/google/pprof/profile/encode.go | 76 +- vendor/github.com/google/pprof/profile/filter.go | 4 + .../google/pprof/profile/legacy_profile.go | 1 - vendor/github.com/google/pprof/profile/merge.go | 257 +- vendor/github.com/google/pprof/profile/profile.go | 52 +- vendor/github.com/google/pprof/profile/proto.go | 19 +- vendor/github.com/google/pprof/profile/prune.go | 26 +- vendor/github.com/google/safehtml/CONTRIBUTING.md | 29 + vendor/github.com/google/safehtml/LICENSE | 27 + vendor/github.com/google/safehtml/README.md | 17 + vendor/github.com/google/safehtml/doc.go | 11 + vendor/github.com/google/safehtml/html.go | 117 + vendor/github.com/google/safehtml/identifier.go | 83 + vendor/github.com/google/safehtml/init.go | 58 + .../github.com/google/safehtml/internal/raw/raw.go | 31 + .../safehtml/internal/safehtmlutil/safehtmlutil.go | 180 + .../google/safehtml/internal/template/raw/raw.go | 16 + vendor/github.com/google/safehtml/script.go | 90 + vendor/github.com/google/safehtml/style.go | 304 + vendor/github.com/google/safehtml/stylesheet.go | 111 + .../github.com/google/safehtml/template/context.go | 183 + .../google/safehtml/template/delim_string.go | 16 + vendor/github.com/google/safehtml/template/doc.go | 291 + .../github.com/google/safehtml/template/error.go | 280 + .../github.com/google/safehtml/template/escape.go | 884 +++ vendor/github.com/google/safehtml/template/init.go | 28 + .../google/safehtml/template/sanitize.go | 258 + .../google/safehtml/template/sanitizers.go | 599 ++ .../google/safehtml/template/state_string.go | 16 + .../google/safehtml/template/template.go | 651 ++ .../template/testdata/dir1/parsefiles_t1.tmpl | 1 + .../template/testdata/dir2/parsefiles_t2.tmpl | 1 + .../google/safehtml/template/testdata/glob_t0.tmpl | 1 + .../google/safehtml/template/testdata/glob_t1.tmpl | 1 + .../google/safehtml/template/testdata/glob_t2.tmpl | 1 + .../safehtml/template/testdata/helpers_t1.tmpl | 1 + .../safehtml/template/testdata/helpers_t2.tmpl | 1 + .../safehtml/template/testdata/share_t0.tmpl | 1 + .../safehtml/template/testdata/share_t1.tmpl | 1 + .../google/safehtml/template/transition.go | 312 + .../google/safehtml/template/trustedfs.go | 98 + .../google/safehtml/template/trustedsource.go | 105 + .../google/safehtml/template/trustedtemplate.go | 36 + vendor/github.com/google/safehtml/template/url.go | 122 + .../google/safehtml/trustedresourceurl.go | 195 + .../uncheckedconversions/uncheckedconversions.go | 131 + vendor/github.com/google/safehtml/url.go | 127 + vendor/github.com/google/safehtml/urlset.go | 167 + vendor/github.com/google/uuid/go.mod | 1 - .../enterprise-certificate-proxy/client/client.go | 52 +- .../client/util/util.go | 35 +- .../gax-go/v2/.release-please-manifest.json | 2 +- vendor/github.com/googleapis/gax-go/v2/CHANGES.md | 15 + .../googleapis/gax-go/v2/apierror/apierror.go | 45 +- .../googleapis/gax-go/v2/content_type.go | 112 + vendor/github.com/googleapis/gax-go/v2/go.mod | 19 - vendor/github.com/googleapis/gax-go/v2/go.sum | 649 -- .../googleapis/gax-go/v2/internal/version.go | 2 +- .../ineffassign/pkg/ineffassign/ineffassign.go | 11 +- vendor/github.com/gorilla/handlers/go.mod | 5 - vendor/github.com/gorilla/handlers/go.sum | 2 - .../gostaticanalysis/analysisutil/go.mod | 10 - .../gostaticanalysis/analysisutil/go.sum | 51 - vendor/github.com/gostaticanalysis/comment/go.mod | 9 - vendor/github.com/gostaticanalysis/comment/go.sum | 48 - .../gostaticanalysis/forcetypeassert/go.mod | 5 - .../gostaticanalysis/forcetypeassert/go.sum | 6 - vendor/github.com/gostaticanalysis/nilerr/go.mod | 8 - vendor/github.com/gostaticanalysis/nilerr/go.sum | 34 - vendor/github.com/hashicorp/errwrap/errwrap.go | 9 + vendor/github.com/hashicorp/errwrap/go.mod | 1 - vendor/github.com/hashicorp/go-multierror/go.mod | 5 - vendor/github.com/hashicorp/go-multierror/go.sum | 2 - vendor/github.com/hashicorp/go-version/go.mod | 1 - vendor/github.com/hashicorp/hcl/go.mod | 3 - vendor/github.com/hashicorp/hcl/go.sum | 2 - vendor/github.com/hexops/gotextdiff/go.mod | 3 - vendor/github.com/ianlancetaylor/demangle/ast.go | 52 +- .../github.com/ianlancetaylor/demangle/demangle.go | 546 +- vendor/github.com/ianlancetaylor/demangle/go.mod | 3 - vendor/github.com/ianlancetaylor/demangle/rust.go | 190 +- .../github.com/inconshreveable/mousetrap/LICENSE | 208 +- .../inconshreveable/mousetrap/trap_others.go | 1 + .../inconshreveable/mousetrap/trap_windows.go | 88 +- .../inconshreveable/mousetrap/trap_windows_1.4.go | 46 - vendor/github.com/jgautheron/goconst/go.mod | 3 - vendor/github.com/json-iterator/go/.codecov.yml | 3 + vendor/github.com/json-iterator/go/.gitignore | 4 + vendor/github.com/json-iterator/go/.travis.yml | 14 + vendor/github.com/json-iterator/go/Gopkg.lock | 21 + vendor/github.com/json-iterator/go/Gopkg.toml | 26 + vendor/github.com/json-iterator/go/LICENSE | 21 + vendor/github.com/json-iterator/go/README.md | 85 + vendor/github.com/json-iterator/go/adapter.go | 150 + vendor/github.com/json-iterator/go/any.go | 325 + vendor/github.com/json-iterator/go/any_array.go | 278 + vendor/github.com/json-iterator/go/any_bool.go | 137 + vendor/github.com/json-iterator/go/any_float.go | 83 + vendor/github.com/json-iterator/go/any_int32.go | 74 + vendor/github.com/json-iterator/go/any_int64.go | 74 + vendor/github.com/json-iterator/go/any_invalid.go | 82 + vendor/github.com/json-iterator/go/any_nil.go | 69 + vendor/github.com/json-iterator/go/any_number.go | 123 + vendor/github.com/json-iterator/go/any_object.go | 374 + vendor/github.com/json-iterator/go/any_str.go | 166 + vendor/github.com/json-iterator/go/any_uint32.go | 74 + vendor/github.com/json-iterator/go/any_uint64.go | 74 + vendor/github.com/json-iterator/go/build.sh | 12 + vendor/github.com/json-iterator/go/config.go | 375 + .../json-iterator/go/fuzzy_mode_convert_table.md | 7 + vendor/github.com/json-iterator/go/iter.go | 349 + vendor/github.com/json-iterator/go/iter_array.go | 64 + vendor/github.com/json-iterator/go/iter_float.go | 342 + vendor/github.com/json-iterator/go/iter_int.go | 346 + vendor/github.com/json-iterator/go/iter_object.go | 267 + vendor/github.com/json-iterator/go/iter_skip.go | 130 + .../json-iterator/go/iter_skip_sloppy.go | 163 + .../json-iterator/go/iter_skip_strict.go | 99 + vendor/github.com/json-iterator/go/iter_str.go | 215 + vendor/github.com/json-iterator/go/jsoniter.go | 18 + vendor/github.com/json-iterator/go/pool.go | 42 + vendor/github.com/json-iterator/go/reflect.go | 337 + .../github.com/json-iterator/go/reflect_array.go | 104 + .../github.com/json-iterator/go/reflect_dynamic.go | 70 + .../json-iterator/go/reflect_extension.go | 483 ++ .../json-iterator/go/reflect_json_number.go | 112 + .../json-iterator/go/reflect_json_raw_message.go | 76 + vendor/github.com/json-iterator/go/reflect_map.go | 346 + .../json-iterator/go/reflect_marshaler.go | 225 + .../github.com/json-iterator/go/reflect_native.go | 453 ++ .../json-iterator/go/reflect_optional.go | 129 + .../github.com/json-iterator/go/reflect_slice.go | 99 + .../json-iterator/go/reflect_struct_decoder.go | 1097 +++ .../json-iterator/go/reflect_struct_encoder.go | 211 + vendor/github.com/json-iterator/go/stream.go | 210 + vendor/github.com/json-iterator/go/stream_float.go | 111 + vendor/github.com/json-iterator/go/stream_int.go | 190 + vendor/github.com/json-iterator/go/stream_str.go | 372 + vendor/github.com/json-iterator/go/test.sh | 12 + vendor/github.com/julz/importas/go.mod | 5 - vendor/github.com/julz/importas/go.sum | 26 - vendor/github.com/junk1tm/musttag/.golangci.yml | 23 + vendor/github.com/junk1tm/musttag/.goreleaser.yml | 30 + vendor/github.com/junk1tm/musttag/LICENSE | 21 + vendor/github.com/junk1tm/musttag/README.md | 93 + vendor/github.com/junk1tm/musttag/builtins.go | 40 + vendor/github.com/junk1tm/musttag/musttag.go | 251 + vendor/github.com/junk1tm/musttag/utils.go | 40 + .../kisielk/errcheck/errcheck/errcheck.go | 141 +- vendor/github.com/kisielk/gotool/go.mod | 1 - vendor/github.com/kkHAIKE/contextcheck/.gitignore | 18 + vendor/github.com/kkHAIKE/contextcheck/LICENSE | 201 + vendor/github.com/kkHAIKE/contextcheck/Makefile | 5 + vendor/github.com/kkHAIKE/contextcheck/README.md | 157 + .../kkHAIKE/contextcheck/contextcheck.go | 835 +++ .../kyoh86/exportloopref/.goreleaser.yml | 88 +- vendor/github.com/kyoh86/exportloopref/README.md | 8 +- .../kyoh86/exportloopref/exportloopref.go | 169 +- vendor/github.com/kyoh86/exportloopref/go.mod | 5 - vendor/github.com/kyoh86/exportloopref/go.sum | 20 - vendor/github.com/ldez/gomoddirectives/go.mod | 8 - vendor/github.com/ldez/gomoddirectives/go.sum | 25 - vendor/github.com/ldez/tagliatelle/.golangci.yml | 17 +- vendor/github.com/ldez/tagliatelle/go.mod | 8 - vendor/github.com/ldez/tagliatelle/go.sum | 38 - vendor/github.com/ldez/tagliatelle/readme.md | 91 + vendor/github.com/ldez/tagliatelle/tagliatelle.go | 6 + vendor/github.com/leonklingele/grouper/LICENSE | 156 +- vendor/github.com/lufeee/execinquery/go.mod | 19 - vendor/github.com/lufeee/execinquery/go.sum | 62 - .../github.com/magiconair/properties/.travis.yml | 17 - .../github.com/magiconair/properties/CHANGELOG.md | 45 + vendor/github.com/magiconair/properties/decode.go | 66 +- vendor/github.com/magiconair/properties/doc.go | 127 +- vendor/github.com/magiconair/properties/go.mod | 3 - .../github.com/magiconair/properties/integrate.go | 7 +- vendor/github.com/magiconair/properties/lex.go | 2 +- vendor/github.com/magiconair/properties/load.go | 2 +- vendor/github.com/magiconair/properties/parser.go | 2 +- .../github.com/magiconair/properties/properties.go | 17 +- .../github.com/magiconair/properties/rangecheck.go | 2 +- .../github.com/maratori/testableexamples/LICENSE | 21 + .../pkg/testableexamples/testableexamples.go | 34 + vendor/github.com/matoous/godox/go.mod | 5 - vendor/github.com/matoous/godox/go.sum | 8 - vendor/github.com/matoous/godox/godox.go | 101 +- vendor/github.com/mattn/go-colorable/go.mod | 5 - vendor/github.com/mattn/go-colorable/go.sum | 4 - vendor/github.com/mattn/go-isatty/go.mod | 5 - vendor/github.com/mattn/go-isatty/go.sum | 2 - vendor/github.com/mattn/go-isatty/isatty_bsd.go | 4 +- vendor/github.com/mattn/go-runewidth/.travis.yml | 16 - vendor/github.com/mattn/go-runewidth/README.md | 2 +- vendor/github.com/mattn/go-runewidth/go.mod | 3 - vendor/github.com/mattn/go-runewidth/go.test.sh | 12 - vendor/github.com/mattn/go-runewidth/runewidth.go | 205 +- .../mattn/go-runewidth/runewidth_appengine.go | 1 + .../github.com/mattn/go-runewidth/runewidth_js.go | 4 +- .../mattn/go-runewidth/runewidth_posix.go | 5 +- .../mattn/go-runewidth/runewidth_table.go | 6 +- .../mattn/go-runewidth/runewidth_windows.go | 4 +- vendor/github.com/mgechev/revive/config/config.go | 1 + .../github.com/mgechev/revive/formatter/sarif.go | 4 +- .../github.com/mgechev/revive/rule/add-constant.go | 101 +- .../mgechev/revive/rule/comment-spacings.go | 82 + .../github.com/mgechev/revive/rule/early-return.go | 156 +- .../github.com/mgechev/revive/rule/empty-lines.go | 4 +- .../mgechev/revive/rule/function-length.go | 8 +- .../mgechev/revive/rule/identical-branches.go | 4 +- .../mgechev/revive/rule/nested-structs.go | 10 + .../mgechev/revive/rule/string-format.go | 36 +- .../mgechev/revive/rule/unconditional-recursion.go | 6 +- .../mgechev/revive/rule/unhandled-error.go | 66 +- vendor/github.com/mitchellh/go-homedir/go.mod | 1 - vendor/github.com/mitchellh/mapstructure/go.mod | 3 - vendor/github.com/modern-go/concurrent/.gitignore | 1 + vendor/github.com/modern-go/concurrent/.travis.yml | 14 + vendor/github.com/modern-go/concurrent/LICENSE | 201 + vendor/github.com/modern-go/concurrent/README.md | 49 + vendor/github.com/modern-go/concurrent/executor.go | 14 + .../github.com/modern-go/concurrent/go_above_19.go | 15 + .../github.com/modern-go/concurrent/go_below_19.go | 33 + vendor/github.com/modern-go/concurrent/log.go | 13 + vendor/github.com/modern-go/concurrent/test.sh | 12 + .../modern-go/concurrent/unbounded_executor.go | 119 + vendor/github.com/modern-go/reflect2/.gitignore | 2 + vendor/github.com/modern-go/reflect2/.travis.yml | 15 + vendor/github.com/modern-go/reflect2/Gopkg.lock | 9 + vendor/github.com/modern-go/reflect2/Gopkg.toml | 31 + vendor/github.com/modern-go/reflect2/LICENSE | 201 + vendor/github.com/modern-go/reflect2/README.md | 71 + .../github.com/modern-go/reflect2/go_above_118.go | 23 + .../github.com/modern-go/reflect2/go_above_19.go | 17 + .../github.com/modern-go/reflect2/go_below_118.go | 21 + vendor/github.com/modern-go/reflect2/reflect2.go | 300 + .../github.com/modern-go/reflect2/reflect2_amd64.s | 0 .../github.com/modern-go/reflect2/reflect2_kind.go | 30 + .../github.com/modern-go/reflect2/relfect2_386.s | 0 .../modern-go/reflect2/relfect2_amd64p32.s | 0 .../github.com/modern-go/reflect2/relfect2_arm.s | 0 .../github.com/modern-go/reflect2/relfect2_arm64.s | 0 .../modern-go/reflect2/relfect2_mips64x.s | 0 .../github.com/modern-go/reflect2/relfect2_mipsx.s | 0 .../modern-go/reflect2/relfect2_ppc64x.s | 0 .../github.com/modern-go/reflect2/relfect2_s390x.s | 0 vendor/github.com/modern-go/reflect2/safe_field.go | 58 + vendor/github.com/modern-go/reflect2/safe_map.go | 101 + vendor/github.com/modern-go/reflect2/safe_slice.go | 92 + .../github.com/modern-go/reflect2/safe_struct.go | 29 + vendor/github.com/modern-go/reflect2/safe_type.go | 78 + vendor/github.com/modern-go/reflect2/type_map.go | 70 + .../github.com/modern-go/reflect2/unsafe_array.go | 65 + .../github.com/modern-go/reflect2/unsafe_eface.go | 59 + .../github.com/modern-go/reflect2/unsafe_field.go | 74 + .../github.com/modern-go/reflect2/unsafe_iface.go | 64 + .../github.com/modern-go/reflect2/unsafe_link.go | 76 + vendor/github.com/modern-go/reflect2/unsafe_map.go | 130 + vendor/github.com/modern-go/reflect2/unsafe_ptr.go | 46 + .../github.com/modern-go/reflect2/unsafe_slice.go | 177 + .../github.com/modern-go/reflect2/unsafe_struct.go | 59 + .../github.com/modern-go/reflect2/unsafe_type.go | 85 + vendor/github.com/moricho/tparallel/go.mod | 8 - vendor/github.com/moricho/tparallel/go.sum | 34 - vendor/github.com/nakabonne/nestif/go.mod | 8 - vendor/github.com/nakabonne/nestif/go.sum | 12 - vendor/github.com/nbutton23/zxcvbn-go/go.mod | 9 - vendor/github.com/nbutton23/zxcvbn-go/go.sum | 5 - vendor/github.com/nishanths/exhaustive/.gitignore | 8 +- vendor/github.com/nishanths/exhaustive/Makefile | 17 +- vendor/github.com/nishanths/exhaustive/README.md | 81 +- vendor/github.com/nishanths/exhaustive/comment.go | 58 +- vendor/github.com/nishanths/exhaustive/common.go | 368 + .../nishanths/exhaustive/common_go118.go | 122 + .../nishanths/exhaustive/common_pre_go118.go | 37 + vendor/github.com/nishanths/exhaustive/enum.go | 92 +- .../github.com/nishanths/exhaustive/exhaustive.go | 493 +- vendor/github.com/nishanths/exhaustive/flag.go | 75 + vendor/github.com/nishanths/exhaustive/go.mod | 5 - vendor/github.com/nishanths/exhaustive/go.sum | 29 - vendor/github.com/nishanths/exhaustive/map.go | 134 + vendor/github.com/nishanths/exhaustive/switch.go | 363 +- vendor/github.com/nunnatsa/ginkgolinter/.gitignore | 2 + vendor/github.com/nunnatsa/ginkgolinter/LICENSE | 21 + vendor/github.com/nunnatsa/ginkgolinter/Makefile | 14 + vendor/github.com/nunnatsa/ginkgolinter/README.md | 181 + .../nunnatsa/ginkgolinter/ginkgo_linter.go | 662 ++ .../nunnatsa/ginkgolinter/gomegahandler/handler.go | 167 + .../reverseassertion/reverse_assertion.go | 17 + .../nunnatsa/ginkgolinter/types/boolean.go | 32 + .../nunnatsa/ginkgolinter/types/suppress.go | 67 + vendor/github.com/olekukonko/tablewriter/go.mod | 5 - vendor/github.com/olekukonko/tablewriter/go.sum | 2 - vendor/github.com/pelletier/go-toml/.dockerignore | 2 - vendor/github.com/pelletier/go-toml/.gitignore | 5 - .../github.com/pelletier/go-toml/CONTRIBUTING.md | 132 - vendor/github.com/pelletier/go-toml/Dockerfile | 11 - vendor/github.com/pelletier/go-toml/LICENSE | 247 - vendor/github.com/pelletier/go-toml/Makefile | 29 - .../pelletier/go-toml/PULL_REQUEST_TEMPLATE.md | 5 - vendor/github.com/pelletier/go-toml/README.md | 176 - vendor/github.com/pelletier/go-toml/SECURITY.md | 19 - .../pelletier/go-toml/azure-pipelines.yml | 188 - vendor/github.com/pelletier/go-toml/benchmark.sh | 35 - vendor/github.com/pelletier/go-toml/doc.go | 23 - .../github.com/pelletier/go-toml/example-crlf.toml | 30 - vendor/github.com/pelletier/go-toml/example.toml | 30 - vendor/github.com/pelletier/go-toml/fuzz.go | 31 - vendor/github.com/pelletier/go-toml/fuzz.sh | 15 - vendor/github.com/pelletier/go-toml/go.mod | 3 - vendor/github.com/pelletier/go-toml/keysparsing.go | 112 - vendor/github.com/pelletier/go-toml/lexer.go | 1031 --- vendor/github.com/pelletier/go-toml/localtime.go | 287 - vendor/github.com/pelletier/go-toml/marshal.go | 1308 ---- .../go-toml/marshal_OrderPreserve_test.toml | 39 - .../github.com/pelletier/go-toml/marshal_test.toml | 39 - vendor/github.com/pelletier/go-toml/parser.go | 507 -- vendor/github.com/pelletier/go-toml/position.go | 29 - vendor/github.com/pelletier/go-toml/token.go | 136 - vendor/github.com/pelletier/go-toml/toml.go | 533 -- vendor/github.com/pelletier/go-toml/tomlpub.go | 71 - .../pelletier/go-toml/tomltree_create.go | 155 - .../github.com/pelletier/go-toml/tomltree_write.go | 552 -- .../pelletier/go-toml/tomltree_writepub.go | 6 - vendor/github.com/pelletier/go-toml/v2/README.md | 11 + vendor/github.com/pelletier/go-toml/v2/decode.go | 88 +- vendor/github.com/pelletier/go-toml/v2/errors.go | 33 +- vendor/github.com/pelletier/go-toml/v2/go.mod | 5 - vendor/github.com/pelletier/go-toml/v2/go.sum | 11 - .../pelletier/go-toml/v2/internal/ast/ast.go | 144 - .../pelletier/go-toml/v2/internal/ast/builder.go | 51 - .../pelletier/go-toml/v2/internal/ast/kind.go | 69 - .../go-toml/v2/internal/characters/ascii.go | 42 + .../go-toml/v2/internal/characters/utf8.go | 199 + .../pelletier/go-toml/v2/internal/tracker/key.go | 12 +- .../pelletier/go-toml/v2/internal/tracker/seen.go | 28 +- .../github.com/pelletier/go-toml/v2/localtime.go | 6 +- .../github.com/pelletier/go-toml/v2/marshaler.go | 95 +- vendor/github.com/pelletier/go-toml/v2/parser.go | 1086 --- vendor/github.com/pelletier/go-toml/v2/scanner.go | 269 - vendor/github.com/pelletier/go-toml/v2/strict.go | 34 +- vendor/github.com/pelletier/go-toml/v2/types.go | 10 +- .../github.com/pelletier/go-toml/v2/unmarshaler.go | 180 +- .../pelletier/go-toml/v2/unstable/ast.go | 136 + .../pelletier/go-toml/v2/unstable/builder.go | 71 + .../pelletier/go-toml/v2/unstable/doc.go | 3 + .../pelletier/go-toml/v2/unstable/kind.go | 71 + .../pelletier/go-toml/v2/unstable/parser.go | 1147 +++ .../pelletier/go-toml/v2/unstable/scanner.go | 271 + vendor/github.com/pelletier/go-toml/v2/utf8.go | 240 - .../github.com/phayes/checkstyle/.scrutinizer.yml | 15 - vendor/github.com/phayes/checkstyle/LICENSE | 29 - vendor/github.com/phayes/checkstyle/README.md | 44 - vendor/github.com/phayes/checkstyle/checkstyle.go | 112 - vendor/github.com/phayes/checkstyle/godoc.go | 36 - .../polyfloyd/go-errorlint/errorlint/allowed.go | 1 + .../polyfloyd/go-errorlint/errorlint/analysis.go | 14 +- .../polyfloyd/go-errorlint/errorlint/lint.go | 83 +- .../polyfloyd/go-errorlint/errorlint/printf.go | 3 + .../client_golang/prometheus/collector.go | 6 +- .../prometheus/client_golang/prometheus/counter.go | 13 +- .../prometheus/client_golang/prometheus/desc.go | 5 +- .../prometheus/client_golang/prometheus/doc.go | 107 +- .../prometheus/client_golang/prometheus/gauge.go | 6 +- .../prometheus/client_golang/prometheus/get_pid.go | 26 + .../client_golang/prometheus/get_pid_gopherjs.go | 23 + .../client_golang/prometheus/go_collector.go | 20 +- .../client_golang/prometheus/go_collector_go116.go | 17 +- .../client_golang/prometheus/go_collector_go117.go | 408 -- .../prometheus/go_collector_latest.go | 568 ++ .../client_golang/prometheus/histogram.go | 980 ++- .../prometheus/internal/almost_equal.go | 60 + .../client_golang/prometheus/internal/difflib.go | 654 ++ .../prometheus/internal/go_collector_options.go | 32 + .../prometheus/internal/go_runtime_metrics.go | 18 +- .../client_golang/prometheus/internal/metric.go | 28 +- .../prometheus/client_golang/prometheus/labels.go | 9 +- .../prometheus/client_golang/prometheus/metric.go | 112 +- .../client_golang/prometheus/num_threads.go | 25 + .../prometheus/num_threads_gopherjs.go | 22 + .../client_golang/prometheus/observer.go | 2 +- .../client_golang/prometheus/process_collector.go | 10 +- .../prometheus/process_collector_js.go | 26 + .../prometheus/process_collector_other.go | 4 +- .../client_golang/prometheus/promauto/auto.go | 170 +- .../client_golang/prometheus/promhttp/delegator.go | 18 +- .../client_golang/prometheus/promhttp/http.go | 20 +- .../prometheus/promhttp/instrument_client.go | 40 +- .../prometheus/promhttp/instrument_server.go | 123 +- .../client_golang/prometheus/promhttp/option.go | 39 +- .../client_golang/prometheus/registry.go | 152 +- .../prometheus/client_golang/prometheus/summary.go | 9 +- .../prometheus/testutil/promlint/promlint.go | 5 +- .../prometheus/client_golang/prometheus/timer.go | 11 +- .../prometheus/client_golang/prometheus/value.go | 47 +- .../prometheus/client_golang/prometheus/vec.go | 88 +- .../prometheus/client_golang/prometheus/wrap.go | 4 +- .../prometheus/client_model/go/metrics.pb.go | 333 +- .../github.com/prometheus/common/expfmt/decode.go | 36 +- vendor/github.com/prometheus/common/expfmt/fuzz.go | 5 +- .../prometheus/common/expfmt/openmetrics_create.go | 26 +- .../prometheus/common/expfmt/text_create.go | 3 +- .../prometheus/common/expfmt/text_parse.go | 10 +- .../internal/bitbucket.org/ww/goautoneg/autoneg.go | 22 +- vendor/github.com/prometheus/common/model/time.go | 2 +- vendor/github.com/prometheus/common/model/value.go | 246 +- .../prometheus/common/model/value_float.go | 109 + .../prometheus/common/model/value_histogram.go | 174 + .../prometheus/common/model/value_marshal.go | 131 + .../prometheus/common/model/value_type.go | 83 + vendor/github.com/prometheus/procfs/.gitignore | 3 +- vendor/github.com/prometheus/procfs/.golangci.yml | 10 +- .../prometheus/procfs/CODE_OF_CONDUCT.md | 4 +- .../github.com/prometheus/procfs/CONTRIBUTING.md | 4 +- vendor/github.com/prometheus/procfs/Makefile | 10 +- .../github.com/prometheus/procfs/Makefile.common | 92 +- vendor/github.com/prometheus/procfs/SECURITY.md | 2 +- vendor/github.com/prometheus/procfs/arp.go | 45 +- vendor/github.com/prometheus/procfs/cpuinfo.go | 41 +- .../github.com/prometheus/procfs/cpuinfo_armx.go | 1 + .../prometheus/procfs/cpuinfo_loong64.go | 19 + .../github.com/prometheus/procfs/cpuinfo_mipsx.go | 1 + .../github.com/prometheus/procfs/cpuinfo_others.go | 4 +- .../github.com/prometheus/procfs/cpuinfo_ppcx.go | 1 + .../github.com/prometheus/procfs/cpuinfo_riscvx.go | 1 + .../github.com/prometheus/procfs/cpuinfo_s390x.go | 1 + vendor/github.com/prometheus/procfs/cpuinfo_x86.go | 1 + vendor/github.com/prometheus/procfs/doc.go | 51 +- vendor/github.com/prometheus/procfs/fixtures.ttar | 7673 -------------------- vendor/github.com/prometheus/procfs/go.mod | 9 - vendor/github.com/prometheus/procfs/go.sum | 8 - .../github.com/prometheus/procfs/internal/fs/fs.go | 2 +- .../prometheus/procfs/internal/util/parse.go | 6 +- .../prometheus/procfs/internal/util/readfile.go | 11 +- .../prometheus/procfs/internal/util/sysreadfile.go | 8 +- .../procfs/internal/util/sysreadfile_compat.go | 3 +- vendor/github.com/prometheus/procfs/ipvs.go | 3 +- .../github.com/prometheus/procfs/kernel_random.go | 1 + vendor/github.com/prometheus/procfs/loadavg.go | 2 +- vendor/github.com/prometheus/procfs/mdstat.go | 10 +- vendor/github.com/prometheus/procfs/mountstats.go | 3 +- .../prometheus/procfs/net_conntrackstat.go | 12 +- vendor/github.com/prometheus/procfs/net_dev.go | 8 +- .../github.com/prometheus/procfs/net_ip_socket.go | 2 +- .../github.com/prometheus/procfs/net_protocols.go | 4 +- vendor/github.com/prometheus/procfs/net_softnet.go | 78 +- vendor/github.com/prometheus/procfs/net_xfrm.go | 189 + vendor/github.com/prometheus/procfs/netstat.go | 59 +- vendor/github.com/prometheus/procfs/proc.go | 10 +- vendor/github.com/prometheus/procfs/proc_cgroup.go | 8 +- .../github.com/prometheus/procfs/proc_cgroups.go | 98 + .../github.com/prometheus/procfs/proc_environ.go | 2 +- vendor/github.com/prometheus/procfs/proc_fdinfo.go | 3 +- .../prometheus/procfs/proc_interrupts.go | 98 + vendor/github.com/prometheus/procfs/proc_limits.go | 2 +- vendor/github.com/prometheus/procfs/proc_maps.go | 12 +- .../github.com/prometheus/procfs/proc_netstat.go | 443 ++ vendor/github.com/prometheus/procfs/proc_psi.go | 14 +- vendor/github.com/prometheus/procfs/proc_smaps.go | 23 +- vendor/github.com/prometheus/procfs/proc_snmp.go | 353 + vendor/github.com/prometheus/procfs/proc_snmp6.go | 381 + vendor/github.com/prometheus/procfs/proc_stat.go | 15 +- vendor/github.com/prometheus/procfs/proc_status.go | 38 +- vendor/github.com/prometheus/procfs/proc_sys.go | 51 + vendor/github.com/prometheus/procfs/schedstat.go | 6 +- vendor/github.com/prometheus/procfs/slab.go | 2 +- vendor/github.com/prometheus/procfs/softirqs.go | 160 + vendor/github.com/prometheus/procfs/stat.go | 32 +- vendor/github.com/prometheus/procfs/thread.go | 79 + vendor/github.com/prometheus/procfs/vm.go | 10 +- vendor/github.com/prometheus/procfs/xfrm.go | 186 - vendor/github.com/prometheus/procfs/zoneinfo.go | 5 +- .../go-ruleguard/internal/xtypes/xtypes.go | 16 +- .../quasilyte/go-ruleguard/ruleguard/engine.go | 1 + .../quasilyte/go-ruleguard/ruleguard/filters.go | 99 +- .../go-ruleguard/ruleguard/ir/filter_op.gen.go | 224 +- .../go-ruleguard/ruleguard/ir/gen_filter_op.go | 1 + .../quasilyte/go-ruleguard/ruleguard/ir_loader.go | 2 + .../go-ruleguard/ruleguard/irconv/irconv.go | 2 + .../quasilyte/go-ruleguard/ruleguard/match_data.go | 35 +- .../quasilyte/go-ruleguard/ruleguard/nodepath.go | 10 +- .../quasilyte/go-ruleguard/ruleguard/ruleguard.go | 32 + .../quasilyte/go-ruleguard/ruleguard/runner.go | 68 +- .../go-ruleguard/ruleguard/typematch/typematch.go | 11 +- .../quasilyte/go-ruleguard/ruleguard/utils.go | 7 + vendor/github.com/quasilyte/gogrep/Makefile | 4 +- vendor/github.com/quasilyte/gogrep/README.md | 2 +- vendor/github.com/quasilyte/gogrep/compile.go | 148 +- .../github.com/quasilyte/gogrep/gen_operations.go | 11 +- vendor/github.com/quasilyte/gogrep/go.mod | 8 - vendor/github.com/quasilyte/gogrep/go.sum | 8 - vendor/github.com/quasilyte/gogrep/gogrep.go | 63 +- vendor/github.com/quasilyte/gogrep/match.go | 211 +- .../github.com/quasilyte/gogrep/nodetag/nodetag.go | 7 + .../quasilyte/gogrep/operation_string.go | 216 +- .../github.com/quasilyte/gogrep/operations.gen.go | 309 +- vendor/github.com/quasilyte/gogrep/parse.go | 22 +- vendor/github.com/quasilyte/gogrep/slices.go | 180 +- vendor/github.com/quasilyte/regex/syntax/go.mod | 3 - vendor/github.com/quasilyte/regex/syntax/parser.go | 4 +- vendor/github.com/quasilyte/stdinfo/go.mod | 3 - vendor/github.com/rivo/uniseg/LICENSE.txt | 21 + vendor/github.com/rivo/uniseg/README.md | 157 + vendor/github.com/rivo/uniseg/doc.go | 108 + vendor/github.com/rivo/uniseg/eastasianwidth.go | 2556 +++++++ vendor/github.com/rivo/uniseg/emojipresentation.go | 285 + vendor/github.com/rivo/uniseg/gen_breaktest.go | 213 + vendor/github.com/rivo/uniseg/gen_properties.go | 256 + vendor/github.com/rivo/uniseg/grapheme.go | 334 + .../github.com/rivo/uniseg/graphemeproperties.go | 1891 +++++ vendor/github.com/rivo/uniseg/graphemerules.go | 138 + vendor/github.com/rivo/uniseg/line.go | 134 + vendor/github.com/rivo/uniseg/lineproperties.go | 3513 +++++++++ vendor/github.com/rivo/uniseg/linerules.go | 470 ++ vendor/github.com/rivo/uniseg/properties.go | 168 + vendor/github.com/rivo/uniseg/sentence.go | 90 + .../github.com/rivo/uniseg/sentenceproperties.go | 2815 +++++++ vendor/github.com/rivo/uniseg/sentencerules.go | 205 + vendor/github.com/rivo/uniseg/step.go | 246 + vendor/github.com/rivo/uniseg/width.go | 54 + vendor/github.com/rivo/uniseg/word.go | 89 + vendor/github.com/rivo/uniseg/wordproperties.go | 1848 +++++ vendor/github.com/rivo/uniseg/wordrules.go | 246 + .../github.com/ryancurrah/gomodguard/.golangci.yml | 3 - .../ryancurrah/gomodguard/.goreleaser.yml | 13 +- vendor/github.com/ryancurrah/gomodguard/Dockerfile | 8 +- .../ryancurrah/gomodguard/Dockerfile.goreleaser | 6 +- vendor/github.com/ryancurrah/gomodguard/Makefile | 6 +- vendor/github.com/ryancurrah/gomodguard/README.md | 2 +- vendor/github.com/ryancurrah/gomodguard/allowed.go | 39 + vendor/github.com/ryancurrah/gomodguard/blocked.go | 189 + vendor/github.com/ryancurrah/gomodguard/cmd.go | 247 - vendor/github.com/ryancurrah/gomodguard/go.mod | 14 - vendor/github.com/ryancurrah/gomodguard/go.sum | 26 - .../github.com/ryancurrah/gomodguard/gomodguard.go | 499 -- vendor/github.com/ryancurrah/gomodguard/issue.go | 20 + .../github.com/ryancurrah/gomodguard/processor.go | 291 + vendor/github.com/ryancurrah/gomodguard/tools.go | 5 + .../sqlclosecheck/pkg/analyzer/analyzer.go | 84 +- .../sanposhiho/wastedassign/v2/README.md | 9 + .../github.com/sanposhiho/wastedassign/v2/go.mod | 5 - .../github.com/sanposhiho/wastedassign/v2/go.sum | 26 - .../sashamelentyev/interfacebloat/LICENSE | 21 + .../interfacebloat/pkg/analyzer/analyzer.go | 57 + .../sashamelentyev/usestdlibvars/LICENSE | 21 + .../usestdlibvars/pkg/analyzer/analyzer.go | 569 ++ .../pkg/analyzer/internal/mapping/mapping.go | 199 + .../github.com/securego/gosec/v2/.goreleaser.yml | 1 + vendor/github.com/securego/gosec/v2/Makefile | 30 +- vendor/github.com/securego/gosec/v2/README.md | 2 +- vendor/github.com/securego/gosec/v2/analyzer.go | 14 +- vendor/github.com/securego/gosec/v2/cwe/data.go | 5 + vendor/github.com/securego/gosec/v2/entrypoint.sh | 4 + vendor/github.com/securego/gosec/v2/go.mod | 27 - vendor/github.com/securego/gosec/v2/go.sum | 671 -- vendor/github.com/securego/gosec/v2/helpers.go | 59 +- .../github.com/securego/gosec/v2/import_tracker.go | 53 +- vendor/github.com/securego/gosec/v2/install.sh | 8 +- vendor/github.com/securego/gosec/v2/issue.go | 1 + .../securego/gosec/v2/rules/bad_defer.go | 28 + .../securego/gosec/v2/rules/fileperms.go | 6 +- .../gosec/v2/rules/hardcoded_credentials.go | 19 +- .../github.com/securego/gosec/v2/rules/readfile.go | 25 +- vendor/github.com/securego/gosec/v2/rules/tls.go | 70 +- .../securego/gosec/v2/rules/tls_config.go | 6 +- vendor/github.com/sirupsen/logrus/go.mod | 9 - vendor/github.com/sirupsen/logrus/go.sum | 14 - vendor/github.com/sivchari/containedctx/go.mod | 19 - vendor/github.com/sivchari/containedctx/go.sum | 61 - vendor/github.com/sivchari/nosnakecase/go.mod | 19 - vendor/github.com/sivchari/nosnakecase/go.sum | 65 - .../github.com/sivchari/nosnakecase/nosnakecase.go | 6 + vendor/github.com/sivchari/tenv/go.mod | 19 - vendor/github.com/sivchari/tenv/go.sum | 54 - vendor/github.com/sivchari/tenv/tenv.go | 6 + vendor/github.com/sonatard/noctx/go.mod | 8 - vendor/github.com/sonatard/noctx/go.sum | 16 - vendor/github.com/sourcegraph/go-diff/LICENSE | 11 + vendor/github.com/sourcegraph/go-diff/diff/diff.go | 4 + .../github.com/sourcegraph/go-diff/diff/parse.go | 304 +- .../sourcegraph/go-diff/diff/reader_util.go | 83 + vendor/github.com/spf13/afero/.travis.yml | 26 - vendor/github.com/spf13/afero/README.md | 2 +- vendor/github.com/spf13/afero/afero.go | 4 +- vendor/github.com/spf13/afero/appveyor.yml | 9 +- vendor/github.com/spf13/afero/basepath.go | 14 +- vendor/github.com/spf13/afero/const_bsds.go | 1 + vendor/github.com/spf13/afero/const_win_unix.go | 8 +- vendor/github.com/spf13/afero/go.mod | 13 - vendor/github.com/spf13/afero/go.sum | 466 -- vendor/github.com/spf13/afero/httpFs.go | 2 +- .../spf13/afero/internal/common/adapters.go | 27 + vendor/github.com/spf13/afero/iofs.go | 38 +- vendor/github.com/spf13/afero/ioutil.go | 10 +- vendor/github.com/spf13/afero/mem/file.go | 30 +- vendor/github.com/spf13/afero/memmap.go | 5 + vendor/github.com/spf13/afero/unionFile.go | 2 +- vendor/github.com/spf13/afero/util.go | 10 +- vendor/github.com/spf13/cast/go.mod | 13 - vendor/github.com/spf13/cast/go.sum | 18 - vendor/github.com/spf13/cobra/.golangci.yml | 14 + vendor/github.com/spf13/cobra/Makefile | 2 +- vendor/github.com/spf13/cobra/README.md | 7 +- vendor/github.com/spf13/cobra/active_help.go | 14 + vendor/github.com/spf13/cobra/args.go | 38 +- vendor/github.com/spf13/cobra/bash_completions.go | 14 + .../github.com/spf13/cobra/bash_completionsV2.go | 16 +- vendor/github.com/spf13/cobra/cobra.go | 25 +- vendor/github.com/spf13/cobra/command.go | 144 +- vendor/github.com/spf13/cobra/command_notwin.go | 14 + vendor/github.com/spf13/cobra/command_win.go | 14 + vendor/github.com/spf13/cobra/completions.go | 43 +- vendor/github.com/spf13/cobra/fish_completions.go | 14 + vendor/github.com/spf13/cobra/flag_groups.go | 9 +- vendor/github.com/spf13/cobra/go.mod | 10 - vendor/github.com/spf13/cobra/go.sum | 12 - .../spf13/cobra/powershell_completions.go | 40 +- .../github.com/spf13/cobra/projects_using_cobra.md | 8 +- vendor/github.com/spf13/cobra/shell_completions.go | 14 + vendor/github.com/spf13/cobra/shell_completions.md | 20 + vendor/github.com/spf13/cobra/user_guide.md | 85 +- vendor/github.com/spf13/cobra/zsh_completions.go | 14 + vendor/github.com/spf13/jwalterweatherman/go.mod | 7 - vendor/github.com/spf13/pflag/go.mod | 3 - vendor/github.com/spf13/pflag/go.sum | 0 vendor/github.com/spf13/viper/Makefile | 4 +- vendor/github.com/spf13/viper/README.md | 21 +- vendor/github.com/spf13/viper/go.mod | 72 - vendor/github.com/spf13/viper/go.sum | 918 --- .../spf13/viper/internal/encoding/toml/codec.go | 29 +- .../spf13/viper/internal/encoding/toml/codec2.go | 19 - .../spf13/viper/internal/encoding/yaml/codec.go | 2 +- .../spf13/viper/internal/encoding/yaml/yaml2.go | 14 - .../spf13/viper/internal/encoding/yaml/yaml3.go | 14 - vendor/github.com/spf13/viper/logger.go | 4 +- vendor/github.com/spf13/viper/util.go | 33 +- vendor/github.com/spf13/viper/viper.go | 120 +- vendor/github.com/spf13/viper/watch.go | 4 +- vendor/github.com/spf13/viper/watch_unsupported.go | 32 + vendor/github.com/spf13/viper/watch_wasm.go | 30 - vendor/github.com/stretchr/objx/Taskfile.yml | 2 +- vendor/github.com/stretchr/objx/go.mod | 8 - vendor/github.com/stretchr/objx/go.sum | 12 - vendor/github.com/subosito/gotenv/go.mod | 11 - vendor/github.com/subosito/gotenv/go.sum | 13 - vendor/github.com/subosito/gotenv/gotenv.go | 45 +- .../github.com/sylvia7788/contextcheck/.gitignore | 18 - vendor/github.com/sylvia7788/contextcheck/LICENSE | 201 - vendor/github.com/sylvia7788/contextcheck/Makefile | 5 - .../github.com/sylvia7788/contextcheck/README.md | 61 - .../sylvia7788/contextcheck/contextcheck.go | 507 -- vendor/github.com/sylvia7788/contextcheck/go.mod | 8 - vendor/github.com/sylvia7788/contextcheck/go.sum | 62 - .../t-yuki/gocover-cobertura/.travis.yml | 12 + vendor/github.com/t-yuki/gocover-cobertura/LICENSE | 19 + .../github.com/t-yuki/gocover-cobertura/README.md | 35 + .../t-yuki/gocover-cobertura/cobertura.go | 178 + .../t-yuki/gocover-cobertura/gocover-cobertura.go | 176 + .../github.com/t-yuki/gocover-cobertura/profile.go | 202 + vendor/github.com/tdakkota/asciicheck/go.mod | 5 - vendor/github.com/tdakkota/asciicheck/go.sum | 20 - vendor/github.com/tetafro/godot/go.mod | 5 - vendor/github.com/tetafro/godot/go.sum | 4 - .../bodyclose/passes/bodyclose/bodyclose.go | 34 +- .../github.com/timonwong/loggercheck/.codecov.yml | 16 + vendor/github.com/timonwong/loggercheck/.gitignore | 9 + .../github.com/timonwong/loggercheck/.golangci.yml | 94 + .../timonwong/loggercheck/.goreleaser.yml | 59 + vendor/github.com/timonwong/loggercheck/LICENSE | 21 + vendor/github.com/timonwong/loggercheck/Makefile | 22 + vendor/github.com/timonwong/loggercheck/README.md | 103 + .../loggercheck/internal/bytebufferpool/pool.go | 22 + .../loggercheck/internal/checkers/checker.go | 59 + .../loggercheck/internal/checkers/common.go | 49 + .../loggercheck/internal/checkers/general.go | 68 + .../loggercheck/internal/checkers/printf/printf.go | 252 + .../timonwong/loggercheck/internal/checkers/zap.go | 42 + .../timonwong/loggercheck/internal/rules/rules.go | 201 + .../timonwong/loggercheck/internal/sets/string.go | 59 + .../loggercheck/internal/stringutil/is.go | 15 + .../timonwong/loggercheck/loggercheck.go | 196 + vendor/github.com/timonwong/loggercheck/options.go | 31 + .../timonwong/loggercheck/staticrules.go | 68 + .../tomarrell/wrapcheck/v2/wrapcheck/wrapcheck.go | 37 +- vendor/github.com/tommy-muehle/go-mnd/v2/README.md | 2 +- .../tommy-muehle/go-mnd/v2/config/config.go | 6 + vendor/github.com/tommy-muehle/go-mnd/v2/go.mod | 9 - vendor/github.com/tommy-muehle/go-mnd/v2/go.sum | 28 - vendor/github.com/ulikunitz/xz/.gitignore | 3 + vendor/github.com/ulikunitz/xz/LICENSE | 2 +- vendor/github.com/ulikunitz/xz/README.md | 4 + vendor/github.com/ulikunitz/xz/TODO.md | 11 +- vendor/github.com/ulikunitz/xz/bits.go | 2 +- vendor/github.com/ulikunitz/xz/crc.go | 2 +- vendor/github.com/ulikunitz/xz/format.go | 2 +- vendor/github.com/ulikunitz/xz/go.mod | 3 - .../ulikunitz/xz/internal/hash/cyclic_poly.go | 2 +- .../github.com/ulikunitz/xz/internal/hash/doc.go | 2 +- .../ulikunitz/xz/internal/hash/rabin_karp.go | 2 +- .../ulikunitz/xz/internal/hash/roller.go | 2 +- .../github.com/ulikunitz/xz/internal/xlog/xlog.go | 5 +- vendor/github.com/ulikunitz/xz/lzma/bintree.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/bitops.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/breader.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/buffer.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/bytewriter.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/decoder.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/decoderdict.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/directcodec.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/distcodec.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/encoder.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/encoderdict.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/hashtable.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/header.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/header2.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/lengthcodec.go | 5 +- .../github.com/ulikunitz/xz/lzma/literalcodec.go | 2 +- .../github.com/ulikunitz/xz/lzma/matchalgorithm.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/operation.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/prob.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/properties.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/rangecodec.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/reader.go | 4 +- vendor/github.com/ulikunitz/xz/lzma/reader2.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/state.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/treecodecs.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/writer.go | 2 +- vendor/github.com/ulikunitz/xz/lzma/writer2.go | 2 +- vendor/github.com/ulikunitz/xz/lzmafilter.go | 2 +- vendor/github.com/ulikunitz/xz/none-check.go | 2 +- vendor/github.com/ulikunitz/xz/reader.go | 2 +- vendor/github.com/ulikunitz/xz/writer.go | 2 +- vendor/github.com/uudashr/gocognit/go.mod | 8 - vendor/github.com/uudashr/gocognit/go.sum | 27 - vendor/github.com/yagipy/maintidx/go.mod | 11 - vendor/github.com/yagipy/maintidx/go.sum | 28 - vendor/github.com/yeya24/promlinter/go.mod | 9 - vendor/github.com/yeya24/promlinter/go.sum | 470 -- 1040 files changed, 63630 insertions(+), 32492 deletions(-) create mode 100644 vendor/github.com/Abirdcfly/dupword/.gitignore create mode 100644 vendor/github.com/Abirdcfly/dupword/.goreleaser.yml create mode 100644 vendor/github.com/Abirdcfly/dupword/LICENSE create mode 100644 vendor/github.com/Abirdcfly/dupword/README.md create mode 100644 vendor/github.com/Abirdcfly/dupword/dupword.go create mode 100644 vendor/github.com/Abirdcfly/dupword/version.go delete mode 100644 vendor/github.com/BurntSushi/toml/go.mod delete mode 100644 vendor/github.com/Djarvur/go-err113/go.mod delete mode 100644 vendor/github.com/Djarvur/go-err113/go.sum delete mode 100644 vendor/github.com/OpenPeeDeeP/depguard/go.mod delete mode 100644 vendor/github.com/OpenPeeDeeP/depguard/go.sum delete mode 100644 vendor/github.com/alingse/asasalint/go.mod delete mode 100644 vendor/github.com/alingse/asasalint/go.sum delete mode 100644 vendor/github.com/blizzy78/varnamelen/go.mod delete mode 100644 vendor/github.com/blizzy78/varnamelen/go.sum create mode 100644 vendor/github.com/bombsimon/wsl/v3/.golangci.yml delete mode 100644 vendor/github.com/bombsimon/wsl/v3/.travis.yml delete mode 100644 vendor/github.com/bombsimon/wsl/v3/go.mod delete mode 100644 vendor/github.com/bombsimon/wsl/v3/go.sum delete mode 100644 vendor/github.com/breml/errchkjson/go.mod delete mode 100644 vendor/github.com/breml/errchkjson/go.sum delete mode 100644 vendor/github.com/cespare/xxhash/v2/go.mod delete mode 100644 vendor/github.com/cespare/xxhash/v2/go.sum create mode 100644 vendor/github.com/cespare/xxhash/v2/testall.sh delete mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_asm.go delete mode 100644 vendor/github.com/charithe/durationcheck/go.mod delete mode 100644 vendor/github.com/charithe/durationcheck/go.sum delete mode 100644 vendor/github.com/chavacava/garif/go.mod delete mode 100644 vendor/github.com/chavacava/garif/go.sum create mode 100644 vendor/github.com/curioswitch/go-reassign/.gitattributes create mode 100644 vendor/github.com/curioswitch/go-reassign/.gitignore create mode 100644 vendor/github.com/curioswitch/go-reassign/.golangci.yml create mode 100644 vendor/github.com/curioswitch/go-reassign/.goreleaser.yaml create mode 100644 vendor/github.com/curioswitch/go-reassign/LICENSE create mode 100644 vendor/github.com/curioswitch/go-reassign/README.md create mode 100644 vendor/github.com/curioswitch/go-reassign/analyzer.go create mode 100644 vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go delete mode 100644 vendor/github.com/denis-tingaikin/go-header/go.mod delete mode 100644 vendor/github.com/denis-tingaikin/go-header/go.sum delete mode 100644 vendor/github.com/ettle/strcase/go.mod delete mode 100644 vendor/github.com/ettle/strcase/go.sum delete mode 100644 vendor/github.com/fatih/color/go.mod delete mode 100644 vendor/github.com/fatih/color/go.sum delete mode 100644 vendor/github.com/fatih/structtag/go.mod delete mode 100644 vendor/github.com/felixge/httpsnoop/go.mod delete mode 100644 vendor/github.com/fsnotify/fsnotify/AUTHORS create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_fen.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_inotify.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_kqueue.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_other.go create mode 100644 vendor/github.com/fsnotify/fsnotify/backend_windows.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/fen.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/go.mod delete mode 100644 vendor/github.com/fsnotify/fsnotify/go.sum delete mode 100644 vendor/github.com/fsnotify/fsnotify/inotify.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/inotify_poller.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/kqueue.go create mode 100644 vendor/github.com/fsnotify/fsnotify/mkdoc.zsh delete mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go create mode 100644 vendor/github.com/fsnotify/fsnotify/system_bsd.go create mode 100644 vendor/github.com/fsnotify/fsnotify/system_darwin.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/windows.go delete mode 100644 vendor/github.com/fzipp/gocyclo/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astcast/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/astcast/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astcast/go.sum delete mode 100644 vendor/github.com/go-toolsmith/astcopy/.travis.yml create mode 100644 vendor/github.com/go-toolsmith/astcopy/astcopy_go117.go create mode 100644 vendor/github.com/go-toolsmith/astcopy/astcopy_go118.go delete mode 100644 vendor/github.com/go-toolsmith/astcopy/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astcopy/go.sum delete mode 100644 vendor/github.com/go-toolsmith/astequal/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/astequal/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astequal/go.sum delete mode 100644 vendor/github.com/go-toolsmith/astfmt/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/astfmt/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astfmt/go.sum delete mode 100644 vendor/github.com/go-toolsmith/astp/.gitignore delete mode 100644 vendor/github.com/go-toolsmith/astp/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/astp/go.mod delete mode 100644 vendor/github.com/go-toolsmith/astp/go.sum delete mode 100644 vendor/github.com/go-toolsmith/strparse/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/strparse/go.mod delete mode 100644 vendor/github.com/go-toolsmith/typep/.travis.yml delete mode 100644 vendor/github.com/go-toolsmith/typep/go.mod delete mode 100644 vendor/github.com/go-toolsmith/typep/safeExpr.go create mode 100644 vendor/github.com/go-toolsmith/typep/safe_expr.go delete mode 100644 vendor/github.com/go-toolsmith/typep/simplePredicates.go create mode 100644 vendor/github.com/go-toolsmith/typep/simple_predicates.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/empty/empty.pb.go create mode 100644 vendor/github.com/golangci/gofmt/gofmt/internal/diff/diff.go create mode 100644 vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go create mode 100644 vendor/github.com/golangci/gofmt/gofmt/readme.md create mode 100644 vendor/github.com/golangci/gofmt/goimports/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/internal/cache/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings_gocritic.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti_go117.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go create mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go delete mode 100644 vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go delete mode 100644 vendor/github.com/golangci/lint-1/go.mod delete mode 100644 vendor/github.com/golangci/lint-1/go.sum create mode 100644 vendor/github.com/golangci/misspell/.golangci.yml delete mode 100644 vendor/github.com/golangci/misspell/.travis.yml delete mode 100644 vendor/github.com/golangci/misspell/Gopkg.lock delete mode 100644 vendor/github.com/golangci/misspell/Gopkg.toml delete mode 100644 vendor/github.com/golangci/revgrep/go.mod delete mode 100644 vendor/github.com/golangci/revgrep/go.sum delete mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/zero.go create mode 100644 vendor/github.com/google/safehtml/CONTRIBUTING.md create mode 100644 vendor/github.com/google/safehtml/LICENSE create mode 100644 vendor/github.com/google/safehtml/README.md create mode 100644 vendor/github.com/google/safehtml/doc.go create mode 100644 vendor/github.com/google/safehtml/html.go create mode 100644 vendor/github.com/google/safehtml/identifier.go create mode 100644 vendor/github.com/google/safehtml/init.go create mode 100644 vendor/github.com/google/safehtml/internal/raw/raw.go create mode 100644 vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go create mode 100644 vendor/github.com/google/safehtml/internal/template/raw/raw.go create mode 100644 vendor/github.com/google/safehtml/script.go create mode 100644 vendor/github.com/google/safehtml/style.go create mode 100644 vendor/github.com/google/safehtml/stylesheet.go create mode 100644 vendor/github.com/google/safehtml/template/context.go create mode 100644 vendor/github.com/google/safehtml/template/delim_string.go create mode 100644 vendor/github.com/google/safehtml/template/doc.go create mode 100644 vendor/github.com/google/safehtml/template/error.go create mode 100644 vendor/github.com/google/safehtml/template/escape.go create mode 100644 vendor/github.com/google/safehtml/template/init.go create mode 100644 vendor/github.com/google/safehtml/template/sanitize.go create mode 100644 vendor/github.com/google/safehtml/template/sanitizers.go create mode 100644 vendor/github.com/google/safehtml/template/state_string.go create mode 100644 vendor/github.com/google/safehtml/template/template.go create mode 100644 vendor/github.com/google/safehtml/template/testdata/dir1/parsefiles_t1.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/dir2/parsefiles_t2.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/glob_t0.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/glob_t1.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/glob_t2.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/helpers_t1.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/helpers_t2.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/share_t0.tmpl create mode 100644 vendor/github.com/google/safehtml/template/testdata/share_t1.tmpl create mode 100644 vendor/github.com/google/safehtml/template/transition.go create mode 100644 vendor/github.com/google/safehtml/template/trustedfs.go create mode 100644 vendor/github.com/google/safehtml/template/trustedsource.go create mode 100644 vendor/github.com/google/safehtml/template/trustedtemplate.go create mode 100644 vendor/github.com/google/safehtml/template/url.go create mode 100644 vendor/github.com/google/safehtml/trustedresourceurl.go create mode 100644 vendor/github.com/google/safehtml/uncheckedconversions/uncheckedconversions.go create mode 100644 vendor/github.com/google/safehtml/url.go create mode 100644 vendor/github.com/google/safehtml/urlset.go delete mode 100644 vendor/github.com/google/uuid/go.mod create mode 100644 vendor/github.com/googleapis/gax-go/v2/content_type.go delete mode 100644 vendor/github.com/googleapis/gax-go/v2/go.mod delete mode 100644 vendor/github.com/googleapis/gax-go/v2/go.sum delete mode 100644 vendor/github.com/gorilla/handlers/go.mod delete mode 100644 vendor/github.com/gorilla/handlers/go.sum delete mode 100644 vendor/github.com/gostaticanalysis/analysisutil/go.mod delete mode 100644 vendor/github.com/gostaticanalysis/analysisutil/go.sum delete mode 100644 vendor/github.com/gostaticanalysis/comment/go.mod delete mode 100644 vendor/github.com/gostaticanalysis/comment/go.sum delete mode 100644 vendor/github.com/gostaticanalysis/forcetypeassert/go.mod delete mode 100644 vendor/github.com/gostaticanalysis/forcetypeassert/go.sum delete mode 100644 vendor/github.com/gostaticanalysis/nilerr/go.mod delete mode 100644 vendor/github.com/gostaticanalysis/nilerr/go.sum delete mode 100644 vendor/github.com/hashicorp/errwrap/go.mod delete mode 100644 vendor/github.com/hashicorp/go-multierror/go.mod delete mode 100644 vendor/github.com/hashicorp/go-multierror/go.sum delete mode 100644 vendor/github.com/hashicorp/go-version/go.mod delete mode 100644 vendor/github.com/hashicorp/hcl/go.mod delete mode 100644 vendor/github.com/hashicorp/hcl/go.sum delete mode 100644 vendor/github.com/hexops/gotextdiff/go.mod delete mode 100644 vendor/github.com/ianlancetaylor/demangle/go.mod delete mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go delete mode 100644 vendor/github.com/jgautheron/goconst/go.mod create mode 100644 vendor/github.com/json-iterator/go/.codecov.yml create mode 100644 vendor/github.com/json-iterator/go/.gitignore create mode 100644 vendor/github.com/json-iterator/go/.travis.yml create mode 100644 vendor/github.com/json-iterator/go/Gopkg.lock create mode 100644 vendor/github.com/json-iterator/go/Gopkg.toml create mode 100644 vendor/github.com/json-iterator/go/LICENSE create mode 100644 vendor/github.com/json-iterator/go/README.md create mode 100644 vendor/github.com/json-iterator/go/adapter.go create mode 100644 vendor/github.com/json-iterator/go/any.go create mode 100644 vendor/github.com/json-iterator/go/any_array.go create mode 100644 vendor/github.com/json-iterator/go/any_bool.go create mode 100644 vendor/github.com/json-iterator/go/any_float.go create mode 100644 vendor/github.com/json-iterator/go/any_int32.go create mode 100644 vendor/github.com/json-iterator/go/any_int64.go create mode 100644 vendor/github.com/json-iterator/go/any_invalid.go create mode 100644 vendor/github.com/json-iterator/go/any_nil.go create mode 100644 vendor/github.com/json-iterator/go/any_number.go create mode 100644 vendor/github.com/json-iterator/go/any_object.go create mode 100644 vendor/github.com/json-iterator/go/any_str.go create mode 100644 vendor/github.com/json-iterator/go/any_uint32.go create mode 100644 vendor/github.com/json-iterator/go/any_uint64.go create mode 100644 vendor/github.com/json-iterator/go/build.sh create mode 100644 vendor/github.com/json-iterator/go/config.go create mode 100644 vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md create mode 100644 vendor/github.com/json-iterator/go/iter.go create mode 100644 vendor/github.com/json-iterator/go/iter_array.go create mode 100644 vendor/github.com/json-iterator/go/iter_float.go create mode 100644 vendor/github.com/json-iterator/go/iter_int.go create mode 100644 vendor/github.com/json-iterator/go/iter_object.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip_sloppy.go create mode 100644 vendor/github.com/json-iterator/go/iter_skip_strict.go create mode 100644 vendor/github.com/json-iterator/go/iter_str.go create mode 100644 vendor/github.com/json-iterator/go/jsoniter.go create mode 100644 vendor/github.com/json-iterator/go/pool.go create mode 100644 vendor/github.com/json-iterator/go/reflect.go create mode 100644 vendor/github.com/json-iterator/go/reflect_array.go create mode 100644 vendor/github.com/json-iterator/go/reflect_dynamic.go create mode 100644 vendor/github.com/json-iterator/go/reflect_extension.go create mode 100644 vendor/github.com/json-iterator/go/reflect_json_number.go create mode 100644 vendor/github.com/json-iterator/go/reflect_json_raw_message.go create mode 100644 vendor/github.com/json-iterator/go/reflect_map.go create mode 100644 vendor/github.com/json-iterator/go/reflect_marshaler.go create mode 100644 vendor/github.com/json-iterator/go/reflect_native.go create mode 100644 vendor/github.com/json-iterator/go/reflect_optional.go create mode 100644 vendor/github.com/json-iterator/go/reflect_slice.go create mode 100644 vendor/github.com/json-iterator/go/reflect_struct_decoder.go create mode 100644 vendor/github.com/json-iterator/go/reflect_struct_encoder.go create mode 100644 vendor/github.com/json-iterator/go/stream.go create mode 100644 vendor/github.com/json-iterator/go/stream_float.go create mode 100644 vendor/github.com/json-iterator/go/stream_int.go create mode 100644 vendor/github.com/json-iterator/go/stream_str.go create mode 100644 vendor/github.com/json-iterator/go/test.sh delete mode 100644 vendor/github.com/julz/importas/go.mod delete mode 100644 vendor/github.com/julz/importas/go.sum create mode 100644 vendor/github.com/junk1tm/musttag/.golangci.yml create mode 100644 vendor/github.com/junk1tm/musttag/.goreleaser.yml create mode 100644 vendor/github.com/junk1tm/musttag/LICENSE create mode 100644 vendor/github.com/junk1tm/musttag/README.md create mode 100644 vendor/github.com/junk1tm/musttag/builtins.go create mode 100644 vendor/github.com/junk1tm/musttag/musttag.go create mode 100644 vendor/github.com/junk1tm/musttag/utils.go delete mode 100644 vendor/github.com/kisielk/gotool/go.mod create mode 100644 vendor/github.com/kkHAIKE/contextcheck/.gitignore create mode 100644 vendor/github.com/kkHAIKE/contextcheck/LICENSE create mode 100644 vendor/github.com/kkHAIKE/contextcheck/Makefile create mode 100644 vendor/github.com/kkHAIKE/contextcheck/README.md create mode 100644 vendor/github.com/kkHAIKE/contextcheck/contextcheck.go delete mode 100644 vendor/github.com/kyoh86/exportloopref/go.mod delete mode 100644 vendor/github.com/kyoh86/exportloopref/go.sum delete mode 100644 vendor/github.com/ldez/gomoddirectives/go.mod delete mode 100644 vendor/github.com/ldez/gomoddirectives/go.sum delete mode 100644 vendor/github.com/ldez/tagliatelle/go.mod delete mode 100644 vendor/github.com/ldez/tagliatelle/go.sum delete mode 100644 vendor/github.com/lufeee/execinquery/go.mod delete mode 100644 vendor/github.com/lufeee/execinquery/go.sum delete mode 100644 vendor/github.com/magiconair/properties/.travis.yml delete mode 100644 vendor/github.com/magiconair/properties/go.mod create mode 100644 vendor/github.com/maratori/testableexamples/LICENSE create mode 100644 vendor/github.com/maratori/testableexamples/pkg/testableexamples/testableexamples.go delete mode 100644 vendor/github.com/matoous/godox/go.mod delete mode 100644 vendor/github.com/matoous/godox/go.sum delete mode 100644 vendor/github.com/mattn/go-colorable/go.mod delete mode 100644 vendor/github.com/mattn/go-colorable/go.sum delete mode 100644 vendor/github.com/mattn/go-isatty/go.mod delete mode 100644 vendor/github.com/mattn/go-isatty/go.sum delete mode 100644 vendor/github.com/mattn/go-runewidth/.travis.yml delete mode 100644 vendor/github.com/mattn/go-runewidth/go.mod delete mode 100644 vendor/github.com/mattn/go-runewidth/go.test.sh create mode 100644 vendor/github.com/mgechev/revive/rule/comment-spacings.go delete mode 100644 vendor/github.com/mitchellh/go-homedir/go.mod delete mode 100644 vendor/github.com/mitchellh/mapstructure/go.mod create mode 100644 vendor/github.com/modern-go/concurrent/.gitignore create mode 100644 vendor/github.com/modern-go/concurrent/.travis.yml create mode 100644 vendor/github.com/modern-go/concurrent/LICENSE create mode 100644 vendor/github.com/modern-go/concurrent/README.md create mode 100644 vendor/github.com/modern-go/concurrent/executor.go create mode 100644 vendor/github.com/modern-go/concurrent/go_above_19.go create mode 100644 vendor/github.com/modern-go/concurrent/go_below_19.go create mode 100644 vendor/github.com/modern-go/concurrent/log.go create mode 100644 vendor/github.com/modern-go/concurrent/test.sh create mode 100644 vendor/github.com/modern-go/concurrent/unbounded_executor.go create mode 100644 vendor/github.com/modern-go/reflect2/.gitignore create mode 100644 vendor/github.com/modern-go/reflect2/.travis.yml create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.lock create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.toml create mode 100644 vendor/github.com/modern-go/reflect2/LICENSE create mode 100644 vendor/github.com/modern-go/reflect2/README.md create mode 100644 vendor/github.com/modern-go/reflect2/go_above_118.go create mode 100644 vendor/github.com/modern-go/reflect2/go_above_19.go create mode 100644 vendor/github.com/modern-go/reflect2/go_below_118.go create mode 100644 vendor/github.com/modern-go/reflect2/reflect2.go create mode 100644 vendor/github.com/modern-go/reflect2/reflect2_amd64.s create mode 100644 vendor/github.com/modern-go/reflect2/reflect2_kind.go create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_386.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_amd64p32.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_arm.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_arm64.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_mips64x.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_mipsx.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_ppc64x.s create mode 100644 vendor/github.com/modern-go/reflect2/relfect2_s390x.s create mode 100644 vendor/github.com/modern-go/reflect2/safe_field.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_map.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_slice.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_struct.go create mode 100644 vendor/github.com/modern-go/reflect2/safe_type.go create mode 100644 vendor/github.com/modern-go/reflect2/type_map.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_array.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_eface.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_field.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_iface.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_link.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_map.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_ptr.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_slice.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_struct.go create mode 100644 vendor/github.com/modern-go/reflect2/unsafe_type.go delete mode 100644 vendor/github.com/moricho/tparallel/go.mod delete mode 100644 vendor/github.com/moricho/tparallel/go.sum delete mode 100644 vendor/github.com/nakabonne/nestif/go.mod delete mode 100644 vendor/github.com/nakabonne/nestif/go.sum delete mode 100644 vendor/github.com/nbutton23/zxcvbn-go/go.mod delete mode 100644 vendor/github.com/nbutton23/zxcvbn-go/go.sum create mode 100644 vendor/github.com/nishanths/exhaustive/common.go create mode 100644 vendor/github.com/nishanths/exhaustive/common_go118.go create mode 100644 vendor/github.com/nishanths/exhaustive/common_pre_go118.go create mode 100644 vendor/github.com/nishanths/exhaustive/flag.go delete mode 100644 vendor/github.com/nishanths/exhaustive/go.mod delete mode 100644 vendor/github.com/nishanths/exhaustive/go.sum create mode 100644 vendor/github.com/nishanths/exhaustive/map.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/.gitignore create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/LICENSE create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/Makefile create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/README.md create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/ginkgo_linter.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/gomegahandler/handler.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/reverseassertion/reverse_assertion.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/types/boolean.go create mode 100644 vendor/github.com/nunnatsa/ginkgolinter/types/suppress.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/go.mod delete mode 100644 vendor/github.com/olekukonko/tablewriter/go.sum delete mode 100644 vendor/github.com/pelletier/go-toml/.dockerignore delete mode 100644 vendor/github.com/pelletier/go-toml/.gitignore delete mode 100644 vendor/github.com/pelletier/go-toml/CONTRIBUTING.md delete mode 100644 vendor/github.com/pelletier/go-toml/Dockerfile delete mode 100644 vendor/github.com/pelletier/go-toml/LICENSE delete mode 100644 vendor/github.com/pelletier/go-toml/Makefile delete mode 100644 vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md delete mode 100644 vendor/github.com/pelletier/go-toml/README.md delete mode 100644 vendor/github.com/pelletier/go-toml/SECURITY.md delete mode 100644 vendor/github.com/pelletier/go-toml/azure-pipelines.yml delete mode 100644 vendor/github.com/pelletier/go-toml/benchmark.sh delete mode 100644 vendor/github.com/pelletier/go-toml/doc.go delete mode 100644 vendor/github.com/pelletier/go-toml/example-crlf.toml delete mode 100644 vendor/github.com/pelletier/go-toml/example.toml delete mode 100644 vendor/github.com/pelletier/go-toml/fuzz.go delete mode 100644 vendor/github.com/pelletier/go-toml/fuzz.sh delete mode 100644 vendor/github.com/pelletier/go-toml/go.mod delete mode 100644 vendor/github.com/pelletier/go-toml/keysparsing.go delete mode 100644 vendor/github.com/pelletier/go-toml/lexer.go delete mode 100644 vendor/github.com/pelletier/go-toml/localtime.go delete mode 100644 vendor/github.com/pelletier/go-toml/marshal.go delete mode 100644 vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml delete mode 100644 vendor/github.com/pelletier/go-toml/marshal_test.toml delete mode 100644 vendor/github.com/pelletier/go-toml/parser.go delete mode 100644 vendor/github.com/pelletier/go-toml/position.go delete mode 100644 vendor/github.com/pelletier/go-toml/token.go delete mode 100644 vendor/github.com/pelletier/go-toml/toml.go delete mode 100644 vendor/github.com/pelletier/go-toml/tomlpub.go delete mode 100644 vendor/github.com/pelletier/go-toml/tomltree_create.go delete mode 100644 vendor/github.com/pelletier/go-toml/tomltree_write.go delete mode 100644 vendor/github.com/pelletier/go-toml/tomltree_writepub.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/go.mod delete mode 100644 vendor/github.com/pelletier/go-toml/v2/go.sum delete mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/ast/ast.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/ast/builder.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/ast/kind.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/parser.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/scanner.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/ast.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/builder.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/doc.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/kind.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/parser.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/utf8.go delete mode 100644 vendor/github.com/phayes/checkstyle/.scrutinizer.yml delete mode 100644 vendor/github.com/phayes/checkstyle/LICENSE delete mode 100644 vendor/github.com/phayes/checkstyle/README.md delete mode 100644 vendor/github.com/phayes/checkstyle/checkstyle.go delete mode 100644 vendor/github.com/phayes/checkstyle/godoc.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/get_pid.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go delete mode 100644 vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/num_threads.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/process_collector_js.go create mode 100644 vendor/github.com/prometheus/common/model/value_float.go create mode 100644 vendor/github.com/prometheus/common/model/value_histogram.go create mode 100644 vendor/github.com/prometheus/common/model/value_marshal.go create mode 100644 vendor/github.com/prometheus/common/model/value_type.go create mode 100644 vendor/github.com/prometheus/procfs/cpuinfo_loong64.go delete mode 100644 vendor/github.com/prometheus/procfs/fixtures.ttar delete mode 100644 vendor/github.com/prometheus/procfs/go.mod delete mode 100644 vendor/github.com/prometheus/procfs/go.sum create mode 100644 vendor/github.com/prometheus/procfs/net_xfrm.go create mode 100644 vendor/github.com/prometheus/procfs/proc_cgroups.go create mode 100644 vendor/github.com/prometheus/procfs/proc_interrupts.go create mode 100644 vendor/github.com/prometheus/procfs/proc_netstat.go create mode 100644 vendor/github.com/prometheus/procfs/proc_snmp.go create mode 100644 vendor/github.com/prometheus/procfs/proc_snmp6.go create mode 100644 vendor/github.com/prometheus/procfs/proc_sys.go create mode 100644 vendor/github.com/prometheus/procfs/softirqs.go create mode 100644 vendor/github.com/prometheus/procfs/thread.go delete mode 100644 vendor/github.com/prometheus/procfs/xfrm.go delete mode 100644 vendor/github.com/quasilyte/gogrep/go.mod delete mode 100644 vendor/github.com/quasilyte/gogrep/go.sum delete mode 100644 vendor/github.com/quasilyte/regex/syntax/go.mod delete mode 100644 vendor/github.com/quasilyte/stdinfo/go.mod create mode 100644 vendor/github.com/rivo/uniseg/LICENSE.txt create mode 100644 vendor/github.com/rivo/uniseg/README.md create mode 100644 vendor/github.com/rivo/uniseg/doc.go create mode 100644 vendor/github.com/rivo/uniseg/eastasianwidth.go create mode 100644 vendor/github.com/rivo/uniseg/emojipresentation.go create mode 100644 vendor/github.com/rivo/uniseg/gen_breaktest.go create mode 100644 vendor/github.com/rivo/uniseg/gen_properties.go create mode 100644 vendor/github.com/rivo/uniseg/grapheme.go create mode 100644 vendor/github.com/rivo/uniseg/graphemeproperties.go create mode 100644 vendor/github.com/rivo/uniseg/graphemerules.go create mode 100644 vendor/github.com/rivo/uniseg/line.go create mode 100644 vendor/github.com/rivo/uniseg/lineproperties.go create mode 100644 vendor/github.com/rivo/uniseg/linerules.go create mode 100644 vendor/github.com/rivo/uniseg/properties.go create mode 100644 vendor/github.com/rivo/uniseg/sentence.go create mode 100644 vendor/github.com/rivo/uniseg/sentenceproperties.go create mode 100644 vendor/github.com/rivo/uniseg/sentencerules.go create mode 100644 vendor/github.com/rivo/uniseg/step.go create mode 100644 vendor/github.com/rivo/uniseg/width.go create mode 100644 vendor/github.com/rivo/uniseg/word.go create mode 100644 vendor/github.com/rivo/uniseg/wordproperties.go create mode 100644 vendor/github.com/rivo/uniseg/wordrules.go create mode 100644 vendor/github.com/ryancurrah/gomodguard/allowed.go create mode 100644 vendor/github.com/ryancurrah/gomodguard/blocked.go delete mode 100644 vendor/github.com/ryancurrah/gomodguard/cmd.go delete mode 100644 vendor/github.com/ryancurrah/gomodguard/go.mod delete mode 100644 vendor/github.com/ryancurrah/gomodguard/go.sum delete mode 100644 vendor/github.com/ryancurrah/gomodguard/gomodguard.go create mode 100644 vendor/github.com/ryancurrah/gomodguard/issue.go create mode 100644 vendor/github.com/ryancurrah/gomodguard/processor.go create mode 100644 vendor/github.com/ryancurrah/gomodguard/tools.go delete mode 100644 vendor/github.com/sanposhiho/wastedassign/v2/go.mod delete mode 100644 vendor/github.com/sanposhiho/wastedassign/v2/go.sum create mode 100644 vendor/github.com/sashamelentyev/interfacebloat/LICENSE create mode 100644 vendor/github.com/sashamelentyev/interfacebloat/pkg/analyzer/analyzer.go create mode 100644 vendor/github.com/sashamelentyev/usestdlibvars/LICENSE create mode 100644 vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/analyzer.go create mode 100644 vendor/github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping/mapping.go delete mode 100644 vendor/github.com/securego/gosec/v2/go.mod delete mode 100644 vendor/github.com/securego/gosec/v2/go.sum delete mode 100644 vendor/github.com/sirupsen/logrus/go.mod delete mode 100644 vendor/github.com/sirupsen/logrus/go.sum delete mode 100644 vendor/github.com/sivchari/containedctx/go.mod delete mode 100644 vendor/github.com/sivchari/containedctx/go.sum delete mode 100644 vendor/github.com/sivchari/nosnakecase/go.mod delete mode 100644 vendor/github.com/sivchari/nosnakecase/go.sum delete mode 100644 vendor/github.com/sivchari/tenv/go.mod delete mode 100644 vendor/github.com/sivchari/tenv/go.sum delete mode 100644 vendor/github.com/sonatard/noctx/go.mod delete mode 100644 vendor/github.com/sonatard/noctx/go.sum delete mode 100644 vendor/github.com/spf13/afero/.travis.yml delete mode 100644 vendor/github.com/spf13/afero/go.mod delete mode 100644 vendor/github.com/spf13/afero/go.sum create mode 100644 vendor/github.com/spf13/afero/internal/common/adapters.go delete mode 100644 vendor/github.com/spf13/cast/go.mod delete mode 100644 vendor/github.com/spf13/cast/go.sum delete mode 100644 vendor/github.com/spf13/cobra/go.mod delete mode 100644 vendor/github.com/spf13/cobra/go.sum delete mode 100644 vendor/github.com/spf13/jwalterweatherman/go.mod delete mode 100644 vendor/github.com/spf13/pflag/go.mod delete mode 100644 vendor/github.com/spf13/pflag/go.sum delete mode 100644 vendor/github.com/spf13/viper/go.mod delete mode 100644 vendor/github.com/spf13/viper/go.sum delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/toml/codec2.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/yaml/yaml2.go delete mode 100644 vendor/github.com/spf13/viper/internal/encoding/yaml/yaml3.go create mode 100644 vendor/github.com/spf13/viper/watch_unsupported.go delete mode 100644 vendor/github.com/spf13/viper/watch_wasm.go delete mode 100644 vendor/github.com/stretchr/objx/go.mod delete mode 100644 vendor/github.com/stretchr/objx/go.sum delete mode 100644 vendor/github.com/subosito/gotenv/go.mod delete mode 100644 vendor/github.com/subosito/gotenv/go.sum delete mode 100644 vendor/github.com/sylvia7788/contextcheck/.gitignore delete mode 100644 vendor/github.com/sylvia7788/contextcheck/LICENSE delete mode 100644 vendor/github.com/sylvia7788/contextcheck/Makefile delete mode 100644 vendor/github.com/sylvia7788/contextcheck/README.md delete mode 100644 vendor/github.com/sylvia7788/contextcheck/contextcheck.go delete mode 100644 vendor/github.com/sylvia7788/contextcheck/go.mod delete mode 100644 vendor/github.com/sylvia7788/contextcheck/go.sum create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/.travis.yml create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/LICENSE create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/README.md create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/cobertura.go create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/gocover-cobertura.go create mode 100644 vendor/github.com/t-yuki/gocover-cobertura/profile.go delete mode 100644 vendor/github.com/tdakkota/asciicheck/go.mod delete mode 100644 vendor/github.com/tdakkota/asciicheck/go.sum delete mode 100644 vendor/github.com/tetafro/godot/go.mod delete mode 100644 vendor/github.com/tetafro/godot/go.sum create mode 100644 vendor/github.com/timonwong/loggercheck/.codecov.yml create mode 100644 vendor/github.com/timonwong/loggercheck/.gitignore create mode 100644 vendor/github.com/timonwong/loggercheck/.golangci.yml create mode 100644 vendor/github.com/timonwong/loggercheck/.goreleaser.yml create mode 100644 vendor/github.com/timonwong/loggercheck/LICENSE create mode 100644 vendor/github.com/timonwong/loggercheck/Makefile create mode 100644 vendor/github.com/timonwong/loggercheck/README.md create mode 100644 vendor/github.com/timonwong/loggercheck/internal/bytebufferpool/pool.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/checkers/checker.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/checkers/common.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/checkers/general.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/checkers/printf/printf.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/checkers/zap.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/rules/rules.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/sets/string.go create mode 100644 vendor/github.com/timonwong/loggercheck/internal/stringutil/is.go create mode 100644 vendor/github.com/timonwong/loggercheck/loggercheck.go create mode 100644 vendor/github.com/timonwong/loggercheck/options.go create mode 100644 vendor/github.com/timonwong/loggercheck/staticrules.go delete mode 100644 vendor/github.com/tommy-muehle/go-mnd/v2/go.mod delete mode 100644 vendor/github.com/tommy-muehle/go-mnd/v2/go.sum delete mode 100644 vendor/github.com/ulikunitz/xz/go.mod delete mode 100644 vendor/github.com/uudashr/gocognit/go.mod delete mode 100644 vendor/github.com/uudashr/gocognit/go.sum delete mode 100644 vendor/github.com/yagipy/maintidx/go.mod delete mode 100644 vendor/github.com/yagipy/maintidx/go.sum delete mode 100644 vendor/github.com/yeya24/promlinter/go.mod delete mode 100644 vendor/github.com/yeya24/promlinter/go.sum (limited to 'vendor/github.com') diff --git a/vendor/github.com/Abirdcfly/dupword/.gitignore b/vendor/github.com/Abirdcfly/dupword/.gitignore new file mode 100644 index 000000000..b5109d2bb --- /dev/null +++ b/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/vendor/github.com/Abirdcfly/dupword/.goreleaser.yml b/vendor/github.com/Abirdcfly/dupword/.goreleaser.yml new file mode 100644 index 000000000..c3401787a --- /dev/null +++ b/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/vendor/github.com/Abirdcfly/dupword/LICENSE b/vendor/github.com/Abirdcfly/dupword/LICENSE new file mode 100644 index 000000000..afa64c6e1 --- /dev/null +++ b/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/vendor/github.com/Abirdcfly/dupword/README.md b/vendor/github.com/Abirdcfly/dupword/README.md new file mode 100644 index 000000000..6917acae2 --- /dev/null +++ b/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 + +- [x] 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/vendor/github.com/Abirdcfly/dupword/dupword.go b/vendor/github.com/Abirdcfly/dupword/dupword.go new file mode 100644 index 000000000..508caca52 --- /dev/null +++ b/vendor/github.com/Abirdcfly/dupword/dupword.go @@ -0,0 +1,302 @@ +// 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.IsDigit(firstRune) { + return true + } + if unicode.IsPunct(firstRune) { + return true + } + if unicode.IsSymbol(firstRune) { + return true + } + return false +} diff --git a/vendor/github.com/Abirdcfly/dupword/version.go b/vendor/github.com/Abirdcfly/dupword/version.go new file mode 100644 index 000000000..9d892d0c9 --- /dev/null +++ b/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/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go index 09523315b..0ca1dc4fe 100644 --- a/vendor/github.com/BurntSushi/toml/decode.go +++ b/vendor/github.com/BurntSushi/toml/decode.go @@ -21,7 +21,9 @@ type Unmarshaler interface { UnmarshalTOML(interface{}) error } -// Unmarshal decodes the contents of `data` in TOML format into a pointer `v`. +// Unmarshal decodes the contents of data in TOML format into a pointer v. +// +// See [Decoder] for a description of the decoding process. func Unmarshal(data []byte, v interface{}) error { _, err := NewDecoder(bytes.NewReader(data)).Decode(v) return err @@ -29,13 +31,12 @@ func Unmarshal(data []byte, v interface{}) error { // Decode the TOML data in to the pointer v. // -// See the documentation on Decoder for a description of the decoding process. +// See [Decoder] for a description of the decoding process. func Decode(data string, v interface{}) (MetaData, error) { return NewDecoder(strings.NewReader(data)).Decode(v) } -// DecodeFile is just like Decode, except it will automatically read the -// contents of the file at path and decode it for you. +// DecodeFile reads the contents of a file and decodes it with [Decode]. func DecodeFile(path string, v interface{}) (MetaData, error) { fp, err := os.Open(path) if err != nil { @@ -48,7 +49,7 @@ func DecodeFile(path string, v interface{}) (MetaData, error) { // Primitive is a TOML value that hasn't been decoded into a Go value. // // This type can be used for any value, which will cause decoding to be delayed. -// You can use the PrimitiveDecode() function to "manually" decode these values. +// You can use [PrimitiveDecode] to "manually" decode these values. // // NOTE: The underlying representation of a `Primitive` value is subject to // change. Do not rely on it. @@ -70,15 +71,15 @@ const ( // Decoder decodes TOML data. // -// TOML tables correspond to Go structs or maps (dealer's choice – they can be -// used interchangeably). +// TOML tables correspond to Go structs or maps; they can be used +// interchangeably, but structs offer better type safety. // // TOML table arrays correspond to either a slice of structs or a slice of maps. // -// TOML datetimes correspond to Go time.Time values. Local datetimes are parsed -// in the local timezone. +// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the +// local timezone. // -// time.Duration types are treated as nanoseconds if the TOML value is an +// [time.Duration] types are treated as nanoseconds if the TOML value is an // integer, or they're parsed with time.ParseDuration() if they're strings. // // All other TOML types (float, string, int, bool and array) correspond to the @@ -90,7 +91,7 @@ const ( // UnmarshalText method. See the Unmarshaler example for a demonstration with // email addresses. // -// Key mapping +// ### Key mapping // // TOML keys can map to either keys in a Go map or field names in a Go struct. // The special `toml` struct tag can be used to map TOML keys to struct fields @@ -168,17 +169,16 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) { return md, md.unify(p.mapping, rv) } -// PrimitiveDecode is just like the other `Decode*` functions, except it -// decodes a TOML value that has already been parsed. Valid primitive values -// can *only* be obtained from values filled by the decoder functions, -// including this method. (i.e., `v` may contain more `Primitive` -// values.) +// PrimitiveDecode is just like the other Decode* functions, except it decodes a +// TOML value that has already been parsed. Valid primitive values can *only* be +// obtained from values filled by the decoder functions, including this method. +// (i.e., v may contain more [Primitive] values.) // -// Meta data for primitive values is included in the meta data returned by -// the `Decode*` functions with one exception: keys returned by the Undecoded -// method will only reflect keys that were decoded. Namely, any keys hidden -// behind a Primitive will be considered undecoded. Executing this method will -// update the undecoded keys in the meta data. (See the example.) +// Meta data for primitive values is included in the meta data returned by the +// Decode* functions with one exception: keys returned by the Undecoded method +// will only reflect keys that were decoded. Namely, any keys hidden behind a +// Primitive will be considered undecoded. Executing this method will update the +// undecoded keys in the meta data. (See the example.) func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { md.context = primValue.context defer func() { md.context = nil }() diff --git a/vendor/github.com/BurntSushi/toml/decode_go116.go b/vendor/github.com/BurntSushi/toml/decode_go116.go index eddfb641b..086d0b686 100644 --- a/vendor/github.com/BurntSushi/toml/decode_go116.go +++ b/vendor/github.com/BurntSushi/toml/decode_go116.go @@ -7,8 +7,8 @@ import ( "io/fs" ) -// DecodeFS is just like Decode, except it will automatically read the contents -// of the file at `path` from a fs.FS instance. +// DecodeFS reads the contents of a file from [fs.FS] and decodes it with +// [Decode]. func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) { fp, err := fsys.Open(path) if err != nil { diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go index 099c4a77d..81a7c0fe9 100644 --- a/vendor/github.com/BurntSushi/toml/doc.go +++ b/vendor/github.com/BurntSushi/toml/doc.go @@ -1,13 +1,11 @@ -/* -Package toml implements decoding and encoding of TOML files. - -This package supports TOML v1.0.0, as listed on https://toml.io - -There is also support for delaying decoding with the Primitive type, and -querying the set of keys in a TOML document with the MetaData type. - -The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, -and can be used to verify if TOML document is valid. It can also be used to -print the type of each key. -*/ +// Package toml implements decoding and encoding of TOML files. +// +// This package supports TOML v1.0.0, as specified at https://toml.io +// +// There is also support for delaying decoding with the Primitive type, and +// querying the set of keys in a TOML document with the MetaData type. +// +// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator, +// and can be used to verify if TOML document is valid. It can also be used to +// print the type of each key. package toml diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go index dc8568d1b..930e1d521 100644 --- a/vendor/github.com/BurntSushi/toml/encode.go +++ b/vendor/github.com/BurntSushi/toml/encode.go @@ -79,12 +79,12 @@ type Marshaler interface { // Encoder encodes a Go to a TOML document. // // The mapping between Go values and TOML values should be precisely the same as -// for the Decode* functions. +// for [Decode]. // // time.Time is encoded as a RFC 3339 string, and time.Duration as its string // representation. // -// The toml.Marshaler and encoder.TextMarshaler interfaces are supported to +// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to // encoding the value as custom TOML. // // If you want to write arbitrary binary data then you will need to use @@ -130,7 +130,7 @@ func NewEncoder(w io.Writer) *Encoder { } } -// Encode writes a TOML representation of the Go value to the Encoder's writer. +// Encode writes a TOML representation of the Go value to the [Encoder]'s writer. // // An error is returned if the value given cannot be encoded to a valid TOML // document. @@ -261,7 +261,7 @@ func (enc *Encoder) eElement(rv reflect.Value) { enc.eElement(reflect.ValueOf(v)) return } - encPanic(errors.New(fmt.Sprintf("Unable to convert \"%s\" to neither int64 nor float64", n))) + encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n)) } switch rv.Kind() { @@ -504,7 +504,8 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) { if opts.name != "" { keyName = opts.name } - if opts.omitempty && isEmpty(fieldVal) { + + if opts.omitempty && enc.isEmpty(fieldVal) { continue } if opts.omitzero && isZero(fieldVal) { @@ -648,12 +649,26 @@ func isZero(rv reflect.Value) bool { return false } -func isEmpty(rv reflect.Value) bool { +func (enc *Encoder) isEmpty(rv reflect.Value) bool { switch rv.Kind() { case reflect.Array, reflect.Slice, reflect.Map, reflect.String: return rv.Len() == 0 case reflect.Struct: - return reflect.Zero(rv.Type()).Interface() == rv.Interface() + if rv.Type().Comparable() { + return reflect.Zero(rv.Type()).Interface() == rv.Interface() + } + // Need to also check if all the fields are empty, otherwise something + // like this with uncomparable types will always return true: + // + // type a struct{ field b } + // type b struct{ s []string } + // s := a{field: b{s: []string{"AAA"}}} + for i := 0; i < rv.NumField(); i++ { + if !enc.isEmpty(rv.Field(i)) { + return false + } + } + return true case reflect.Bool: return !rv.Bool() } @@ -668,16 +683,15 @@ func (enc *Encoder) newline() { // Write a key/value pair: // -// key = +// key = // // This is also used for "k = v" in inline tables; so something like this will // be written in three calls: // -// ┌────────────────────┐ -// │ ┌───┐ ┌─────┐│ -// v v v v vv -// key = {k = v, k2 = v2} -// +// ┌───────────────────┐ +// │ ┌───┐ ┌────┐│ +// v v v v vv +// key = {k = 1, k2 = 2} func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { if len(key) == 0 { encPanic(errNoKey) diff --git a/vendor/github.com/BurntSushi/toml/error.go b/vendor/github.com/BurntSushi/toml/error.go index 2ac24e77e..f4f390e64 100644 --- a/vendor/github.com/BurntSushi/toml/error.go +++ b/vendor/github.com/BurntSushi/toml/error.go @@ -5,57 +5,60 @@ import ( "strings" ) -// ParseError is returned when there is an error parsing the TOML syntax. -// -// For example invalid syntax, duplicate keys, etc. +// ParseError is returned when there is an error parsing the TOML syntax such as +// invalid syntax, duplicate keys, etc. // // In addition to the error message itself, you can also print detailed location -// information with context by using ErrorWithPosition(): +// information with context by using [ErrorWithPosition]: // -// toml: error: Key 'fruit' was already created and cannot be used as an array. +// toml: error: Key 'fruit' was already created and cannot be used as an array. // -// At line 4, column 2-7: +// At line 4, column 2-7: // -// 2 | fruit = [] -// 3 | -// 4 | [[fruit]] # Not allowed -// ^^^^^ +// 2 | fruit = [] +// 3 | +// 4 | [[fruit]] # Not allowed +// ^^^^^ // -// Furthermore, the ErrorWithUsage() can be used to print the above with some -// more detailed usage guidance: +// [ErrorWithUsage] can be used to print the above with some more detailed usage +// guidance: // -// toml: error: newlines not allowed within inline tables +// toml: error: newlines not allowed within inline tables // -// At line 1, column 18: +// At line 1, column 18: // -// 1 | x = [{ key = 42 # -// ^ +// 1 | x = [{ key = 42 # +// ^ // -// Error help: +// Error help: // -// Inline tables must always be on a single line: +// Inline tables must always be on a single line: // -// table = {key = 42, second = 43} +// table = {key = 42, second = 43} // -// It is invalid to split them over multiple lines like so: +// It is invalid to split them over multiple lines like so: // -// # INVALID -// table = { -// key = 42, -// second = 43 -// } +// # INVALID +// table = { +// key = 42, +// second = 43 +// } // -// Use regular for this: +// Use regular for this: // -// [table] -// key = 42 -// second = 43 +// [table] +// key = 42 +// second = 43 type ParseError struct { Message string // Short technical message. Usage string // Longer message with usage guidance; may be blank. Position Position // Position of the error LastKey string // Last parsed key, may be blank. - Line int // Line the error occurred. Deprecated: use Position. + + // Line the error occurred. + // + // Deprecated: use [Position]. + Line int err error input string @@ -83,7 +86,7 @@ func (pe ParseError) Error() string { // ErrorWithUsage() returns the error with detailed location context. // -// See the documentation on ParseError. +// See the documentation on [ParseError]. func (pe ParseError) ErrorWithPosition() string { if pe.input == "" { // Should never happen, but just in case. return pe.Error() @@ -124,7 +127,7 @@ func (pe ParseError) ErrorWithPosition() string { // ErrorWithUsage() returns the error with detailed location context and usage // guidance. // -// See the documentation on ParseError. +// See the documentation on [ParseError]. func (pe ParseError) ErrorWithUsage() string { m := pe.ErrorWithPosition() if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" { diff --git a/vendor/github.com/BurntSushi/toml/go.mod b/vendor/github.com/BurntSushi/toml/go.mod deleted file mode 100644 index 82989481d..000000000 --- a/vendor/github.com/BurntSushi/toml/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/BurntSushi/toml - -go 1.16 diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go index 28ed4dd35..d4d70871d 100644 --- a/vendor/github.com/BurntSushi/toml/lex.go +++ b/vendor/github.com/BurntSushi/toml/lex.go @@ -771,7 +771,7 @@ func lexRawString(lx *lexer) stateFn { } // lexMultilineRawString consumes a raw string. Nothing can be escaped in such -// a string. It assumes that the beginning "'''" has already been consumed and +// a string. It assumes that the beginning ''' has already been consumed and // ignored. func lexMultilineRawString(lx *lexer) stateFn { r := lx.next() diff --git a/vendor/github.com/BurntSushi/toml/meta.go b/vendor/github.com/BurntSushi/toml/meta.go index d284f2a0c..71847a041 100644 --- a/vendor/github.com/BurntSushi/toml/meta.go +++ b/vendor/github.com/BurntSushi/toml/meta.go @@ -71,7 +71,7 @@ func (md *MetaData) Keys() []Key { // Undecoded returns all keys that have not been decoded in the order in which // they appear in the original TOML document. // -// This includes keys that haven't been decoded because of a Primitive value. +// This includes keys that haven't been decoded because of a [Primitive] value. // Once the Primitive value is decoded, the keys will be considered decoded. // // Also note that decoding into an empty interface will result in no decoding, @@ -89,7 +89,7 @@ func (md *MetaData) Undecoded() []Key { return undecoded } -// Key represents any TOML key, including key groups. Use (MetaData).Keys to get +// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get // values of this type. type Key []string diff --git a/vendor/github.com/Djarvur/go-err113/go.mod b/vendor/github.com/Djarvur/go-err113/go.mod deleted file mode 100644 index 6e28e9336..000000000 --- a/vendor/github.com/Djarvur/go-err113/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/Djarvur/go-err113 - -go 1.13 - -require golang.org/x/tools v0.0.0-20200324003944-a576cf524670 diff --git a/vendor/github.com/Djarvur/go-err113/go.sum b/vendor/github.com/Djarvur/go-err113/go.sum deleted file mode 100644 index dab64209d..000000000 --- a/vendor/github.com/Djarvur/go-err113/go.sum +++ /dev/null @@ -1,20 +0,0 @@ -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670 h1:fW7EP/GZqIvbHessHd1PLca+77TBOsRBqtaybMgXJq8= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go index 49948e12e..279f2189d 100644 --- a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/analyzer.go @@ -21,10 +21,10 @@ type analyzer struct { include PatternsList exclude PatternsList - typesProcessCache map[string]bool + typesProcessCache map[types.Type]bool typesProcessCacheMu sync.RWMutex - structFieldsCache map[string]*StructFields + structFieldsCache map[types.Type]*StructFields structFieldsCacheMu sync.RWMutex } @@ -33,9 +33,9 @@ type analyzer struct { // -e arguments adds exclude patterns func NewAnalyzer(include []string, exclude []string) (*analysis.Analyzer, error) { a := analyzer{ //nolint:exhaustruct - typesProcessCache: map[string]bool{}, + typesProcessCache: map[types.Type]bool{}, - structFieldsCache: map[string]*StructFields{}, + structFieldsCache: map[types.Type]*StructFields{}, } var err error @@ -123,7 +123,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { return } - if !a.shouldProcessType(typ.String()) { + if !a.shouldProcessType(typ) { return } @@ -138,7 +138,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { } } - missingFields := a.structMissingFields(lit, strct, typ.String(), pass.Pkg.Path()) + missingFields := a.structMissingFields(lit, strct, strings.HasPrefix(typ.String(), pass.Pkg.Path()+".")) if len(missingFields) == 1 { pass.Reportf(node.Pos(), "%s is missing in %s", missingFields[0], strctName) @@ -148,7 +148,7 @@ func (a *analyzer) newVisitor(pass *analysis.Pass) func(node ast.Node) { } } -func (a *analyzer) shouldProcessType(typ string) bool { +func (a *analyzer) shouldProcessType(typ types.Type) bool { if len(a.include) == 0 && len(a.exclude) == 0 { // skip whole part with cache, since we have no restrictions and have to check everything return true @@ -163,12 +163,13 @@ func (a *analyzer) shouldProcessType(typ string) bool { defer a.typesProcessCacheMu.Unlock() v = true + typStr := typ.String() - if len(a.include) > 0 && !a.include.MatchesAny(typ) { + if len(a.include) > 0 && !a.include.MatchesAny(typStr) { v = false } - if v && a.exclude.MatchesAny(typ) { + if v && a.exclude.MatchesAny(typStr) { v = false } @@ -178,32 +179,28 @@ func (a *analyzer) shouldProcessType(typ string) bool { return v } -func (a *analyzer) structMissingFields( - lit *ast.CompositeLit, - strct *types.Struct, - typ string, - pkgPath string, -) []string { +func (a *analyzer) structMissingFields(lit *ast.CompositeLit, strct *types.Struct, private bool) []string { keys, unnamed := literalKeys(lit) - fields := a.structFields(typ, strct) + fields := a.structFields(strct) - var fieldNames []string + if unnamed { + if private { + return fields.All[len(keys):] + } - if strings.HasPrefix(typ, pkgPath+".") { - // we're in same package and should match private fields - fieldNames = fields.All - } else { - fieldNames = fields.Public + return fields.Public[len(keys):] } - if unnamed { - return fieldNames[len(keys):] + if private { + return difference(fields.AllRequired, keys) } - return difference(fieldNames, keys) + return difference(fields.PublicRequired, keys) } -func (a *analyzer) structFields(typ string, strct *types.Struct) *StructFields { +func (a *analyzer) structFields(strct *types.Struct) *StructFields { + typ := strct.Underlying() + a.structFieldsCacheMu.RLock() fields, ok := a.structFieldsCache[typ] a.structFieldsCacheMu.RUnlock() diff --git a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go index e7d004250..56eda05f7 100644 --- a/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go +++ b/vendor/github.com/GaijinEntertainment/go-exhaustruct/v2/pkg/analyzer/struct-fields.go @@ -2,26 +2,60 @@ package analyzer import ( "go/types" + "reflect" + + "golang.org/x/exp/slices" ) type StructFields struct { - Public []string + All []string + AllRequired []string - All []string + Public []string + PublicRequired []string } func NewStructFields(strct *types.Struct) *StructFields { - sf := StructFields{} //nolint:exhaustruct + sf := StructFields{ + All: make([]string, strct.NumFields()), + AllRequired: make([]string, 0, strct.NumFields()), + Public: make([]string, 0, strct.NumFields()), + PublicRequired: make([]string, 0, strct.NumFields()), + } for i := 0; i < strct.NumFields(); i++ { f := strct.Field(i) + isOptional := isFieldOptional(strct.Tag(i)) - sf.All = append(sf.All, f.Name()) + sf.All[i] = f.Name() + if !isOptional { + sf.AllRequired = append(sf.AllRequired, f.Name()) + } if f.Exported() { sf.Public = append(sf.Public, f.Name()) + + if !isOptional { + sf.PublicRequired = append(sf.PublicRequired, f.Name()) + } } } + sf.All = slices.Clip(sf.All) + sf.AllRequired = slices.Clip(sf.AllRequired) + sf.Public = slices.Clip(sf.Public) + sf.PublicRequired = slices.Clip(sf.PublicRequired) + return &sf } + +const ( + TagName = "exhaustruct" + OptionalTagValue = "optional" +) + +// isFieldOptional checks if field tags has an optional tag, and therefore can +// be omitted during structure initialization. +func isFieldOptional(tags string) bool { + return reflect.StructTag(tags).Get(TagName) == OptionalTagValue +} diff --git a/vendor/github.com/OpenPeeDeeP/depguard/README.md b/vendor/github.com/OpenPeeDeeP/depguard/README.md index b9422757d..07e9f915d 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/README.md +++ b/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/vendor/github.com/OpenPeeDeeP/depguard/depguard.go b/vendor/github.com/OpenPeeDeeP/depguard/depguard.go index b72754913..d7011cd9f 100644 --- a/vendor/github.com/OpenPeeDeeP/depguard/depguard.go +++ b/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/vendor/github.com/OpenPeeDeeP/depguard/go.mod b/vendor/github.com/OpenPeeDeeP/depguard/go.mod deleted file mode 100644 index 68daf00d7..000000000 --- a/vendor/github.com/OpenPeeDeeP/depguard/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/OpenPeeDeeP/depguard - -go 1.13 - -require ( - github.com/gobwas/glob v0.2.3 - github.com/kisielk/gotool v1.0.0 - github.com/stretchr/testify v1.7.0 // indirect - golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b -) diff --git a/vendor/github.com/OpenPeeDeeP/depguard/go.sum b/vendor/github.com/OpenPeeDeeP/depguard/go.sum deleted file mode 100644 index 11a8c1c4a..000000000 --- a/vendor/github.com/OpenPeeDeeP/depguard/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b h1:7tibmaEqrQYA+q6ri7NQjuxqSwechjtDHKq6/e85S38= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/alingse/asasalint/asasalint.go b/vendor/github.com/alingse/asasalint/asasalint.go index 544bad84c..f34516a46 100644 --- a/vendor/github.com/alingse/asasalint/asasalint.go +++ b/vendor/github.com/alingse/asasalint/asasalint.go @@ -16,7 +16,7 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -const BuiltinExclusions = `^(fmt|log|logger)\.(Print|Fprint|Sprint|Fatal|Panic|Error|Warn|Warning|Info|Debug)(|f|ln)$` +const BuiltinExclusions = `^(fmt|log|logger|t|)\.(Print|Fprint|Sprint|Fatal|Panic|Error|Warn|Warning|Info|Debug|Log)(|f|ln)$` type LinterSetting struct { Exclude []string diff --git a/vendor/github.com/alingse/asasalint/go.mod b/vendor/github.com/alingse/asasalint/go.mod deleted file mode 100644 index 928e71c18..000000000 --- a/vendor/github.com/alingse/asasalint/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/alingse/asasalint - -go 1.18 - -require golang.org/x/tools v0.1.11 - -require ( - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect -) diff --git a/vendor/github.com/alingse/asasalint/go.sum b/vendor/github.com/alingse/asasalint/go.sum deleted file mode 100644 index 7ec6d5e77..000000000 --- a/vendor/github.com/alingse/asasalint/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go b/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go index 17740faa7..9b3765405 100644 --- a/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go +++ b/vendor/github.com/ashanbrown/forbidigo/forbidigo/forbidigo.go @@ -7,6 +7,7 @@ import ( "go/ast" "go/printer" "go/token" + "go/types" "log" "regexp" "strings" @@ -16,6 +17,7 @@ import ( type Issue interface { Details() string + Pos() token.Pos Position() token.Position String() string } @@ -23,6 +25,7 @@ type Issue interface { type UsedIssue struct { identifier string pattern string + pos token.Pos position token.Position customMsg string } @@ -39,6 +42,10 @@ func (a UsedIssue) Position() token.Position { return a.position } +func (a UsedIssue) Pos() token.Pos { + return a.pos +} + func (a UsedIssue) String() string { return toString(a) } func toString(i UsedIssue) string { @@ -91,19 +98,43 @@ type visitor struct { linter *Linter comments []*ast.CommentGroup - fset *token.FileSet - issues []Issue + runConfig RunConfig + issues []Issue } +// Deprecated: Run was the original entrypoint before RunWithConfig was introduced to support +// additional match patterns that need additional information. func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { - var issues []Issue //nolint:prealloc // we don't know how many there will be + return l.RunWithConfig(RunConfig{Fset: fset}, nodes...) +} + +// RunConfig provides information that the linter needs for different kinds +// of match patterns. Ideally, all fields should get set. More fields may get +// added in the future as needed. +type RunConfig struct { + // FSet is required. + Fset *token.FileSet + + // TypesInfo is needed for expanding source code expressions. + // Nil disables that step, i.e. patterns match the literal source code. + TypesInfo *types.Info + + // DebugLog is used to print debug messages. May be nil. + DebugLog func(format string, args ...interface{}) +} + +func (l *Linter) RunWithConfig(config RunConfig, nodes ...ast.Node) ([]Issue, error) { + if config.DebugLog == nil { + config.DebugLog = func(format string, args ...interface{}) {} + } + var issues []Issue for _, node := range nodes { var comments []*ast.CommentGroup isTestFile := false isWholeFileExample := false if file, ok := node.(*ast.File); ok { comments = file.Comments - fileName := fset.Position(file.Pos()).Filename + fileName := config.Fset.Position(file.Pos()).Filename isTestFile = strings.HasSuffix(fileName, "_test.go") // From https://blog.golang.org/examples, a "whole file example" is: @@ -139,7 +170,7 @@ func (l *Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { cfg: l.cfg, isTestFile: isTestFile, linter: l, - fset: fset, + runConfig: config, comments: comments, } ast.Walk(&visitor, node) @@ -157,40 +188,169 @@ func (v *visitor) Visit(node ast.Node) ast.Visitor { return nil } return v + // The following two are handled below. case *ast.SelectorExpr: case *ast.Ident: + // Everything else isn't. default: return v } + + // The text as it appears in the source is always used because issues + // use that. It's used for matching unless usage of type information + // is enabled. + srcText := v.textFor(node) + matchTexts, pkgText := v.expandMatchText(node, srcText) + v.runConfig.DebugLog("%s: match %v, package %q", v.runConfig.Fset.Position(node.Pos()), matchTexts, pkgText) for _, p := range v.linter.patterns { - if p.pattern.MatchString(v.textFor(node)) && !v.permit(node) { + if p.matches(matchTexts) && + (p.Package == "" || p.pkgRe.MatchString(pkgText)) && + !v.permit(node) { v.issues = append(v.issues, UsedIssue{ - identifier: v.textFor(node), - pattern: p.pattern.String(), - position: v.fset.Position(node.Pos()), - customMsg: p.msg, + identifier: srcText, // Always report the expression as it appears in the source code. + pattern: p.re.String(), + pos: node.Pos(), + position: v.runConfig.Fset.Position(node.Pos()), + customMsg: p.Msg, }) } } return nil } +// textFor returns the expression as it appears in the source code (for +// example, .). func (v *visitor) textFor(node ast.Node) string { buf := new(bytes.Buffer) - if err := printer.Fprint(buf, v.fset, node); err != nil { - log.Fatalf("ERROR: unable to print node at %s: %s", v.fset.Position(node.Pos()), err) + if err := printer.Fprint(buf, v.runConfig.Fset, node); err != nil { + log.Fatalf("ERROR: unable to print node at %s: %s", v.runConfig.Fset.Position(node.Pos()), err) } return buf.String() } +// expandMatchText expands the selector in a selector expression to the full package +// name and (for variables) the type: +// +// - example.com/some/pkg.Function +// - example.com/some/pkg.CustomType.Method +// +// It updates the text to match against and fills the package string if possible, +// otherwise it just returns. +func (v *visitor) expandMatchText(node ast.Node, srcText string) (matchTexts []string, pkgText string) { + // The text to match against is the literal source code if we cannot + // come up with something different. + matchText := srcText + + if v.runConfig.TypesInfo == nil { + return []string{matchText}, pkgText + } + + location := v.runConfig.Fset.Position(node.Pos()) + + switch node := node.(type) { + case *ast.Ident: + object, ok := v.runConfig.TypesInfo.Uses[node] + if !ok { + // No information about the identifier. Should + // not happen, but perhaps there were compile + // errors? + v.runConfig.DebugLog("%s: unknown identifier %q", location, srcText) + return []string{matchText}, pkgText + } + if pkg := object.Pkg(); pkg != nil { + pkgText = pkg.Path() + v.runConfig.DebugLog("%s: identifier: %q -> %q in package %q", location, srcText, matchText, pkgText) + // match either with or without package name + return []string{pkg.Name() + "." + srcText, srcText}, pkgText + } else { + v.runConfig.DebugLog("%s: identifier: %q -> %q without package", location, srcText, matchText) + } + return []string{matchText}, pkgText + case *ast.SelectorExpr: + selector := node.X + field := node.Sel.Name + + // If we are lucky, the entire selector expression has a known + // type. We don't care about the value. + selectorText := v.textFor(node) + if typeAndValue, ok := v.runConfig.TypesInfo.Types[selector]; ok { + m, p, ok := pkgFromType(typeAndValue.Type) + if !ok { + v.runConfig.DebugLog("%s: selector %q with supported type %T", location, selectorText, typeAndValue.Type) + } + matchText = m + "." + field + pkgText = p + v.runConfig.DebugLog("%s: selector %q with supported type %q: %q -> %q, package %q", location, selectorText, typeAndValue.Type.String(), srcText, matchText, pkgText) + return []string{matchText}, pkgText + } + // Some expressions need special treatment. + switch selector := selector.(type) { + case *ast.Ident: + object, ok := v.runConfig.TypesInfo.Uses[selector] + if !ok { + // No information about the identifier. Should + // not happen, but perhaps there were compile + // errors? + v.runConfig.DebugLog("%s: unknown selector identifier %q", location, selectorText) + return []string{matchText}, pkgText + } + switch object := object.(type) { + case *types.PkgName: + pkgText = object.Imported().Path() + matchText = object.Imported().Name() + "." + field + v.runConfig.DebugLog("%s: selector %q is package: %q -> %q, package %q", location, selectorText, srcText, matchText, pkgText) + return []string{matchText}, pkgText + case *types.Var: + m, p, ok := pkgFromType(object.Type()) + if !ok { + v.runConfig.DebugLog("%s: selector %q is variable with unsupported type %T", location, selectorText, object.Type()) + } + matchText = m + "." + field + pkgText = p + v.runConfig.DebugLog("%s: selector %q is variable of type %q: %q -> %q, package %q", location, selectorText, object.Type().String(), srcText, matchText, pkgText) + default: + // Something else? + v.runConfig.DebugLog("%s: selector %q is identifier with unsupported type %T", location, selectorText, object) + } + default: + v.runConfig.DebugLog("%s: selector %q of unsupported type %T", location, selectorText, selector) + } + return []string{matchText}, pkgText + default: + v.runConfig.DebugLog("%s: unsupported type %T", location, node) + return []string{matchText}, pkgText + } +} + +// pkgFromType tries to determine `.` and the full +// package path. This only needs to work for types of a selector in a selector +// expression. +func pkgFromType(t types.Type) (typeStr, pkgStr string, ok bool) { + if ptr, ok := t.(*types.Pointer); ok { + t = ptr.Elem() + } + + switch t := t.(type) { + case *types.Named: + obj := t.Obj() + pkg := obj.Pkg() + if pkg == nil { + return "", "", false + } + return pkg.Name() + "." + obj.Name(), pkg.Path(), true + default: + return "", "", false + } +} + func (v *visitor) permit(node ast.Node) bool { if v.cfg.IgnorePermitDirectives { return false } - nodePos := v.fset.Position(node.Pos()) - var nolint = regexp.MustCompile(fmt.Sprintf(`^//\s?permit:%s\b`, regexp.QuoteMeta(v.textFor(node)))) + nodePos := v.runConfig.Fset.Position(node.Pos()) + nolint := regexp.MustCompile(fmt.Sprintf(`^//\s?permit:%s\b`, regexp.QuoteMeta(v.textFor(node)))) for _, c := range v.comments { - commentPos := v.fset.Position(c.Pos()) + commentPos := v.runConfig.Fset.Position(c.Pos()) if commentPos.Line == nodePos.Line && len(c.List) > 0 && nolint.MatchString(c.List[0].Text) { return true } diff --git a/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go b/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go index c23648822..2692dcd24 100644 --- a/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go +++ b/vendor/github.com/ashanbrown/forbidigo/forbidigo/patterns.go @@ -5,39 +5,123 @@ import ( "regexp" "regexp/syntax" "strings" + + "gopkg.in/yaml.v2" ) +// pattern matches code that is not supposed to be used. type pattern struct { - pattern *regexp.Regexp - msg string + re, pkgRe *regexp.Regexp + + // Pattern is the regular expression string that is used for matching. + // It gets matched against the literal source code text or the expanded + // text, depending on the mode in which the analyzer runs. + Pattern string `yaml:"p"` + + // Package is a regular expression for the full package path of + // an imported item. Ignored unless the analyzer is configured to + // determine that information. + Package string `yaml:"pkg,omitempty"` + + // Msg gets printed in addition to the normal message if a match is + // found. + Msg string `yaml:"msg,omitempty"` +} + +// A yamlPattern pattern in a YAML string may be represented either by a string +// (the traditional regular expression syntax) or a struct (for more complex +// patterns). +type yamlPattern pattern + +func (p *yamlPattern) UnmarshalYAML(unmarshal func(interface{}) error) error { + // Try struct first. It's unlikely that a regular expression string + // is valid YAML for a struct. + var ptrn pattern + if err := unmarshal(&ptrn); err != nil { + errStr := err.Error() + // Didn't work, try plain string. + var ptrn string + if err := unmarshal(&ptrn); err != nil { + return fmt.Errorf("pattern is neither a regular expression string (%s) nor a Pattern struct (%s)", err.Error(), errStr) + } + p.Pattern = ptrn + } else { + *p = yamlPattern(ptrn) + } + return ((*pattern)(p)).validate() } +var _ yaml.Unmarshaler = &yamlPattern{} + +// parse accepts a regular expression or, if the string starts with { or contains a line break, a +// JSON or YAML representation of a Pattern. func parse(ptrn string) (*pattern, error) { - ptrnRe, err := regexp.Compile(ptrn) + pattern := &pattern{} + + if strings.HasPrefix(strings.TrimSpace(ptrn), "{") || + strings.Contains(ptrn, "\n") { + // Embedded JSON or YAML. We can decode both with the YAML decoder. + if err := yaml.UnmarshalStrict([]byte(ptrn), pattern); err != nil { + return nil, fmt.Errorf("parsing as JSON or YAML failed: %v", err) + } + } else { + pattern.Pattern = ptrn + } + + if err := pattern.validate(); err != nil { + return nil, err + } + return pattern, nil +} + +func (p *pattern) validate() error { + ptrnRe, err := regexp.Compile(p.Pattern) if err != nil { - return nil, fmt.Errorf("unable to compile pattern `%s`: %s", ptrn, err) + return fmt.Errorf("unable to compile source code pattern `%s`: %s", p.Pattern, err) } - re, err := syntax.Parse(ptrn, syntax.Perl) + re, err := syntax.Parse(p.Pattern, syntax.Perl) if err != nil { - return nil, fmt.Errorf("unable to parse pattern `%s`: %s", ptrn, err) + return fmt.Errorf("unable to parse source code pattern `%s`: %s", p.Pattern, err) } msg := extractComment(re) - return &pattern{pattern: ptrnRe, msg: msg}, nil + if msg != "" { + p.Msg = msg + } + p.re = ptrnRe + + if p.Package != "" { + pkgRe, err := regexp.Compile(p.Package) + if err != nil { + return fmt.Errorf("unable to compile package pattern `%s`: %s", p.Package, err) + } + p.pkgRe = pkgRe + } + + return nil +} + +func (p *pattern) matches(matchTexts []string) bool { + for _, text := range matchTexts { + if p.re.MatchString(text) { + return true + } + } + return false } // Traverse the leaf submatches in the regex tree and extract a comment, if any // is present. func extractComment(re *syntax.Regexp) string { for _, sub := range re.Sub { + subStr := sub.String() + if strings.HasPrefix(subStr, "#") { + return strings.TrimSpace(strings.TrimPrefix(sub.String(), "#")) + } if len(sub.Sub) > 0 { if comment := extractComment(sub); comment != "" { return comment } } - subStr := sub.String() - if strings.HasPrefix(subStr, "#") { - return strings.TrimSpace(strings.TrimPrefix(subStr, "#")) - } } return "" } diff --git a/vendor/github.com/blizzy78/varnamelen/go.mod b/vendor/github.com/blizzy78/varnamelen/go.mod deleted file mode 100644 index 29bece721..000000000 --- a/vendor/github.com/blizzy78/varnamelen/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module github.com/blizzy78/varnamelen - -go 1.16 - -require ( - github.com/matryer/is v1.4.0 - golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c // indirect - golang.org/x/tools v0.1.10 -) - -retract ( - v0.6.1 // see https://github.com/blizzy78/varnamelen/issues/13, use 0.6.2 or later instead -) diff --git a/vendor/github.com/blizzy78/varnamelen/go.sum b/vendor/github.com/blizzy78/varnamelen/go.sum deleted file mode 100644 index 6845d4300..000000000 --- a/vendor/github.com/blizzy78/varnamelen/go.sum +++ /dev/null @@ -1,32 +0,0 @@ -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= -github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c h1:+8miTPjMCTXwih7BQmvWwd0PjdBZq2MKp/qQaahSzEM= -golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/bombsimon/wsl/v3/.golangci.yml b/vendor/github.com/bombsimon/wsl/v3/.golangci.yml new file mode 100644 index 000000000..336ad4bc8 --- /dev/null +++ b/vendor/github.com/bombsimon/wsl/v3/.golangci.yml @@ -0,0 +1,78 @@ +--- +run: + deadline: 1m + issues-exit-code: 1 + tests: true + skip-dirs: + - vendor$ + +output: + format: colored-line-number + print-issued-lines: false + +linters-settings: + gocognit: + min-complexity: 10 + + depguard: + list-type: blacklist + include-go-root: false + packages: + - github.com/davecgh/go-spew/spew + + misspell: + locale: US + + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` + # to see all tags and checks. Empty list by default. See + # https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + +linters: + enable-all: true + disable: + - cyclop + - deadcode + - dupl + - dupword + - exhaustivestruct + - exhaustruct + - forbidigo + - funlen + - gci + - gocognit + - gocyclo + - godox + - golint + - gomnd + - ifshort + - interfacer + - lll + - maintidx + - maligned + - nakedret + - nestif + - nlreturn + - nosnakecase + - paralleltest + - prealloc + - scopelint + - structcheck + - testpackage + - varcheck + - varnamelen + fast: false + + +issues: + exclude-use-default: true + max-issues-per-linter: 0 + max-same-issues: 0 + +# vim: set sw=2 ts=2 et: diff --git a/vendor/github.com/bombsimon/wsl/v3/.travis.yml b/vendor/github.com/bombsimon/wsl/v3/.travis.yml deleted file mode 100644 index 5e2e26ed1..000000000 --- a/vendor/github.com/bombsimon/wsl/v3/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -language: go - -go: - - 1.13.x - - 1.12.x - - 1.11.x - -env: - global: - - GO111MODULE=on - -install: - - go get -v golang.org/x/tools/cmd/cover github.com/mattn/goveralls - -script: - - go test -v -covermode=count -coverprofile=coverage.out - -after_script: - - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci - -notifications: - email: false - -# vim: set ts=2 sw=2 et: diff --git a/vendor/github.com/bombsimon/wsl/v3/README.md b/vendor/github.com/bombsimon/wsl/v3/README.md index 9812f94a7..8ff74392b 100644 --- a/vendor/github.com/bombsimon/wsl/v3/README.md +++ b/vendor/github.com/bombsimon/wsl/v3/README.md @@ -3,7 +3,7 @@ [![forthebadge](https://forthebadge.com/images/badges/made-with-go.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) -[![Build Status](https://travis-ci.org/bombsimon/wsl.svg?branch=master)](https://travis-ci.org/bombsimon/wsl) +[![GitHub Actions](https://github.com/bombsimon/wsl/actions/workflows/go.yml/badge.svg)](https://github.com/bombsimon/wsl/actions/workflows/go.yml) [![Coverage Status](https://coveralls.io/repos/github/bombsimon/wsl/badge.svg?branch=master)](https://coveralls.io/github/bombsimon/wsl?branch=master) WSL is a linter that enforces a very **non scientific** vision of how to make @@ -28,7 +28,7 @@ make something configurable! You can do that by using: ```sh -go get -u github.com/bombsimon/wsl/cmd/... +go get -u github.com/bombsimon/wsl/v3/cmd/... ``` ### By golangci-lint (CI automation) diff --git a/vendor/github.com/bombsimon/wsl/v3/go.mod b/vendor/github.com/bombsimon/wsl/v3/go.mod deleted file mode 100644 index 0c325eda1..000000000 --- a/vendor/github.com/bombsimon/wsl/v3/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/bombsimon/wsl/v3 - -go 1.12 - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/stretchr/testify v1.5.1 - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect -) diff --git a/vendor/github.com/bombsimon/wsl/v3/go.sum b/vendor/github.com/bombsimon/wsl/v3/go.sum deleted file mode 100644 index 3bdb59247..000000000 --- a/vendor/github.com/bombsimon/wsl/v3/go.sum +++ /dev/null @@ -1,25 +0,0 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -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= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/bombsimon/wsl/v3/wsl.go b/vendor/github.com/bombsimon/wsl/v3/wsl.go index 313b52787..1b139c047 100644 --- a/vendor/github.com/bombsimon/wsl/v3/wsl.go +++ b/vendor/github.com/bombsimon/wsl/v3/wsl.go @@ -5,12 +5,12 @@ import ( "go/ast" "go/parser" "go/token" - "io/ioutil" + "os" "reflect" "strings" ) -// Error reason strings +// Error reason strings. const ( reasonMustCuddleErrCheck = "if statements that check an error must be cuddled with the statement that assigned the error" reasonOnlyCuddleIfWithAssign = "if statements should only be cuddled with assignments" @@ -44,7 +44,7 @@ const ( reasonShortDeclNotExclusive = "short declaration should cuddle only with other short declarations" ) -// Warning strings +// Warning strings. const ( warnTypeNotImplement = "type not implemented" warnStmtNotImplemented = "stmt type not implemented" @@ -176,7 +176,7 @@ type Configuration struct { ForceExclusiveShortDeclarations bool } -// DefaultConfig returns default configuration +// DefaultConfig returns default configuration. func DefaultConfig() Configuration { return Configuration{ StrictAppend: true, @@ -216,6 +216,8 @@ type Processor struct { } // NewProcessor will create a Processor. +// +//nolint:gocritic // It's fine to copy config struct func NewProcessorWithConfig(cfg Configuration) *Processor { return &Processor{ result: []Result{}, @@ -230,10 +232,11 @@ func NewProcessor() *Processor { // ProcessFiles takes a string slice with file names (full paths) and lints // them. -// nolint: gocritic +// +//nolint:gocritic // Don't want named returns func (p *Processor) ProcessFiles(filenames []string) ([]Result, []string) { for _, filename := range filenames { - data, err := ioutil.ReadFile(filename) + data, err := os.ReadFile(filename) if err != nil { panic(err) } @@ -247,7 +250,6 @@ func (p *Processor) ProcessFiles(filenames []string) ([]Result, []string) { func (p *Processor) process(filename string, data []byte) { fileSet := token.NewFileSet() file, err := parser.ParseFile(fileSet, filename, data, parser.ParseComments) - // If the file is not parsable let's add a syntax error and move on. if err != nil { p.result = append(p.result, Result{ @@ -292,7 +294,6 @@ func (p *Processor) parseBlockBody(ident *ast.Ident, block *ast.BlockStmt) { // parseBlockStatements will parse all the statements found in the body of a // node. A list of Result is returned. -// nolint: gocognit func (p *Processor) parseBlockStatements(statements []ast.Stmt) { for i, stmt := range statements { // Start by checking if this statement is another block (other than if, @@ -335,7 +336,7 @@ func (p *Processor) parseBlockStatements(statements []ast.Stmt) { var calledOnLineAbove []string // Check if the previous statement spans over multiple lines. - var cuddledWithMultiLineAssignment = cuddledWithLastStmt && p.nodeStart(previousStatement) != p.nodeStart(stmt)-1 + cuddledWithMultiLineAssignment := cuddledWithLastStmt && p.nodeStart(previousStatement) != p.nodeStart(stmt)-1 // Ensure previous line is not a multi line assignment and if not get // rightAndLeftHandSide assigned variables. @@ -397,8 +398,7 @@ func (p *Processor) parseBlockStatements(statements []ast.Stmt) { // t.X = true // return t // } - // nolint: gocritic - if i == len(statements)-1 && i == 1 { + if len(statements) == 2 && i == 1 { if p.nodeEnd(stmt)-p.nodeStart(previousStatement) <= 2 { return true } @@ -672,6 +672,22 @@ func (p *Processor) parseBlockStatements(statements []ast.Stmt) { continue } + if c, ok := t.Call.Fun.(*ast.SelectorExpr); ok { + goCallArgs := append(p.findLHS(c.X), p.findRHS(c.X)...) + + if atLeastOneInListsMatch(calledOnLineAbove, goCallArgs) { + continue + } + } + + if c, ok := t.Call.Fun.(*ast.FuncLit); ok { + goCallArgs := append(p.findLHS(c.Body), p.findRHS(c.Body)...) + + if atLeastOneInListsMatch(assignedOnLineAbove, goCallArgs) { + continue + } + } + if !atLeastOneInListsMatch(rightAndLeftHandSide, assignedOnLineAbove) { p.addError(t.Pos(), reasonGoFuncWithoutAssign) } @@ -845,8 +861,7 @@ func (p *Processor) findRHS(node ast.Node) []string { case *ast.BasicLit, *ast.SelectStmt, *ast.ChanType, *ast.LabeledStmt, *ast.DeclStmt, *ast.BranchStmt, *ast.TypeSpec, *ast.ArrayType, *ast.CaseClause, - *ast.CommClause, *ast.KeyValueExpr, *ast.MapType, - *ast.FuncLit: + *ast.CommClause, *ast.MapType, *ast.FuncLit: // Nothing to add to RHS case *ast.Ident: return []string{t.Name} @@ -905,6 +920,9 @@ func (p *Processor) findRHS(node ast.Node) []string { rhs = append(rhs, p.findRHS(t.X)...) rhs = append(rhs, p.findRHS(t.Low)...) rhs = append(rhs, p.findRHS(t.High)...) + case *ast.KeyValueExpr: + rhs = p.findRHS(t.Key) + rhs = append(rhs, p.findRHS(t.Value)...) default: if x, ok := maybeX(t); ok { return p.findRHS(x) @@ -1002,7 +1020,6 @@ func atLeastOneInListsMatch(listOne, listTwo []string) bool { // findLeadingAndTrailingWhitespaces will find leading and trailing whitespaces // in a node. The method takes comments in consideration which will make the // parser more gentle. -// nolint: gocognit func (p *Processor) findLeadingAndTrailingWhitespaces(ident *ast.Ident, stmt, nextStatement ast.Node) { var ( allowedLinesBeforeFirstStatement = 1 @@ -1094,7 +1111,7 @@ func (p *Processor) findLeadingAndTrailingWhitespaces(ident *ast.Ident, stmt, ne if seenCommentGroups > 1 { allowedLinesBeforeFirstStatement += seenCommentGroups - 1 } else if seenCommentGroups == 1 { - allowedLinesBeforeFirstStatement += 1 + allowedLinesBeforeFirstStatement++ } } @@ -1205,7 +1222,7 @@ func (p *Processor) nodeStart(node ast.Node) int { } func (p *Processor) nodeEnd(node ast.Node) int { - var line = p.fileSet.Position(node.End()).Line + line := p.fileSet.Position(node.End()).Line if isEmptyLabeledStmt(node) { return p.fileSet.Position(node.Pos()).Line diff --git a/vendor/github.com/breml/errchkjson/go.mod b/vendor/github.com/breml/errchkjson/go.mod deleted file mode 100644 index 75704c4bb..000000000 --- a/vendor/github.com/breml/errchkjson/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/breml/errchkjson - -go 1.17 - -require golang.org/x/tools v0.1.10 - -require ( - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect -) diff --git a/vendor/github.com/breml/errchkjson/go.sum b/vendor/github.com/breml/errchkjson/go.sum deleted file mode 100644 index 0e4a1ee18..000000000 --- a/vendor/github.com/breml/errchkjson/go.sum +++ /dev/null @@ -1,30 +0,0 @@ -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md index 792b4a60b..8bf0e5b78 100644 --- a/vendor/github.com/cespare/xxhash/v2/README.md +++ b/vendor/github.com/cespare/xxhash/v2/README.md @@ -3,8 +3,7 @@ [![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2) [![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml) -xxhash is a Go implementation of the 64-bit -[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a +xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a high-quality hashing algorithm that is much faster than anything in the Go standard library. @@ -25,8 +24,11 @@ func (*Digest) WriteString(string) (int, error) func (*Digest) Sum64() uint64 ``` -This implementation provides a fast pure-Go implementation and an even faster -assembly implementation for amd64. +The package is written with optimized pure Go and also contains even faster +assembly implementations for amd64 and arm64. If desired, the `purego` build tag +opts into using the Go code even on those architectures. + +[xxHash]: http://cyan4973.github.io/xxHash/ ## Compatibility @@ -45,19 +47,20 @@ I recommend using the latest release of Go. Here are some quick benchmarks comparing the pure-Go and assembly implementations of Sum64. -| input size | purego | asm | -| --- | --- | --- | -| 5 B | 979.66 MB/s | 1291.17 MB/s | -| 100 B | 7475.26 MB/s | 7973.40 MB/s | -| 4 KB | 17573.46 MB/s | 17602.65 MB/s | -| 10 MB | 17131.46 MB/s | 17142.16 MB/s | +| input size | purego | asm | +| ---------- | --------- | --------- | +| 4 B | 1.3 GB/s | 1.2 GB/s | +| 16 B | 2.9 GB/s | 3.5 GB/s | +| 100 B | 6.9 GB/s | 8.1 GB/s | +| 4 KB | 11.7 GB/s | 16.7 GB/s | +| 10 MB | 12.0 GB/s | 17.3 GB/s | -These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using -the following commands under Go 1.11.2: +These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C +CPU using the following commands under Go 1.19.2: ``` -$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes' -$ go test -benchtime 10s -bench '/xxhash,direct,bytes' +benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$') +benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') ``` ## Projects using this package diff --git a/vendor/github.com/cespare/xxhash/v2/go.mod b/vendor/github.com/cespare/xxhash/v2/go.mod deleted file mode 100644 index 49f67608b..000000000 --- a/vendor/github.com/cespare/xxhash/v2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/cespare/xxhash/v2 - -go 1.11 diff --git a/vendor/github.com/cespare/xxhash/v2/go.sum b/vendor/github.com/cespare/xxhash/v2/go.sum deleted file mode 100644 index e69de29bb..000000000 diff --git a/vendor/github.com/cespare/xxhash/v2/testall.sh b/vendor/github.com/cespare/xxhash/v2/testall.sh new file mode 100644 index 000000000..94b9c4439 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/testall.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -eu -o pipefail + +# Small convenience script for running the tests with various combinations of +# arch/tags. This assumes we're running on amd64 and have qemu available. + +go test ./... +go test -tags purego ./... +GOARCH=arm64 go test +GOARCH=arm64 go test -tags purego diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go index 15c835d54..a9e0d45c9 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go @@ -16,19 +16,11 @@ const ( prime5 uint64 = 2870177450012600261 ) -// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where -// possible in the Go code is worth a small (but measurable) performance boost -// by avoiding some MOVQs. Vars are needed for the asm and also are useful for -// convenience in the Go code in a few places where we need to intentionally -// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the -// result overflows a uint64). -var ( - prime1v = prime1 - prime2v = prime2 - prime3v = prime3 - prime4v = prime4 - prime5v = prime5 -) +// Store the primes in an array as well. +// +// The consts are used when possible in Go code to avoid MOVs but we need a +// contiguous array of the assembly code. +var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} // Digest implements hash.Hash64. type Digest struct { @@ -50,10 +42,10 @@ func New() *Digest { // Reset clears the Digest's state so that it can be reused. func (d *Digest) Reset() { - d.v1 = prime1v + prime2 + d.v1 = primes[0] + prime2 d.v2 = prime2 d.v3 = 0 - d.v4 = -prime1v + d.v4 = -primes[0] d.total = 0 d.n = 0 } @@ -69,21 +61,23 @@ func (d *Digest) Write(b []byte) (n int, err error) { n = len(b) d.total += uint64(n) + memleft := d.mem[d.n&(len(d.mem)-1):] + if d.n+n < 32 { // This new data doesn't even fill the current block. - copy(d.mem[d.n:], b) + copy(memleft, b) d.n += n return } if d.n > 0 { // Finish off the partial block. - copy(d.mem[d.n:], b) + c := copy(memleft, b) d.v1 = round(d.v1, u64(d.mem[0:8])) d.v2 = round(d.v2, u64(d.mem[8:16])) d.v3 = round(d.v3, u64(d.mem[16:24])) d.v4 = round(d.v4, u64(d.mem[24:32])) - b = b[32-d.n:] + b = b[c:] d.n = 0 } @@ -133,21 +127,20 @@ func (d *Digest) Sum64() uint64 { h += d.total - i, end := 0, d.n - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(d.mem[i:i+8])) + b := d.mem[:d.n&(len(d.mem)-1)] + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) h ^= k1 h = rol27(h)*prime1 + prime4 } - if i+4 <= end { - h ^= uint64(u32(d.mem[i:i+4])) * prime1 + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 h = rol23(h)*prime2 + prime3 - i += 4 + b = b[4:] } - for i < end { - h ^= uint64(d.mem[i]) * prime5 + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 h = rol11(h) * prime1 - i++ } h ^= h >> 33 diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go deleted file mode 100644 index ad14b807f..000000000 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build !appengine -// +build gc -// +build !purego - -package xxhash - -// Sum64 computes the 64-bit xxHash digest of b. -// -//go:noescape -func Sum64(b []byte) uint64 - -//go:noescape -func writeBlocks(d *Digest, b []byte) int diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s index be8db5bf7..3e8b13257 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s @@ -1,215 +1,209 @@ +//go:build !appengine && gc && !purego // +build !appengine // +build gc // +build !purego #include "textflag.h" -// Register allocation: -// AX h -// SI pointer to advance through b -// DX n -// BX loop end -// R8 v1, k1 -// R9 v2 -// R10 v3 -// R11 v4 -// R12 tmp -// R13 prime1v -// R14 prime2v -// DI prime4v - -// round reads from and advances the buffer pointer in SI. -// It assumes that R13 has prime1v and R14 has prime2v. -#define round(r) \ - MOVQ (SI), R12 \ - ADDQ $8, SI \ - IMULQ R14, R12 \ - ADDQ R12, r \ - ROLQ $31, r \ - IMULQ R13, r - -// mergeRound applies a merge round on the two registers acc and val. -// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v. -#define mergeRound(acc, val) \ - IMULQ R14, val \ - ROLQ $31, val \ - IMULQ R13, val \ - XORQ val, acc \ - IMULQ R13, acc \ - ADDQ DI, acc +// Registers: +#define h AX +#define d AX +#define p SI // pointer to advance through b +#define n DX +#define end BX // loop end +#define v1 R8 +#define v2 R9 +#define v3 R10 +#define v4 R11 +#define x R12 +#define prime1 R13 +#define prime2 R14 +#define prime4 DI + +#define round(acc, x) \ + IMULQ prime2, x \ + ADDQ x, acc \ + ROLQ $31, acc \ + IMULQ prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + IMULQ prime2, x \ + ROLQ $31, x \ + IMULQ prime1, x + +// mergeRound applies a merge round on the two registers acc and x. +// It assumes that prime1, prime2, and prime4 have been loaded. +#define mergeRound(acc, x) \ + round0(x) \ + XORQ x, acc \ + IMULQ prime1, acc \ + ADDQ prime4, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that there is at least one block +// to process. +#define blockLoop() \ +loop: \ + MOVQ +0(p), x \ + round(v1, x) \ + MOVQ +8(p), x \ + round(v2, x) \ + MOVQ +16(p), x \ + round(v3, x) \ + MOVQ +24(p), x \ + round(v4, x) \ + ADDQ $32, p \ + CMPQ p, end \ + JLE loop // func Sum64(b []byte) uint64 -TEXT ·Sum64(SB), NOSPLIT, $0-32 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 // Load fixed primes. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 - MOVQ ·prime4v(SB), DI + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 + MOVQ ·primes+24(SB), prime4 // Load slice. - MOVQ b_base+0(FP), SI - MOVQ b_len+8(FP), DX - LEAQ (SI)(DX*1), BX + MOVQ b_base+0(FP), p + MOVQ b_len+8(FP), n + LEAQ (p)(n*1), end // The first loop limit will be len(b)-32. - SUBQ $32, BX + SUBQ $32, end // Check whether we have at least one block. - CMPQ DX, $32 + CMPQ n, $32 JLT noBlocks // Set up initial state (v1, v2, v3, v4). - MOVQ R13, R8 - ADDQ R14, R8 - MOVQ R14, R9 - XORQ R10, R10 - XORQ R11, R11 - SUBQ R13, R11 - - // Loop until SI > BX. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ SI, BX - JLE blockLoop - - MOVQ R8, AX - ROLQ $1, AX - MOVQ R9, R12 - ROLQ $7, R12 - ADDQ R12, AX - MOVQ R10, R12 - ROLQ $12, R12 - ADDQ R12, AX - MOVQ R11, R12 - ROLQ $18, R12 - ADDQ R12, AX - - mergeRound(AX, R8) - mergeRound(AX, R9) - mergeRound(AX, R10) - mergeRound(AX, R11) + MOVQ prime1, v1 + ADDQ prime2, v1 + MOVQ prime2, v2 + XORQ v3, v3 + XORQ v4, v4 + SUBQ prime1, v4 + + blockLoop() + + MOVQ v1, h + ROLQ $1, h + MOVQ v2, x + ROLQ $7, x + ADDQ x, h + MOVQ v3, x + ROLQ $12, x + ADDQ x, h + MOVQ v4, x + ROLQ $18, x + ADDQ x, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) JMP afterBlocks noBlocks: - MOVQ ·prime5v(SB), AX + MOVQ ·primes+32(SB), h afterBlocks: - ADDQ DX, AX - - // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8. - ADDQ $24, BX - - CMPQ SI, BX - JG fourByte - -wordLoop: - // Calculate k1. - MOVQ (SI), R8 - ADDQ $8, SI - IMULQ R14, R8 - ROLQ $31, R8 - IMULQ R13, R8 - - XORQ R8, AX - ROLQ $27, AX - IMULQ R13, AX - ADDQ DI, AX - - CMPQ SI, BX - JLE wordLoop - -fourByte: - ADDQ $4, BX - CMPQ SI, BX - JG singles - - MOVL (SI), R8 - ADDQ $4, SI - IMULQ R13, R8 - XORQ R8, AX - - ROLQ $23, AX - IMULQ R14, AX - ADDQ ·prime3v(SB), AX - -singles: - ADDQ $4, BX - CMPQ SI, BX + ADDQ n, h + + ADDQ $24, end + CMPQ p, end + JG try4 + +loop8: + MOVQ (p), x + ADDQ $8, p + round0(x) + XORQ x, h + ROLQ $27, h + IMULQ prime1, h + ADDQ prime4, h + + CMPQ p, end + JLE loop8 + +try4: + ADDQ $4, end + CMPQ p, end + JG try1 + + MOVL (p), x + ADDQ $4, p + IMULQ prime1, x + XORQ x, h + + ROLQ $23, h + IMULQ prime2, h + ADDQ ·primes+16(SB), h + +try1: + ADDQ $4, end + CMPQ p, end JGE finalize -singlesLoop: - MOVBQZX (SI), R12 - ADDQ $1, SI - IMULQ ·prime5v(SB), R12 - XORQ R12, AX +loop1: + MOVBQZX (p), x + ADDQ $1, p + IMULQ ·primes+32(SB), x + XORQ x, h + ROLQ $11, h + IMULQ prime1, h - ROLQ $11, AX - IMULQ R13, AX - - CMPQ SI, BX - JL singlesLoop + CMPQ p, end + JL loop1 finalize: - MOVQ AX, R12 - SHRQ $33, R12 - XORQ R12, AX - IMULQ R14, AX - MOVQ AX, R12 - SHRQ $29, R12 - XORQ R12, AX - IMULQ ·prime3v(SB), AX - MOVQ AX, R12 - SHRQ $32, R12 - XORQ R12, AX - - MOVQ AX, ret+24(FP) + MOVQ h, x + SHRQ $33, x + XORQ x, h + IMULQ prime2, h + MOVQ h, x + SHRQ $29, x + XORQ x, h + IMULQ ·primes+16(SB), h + MOVQ h, x + SHRQ $32, x + XORQ x, h + + MOVQ h, ret+24(FP) RET -// writeBlocks uses the same registers as above except that it uses AX to store -// the d pointer. - // func writeBlocks(d *Digest, b []byte) int -TEXT ·writeBlocks(SB), NOSPLIT, $0-40 +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 // Load fixed primes needed for round. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 // Load slice. - MOVQ b_base+8(FP), SI - MOVQ b_len+16(FP), DX - LEAQ (SI)(DX*1), BX - SUBQ $32, BX + MOVQ b_base+8(FP), p + MOVQ b_len+16(FP), n + LEAQ (p)(n*1), end + SUBQ $32, end // Load vN from d. - MOVQ d+0(FP), AX - MOVQ 0(AX), R8 // v1 - MOVQ 8(AX), R9 // v2 - MOVQ 16(AX), R10 // v3 - MOVQ 24(AX), R11 // v4 + MOVQ s+0(FP), d + MOVQ 0(d), v1 + MOVQ 8(d), v2 + MOVQ 16(d), v3 + MOVQ 24(d), v4 // We don't need to check the loop condition here; this function is // always called with at least one block of data to process. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ SI, BX - JLE blockLoop + blockLoop() // Copy vN back to d. - MOVQ R8, 0(AX) - MOVQ R9, 8(AX) - MOVQ R10, 16(AX) - MOVQ R11, 24(AX) - - // The number of bytes written is SI minus the old base pointer. - SUBQ b_base+8(FP), SI - MOVQ SI, ret+32(FP) + MOVQ v1, 0(d) + MOVQ v2, 8(d) + MOVQ v3, 16(d) + MOVQ v4, 24(d) + + // The number of bytes written is p minus the old base pointer. + SUBQ b_base+8(FP), p + MOVQ p, ret+32(FP) RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s new file mode 100644 index 000000000..7e3145a22 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s @@ -0,0 +1,183 @@ +//go:build !appengine && gc && !purego +// +build !appengine +// +build gc +// +build !purego + +#include "textflag.h" + +// Registers: +#define digest R1 +#define h R2 // return value +#define p R3 // input pointer +#define n R4 // input length +#define nblocks R5 // n / 32 +#define prime1 R7 +#define prime2 R8 +#define prime3 R9 +#define prime4 R10 +#define prime5 R11 +#define v1 R12 +#define v2 R13 +#define v3 R14 +#define v4 R15 +#define x1 R20 +#define x2 R21 +#define x3 R22 +#define x4 R23 + +#define round(acc, x) \ + MADD prime2, acc, x, acc \ + ROR $64-31, acc \ + MUL prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + MUL prime2, x \ + ROR $64-31, x \ + MUL prime1, x + +#define mergeRound(acc, x) \ + round0(x) \ + EOR x, acc \ + MADD acc, prime4, prime1, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that n >= 32. +#define blockLoop() \ + LSR $5, n, nblocks \ + PCALIGN $16 \ + loop: \ + LDP.P 16(p), (x1, x2) \ + LDP.P 16(p), (x3, x4) \ + round(v1, x1) \ + round(v2, x2) \ + round(v3, x3) \ + round(v4, x4) \ + SUB $1, nblocks \ + CBNZ nblocks, loop + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 + LDP b_base+0(FP), (p, n) + + LDP ·primes+0(SB), (prime1, prime2) + LDP ·primes+16(SB), (prime3, prime4) + MOVD ·primes+32(SB), prime5 + + CMP $32, n + CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 } + BLT afterLoop + + ADD prime1, prime2, v1 + MOVD prime2, v2 + MOVD $0, v3 + NEG prime1, v4 + + blockLoop() + + ROR $64-1, v1, x1 + ROR $64-7, v2, x2 + ADD x1, x2 + ROR $64-12, v3, x3 + ROR $64-18, v4, x4 + ADD x3, x4 + ADD x2, x4, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) + +afterLoop: + ADD n, h + + TBZ $4, n, try8 + LDP.P 16(p), (x1, x2) + + round0(x1) + + // NOTE: here and below, sequencing the EOR after the ROR (using a + // rotated register) is worth a small but measurable speedup for small + // inputs. + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + + round0(x2) + ROR $64-27, h + EOR x2 @> 64-27, h, h + MADD h, prime4, prime1, h + +try8: + TBZ $3, n, try4 + MOVD.P 8(p), x1 + + round0(x1) + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + +try4: + TBZ $2, n, try2 + MOVWU.P 4(p), x2 + + MUL prime1, x2 + ROR $64-23, h + EOR x2 @> 64-23, h, h + MADD h, prime3, prime2, h + +try2: + TBZ $1, n, try1 + MOVHU.P 2(p), x3 + AND $255, x3, x1 + LSR $8, x3, x2 + + MUL prime5, x1 + ROR $64-11, h + EOR x1 @> 64-11, h, h + MUL prime1, h + + MUL prime5, x2 + ROR $64-11, h + EOR x2 @> 64-11, h, h + MUL prime1, h + +try1: + TBZ $0, n, finalize + MOVBU (p), x4 + + MUL prime5, x4 + ROR $64-11, h + EOR x4 @> 64-11, h, h + MUL prime1, h + +finalize: + EOR h >> 33, h + MUL prime2, h + EOR h >> 29, h + MUL prime3, h + EOR h >> 32, h + + MOVD h, ret+24(FP) + RET + +// func writeBlocks(d *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 + LDP ·primes+0(SB), (prime1, prime2) + + // Load state. Assume v[1-4] are stored contiguously. + MOVD d+0(FP), digest + LDP 0(digest), (v1, v2) + LDP 16(digest), (v3, v4) + + LDP b_base+8(FP), (p, n) + + blockLoop() + + // Store updated state. + STP (v1, v2), 0(digest) + STP (v3, v4), 16(digest) + + BIC $31, n + MOVD n, ret+32(FP) + RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go new file mode 100644 index 000000000..9216e0a40 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go @@ -0,0 +1,15 @@ +//go:build (amd64 || arm64) && !appengine && gc && !purego +// +build amd64 arm64 +// +build !appengine +// +build gc +// +build !purego + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b. +// +//go:noescape +func Sum64(b []byte) uint64 + +//go:noescape +func writeBlocks(d *Digest, b []byte) int diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go index 4a5a82160..26df13bba 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go @@ -1,4 +1,5 @@ -// +build !amd64 appengine !gc purego +//go:build (!amd64 && !arm64) || appengine || !gc || purego +// +build !amd64,!arm64 appengine !gc purego package xxhash @@ -14,10 +15,10 @@ func Sum64(b []byte) uint64 { var h uint64 if n >= 32 { - v1 := prime1v + prime2 + v1 := primes[0] + prime2 v2 := prime2 v3 := uint64(0) - v4 := -prime1v + v4 := -primes[0] for len(b) >= 32 { v1 = round(v1, u64(b[0:8:len(b)])) v2 = round(v2, u64(b[8:16:len(b)])) @@ -36,19 +37,18 @@ func Sum64(b []byte) uint64 { h += uint64(n) - i, end := 0, len(b) - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(b[i:i+8:len(b)])) + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) h ^= k1 h = rol27(h)*prime1 + prime4 } - if i+4 <= end { - h ^= uint64(u32(b[i:i+4:len(b)])) * prime1 + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 h = rol23(h)*prime2 + prime3 - i += 4 + b = b[4:] } - for ; i < end; i++ { - h ^= uint64(b[i]) * prime5 + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 h = rol11(h) * prime1 } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go index fc9bea7a3..e86f1b5fd 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go @@ -1,3 +1,4 @@ +//go:build appengine // +build appengine // This file contains the safe implementations of otherwise unsafe-using code. diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go index 376e0ca2e..1c1638fd8 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go @@ -1,3 +1,4 @@ +//go:build !appengine // +build !appengine // This file encapsulates usage of unsafe. @@ -11,7 +12,7 @@ import ( // In the future it's possible that compiler optimizations will make these // XxxString functions unnecessary by realizing that calls such as -// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205. +// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205. // If that happens, even if we keep these functions they can be replaced with // the trivial safe code. diff --git a/vendor/github.com/charithe/durationcheck/go.mod b/vendor/github.com/charithe/durationcheck/go.mod deleted file mode 100644 index eb058f21d..000000000 --- a/vendor/github.com/charithe/durationcheck/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/charithe/durationcheck - -go 1.14 - -require golang.org/x/tools v0.1.0 diff --git a/vendor/github.com/charithe/durationcheck/go.sum b/vendor/github.com/charithe/durationcheck/go.sum deleted file mode 100644 index 21d696a65..000000000 --- a/vendor/github.com/charithe/durationcheck/go.sum +++ /dev/null @@ -1,26 +0,0 @@ -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/chavacava/garif/go.mod b/vendor/github.com/chavacava/garif/go.mod deleted file mode 100644 index 7b2793d8f..000000000 --- a/vendor/github.com/chavacava/garif/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/chavacava/garif - -go 1.16 - -require github.com/stretchr/testify v1.8.0 diff --git a/vendor/github.com/chavacava/garif/go.sum b/vendor/github.com/chavacava/garif/go.sum deleted file mode 100644 index 51648299d..000000000 --- a/vendor/github.com/chavacava/garif/go.sum +++ /dev/null @@ -1,15 +0,0 @@ -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= -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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/curioswitch/go-reassign/.gitattributes b/vendor/github.com/curioswitch/go-reassign/.gitattributes new file mode 100644 index 000000000..d020be8ea --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/.gitattributes @@ -0,0 +1,2 @@ +*.go text eol=lf + diff --git a/vendor/github.com/curioswitch/go-reassign/.gitignore b/vendor/github.com/curioswitch/go-reassign/.gitignore new file mode 100644 index 000000000..59fa33613 --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/.gitignore @@ -0,0 +1,6 @@ +.idea +.VSCode +.envrc + +build +dist diff --git a/vendor/github.com/curioswitch/go-reassign/.golangci.yml b/vendor/github.com/curioswitch/go-reassign/.golangci.yml new file mode 100644 index 000000000..e3bf79ae7 --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/.golangci.yml @@ -0,0 +1,38 @@ +linters: + enable: + - asasalint + - bidichk + - bodyclose + - decorder + - durationcheck + - errchkjson + - errname + - errorlint + - execinquery + - exhaustive + - exportloopref + - gocritic + - goerr113 + - gofmt + - goimports + - goprintffuncname + - gosec + - importas + - misspell + - nolintlint + - nosnakecase + - prealloc + - predeclared + - promlinter + - revive + - stylecheck + - tagliatelle + - tenv + - thelper + - unconvert + - usestdlibvars +issues: + exclude-rules: + - path: magefile\.go + linters: + - deadcode diff --git a/vendor/github.com/curioswitch/go-reassign/.goreleaser.yaml b/vendor/github.com/curioswitch/go-reassign/.goreleaser.yaml new file mode 100644 index 000000000..25f2dc0c1 --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/.goreleaser.yaml @@ -0,0 +1,27 @@ +builds: + - main: ./cmd + env: + - CGO_ENABLED=0 + targets: + - linux_amd64 + - linux_arm64 + - darwin_amd64 + - darwin_arm64 + - windows_amd64 + - windows_arm64 +archives: + - format_overrides: + - goos: windows + format: zip +release: + mode: append +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Version }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/vendor/github.com/curioswitch/go-reassign/LICENSE b/vendor/github.com/curioswitch/go-reassign/LICENSE new file mode 100644 index 000000000..9f18bde00 --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Choko (choko@curioswitch.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/curioswitch/go-reassign/README.md b/vendor/github.com/curioswitch/go-reassign/README.md new file mode 100644 index 000000000..ac9c131df --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/README.md @@ -0,0 +1,53 @@ +# reassign + +A linter that detects when reassigning a top-level variable in another package. + +## Install + +```bash +go install github.com/curioswitch/go-reassign +``` + +## Usage + +```bash +reassign ./... +``` + +Change the pattern to match against variables being reassigned. By default, only `EOF` and `Err*` variables are checked. + +```bash +reassign -pattern ".*" ./... +``` + +## Background + +Package variables are commonly used to define sentinel errors which callers can use with `errors.Is` to determine the +type of a returned `error`. Some examples exist in the standard [os](https://pkg.go.dev/os#pkg-variables) library. + +Unfortunately, as with any variable, these are mutable, and it is possible to write this very dangerous code. + +```go +package main +import "io" +func bad() { + // breaks file reading + io.EOF = nil +} +``` + +This caused a new pattern for [constant errors](https://dave.cheney.net/2016/04/07/constant-errors) +to gain popularity, but they don't work well with improvements to the `errors` package in recent versions of Go and may +be considered to be non-idiomatic compared to normal `errors.New`. If we can catch reassignment of sentinel errors, we +gain much of the safety of constant errors. + +This linter will catch reassignment of variables in other packages. By default it intends to apply to as many codebases +as possible and only checks a restricted set of variable names, `EOF` and `ErrFoo`, to restrict to sentinel errors. +Package variable reassignment is generally confusing, though, and we recommend avoiding it for all variables, not just errors. +The `pattern` flag can be set to a regular expression to define what variables cannot be reassigned, and `.*` is +recommended if it works with your code. + +## Limitations + +If a variable shadows the name of an import, an assignment of a field in the variable will trigger the linter. Shadowing +can be confusing, so it's recommended to rename the variable. diff --git a/vendor/github.com/curioswitch/go-reassign/analyzer.go b/vendor/github.com/curioswitch/go-reassign/analyzer.go new file mode 100644 index 000000000..48707adeb --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/analyzer.go @@ -0,0 +1,13 @@ +package reassign + +import ( + "github.com/curioswitch/go-reassign/internal/analyzer" + "golang.org/x/tools/go/analysis" +) + +const FlagPattern = analyzer.FlagPattern + +// NewAnalyzer returns an analyzer for checking that package variables are not reassigned. +func NewAnalyzer() *analysis.Analyzer { + return analyzer.New() +} diff --git a/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go b/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go new file mode 100644 index 000000000..e1b47d5b9 --- /dev/null +++ b/vendor/github.com/curioswitch/go-reassign/internal/analyzer/analyzer.go @@ -0,0 +1,84 @@ +package analyzer + +import ( + "fmt" + "go/ast" + "go/types" + "regexp" + + "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", + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, + } + a.Flags.String(FlagPattern, `^(Err.*|EOF)$`, "Pattern to match package variables against to prevent reassignment") + return a +} + +func run(pass *analysis.Pass) (interface{}, error) { + checkRE, err := regexp.Compile(pass.Analyzer.Flags.Lookup(FlagPattern).Value.String()) + if err != nil { + return nil, fmt.Errorf("invalid pattern: %w", err) + } + + 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 +} + +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 + } + + 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 + } + } + + pass.Reportf(expr.Pos(), "%s variable %s in other package %s", prefix, x.Sel.Name, selectIdent.Name) + + case *ast.Ident: + use, ok := pass.TypesInfo.Uses[x].(*types.Var) + if !ok { + return + } + + if use.Pkg() == pass.Pkg { + return + } + + if !checkRE.MatchString(x.Name) { + return + } + + pass.Reportf(expr.Pos(), "%s variable %s from other package %s", prefix, x.Name, use.Pkg().Path()) + } +} diff --git a/vendor/github.com/daixiang0/gci/pkg/gci/gci.go b/vendor/github.com/daixiang0/gci/pkg/gci/gci.go index a8a64a278..7418db209 100644 --- a/vendor/github.com/daixiang0/gci/pkg/gci/gci.go +++ b/vendor/github.com/daixiang0/gci/pkg/gci/gci.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + goFormat "go/format" "os" "sync" @@ -120,7 +121,7 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err return src, src, nil } - imports, headEnd, tailStart, err := parse.ParseFile(src, file.Path()) + imports, headEnd, tailStart, cStart, cEnd, err := parse.ParseFile(src, file.Path()) if err != nil { if errors.Is(err, parse.NoImportError{}) { return src, src, nil @@ -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,9 +139,6 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err return nil, nil, err } - head := src[:headEnd] - tail := src[tailStart:] - firstWithIndex := true var body []byte @@ -158,13 +156,30 @@ 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] + head := make([]byte, headEnd) + copy(head, src[:headEnd]) + tail := make([]byte, len(src)-tailStart) + copy(tail, src[tailStart:]) + + head = append(head, utils.Linebreak) + // ensure C + if cStart != 0 { + head = append(head, src[cStart:cEnd]...) + head = append(head, utils.Linebreak) } - if tail[0] != utils.Linebreak { - body = append(body, utils.Linebreak) + // add beginning of import block + head = append(head, `import (`...) + head = append(head, utils.Linebreak) + // add end of import block + body = append(body, []byte{utils.RightParenthesis, utils.Linebreak}...) + + log.L().Debug(fmt.Sprintf("head:\n%s", head)) + log.L().Debug(fmt.Sprintf("body:\n%s", body)) + if len(tail) > 20 { + log.L().Debug(fmt.Sprintf("tail:\n%s", tail[:20])) + } else { + log.L().Debug(fmt.Sprintf("tail:\n%s", tail)) } var totalLen int @@ -177,6 +192,11 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err for _, s := range slices { i += copy(dist[i:], s) } + log.L().Debug(fmt.Sprintf("raw:\n%s", dist)) + dist, err = goFormat.Source(dist) + if err != nil { + return nil, nil, err + } return src, dist, nil } diff --git a/vendor/github.com/daixiang0/gci/pkg/parse/parse.go b/vendor/github.com/daixiang0/gci/pkg/parse/parse.go index d84ed1335..33d6e1705 100644 --- a/vendor/github.com/daixiang0/gci/pkg/parse/parse.go +++ b/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 @@ -68,41 +70,96 @@ func getImports(imp *ast.ImportSpec) (start, end int, name string) { return } -func ParseFile(src []byte, filename string) (ImportList, int, int, error) { +func ParseFile(src []byte, filename string) (ImportList, int, int, int, int, error) { fileSet := token.NewFileSet() f, err := parser.ParseFile(fileSet, filename, src, parser.ParseComments) if err != nil { - return nil, 0, 0, err + return nil, 0, 0, 0, 0, err } if len(f.Imports) == 0 { - return nil, 0, 0, NoImportError{} + return nil, 0, 0, 0, 0, NoImportError{} } - var headEnd int - var tailStart int - - var data ImportList - for i, imp := range f.Imports { - start, end, name := getImports(imp) + var ( + // headEnd means the start of import block + headEnd int + // tailStart means the end + 1 of import block + tailStart int + // cStart means the start of C import block + cStart int + // cEnd means the end of C import block + cEnd int + data ImportList + ) - if i == 0 { - headEnd = start + for index, decl := range f.Decls { + switch decl.(type) { + // skip BadDecl and FuncDecl + case *ast.GenDecl: + genDecl := decl.(*ast.GenDecl) + + if genDecl.Tok == token.IMPORT { + // there are two cases, both end with linebreak: + // 1. + // import ( + // "xxxx" + // ) + // 2. + // import "xxx" + if headEnd == 0 { + headEnd = int(decl.Pos()) - 1 + } + tailStart = int(decl.End()) + + for _, spec := range genDecl.Specs { + imp := spec.(*ast.ImportSpec) + // there are only one C import block + // ensure C import block is the first import block + if imp.Path.Value == C { + /* + common case: + + // #include + import "C" + + notice that decl.Pos() == genDecl.Pos() > genDecl.Doc.Pos() + */ + if genDecl.Doc != nil { + cStart = int(genDecl.Doc.Pos()) - 1 + // if C import block is the first, update headEnd + if index == 0 { + headEnd = cStart + } + } else { + /* + special case: + + import "C" + */ + cStart = int(decl.Pos()) - 1 + } + + cEnd = int(decl.End()) + + continue + } + + start, end, name := getImports(imp) + + data = append(data, &GciImports{ + Start: start, + End: end, + Name: name, + Path: strings.Trim(imp.Path.Value, `"`), + }) + } + } } - if i == len(f.Imports)-1 { - tailStart = end - } - - data = append(data, &GciImports{ - Start: start, - End: end, - Name: name, - Path: strings.Trim(imp.Path.Value, `"`), - }) } sort.Sort(data) - return data, headEnd, tailStart, nil + return data, headEnd, tailStart, cStart, cEnd, nil } // IsGeneratedFileByComment reports whether the source file is generated code. @@ -113,10 +170,11 @@ func IsGeneratedFileByComment(in string) bool { const ( genCodeGenerated = "code generated" genDoNotEdit = "do not edit" - genAutoFile = "autogenerated file" // easyjson + genAutoFile = "autogenerated file" // easyjson + genAutoGenerated = "automatically generated" // genny ) - markers := []string{genCodeGenerated, genDoNotEdit, genAutoFile} + markers := []string{genCodeGenerated, genDoNotEdit, genAutoFile, genAutoGenerated} in = strings.ToLower(in) for _, marker := range markers { if strings.Contains(in, marker) { diff --git a/vendor/github.com/daixiang0/gci/pkg/section/errors.go b/vendor/github.com/daixiang0/gci/pkg/section/errors.go index 1aa42ecdf..0a1209135 100644 --- a/vendor/github.com/daixiang0/gci/pkg/section/errors.go +++ b/vendor/github.com/daixiang0/gci/pkg/section/errors.go @@ -25,9 +25,9 @@ func (s SectionParsingError) Is(err error) bool { return ok } -var MissingParameterClosingBracketsError = fmt.Errorf("section parameter is missing closing %q", utils.ParameterClosingBrackets) +var MissingParameterClosingBracketsError = fmt.Errorf("section parameter is missing closing %q", utils.RightParenthesis) -var MoreThanOneOpeningQuotesError = fmt.Errorf("found more than one %q parameter start sequences", utils.ParameterClosingBrackets) +var MoreThanOneOpeningQuotesError = fmt.Errorf("found more than one %q parameter start sequences", utils.RightParenthesis) var SectionTypeDoesNotAcceptParametersError = errors.New("section type does not accept a parameter") diff --git a/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go b/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go index b5d884d37..62decfe1c 100644 --- a/vendor/github.com/daixiang0/gci/pkg/section/standard_list.go +++ b/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.2. 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/vendor/github.com/daixiang0/gci/pkg/utils/constants.go b/vendor/github.com/daixiang0/gci/pkg/utils/constants.go index b1de2ea25..0e7cce757 100644 --- a/vendor/github.com/daixiang0/gci/pkg/utils/constants.go +++ b/vendor/github.com/daixiang0/gci/pkg/utils/constants.go @@ -4,8 +4,8 @@ const ( Indent = '\t' Linebreak = '\n' - SectionSeparator = ":" + Colon = ":" - ParameterOpeningBrackets = "(" - ParameterClosingBrackets = ")" + LeftParenthesis = '(' + RightParenthesis = ')' ) diff --git a/vendor/github.com/denis-tingaikin/go-header/go.mod b/vendor/github.com/denis-tingaikin/go-header/go.mod deleted file mode 100644 index bbb4d6066..000000000 --- a/vendor/github.com/denis-tingaikin/go-header/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module github.com/denis-tingaikin/go-header - -go 1.17 - -require ( - github.com/stretchr/testify v1.7.0 - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect -) diff --git a/vendor/github.com/denis-tingaikin/go-header/go.sum b/vendor/github.com/denis-tingaikin/go-header/go.sum deleted file mode 100644 index ae276f48f..000000000 --- a/vendor/github.com/denis-tingaikin/go-header/go.sum +++ /dev/null @@ -1,12 +0,0 @@ -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= -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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go index 070863d89..edafad179 100644 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go +++ b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/cover.go @@ -451,7 +451,7 @@ func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup { for _, group := range file.Comments { var list []*ast.Comment for _, comment := range group.List { - if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 { + if strings.HasPrefix(comment.Text, "//go:") && !strings.HasPrefix(comment.Text, "//go:build") && fset.Position(comment.Slash).Column == 1 { list = append(list, comment) } } diff --git a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go index e2d476929..91305ee37 100644 --- a/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go +++ b/vendor/github.com/dvyukov/go-fuzz/go-fuzz-build/main.go @@ -40,6 +40,7 @@ var ( flagLibFuzzer = flag.Bool("libfuzzer", false, "output static archive for use with libFuzzer") flagBuildX = flag.Bool("x", false, "print the commands if build fails") flagPreserve = flag.String("preserve", "", "a comma-separated list of import paths not to instrument") + flagGoCmd = flag.String("go", "go", `path to "go" command`) ) func makeTags() string { @@ -229,7 +230,7 @@ func (c *Context) getEnv() { continue } // TODO: make a single call ("go env GOROOT GOPATH") instead - out, err := exec.Command("go", "env", k).CombinedOutput() + out, err := exec.Command(*flagGoCmd, "env", k).CombinedOutput() if err != nil || len(out) == 0 { c.failf("%s is not set and failed to locate it: 'go env %s' returned '%s' (%v)", k, k, out, err) } @@ -238,7 +239,7 @@ func (c *Context) getEnv() { c.GOROOT = env["GOROOT"] c.GOPATH = env["GOPATH"] - out, err := exec.Command("go", "list", "-f", "'{{context.ReleaseTags}}'", "runtime").CombinedOutput() + out, err := exec.Command(*flagGoCmd, "list", "-f", "'{{context.ReleaseTags}}'", "runtime").CombinedOutput() if err != nil || len(out) == 0 { c.failf("go list -f '{{context.ReleaseTags}}' runtime returned '%s' (%v)", out, err) } @@ -477,6 +478,11 @@ func (c *Context) populateWorkdir() { // Cross-compilation is not implemented. c.copyDir(filepath.Join(c.GOROOT, "pkg", runtime.GOOS+"_"+runtime.GOARCH), filepath.Join(c.workdir, "goroot", "pkg", runtime.GOOS+"_"+runtime.GOARCH)) } + // go1.17 added abi_amd64.h + if _, err := os.Stat(filepath.Join(c.GOROOT, "src", "runtime", "cgo", "abi_amd64.h")); err == nil { + c.mkdirAll(filepath.Join(c.workdir, "goroot", "src", "runtime", "cgo")) + c.copyFile(filepath.Join(c.GOROOT, "src", "runtime", "cgo", "abi_amd64.h"), filepath.Join(c.workdir, "goroot", "src", "runtime", "cgo", "abi_amd64.h")) + } // Clone our package, go-fuzz-deps, and all dependencies. // TODO: we might not need to do this for all packages. @@ -526,7 +532,7 @@ func (c *Context) buildInstrumentedBinary(blocks *[]CoverBlock, sonar *[]CoverBl args = append(args, "-trimpath") } args = append(args, "-o", outf, mainPkg) - cmd := exec.Command("go", args...) + cmd := exec.Command(*flagGoCmd, args...) // We are constructing a GOPATH environment, so while building // we force GOPATH mode here via GO111MODULE=off. @@ -644,6 +650,22 @@ func (c *Context) clonePackage(p *packages.Package) { newDir := filepath.Join(c.workdir, root, "src", p.PkgPath) c.mkdirAll(newDir) + // examine "go:embed" directives, collect embedded filenames, use later + for i, fullName := range p.CompiledGoFiles { + if strings.HasSuffix(fullName, ".go") { + for _, commentGroup := range trimComments(p.Syntax[i], p.Fset) { + for _, comment := range commentGroup.List { + if strings.HasPrefix(comment.Text, "//go:embed") { + filename := comment.Text[len("//go:embed "):] + dirname := filepath.Dir(fullName) + fullname := fmt.Sprintf("%s/%s", dirname, filename) + p.OtherFiles = append(p.OtherFiles, fullname) + } + } + } + } + } + if p.PkgPath == "unsafe" { // Write a dummy file. go/packages explicitly returns an empty GoFiles for it, // for reasons that are unclear, but cmd/go wants there to be a Go file in the package. @@ -737,19 +759,19 @@ func (c *Context) instrumentPackages(blocks *[]CoverBlock, sonar *[]CoverBlock) } func (c *Context) copyDir(dir, newDir string) { - c.mkdirAll(newDir) files, err := ioutil.ReadDir(dir) if err != nil { c.failf("failed to scan dir '%v': %v", dir, err) } + c.mkdirAll(newDir) for _, f := range files { - if f.IsDir() { - c.copyDir(filepath.Join(dir, f.Name()), filepath.Join(newDir, f.Name())) - continue - } src := filepath.Join(dir, f.Name()) dst := filepath.Join(newDir, f.Name()) - c.copyFile(src, dst) + if f.IsDir() { + c.copyDir(src, dst) + } else { + c.copyFile(src, dst) + } } } diff --git a/vendor/github.com/ettle/strcase/go.mod b/vendor/github.com/ettle/strcase/go.mod deleted file mode 100644 index 0219bfaa0..000000000 --- a/vendor/github.com/ettle/strcase/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/ettle/strcase - -go 1.12 - -require github.com/stretchr/testify v1.5.1 diff --git a/vendor/github.com/ettle/strcase/go.sum b/vendor/github.com/ettle/strcase/go.sum deleted file mode 100644 index 331fa6982..000000000 --- a/vendor/github.com/ettle/strcase/go.sum +++ /dev/null @@ -1,11 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index 5152bf59b..be82827ca 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -7,7 +7,6 @@ suits you. ![Color](https://user-images.githubusercontent.com/438920/96832689-03b3e000-13f4-11eb-9803-46f4c4de3406.jpg) - ## Install ```bash @@ -124,17 +123,17 @@ fmt.Println("All text will now be bold magenta.") ``` ### Disable/Enable color - + There might be a case where you want to explicitly disable/enable color output. the `go-isatty` package will automatically disable color output for non-tty output streams (for example if the output were piped directly to `less`). The `color` package also disables color output if the [`NO_COLOR`](https://no-color.org) environment -variable is set (regardless of its value). +variable is set to a non-empty string. -`Color` has support to disable/enable colors programatically both globally and +`Color` has support to disable/enable colors programmatically both globally and for single color definitions. For example suppose you have a CLI app and a -`--no-color` bool flag. You can easily disable the color output with: +`-no-color` bool flag. You can easily disable the color output with: ```go var flagNoColor = flag.Bool("no-color", false, "Disable color output") @@ -167,11 +166,10 @@ To output color in GitHub Actions (or other CI systems that support ANSI colors) * Save/Return previous values * Evaluate fmt.Formatter interface - ## Credits - * [Fatih Arslan](https://github.com/fatih) - * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) +* [Fatih Arslan](https://github.com/fatih) +* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) ## License diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 98a60f3c8..889f9e77b 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -19,10 +19,10 @@ var ( // set (regardless of its value). This is a global option and affects all // colors. For more control over each color block use the methods // DisableColor() individually. - NoColor = noColorExists() || os.Getenv("TERM") == "dumb" || + NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) - // Output defines the standard output of the print functions. By default + // Output defines the standard output of the print functions. By default, // os.Stdout is used. Output = colorable.NewColorableStdout() @@ -35,10 +35,9 @@ var ( colorsCacheMu sync.Mutex // protects colorsCache ) -// noColorExists returns true if the environment variable NO_COLOR exists. -func noColorExists() bool { - _, exists := os.LookupEnv("NO_COLOR") - return exists +// noColorIsSet returns true if the environment variable NO_COLOR is set to a non-empty string. +func noColorIsSet() bool { + return os.Getenv("NO_COLOR") != "" } // Color defines a custom color object which is defined by SGR parameters. @@ -120,7 +119,7 @@ func New(value ...Attribute) *Color { params: make([]Attribute, 0), } - if noColorExists() { + if noColorIsSet() { c.noColor = boolPtr(true) } @@ -152,7 +151,7 @@ func (c *Color) Set() *Color { return c } - fmt.Fprintf(Output, c.format()) + fmt.Fprint(Output, c.format()) return c } @@ -164,16 +163,21 @@ func (c *Color) unset() { Unset() } -func (c *Color) setWriter(w io.Writer) *Color { +// SetWriter is used to set the SGR sequence with the given io.Writer. This is +// a low-level function, and users should use the higher-level functions, such +// as color.Fprint, color.Print, etc. +func (c *Color) SetWriter(w io.Writer) *Color { if c.isNoColorSet() { return c } - fmt.Fprintf(w, c.format()) + fmt.Fprint(w, c.format()) return c } -func (c *Color) unsetWriter(w io.Writer) { +// UnsetWriter resets all escape attributes and clears the output with the give +// io.Writer. Usually should be called after SetWriter(). +func (c *Color) UnsetWriter(w io.Writer) { if c.isNoColorSet() { return } @@ -192,20 +196,14 @@ func (c *Color) Add(value ...Attribute) *Color { return c } -func (c *Color) prepend(value Attribute) { - c.params = append(c.params, 0) - copy(c.params[1:], c.params[0:]) - c.params[0] = value -} - // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprint(w, a...) } @@ -227,8 +225,8 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprintf(w, format, a...) } @@ -248,8 +246,8 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprintln(w, a...) } @@ -396,7 +394,7 @@ func (c *Color) DisableColor() { } // EnableColor enables the color output. Use it in conjunction with -// DisableColor(). Otherwise this method has no side effects. +// DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) } diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 04541de78..9491ad541 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -5,106 +5,105 @@ that suits you. Use simple and default helper functions with predefined foreground colors: - color.Cyan("Prints text in cyan.") + color.Cyan("Prints text in cyan.") - // a newline will be appended automatically - color.Blue("Prints %s in blue.", "text") + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") - // More default foreground colors.. - color.Red("We have red") - color.Yellow("Yellow color too!") - color.Magenta("And many others ..") + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") - // Hi-intensity colors - color.HiGreen("Bright green color.") - color.HiBlack("Bright black means gray..") - color.HiWhite("Shiny white color!") + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") -However there are times where custom color mixes are required. Below are some +However, there are times when custom color mixes are required. Below are some examples to create custom color objects and use the print functions of each separate color object. - // Create a new color object - c := color.New(color.FgCyan).Add(color.Underline) - c.Println("Prints cyan text with an underline.") + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") - // Or just add them to New() - d := color.New(color.FgCyan, color.Bold) - d.Printf("This prints bold cyan %s\n", "too!.") + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") - // Mix up foreground and background colors, create new mixes! - red := color.New(color.FgRed) + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) - boldRed := red.Add(color.Bold) - boldRed.Println("This will print text in bold red.") + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") - whiteBackground := red.Add(color.BgWhite) - whiteBackground.Println("Red text with White background.") + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") - // Use your own io.Writer output - color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - blue := color.New(color.FgBlue) - blue.Fprint(myWriter, "This will print text in blue.") + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: - // Create a custom print function for convenient - red := color.New(color.FgRed).PrintfFunc() - red("warning") - red("error: %s", err) + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) - // Mix up multiple attributes - notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() - notice("don't forget this...") + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") You can also FprintXxx functions to pass your own io.Writer: - blue := color.New(FgBlue).FprintfFunc() - blue(myWriter, "important notice: %s", stars) - - // Mix up with multiple attributes - success := color.New(color.Bold, color.FgGreen).FprintlnFunc() - success(myWriter, don't forget this...") + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") Or create SprintXxx functions to mix strings with other non-colorized strings: - yellow := New(FgYellow).SprintFunc() - red := New(FgRed).SprintFunc() + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() - fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Printf("this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) Windows support is enabled by default. All Print functions work as intended. -However only for color.SprintXXX functions, user should use fmt.FprintXXX and +However, only for color.SprintXXX functions, user should use fmt.FprintXXX and set the output to color.Output: - fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) Using with existing code is possible. Just use the Set() method to set the standard output to the given parameters. That way a rewrite of an existing code is not required. - // Use handy standard colors. - color.Set(color.FgYellow) + // Use handy standard colors. + color.Set(color.FgYellow) - fmt.Println("Existing text will be now in Yellow") - fmt.Printf("This one %s\n", "too") + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") - color.Unset() // don't forget to unset + color.Unset() // don't forget to unset - // You can mix up parameters - color.Set(color.FgMagenta, color.Bold) - defer color.Unset() // use it in your function + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function - fmt.Println("All text will be now bold magenta.") + fmt.Println("All text will be now bold magenta.") There might be a case where you want to disable color output (for example to pipe the standard output of your app to somewhere else). `Color` has support to @@ -112,24 +111,24 @@ disable colors both globally and for single color definition. For example suppose you have a CLI app and a `--no-color` bool flag. You can easily disable the color output with: - var flagNoColor = flag.Bool("no-color", false, "Disable color output") + var flagNoColor = flag.Bool("no-color", false, "Disable color output") - if *flagNoColor { - color.NoColor = true // disables colorized output - } + if *flagNoColor { + color.NoColor = true // disables colorized output + } You can also disable the color by setting the NO_COLOR environment variable to any value. It also has support for single color definitions (local). You can disable/enable color output on the fly: - c := color.New(color.FgCyan) - c.Println("Prints cyan text") + c := color.New(color.FgCyan) + c.Println("Prints cyan text") - c.DisableColor() - c.Println("This is printed without any color") + c.DisableColor() + c.Println("This is printed without any color") - c.EnableColor() - c.Println("This prints again cyan...") + c.EnableColor() + c.Println("This prints again cyan...") */ package color diff --git a/vendor/github.com/fatih/color/go.mod b/vendor/github.com/fatih/color/go.mod deleted file mode 100644 index c9b3cd59a..000000000 --- a/vendor/github.com/fatih/color/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/fatih/color - -go 1.13 - -require ( - github.com/mattn/go-colorable v0.1.9 - github.com/mattn/go-isatty v0.0.14 -) diff --git a/vendor/github.com/fatih/color/go.sum b/vendor/github.com/fatih/color/go.sum deleted file mode 100644 index cbbcfb644..000000000 --- a/vendor/github.com/fatih/color/go.sum +++ /dev/null @@ -1,9 +0,0 @@ -github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/fatih/structtag/go.mod b/vendor/github.com/fatih/structtag/go.mod deleted file mode 100644 index 660d6a1f1..000000000 --- a/vendor/github.com/fatih/structtag/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/fatih/structtag - -go 1.12 diff --git a/vendor/github.com/felixge/httpsnoop/README.md b/vendor/github.com/felixge/httpsnoop/README.md index ae44137e9..ddcecd13e 100644 --- a/vendor/github.com/felixge/httpsnoop/README.md +++ b/vendor/github.com/felixge/httpsnoop/README.md @@ -65,7 +65,8 @@ being called, or called more than once, as well as concurrent calls to Unfortunately this package is not perfect either. It's possible that it is still missing some interfaces provided by the go core (let me know if you find one), and it won't work for applications adding their own interfaces into the -mix. +mix. You can however use `httpsnoop.Unwrap(w)` to access the underlying +`http.ResponseWriter` and type-assert the result to its other interfaces. However, hopefully the explanation above has sufficiently scared you of rolling your own solution to this problem. httpsnoop may still break your application, diff --git a/vendor/github.com/felixge/httpsnoop/capture_metrics.go b/vendor/github.com/felixge/httpsnoop/capture_metrics.go index 4c45b1a8c..b77cc7c00 100644 --- a/vendor/github.com/felixge/httpsnoop/capture_metrics.go +++ b/vendor/github.com/felixge/httpsnoop/capture_metrics.go @@ -3,7 +3,6 @@ package httpsnoop import ( "io" "net/http" - "sync" "time" ) @@ -36,17 +35,23 @@ func CaptureMetrics(hnd http.Handler, w http.ResponseWriter, r *http.Request) Me // sugar on top of this func), but is a more usable interface if your // application doesn't use the Go http.Handler interface. func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metrics { + m := Metrics{Code: http.StatusOK} + m.CaptureMetrics(w, fn) + return m +} + +// CaptureMetrics wraps w and calls fn with the wrapped w and updates +// Metrics m with the resulting metrics. This is similar to CaptureMetricsFn, +// but allows one to customize starting Metrics object. +func (m *Metrics) CaptureMetrics(w http.ResponseWriter, fn func(http.ResponseWriter)) { var ( start = time.Now() - m = Metrics{Code: http.StatusOK} headerWritten bool - lock sync.Mutex hooks = Hooks{ WriteHeader: func(next WriteHeaderFunc) WriteHeaderFunc { return func(code int) { next(code) - lock.Lock() - defer lock.Unlock() + if !headerWritten { m.Code = code headerWritten = true @@ -57,8 +62,7 @@ func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metri Write: func(next WriteFunc) WriteFunc { return func(p []byte) (int, error) { n, err := next(p) - lock.Lock() - defer lock.Unlock() + m.Written += int64(n) headerWritten = true return n, err @@ -68,8 +72,7 @@ func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metri ReadFrom: func(next ReadFromFunc) ReadFromFunc { return func(src io.Reader) (int64, error) { n, err := next(src) - lock.Lock() - defer lock.Unlock() + headerWritten = true m.Written += n return n, err @@ -79,6 +82,5 @@ func CaptureMetricsFn(w http.ResponseWriter, fn func(http.ResponseWriter)) Metri ) fn(Wrap(w, hooks)) - m.Duration = time.Since(start) - return m + m.Duration += time.Since(start) } diff --git a/vendor/github.com/felixge/httpsnoop/go.mod b/vendor/github.com/felixge/httpsnoop/go.mod deleted file mode 100644 index 73b394690..000000000 --- a/vendor/github.com/felixge/httpsnoop/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/felixge/httpsnoop - -go 1.13 diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go index 41a20da9e..31cbdfb8e 100644 --- a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go @@ -74,243 +74,275 @@ func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { // combination 1/32 case !i0 && !i1 && !i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter - }{rw} + }{rw, rw} // combination 2/32 case !i0 && !i1 && !i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Pusher - }{rw, rw} + }{rw, rw, rw} // combination 3/32 case !i0 && !i1 && !i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter io.ReaderFrom - }{rw, rw} + }{rw, rw, rw} // combination 4/32 case !i0 && !i1 && !i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter io.ReaderFrom http.Pusher - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 5/32 case !i0 && !i1 && i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Hijacker - }{rw, rw} + }{rw, rw, rw} // combination 6/32 case !i0 && !i1 && i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Hijacker http.Pusher - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 7/32 case !i0 && !i1 && i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 8/32 case !i0 && !i1 && i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 9/32 case !i0 && i1 && !i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier - }{rw, rw} + }{rw, rw, rw} // combination 10/32 case !i0 && i1 && !i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Pusher - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 11/32 case !i0 && i1 && !i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 12/32 case !i0 && i1 && !i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 13/32 case !i0 && i1 && i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 14/32 case !i0 && i1 && i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 15/32 case !i0 && i1 && i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 16/32 case !i0 && i1 && i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} // combination 17/32 case i0 && !i1 && !i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher - }{rw, rw} + }{rw, rw, rw} // combination 18/32 case i0 && !i1 && !i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Pusher - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 19/32 case i0 && !i1 && !i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 20/32 case i0 && !i1 && !i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 21/32 case i0 && !i1 && i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 22/32 case i0 && !i1 && i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 23/32 case i0 && !i1 && i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 24/32 case i0 && !i1 && i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom http.Pusher - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} // combination 25/32 case i0 && i1 && !i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 26/32 case i0 && i1 && !i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Pusher - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 27/32 case i0 && i1 && !i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 28/32 case i0 && i1 && !i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom http.Pusher - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} // combination 29/32 case i0 && i1 && i2 && !i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 30/32 case i0 && i1 && i2 && !i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker http.Pusher - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} // combination 31/32 case i0 && i1 && i2 && i3 && !i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} // combination 32/32 case i0 && i1 && i2 && i3 && i4: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom http.Pusher - }{rw, rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw, rw} } panic("unreachable") } @@ -320,6 +352,10 @@ type rw struct { h Hooks } +func (w *rw) Unwrap() http.ResponseWriter { + return w.w +} + func (w *rw) Header() http.Header { f := w.w.(http.ResponseWriter).Header if w.h.Header != nil { @@ -383,3 +419,18 @@ func (w *rw) Push(target string, opts *http.PushOptions) error { } return f(target, opts) } + +type Unwrapper interface { + Unwrap() http.ResponseWriter +} + +// Unwrap returns the underlying http.ResponseWriter from within zero or more +// layers of httpsnoop wrappers. +func Unwrap(w http.ResponseWriter) http.ResponseWriter { + if rw, ok := w.(Unwrapper); ok { + // recurse until rw.Unwrap() returns a non-Unwrapper + return Unwrap(rw.Unwrap()) + } else { + return w + } +} diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go index 36bb59b83..ab99c07c7 100644 --- a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go @@ -68,115 +68,131 @@ func Wrap(w http.ResponseWriter, hooks Hooks) http.ResponseWriter { // combination 1/16 case !i0 && !i1 && !i2 && !i3: return struct { + Unwrapper http.ResponseWriter - }{rw} + }{rw, rw} // combination 2/16 case !i0 && !i1 && !i2 && i3: return struct { + Unwrapper http.ResponseWriter io.ReaderFrom - }{rw, rw} + }{rw, rw, rw} // combination 3/16 case !i0 && !i1 && i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.Hijacker - }{rw, rw} + }{rw, rw, rw} // combination 4/16 case !i0 && !i1 && i2 && i3: return struct { + Unwrapper http.ResponseWriter http.Hijacker io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 5/16 case !i0 && i1 && !i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier - }{rw, rw} + }{rw, rw, rw} // combination 6/16 case !i0 && i1 && !i2 && i3: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 7/16 case !i0 && i1 && i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 8/16 case !i0 && i1 && i2 && i3: return struct { + Unwrapper http.ResponseWriter http.CloseNotifier http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 9/16 case i0 && !i1 && !i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.Flusher - }{rw, rw} + }{rw, rw, rw} // combination 10/16 case i0 && !i1 && !i2 && i3: return struct { + Unwrapper http.ResponseWriter http.Flusher io.ReaderFrom - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 11/16 case i0 && !i1 && i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 12/16 case i0 && !i1 && i2 && i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 13/16 case i0 && i1 && !i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier - }{rw, rw, rw} + }{rw, rw, rw, rw} // combination 14/16 case i0 && i1 && !i2 && i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier io.ReaderFrom - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 15/16 case i0 && i1 && i2 && !i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker - }{rw, rw, rw, rw} + }{rw, rw, rw, rw, rw} // combination 16/16 case i0 && i1 && i2 && i3: return struct { + Unwrapper http.ResponseWriter http.Flusher http.CloseNotifier http.Hijacker io.ReaderFrom - }{rw, rw, rw, rw, rw} + }{rw, rw, rw, rw, rw, rw} } panic("unreachable") } @@ -186,6 +202,10 @@ type rw struct { h Hooks } +func (w *rw) Unwrap() http.ResponseWriter { + return w.w +} + func (w *rw) Header() http.Header { f := w.w.(http.ResponseWriter).Header if w.h.Header != nil { @@ -241,3 +261,18 @@ func (w *rw) ReadFrom(src io.Reader) (int64, error) { } return f(src) } + +type Unwrapper interface { + Unwrap() http.ResponseWriter +} + +// Unwrap returns the underlying http.ResponseWriter from within zero or more +// layers of httpsnoop wrappers. +func Unwrap(w http.ResponseWriter) http.ResponseWriter { + if rw, ok := w.(Unwrapper); ok { + // recurse until rw.Unwrap() returns a non-Unwrapper + return Unwrap(rw.Unwrap()) + } else { + return w + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/.gitignore b/vendor/github.com/fsnotify/fsnotify/.gitignore index 4cd0cbaf4..1d89d85ce 100644 --- a/vendor/github.com/fsnotify/fsnotify/.gitignore +++ b/vendor/github.com/fsnotify/fsnotify/.gitignore @@ -1,6 +1,6 @@ -# Setup a Global .gitignore for OS and editor generated files: -# https://help.github.com/articles/ignoring-files -# git config --global core.excludesfile ~/.gitignore_global +# go test -c output +*.test +*.test.exe -.vagrant -*.sublime-project +# Output of go build ./cmd/fsnotify +/fsnotify diff --git a/vendor/github.com/fsnotify/fsnotify/AUTHORS b/vendor/github.com/fsnotify/fsnotify/AUTHORS deleted file mode 100644 index 6cbabe5ef..000000000 --- a/vendor/github.com/fsnotify/fsnotify/AUTHORS +++ /dev/null @@ -1,62 +0,0 @@ -# Names should be added to this file as -# Name or Organization -# The email address is not required for organizations. - -# You can update this list using the following command: -# -# $ (head -n10 AUTHORS && git shortlog -se | sed -E 's/^\s+[0-9]+\t//') | tee AUTHORS - -# Please keep the list sorted. - -Aaron L -Adrien Bustany -Alexey Kazakov -Amit Krishnan -Anmol Sethi -Bjørn Erik Pedersen -Brian Goff -Bruno Bigras -Caleb Spare -Case Nelson -Chris Howey -Christoffer Buchholz -Daniel Wagner-Hall -Dave Cheney -Eric Lin -Evan Phoenix -Francisco Souza -Gautam Dey -Hari haran -Ichinose Shogo -Johannes Ebke -John C Barstow -Kelvin Fo -Ken-ichirou MATSUZAWA -Matt Layher -Matthias Stone -Nathan Youngman -Nickolai Zeldovich -Oliver Bristow -Patrick -Paul Hammond -Pawel Knap -Pieter Droogendijk -Pratik Shinde -Pursuit92 -Riku Voipio -Rob Figueiredo -Rodrigo Chiossi -Slawek Ligus -Soge Zhang -Tiffany Jernigan -Tilak Sharma -Tobias Klauser -Tom Payne -Travis Cline -Tudor Golubenco -Vahe Khachikyan -Yukang -bronze1man -debrando -henrikedwards -铁哥 diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md index cc01c08f5..77f9593bd 100644 --- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +Nothing yet. + +## [1.6.0] - 2022-10-13 + +This version of fsnotify needs Go 1.16 (this was already the case since 1.5.1, +but not documented). It also increases the minimum Linux version to 2.6.32. + +### Additions + +- all: add `Event.Has()` and `Op.Has()` ([#477]) + + This makes checking events a lot easier; for example: + + if event.Op&Write == Write && !(event.Op&Remove == Remove) { + } + + Becomes: + + if event.Has(Write) && !event.Has(Remove) { + } + +- all: add cmd/fsnotify ([#463]) + + A command-line utility for testing and some examples. + +### Changes and fixes + +- inotify: don't ignore events for files that don't exist ([#260], [#470]) + + Previously the inotify watcher would call `os.Lstat()` to check if a file + still exists before emitting events. + + This was inconsistent with other platforms and resulted in inconsistent event + reporting (e.g. when a file is quickly removed and re-created), and generally + a source of confusion. It was added in 2013 to fix a memory leak that no + longer exists. + +- all: return `ErrNonExistentWatch` when `Remove()` is called on a path that's + not watched ([#460]) + +- inotify: replace epoll() with non-blocking inotify ([#434]) + + Non-blocking inotify was not generally available at the time this library was + written in 2014, but now it is. As a result, the minimum Linux version is + bumped from 2.6.27 to 2.6.32. This hugely simplifies the code and is faster. + +- kqueue: don't check for events every 100ms ([#480]) + + The watcher would wake up every 100ms, even when there was nothing to do. Now + it waits until there is something to do. + +- macos: retry opening files on EINTR ([#475]) + +- kqueue: skip unreadable files ([#479]) + + kqueue requires a file descriptor for every file in a directory; this would + fail if a file was unreadable by the current user. Now these files are simply + skipped. + +- windows: fix renaming a watched directory if the parent is also watched ([#370]) + +- windows: increase buffer size from 4K to 64K ([#485]) + +- windows: close file handle on Remove() ([#288]) + +- kqueue: put pathname in the error if watching a file fails ([#471]) + +- inotify, windows: calling Close() more than once could race ([#465]) + +- kqueue: improve Close() performance ([#233]) + +- all: various documentation additions and clarifications. + +[#233]: https://github.com/fsnotify/fsnotify/pull/233 +[#260]: https://github.com/fsnotify/fsnotify/pull/260 +[#288]: https://github.com/fsnotify/fsnotify/pull/288 +[#370]: https://github.com/fsnotify/fsnotify/pull/370 +[#434]: https://github.com/fsnotify/fsnotify/pull/434 +[#460]: https://github.com/fsnotify/fsnotify/pull/460 +[#463]: https://github.com/fsnotify/fsnotify/pull/463 +[#465]: https://github.com/fsnotify/fsnotify/pull/465 +[#470]: https://github.com/fsnotify/fsnotify/pull/470 +[#471]: https://github.com/fsnotify/fsnotify/pull/471 +[#475]: https://github.com/fsnotify/fsnotify/pull/475 +[#477]: https://github.com/fsnotify/fsnotify/pull/477 +[#479]: https://github.com/fsnotify/fsnotify/pull/479 +[#480]: https://github.com/fsnotify/fsnotify/pull/480 +[#485]: https://github.com/fsnotify/fsnotify/pull/485 + ## [1.5.4] - 2022-04-25 * Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447) @@ -40,6 +129,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#385](https://github.com/fsnotify/fsnotify/pull/385) * Go 1.14+: Fix unsafe pointer conversion [#325](https://github.com/fsnotify/fsnotify/pull/325) +## [1.4.9] - 2020-03-11 + +* Move example usage to the readme #329. This may resolve #328. + +## [1.4.8] - 2020-03-10 + +* CI: test more go versions (@nathany 1d13583d846ea9d66dcabbfefbfb9d8e6fb05216) +* Tests: Queued inotify events could have been read by the test before max_queued_events was hit (@matthias-stone #265) +* Tests: t.Fatalf -> t.Errorf in go routines (@gdey #266) +* CI: Less verbosity (@nathany #267) +* Tests: Darwin: Exchangedata is deprecated on 10.13 (@nathany #267) +* Tests: Check if channels are closed in the example (@alexeykazakov #244) +* CI: Only run golint on latest version of go and fix issues (@cpuguy83 #284) +* CI: Add windows to travis matrix (@cpuguy83 #284) +* Docs: Remover appveyor badge (@nathany 11844c0959f6fff69ba325d097fce35bd85a8e93) +* Linux: create epoll and pipe fds with close-on-exec (@JohannesEbke #219) +* Linux: open files with close-on-exec (@linxiulei #273) +* Docs: Plan to support fanotify (@nathany ab058b44498e8b7566a799372a39d150d9ea0119 ) +* Project: Add go.mod (@nathany #309) +* Project: Revise editor config (@nathany #309) +* Project: Update copyright for 2019 (@nathany #309) +* CI: Drop go1.8 from CI matrix (@nathany #309) +* Docs: Updating the FAQ section for supportability with NFS & FUSE filesystems (@Pratik32 4bf2d1fec78374803a39307bfb8d340688f4f28e ) + ## [1.4.7] - 2018-01-09 * BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md index 8a642563d..ea379759d 100644 --- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -1,60 +1,26 @@ -# Contributing +Thank you for your interest in contributing to fsnotify! We try to review and +merge PRs in a reasonable timeframe, but please be aware that: -## Issues +- To avoid "wasted" work, please discus changes on the issue tracker first. You + can just send PRs, but they may end up being rejected for one reason or the + other. -* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues). -* Please indicate the platform you are using fsnotify on. -* A code example to reproduce the problem is appreciated. +- fsnotify is a cross-platform library, and changes must work reasonably well on + all supported platforms. -## Pull Requests +- Changes will need to be compatible; old code should still compile, and the + runtime behaviour can't change in ways that are likely to lead to problems for + users. -### Contributor License Agreement +Testing +------- +Just `go test ./...` runs all the tests; the CI runs this on all supported +platforms. Testing different platforms locally can be done with something like +[goon] or [Vagrant], but this isn't super-easy to set up at the moment. -fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual). +Use the `-short` flag to make the "stress test" run faster. -Please indicate that you have signed the CLA in your pull request. -### How fsnotify is Developed - -* Development is done on feature branches. -* Tests are run on BSD, Linux, macOS and Windows. -* Pull requests are reviewed and [applied to master][am] using [hub][]. - * Maintainers may modify or squash commits rather than asking contributors to. -* To issue a new release, the maintainers will: - * Update the CHANGELOG - * Tag a version, which will become available through gopkg.in. - -### How to Fork - -For smooth sailing, always use the original import path. Installing with `go get` makes this easy. - -1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`) -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Ensure everything works and the tests pass (see below) -4. Commit your changes (`git commit -am 'Add some feature'`) - -Contribute upstream: - -1. Fork fsnotify on GitHub -2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`) -3. Push to the branch (`git push fork my-new-feature`) -4. Create a new Pull Request on GitHub - -This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/). - -### Testing - -fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows. - -Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. - -### Maintainers - -Help maintaining fsnotify is welcome. To be a maintainer: - -* Submit a pull request and sign the CLA as above. -* You must be able to run the test suite on Mac, Windows, Linux and BSD. - -All code changes should be internal pull requests. - -Releases are tagged using [Semantic Versioning](http://semver.org/). +[goon]: https://github.com/arp242/goon +[Vagrant]: https://www.vagrantup.com/ +[integration_test.go]: /integration_test.go diff --git a/vendor/github.com/fsnotify/fsnotify/LICENSE b/vendor/github.com/fsnotify/fsnotify/LICENSE index e180c8fb0..fb03ade75 100644 --- a/vendor/github.com/fsnotify/fsnotify/LICENSE +++ b/vendor/github.com/fsnotify/fsnotify/LICENSE @@ -1,28 +1,25 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. -Copyright (c) 2012-2019 fsnotify Authors. All rights reserved. +Copyright © 2012 The Go Authors. All rights reserved. +Copyright © fsnotify Authors. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +* Neither the name of Google Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md index 0731c5ef8..d4e6080fe 100644 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -1,120 +1,161 @@ -# File system notifications for Go +fsnotify is a Go library to provide cross-platform filesystem notifications on +Windows, Linux, macOS, and BSD systems. -[![Go Reference](https://pkg.go.dev/badge/github.com/fsnotify/fsnotify.svg)](https://pkg.go.dev/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/fsnotify/fsnotify/issues/413) +Go 1.16 or newer is required; the full documentation is at +https://pkg.go.dev/github.com/fsnotify/fsnotify -fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library. +**It's best to read the documentation at pkg.go.dev, as it's pinned to the last +released version, whereas this README is for the last development version which +may include additions/changes.** -Cross platform: Windows, Linux, BSD and macOS. +--- -| Adapter | OS | Status | -| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| inotify | Linux 2.6.27 or later, Android\* | Supported | -| kqueue | BSD, macOS, iOS\* | Supported | -| ReadDirectoryChangesW | Windows | Supported | -| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | -| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) | -| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) | -| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | -| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | +Platform support: -\* Android and iOS are untested. +| Adapter | OS | Status | +| --------------------- | ---------------| -------------------------------------------------------------| +| inotify | Linux 2.6.32+ | Supported | +| kqueue | BSD, macOS | Supported | +| ReadDirectoryChangesW | Windows | Supported | +| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) | +| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) | +| fanotify | Linux 5.9+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) | +| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) | +| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) | -Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. +Linux and macOS should include Android and iOS, but these are currently untested. -## API stability - -fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). - -All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). - -## Usage +Usage +----- +A basic example: ```go package main import ( - "log" + "log" - "github.com/fsnotify/fsnotify" + "github.com/fsnotify/fsnotify" ) func main() { - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Fatal(err) - } - defer watcher.Close() - - done := make(chan bool) - go func() { - for { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - log.Println("event:", event) - if event.Op&fsnotify.Write == fsnotify.Write { - log.Println("modified file:", event.Name) - } - case err, ok := <-watcher.Errors: - if !ok { - return - } - log.Println("error:", err) - } - } - }() - - err = watcher.Add("/tmp/foo") - if err != nil { - log.Fatal(err) - } - <-done + // Create new watcher. + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Fatal(err) + } + defer watcher.Close() + + // Start listening for events. + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + log.Println("event:", event) + if event.Has(fsnotify.Write) { + log.Println("modified file:", event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("error:", err) + } + } + }() + + // Add a path. + err = watcher.Add("/tmp") + if err != nil { + log.Fatal(err) + } + + // Block main goroutine forever. + <-make(chan struct{}) } ``` -## Contributing +Some more examples can be found in [cmd/fsnotify](cmd/fsnotify), which can be +run with: -Please refer to [CONTRIBUTING][] before opening an issue or pull request. + % go run ./cmd/fsnotify -## FAQ +FAQ +--- +### Will a file still be watched when it's moved to another directory? +No, not unless you are watching the location it was moved to. -**When a file is moved to another directory is it still being watched?** +### Are subdirectories watched too? +No, you must add watches for any directory you want to watch (a recursive +watcher is on the roadmap: [#18]). -No (it shouldn't be, unless you are watching where it was moved to). +[#18]: https://github.com/fsnotify/fsnotify/issues/18 -**When I watch a directory, are all subdirectories watched as well?** +### Do I have to watch the Error and Event channels in a goroutine? +As of now, yes (you can read both channels in the same goroutine using `select`, +you don't need a separate goroutine for both channels; see the example). -No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). +### Why don't notifications work with NFS, SMB, FUSE, /proc, or /sys? +fsnotify requires support from underlying OS to work. The current NFS and SMB +protocols does not provide network level support for file notifications, and +neither do the /proc and /sys virtual filesystems. -**Do I have to watch the Error and Event channels in a separate goroutine?** +This could be fixed with a polling watcher ([#9]), but it's not yet implemented. -As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) +[#9]: https://github.com/fsnotify/fsnotify/issues/9 -**Why am I receiving multiple events for the same file on OS X?** +Platform-specific notes +----------------------- +### Linux +When a file is removed a REMOVE event won't be emitted until all file +descriptors are closed; it will emit a CHMOD instead: -Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). + fp := os.Open("file") + os.Remove("file") // CHMOD + fp.Close() // REMOVE -**How many files can be watched at once?** +This is the event that inotify sends, so not much can be changed about this. -There are OS-specific limits as to how many watches can be created: -* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. -* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. +The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for +the number of watches per user, and `fs.inotify.max_user_instances` specifies +the maximum number of inotify instances per user. Every Watcher you create is an +"instance", and every path you add is a "watch". -**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?** +These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and +`/proc/sys/fs/inotify/max_user_instances` -fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications. +To increase them you can use `sysctl` or write the value to proc file: -[#62]: https://github.com/howeyc/fsnotify/issues/62 -[#18]: https://github.com/fsnotify/fsnotify/issues/18 -[#11]: https://github.com/fsnotify/fsnotify/issues/11 -[#7]: https://github.com/howeyc/fsnotify/issues/7 + # The default values on Linux 5.18 + sysctl fs.inotify.max_user_watches=124983 + sysctl fs.inotify.max_user_instances=128 + +To make the changes persist on reboot edit `/etc/sysctl.conf` or +`/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your +distro's documentation): + + fs.inotify.max_user_watches=124983 + fs.inotify.max_user_instances=128 -[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md +Reaching the limit will result in a "no space left on device" or "too many open +files" error. -## Related Projects +### kqueue (macOS, all BSD systems) +kqueue requires opening a file descriptor for every file that's being watched; +so if you're watching a directory with five files then that's six file +descriptors. You will run in to your system's "max open files" limit faster on +these platforms. -* [notify](https://github.com/rjeczalik/notify) -* [fsevents](https://github.com/fsnotify/fsevents) +The sysctl variables `kern.maxfiles` and `kern.maxfilesperproc` can be used to +control the maximum number of open files. +### macOS +Spotlight indexing on macOS can result in multiple events (see [#15]). A temporary +workaround is to add your folder(s) to the *Spotlight Privacy settings* until we +have a native FSEvents implementation (see [#11]). + +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#15]: https://github.com/fsnotify/fsnotify/issues/15 diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go new file mode 100644 index 000000000..1a95ad8e7 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_fen.go @@ -0,0 +1,162 @@ +//go:build solaris +// +build solaris + +package fsnotify + +import ( + "errors" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go new file mode 100644 index 000000000..54c77fbb0 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go @@ -0,0 +1,459 @@ +//go:build linux +// +build linux + +package fsnotify + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + // Store fd here as os.File.Read() will no longer return on close after + // calling Fd(). See: https://github.com/golang/go/issues/26439 + fd int + mu sync.Mutex // Map access + inotifyFile *os.File + watches map[string]*watch // Map of inotify watches (key: path) + paths map[int]string // Map of watched paths (key: watch descriptor) + done chan struct{} // Channel for sending a "quit message" to the reader goroutine + doneResp chan struct{} // Channel to respond to Close +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + // Create inotify fd + // Need to set the FD to nonblocking mode in order for SetDeadline methods to work + // Otherwise, blocking i/o operations won't terminate on close + fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK) + if fd == -1 { + return nil, errno + } + + w := &Watcher{ + fd: fd, + inotifyFile: os.NewFile(uintptr(fd), ""), + watches: make(map[string]*watch), + paths: make(map[int]string), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + doneResp: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + } + return false +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + return false + } +} + +func (w *Watcher) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed() { + w.mu.Unlock() + return nil + } + + // Send 'close' signal to goroutine, and set the Watcher to closed. + close(w.done) + w.mu.Unlock() + + // Causes any blocking reads to return with an error, provided the file + // still supports deadline operations. + err := w.inotifyFile.Close() + if err != nil { + return err + } + + // Wait for goroutine to close + <-w.doneResp + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + name = filepath.Clean(name) + if w.isClosed() { + return errors.New("inotify instance already closed") + } + + var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | + unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | + unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF + + w.mu.Lock() + defer w.mu.Unlock() + watchEntry := w.watches[name] + if watchEntry != nil { + flags |= watchEntry.flags | unix.IN_MASK_ADD + } + wd, errno := unix.InotifyAddWatch(w.fd, name, flags) + if wd == -1 { + return errno + } + + if watchEntry == nil { + w.watches[name] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = name + } else { + watchEntry.wd = uint32(wd) + watchEntry.flags = flags + } + + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + + // Fetch the watch. + w.mu.Lock() + defer w.mu.Unlock() + watch, ok := w.watches[name] + + // Remove it from inotify. + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + // We successfully removed the watch if InotifyRmWatch doesn't return an + // error, we need to clean up our internal state to ensure it matches + // inotify's kernel state. + delete(w.paths, int(watch.wd)) + delete(w.watches, name) + + // inotify_rm_watch will return EINVAL if the file has been deleted; + // the inotify will already have been removed. + // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously + // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE + // so that EINVAL means that the wd is being rm_watch()ed or its file removed + // by another thread and we have not received IN_IGNORE event. + success, errno := unix.InotifyRmWatch(w.fd, watch.wd) + if success == -1 { + // TODO: Perhaps it's not helpful to return an error here in every case; + // The only two possible errors are: + // + // - EBADF, which happens when w.fd is not a valid file descriptor + // of any kind. + // - EINVAL, which is when fd is not an inotify descriptor or wd + // is not a valid watch descriptor. Watch descriptors are + // invalidated when they are removed explicitly or implicitly; + // explicitly by inotify_rm_watch, implicitly when the file they + // are watching is deleted. + return errno + } + + return nil +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)) + for pathname := range w.watches { + entries = append(entries, pathname) + } + + return entries +} + +type watch struct { + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) +} + +// readEvents reads from the inotify file descriptor, converts the +// received events into Event objects and sends them via the Events channel +func (w *Watcher) readEvents() { + defer func() { + close(w.doneResp) + close(w.Errors) + close(w.Events) + }() + + var ( + buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events + errno error // Syscall errno + ) + for { + // See if we have been closed. + if w.isClosed() { + return + } + + n, err := w.inotifyFile.Read(buf[:]) + switch { + case errors.Unwrap(err) == os.ErrClosed: + return + case err != nil: + if !w.sendError(err) { + return + } + continue + } + + if n < unix.SizeofInotifyEvent { + var err error + if n == 0 { + // If EOF is received. This should really never happen. + err = io.EOF + } else if n < 0 { + // If an error occurred while reading. + err = errno + } else { + // Read was too short. + err = errors.New("notify: short read in readEvents()") + } + if !w.sendError(err) { + return + } + continue + } + + var offset uint32 + // We don't know how many events we just read into the buffer + // While the offset points to at least one whole event... + for offset <= uint32(n-unix.SizeofInotifyEvent) { + var ( + // Point "raw" to the event in the buffer + raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + mask = uint32(raw.Mask) + nameLen = uint32(raw.Len) + ) + + if mask&unix.IN_Q_OVERFLOW != 0 { + if !w.sendError(ErrEventOverflow) { + return + } + } + + // If the event happened to the watched directory or the watched file, the kernel + // doesn't append the filename to the event, but we would like to always fill the + // the "Name" field with a valid filename. We retrieve the path of the watch from + // the "paths" map. + w.mu.Lock() + name, ok := w.paths[int(raw.Wd)] + // IN_DELETE_SELF occurs when the file/directory being watched is removed. + // This is a sign to clean up the maps, otherwise we are no longer in sync + // with the inotify kernel state which has already deleted the watch + // automatically. + if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + delete(w.paths, int(raw.Wd)) + delete(w.watches, name) + } + w.mu.Unlock() + + if nameLen > 0 { + // Point "bytes" at the first byte of the filename + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] + // The filename is padded with NULL bytes. TrimRight() gets rid of those. + name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + } + + event := w.newEvent(name, mask) + + // Send the events that are not ignored on the events channel + if mask&unix.IN_IGNORED == 0 { + if !w.sendEvent(event) { + return + } + } + + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + nameLen + } + } +} + +// newEvent returns an platform-independent Event based on an inotify mask. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { + e.Op |= Create + } + if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { + e.Op |= Remove + } + if mask&unix.IN_MODIFY == unix.IN_MODIFY { + e.Op |= Write + } + if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { + e.Op |= Rename + } + if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { + e.Op |= Chmod + } + return e +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go new file mode 100644 index 000000000..29087469b --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go @@ -0,0 +1,707 @@ +//go:build freebsd || openbsd || netbsd || dragonfly || darwin +// +build freebsd openbsd netbsd dragonfly darwin + +package fsnotify + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "golang.org/x/sys/unix" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + done chan struct{} + kq int // File descriptor (as returned by the kqueue() syscall). + closepipe [2]int // Pipe used for closing. + mu sync.Mutex // Protects access to watcher data + watches map[string]int // Watched file descriptors (key: path). + watchesByDir map[string]map[int]struct{} // Watched file descriptors indexed by the parent directory (key: dirname(path)). + userWatches map[string]struct{} // Watches added with Watcher.Add() + dirFlags map[string]uint32 // Watched directories to fflags used in kqueue. + paths map[int]pathInfo // File descriptors to path names for processing kqueue events. + fileExists map[string]struct{} // Keep track of if we know this file exists (to stop duplicate create events). + isClosed bool // Set to true when Close() is first called +} + +type pathInfo struct { + name string + isDir bool +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + kq, closepipe, err := newKqueue() + if err != nil { + return nil, err + } + + w := &Watcher{ + kq: kq, + closepipe: closepipe, + watches: make(map[string]int), + watchesByDir: make(map[string]map[int]struct{}), + dirFlags: make(map[string]uint32), + paths: make(map[int]pathInfo), + fileExists: make(map[string]struct{}), + userWatches: make(map[string]struct{}), + Events: make(chan Event), + Errors: make(chan error), + done: make(chan struct{}), + } + + go w.readEvents() + return w, nil +} + +// newKqueue creates a new kernel event queue and returns a descriptor. +// +// This registers a new event on closepipe, which will trigger an event when +// it's closed. This way we can use kevent() without timeout/polling; without +// the closepipe, it would block forever and we wouldn't be able to stop it at +// all. +func newKqueue() (kq int, closepipe [2]int, err error) { + kq, err = unix.Kqueue() + if kq == -1 { + return kq, closepipe, err + } + + // Register the close pipe. + err = unix.Pipe(closepipe[:]) + if err != nil { + unix.Close(kq) + return kq, closepipe, err + } + + // Register changes to listen on the closepipe. + changes := make([]unix.Kevent_t, 1) + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ, + unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT) + + ok, err := unix.Kevent(kq, changes, nil, nil) + if ok == -1 { + unix.Close(kq) + unix.Close(closepipe[0]) + unix.Close(closepipe[1]) + return kq, closepipe, err + } + return kq, closepipe, nil +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *Watcher) sendEvent(e Event) bool { + select { + case w.Events <- e: + return true + case <-w.done: + } + return false +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.done: + } + return false +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + + // copy paths to remove while locked + pathsToRemove := make([]string, 0, len(w.watches)) + for name := range w.watches { + pathsToRemove = append(pathsToRemove, name) + } + w.mu.Unlock() // Unlock before calling Remove, which also locks + for _, name := range pathsToRemove { + w.Remove(name) + } + + // Send "quit" message to the reader goroutine. + unix.Close(w.closepipe[1]) + close(w.done) + + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + w.mu.Lock() + w.userWatches[name] = struct{}{} + w.mu.Unlock() + _, err := w.addWatch(name, noteAllEvents) + return err +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + name = filepath.Clean(name) + w.mu.Lock() + watchfd, ok := w.watches[name] + w.mu.Unlock() + if !ok { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, name) + } + + err := w.register([]int{watchfd}, unix.EV_DELETE, 0) + if err != nil { + return err + } + + unix.Close(watchfd) + + w.mu.Lock() + isDir := w.paths[watchfd].isDir + delete(w.watches, name) + delete(w.userWatches, name) + + parentName := filepath.Dir(name) + delete(w.watchesByDir[parentName], watchfd) + + if len(w.watchesByDir[parentName]) == 0 { + delete(w.watchesByDir, parentName) + } + + delete(w.paths, watchfd) + delete(w.dirFlags, name) + delete(w.fileExists, name) + w.mu.Unlock() + + // Find all watched paths that are in this directory that are not external. + if isDir { + var pathsToRemove []string + w.mu.Lock() + for fd := range w.watchesByDir[name] { + path := w.paths[fd] + if _, ok := w.userWatches[path.name]; !ok { + pathsToRemove = append(pathsToRemove, path.name) + } + } + w.mu.Unlock() + for _, name := range pathsToRemove { + // Since these are internal, not much sense in propagating error + // to the user, as that will just confuse them with an error about + // a path they did not explicitly watch themselves. + w.Remove(name) + } + } + + return nil +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.userWatches)) + for pathname := range w.userWatches { + entries = append(entries, pathname) + } + + return entries +} + +// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) +const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME + +// addWatch adds name to the watched file set. +// The flags are interpreted as described in kevent(2). +// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. +func (w *Watcher) addWatch(name string, flags uint32) (string, error) { + var isDir bool + // Make ./name and name equivalent + name = filepath.Clean(name) + + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return "", errors.New("kevent instance already closed") + } + watchfd, alreadyWatching := w.watches[name] + // We already have a watch, but we can still override flags. + if alreadyWatching { + isDir = w.paths[watchfd].isDir + } + w.mu.Unlock() + + if !alreadyWatching { + fi, err := os.Lstat(name) + if err != nil { + return "", err + } + + // Don't watch sockets or named pipes + if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) { + return "", nil + } + + // Follow Symlinks + // + // Linux can add unresolvable symlinks to the watch list without issue, + // and Windows can't do symlinks period. To maintain consistency, we + // will act like everything is fine if the link can't be resolved. + // There will simply be no file events for broken symlinks. Hence the + // returns of nil on errors. + if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + name, err = filepath.EvalSymlinks(name) + if err != nil { + return "", nil + } + + w.mu.Lock() + _, alreadyWatching = w.watches[name] + w.mu.Unlock() + + if alreadyWatching { + return name, nil + } + + fi, err = os.Lstat(name) + if err != nil { + return "", nil + } + } + + // Retry on EINTR; open() can return EINTR in practice on macOS. + // See #354, and go issues 11180 and 39237. + for { + watchfd, err = unix.Open(name, openMode, 0) + if err == nil { + break + } + if errors.Is(err, unix.EINTR) { + continue + } + + return "", err + } + + isDir = fi.IsDir() + } + + err := w.register([]int{watchfd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags) + if err != nil { + unix.Close(watchfd) + return "", err + } + + if !alreadyWatching { + w.mu.Lock() + parentName := filepath.Dir(name) + w.watches[name] = watchfd + + watchesByDir, ok := w.watchesByDir[parentName] + if !ok { + watchesByDir = make(map[int]struct{}, 1) + w.watchesByDir[parentName] = watchesByDir + } + watchesByDir[watchfd] = struct{}{} + + w.paths[watchfd] = pathInfo{name: name, isDir: isDir} + w.mu.Unlock() + } + + if isDir { + // Watch the directory if it has not been watched before, + // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) + w.mu.Lock() + + watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && + (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) + // Store flags so this watch can be updated later + w.dirFlags[name] = flags + w.mu.Unlock() + + if watchDir { + if err := w.watchDirectoryFiles(name); err != nil { + return "", err + } + } + } + return name, nil +} + +// readEvents reads from kqueue and converts the received kevents into +// Event values that it sends down the Events channel. +func (w *Watcher) readEvents() { + defer func() { + err := unix.Close(w.kq) + if err != nil { + w.Errors <- err + } + unix.Close(w.closepipe[0]) + close(w.Events) + close(w.Errors) + }() + + eventBuffer := make([]unix.Kevent_t, 10) + for closed := false; !closed; { + kevents, err := w.read(eventBuffer) + // EINTR is okay, the syscall was interrupted before timeout expired. + if err != nil && err != unix.EINTR { + if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) { + closed = true + } + continue + } + + // Flush the events we received to the Events channel + for _, kevent := range kevents { + var ( + watchfd = int(kevent.Ident) + mask = uint32(kevent.Fflags) + ) + + // Shut down the loop when the pipe is closed, but only after all + // other events have been processed. + if watchfd == w.closepipe[0] { + closed = true + continue + } + + w.mu.Lock() + path := w.paths[watchfd] + w.mu.Unlock() + + event := w.newEvent(path.name, mask) + + if path.isDir && !event.Has(Remove) { + // Double check to make sure the directory exists. This can + // happen when we do a rm -fr on a recursively watched folders + // and we receive a modification event first but the folder has + // been deleted and later receive the delete event. + if _, err := os.Lstat(event.Name); os.IsNotExist(err) { + event.Op |= Remove + } + } + + if event.Has(Rename) || event.Has(Remove) { + w.Remove(event.Name) + w.mu.Lock() + delete(w.fileExists, event.Name) + w.mu.Unlock() + } + + if path.isDir && event.Has(Write) && !event.Has(Remove) { + w.sendDirectoryChangeEvents(event.Name) + } else { + if !w.sendEvent(event) { + closed = true + continue + } + } + + if event.Has(Remove) { + // Look for a file that may have overwritten this. + // For example, mv f1 f2 will delete f2, then create f2. + if path.isDir { + fileDir := filepath.Clean(event.Name) + w.mu.Lock() + _, found := w.watches[fileDir] + w.mu.Unlock() + if found { + // make sure the directory exists before we watch for changes. When we + // do a recursive watch and perform rm -fr, the parent directory might + // have gone missing, ignore the missing directory and let the + // upcoming delete event remove the watch from the parent directory. + if _, err := os.Lstat(fileDir); err == nil { + w.sendDirectoryChangeEvents(fileDir) + } + } + } else { + filePath := filepath.Clean(event.Name) + if fileInfo, err := os.Lstat(filePath); err == nil { + w.sendFileCreatedEventIfNew(filePath, fileInfo) + } + } + } + } + } +} + +// newEvent returns an platform-independent Event based on kqueue Fflags. +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { + e.Op |= Remove + } + if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { + e.Op |= Write + } + if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { + e.Op |= Rename + } + if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { + e.Op |= Chmod + } + return e +} + +// watchDirectoryFiles to mimic inotify when adding a watch on a directory +func (w *Watcher) watchDirectoryFiles(dirPath string) error { + // Get all files + files, err := ioutil.ReadDir(dirPath) + if err != nil { + return err + } + + for _, fileInfo := range files { + path := filepath.Join(dirPath, fileInfo.Name()) + + cleanPath, err := w.internalWatch(path, fileInfo) + if err != nil { + // No permission to read the file; that's not a problem: just skip. + // But do add it to w.fileExists to prevent it from being picked up + // as a "new" file later (it still shows up in the directory + // listing). + switch { + case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM): + cleanPath = filepath.Clean(path) + default: + return fmt.Errorf("%q: %w", filepath.Join(dirPath, fileInfo.Name()), err) + } + } + + w.mu.Lock() + w.fileExists[cleanPath] = struct{}{} + w.mu.Unlock() + } + + return nil +} + +// Search the directory for new files and send an event for them. +// +// This functionality is to have the BSD watcher match the inotify, which sends +// a create event for files created in a watched directory. +func (w *Watcher) sendDirectoryChangeEvents(dir string) { + // Get all files + files, err := ioutil.ReadDir(dir) + if err != nil { + if !w.sendError(fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)) { + return + } + } + + // Search for new files + for _, fi := range files { + err := w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi) + if err != nil { + return + } + } +} + +// sendFileCreatedEvent sends a create event if the file isn't already being tracked. +func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { + w.mu.Lock() + _, doesExist := w.fileExists[filePath] + w.mu.Unlock() + if !doesExist { + if !w.sendEvent(Event{Name: filePath, Op: Create}) { + return + } + } + + // like watchDirectoryFiles (but without doing another ReadDir) + filePath, err = w.internalWatch(filePath, fileInfo) + if err != nil { + return err + } + + w.mu.Lock() + w.fileExists[filePath] = struct{}{} + w.mu.Unlock() + + return nil +} + +func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { + if fileInfo.IsDir() { + // mimic Linux providing delete events for subdirectories + // but preserve the flags used if currently watching subdirectory + w.mu.Lock() + flags := w.dirFlags[name] + w.mu.Unlock() + + flags |= unix.NOTE_DELETE | unix.NOTE_RENAME + return w.addWatch(name, flags) + } + + // watch file to mimic Linux inotify + return w.addWatch(name, noteAllEvents) +} + +// Register events with the queue. +func (w *Watcher) register(fds []int, flags int, fflags uint32) error { + changes := make([]unix.Kevent_t, len(fds)) + for i, fd := range fds { + // SetKevent converts int to the platform-specific types. + unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) + changes[i].Fflags = fflags + } + + // Register the events. + success, err := unix.Kevent(w.kq, changes, nil, nil) + if success == -1 { + return err + } + return nil +} + +// read retrieves pending events, or waits until an event occurs. +func (w *Watcher) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) { + n, err := unix.Kevent(w.kq, nil, events, nil) + if err != nil { + return nil, err + } + return events[0:n], nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_other.go b/vendor/github.com/fsnotify/fsnotify/backend_other.go new file mode 100644 index 000000000..a9bb1c3c4 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_other.go @@ -0,0 +1,66 @@ +//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows +// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows + +package fsnotify + +import ( + "fmt" + "runtime" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct{} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS) +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go new file mode 100644 index 000000000..ae392867c --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/backend_windows.go @@ -0,0 +1,746 @@ +//go:build windows +// +build windows + +package fsnotify + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "sync" + "unsafe" + + "golang.org/x/sys/windows" +) + +// Watcher watches a set of paths, delivering events on a channel. +// +// A watcher should not be copied (e.g. pass it by pointer, rather than by +// value). +// +// # Linux notes +// +// When a file is removed a Remove event won't be emitted until all file +// descriptors are closed, and deletes will always emit a Chmod. For example: +// +// fp := os.Open("file") +// os.Remove("file") // Triggers Chmod +// fp.Close() // Triggers Remove +// +// This is the event that inotify sends, so not much can be changed about this. +// +// The fs.inotify.max_user_watches sysctl variable specifies the upper limit +// for the number of watches per user, and fs.inotify.max_user_instances +// specifies the maximum number of inotify instances per user. Every Watcher you +// create is an "instance", and every path you add is a "watch". +// +// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and +// /proc/sys/fs/inotify/max_user_instances +// +// To increase them you can use sysctl or write the value to the /proc file: +// +// # Default values on Linux 5.18 +// sysctl fs.inotify.max_user_watches=124983 +// sysctl fs.inotify.max_user_instances=128 +// +// To make the changes persist on reboot edit /etc/sysctl.conf or +// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check +// your distro's documentation): +// +// fs.inotify.max_user_watches=124983 +// fs.inotify.max_user_instances=128 +// +// Reaching the limit will result in a "no space left on device" or "too many open +// files" error. +// +// # kqueue notes (macOS, BSD) +// +// kqueue requires opening a file descriptor for every file that's being watched; +// so if you're watching a directory with five files then that's six file +// descriptors. You will run in to your system's "max open files" limit faster on +// these platforms. +// +// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to +// control the maximum number of open files, as well as /etc/login.conf on BSD +// systems. +// +// # macOS notes +// +// Spotlight indexing on macOS can result in multiple events (see [#15]). A +// temporary workaround is to add your folder(s) to the "Spotlight Privacy +// Settings" until we have a native FSEvents implementation (see [#11]). +// +// [#11]: https://github.com/fsnotify/fsnotify/issues/11 +// [#15]: https://github.com/fsnotify/fsnotify/issues/15 +type Watcher struct { + // Events sends the filesystem change events. + // + // fsnotify can send the following events; a "path" here can refer to a + // file, directory, symbolic link, or special file like a FIFO. + // + // fsnotify.Create A new path was created; this may be followed by one + // or more Write events if data also gets written to a + // file. + // + // fsnotify.Remove A path was removed. + // + // fsnotify.Rename A path was renamed. A rename is always sent with the + // old path as Event.Name, and a Create event will be + // sent with the new name. Renames are only sent for + // paths that are currently watched; e.g. moving an + // unmonitored file into a monitored directory will + // show up as just a Create. Similarly, renaming a file + // to outside a monitored directory will show up as + // only a Rename. + // + // fsnotify.Write A file or named pipe was written to. A Truncate will + // also trigger a Write. A single "write action" + // initiated by the user may show up as one or multiple + // writes, depending on when the system syncs things to + // disk. For example when compiling a large Go program + // you may get hundreds of Write events, so you + // probably want to wait until you've stopped receiving + // them (see the dedup example in cmd/fsnotify). + // + // fsnotify.Chmod Attributes were changed. On Linux this is also sent + // when a file is removed (or more accurately, when a + // link to an inode is removed). On kqueue it's sent + // and on kqueue when a file is truncated. On Windows + // it's never sent. + Events chan Event + + // Errors sends any errors. + Errors chan error + + port windows.Handle // Handle to completion port + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error + + mu sync.Mutex // Protects access to watches, isClosed + watches watchMap // Map of watches (key: i-number) + isClosed bool // Set to true when Close() is first called +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) + if err != nil { + return nil, os.NewSyscallError("CreateIoCompletionPort", err) + } + w := &Watcher{ + port: port, + watches: make(watchMap), + input: make(chan *input, 1), + Events: make(chan Event, 50), + Errors: make(chan error), + quit: make(chan chan<- error, 1), + } + go w.readEvents() + return w, nil +} + +func (w *Watcher) sendEvent(name string, mask uint64) bool { + if mask == 0 { + return false + } + + event := w.newEvent(name, uint32(mask)) + select { + case ch := <-w.quit: + w.quit <- ch + case w.Events <- event: + } + return true +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *Watcher) sendError(err error) bool { + select { + case w.Errors <- err: + return true + case <-w.quit: + } + return false +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return nil + } + w.isClosed = true + w.mu.Unlock() + + // Send "quit" message to the reader goroutine + ch := make(chan error) + w.quit <- ch + if err := w.wakeupReader(); err != nil { + return err + } + return <-ch +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + w.mu.Lock() + if w.isClosed { + w.mu.Unlock() + return errors.New("watcher already closed") + } + w.mu.Unlock() + + in := &input{ + op: opAddWatch, + path: filepath.Clean(name), + flags: sysFSALLEVENTS, + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + in := &input{ + op: opRemoveWatch, + path: filepath.Clean(name), + reply: make(chan error), + } + w.input <- in + if err := w.wakeupReader(); err != nil { + return err + } + return <-in.reply +} + +// WatchList returns all paths added with [Add] (and are not yet removed). +func (w *Watcher) WatchList() []string { + w.mu.Lock() + defer w.mu.Unlock() + + entries := make([]string, 0, len(w.watches)) + for _, entry := range w.watches { + for _, watchEntry := range entry { + entries = append(entries, watchEntry.path) + } + } + + return entries +} + +// These options are from the old golang.org/x/exp/winfsnotify, where you could +// add various options to the watch. This has long since been removed. +// +// The "sys" in the name is misleading as they're not part of any "system". +// +// This should all be removed at some point, and just use windows.FILE_NOTIFY_* +const ( + sysFSALLEVENTS = 0xfff + sysFSATTRIB = 0x4 + sysFSCREATE = 0x100 + sysFSDELETE = 0x200 + sysFSDELETESELF = 0x400 + sysFSMODIFY = 0x2 + sysFSMOVE = 0xc0 + sysFSMOVEDFROM = 0x40 + sysFSMOVEDTO = 0x80 + sysFSMOVESELF = 0x800 + sysFSIGNORED = 0x8000 +) + +func (w *Watcher) newEvent(name string, mask uint32) Event { + e := Event{Name: name} + if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { + e.Op |= Create + } + if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { + e.Op |= Remove + } + if mask&sysFSMODIFY == sysFSMODIFY { + e.Op |= Write + } + if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { + e.Op |= Rename + } + if mask&sysFSATTRIB == sysFSATTRIB { + e.Op |= Chmod + } + return e +} + +const ( + opAddWatch = iota + opRemoveWatch +) + +const ( + provisional uint64 = 1 << (32 + iota) +) + +type input struct { + op int + path string + flags uint32 + reply chan error +} + +type inode struct { + handle windows.Handle + volume uint32 + index uint64 +} + +type watch struct { + ov windows.Overlapped + ino *inode // i-number + path string // Directory path + mask uint64 // Directory itself is being watched with these notify flags + names map[string]uint64 // Map of names being watched and their notify flags + rename string // Remembers the old name while renaming a file + buf [65536]byte // 64K buffer +} + +type ( + indexMap map[uint64]*watch + watchMap map[uint32]indexMap +) + +func (w *Watcher) wakeupReader() error { + err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil) + if err != nil { + return os.NewSyscallError("PostQueuedCompletionStatus", err) + } + return nil +} + +func (w *Watcher) getDir(pathname string) (dir string, err error) { + attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname)) + if err != nil { + return "", os.NewSyscallError("GetFileAttributes", err) + } + if attr&windows.FILE_ATTRIBUTE_DIRECTORY != 0 { + dir = pathname + } else { + dir, _ = filepath.Split(pathname) + dir = filepath.Clean(dir) + } + return +} + +func (w *Watcher) getIno(path string) (ino *inode, err error) { + h, err := windows.CreateFile(windows.StringToUTF16Ptr(path), + windows.FILE_LIST_DIRECTORY, + windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, + nil, windows.OPEN_EXISTING, + windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED, 0) + if err != nil { + return nil, os.NewSyscallError("CreateFile", err) + } + + var fi windows.ByHandleFileInformation + err = windows.GetFileInformationByHandle(h, &fi) + if err != nil { + windows.CloseHandle(h) + return nil, os.NewSyscallError("GetFileInformationByHandle", err) + } + ino = &inode{ + handle: h, + volume: fi.VolumeSerialNumber, + index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), + } + return ino, nil +} + +// Must run within the I/O thread. +func (m watchMap) get(ino *inode) *watch { + if i := m[ino.volume]; i != nil { + return i[ino.index] + } + return nil +} + +// Must run within the I/O thread. +func (m watchMap) set(ino *inode, watch *watch) { + i := m[ino.volume] + if i == nil { + i = make(indexMap) + m[ino.volume] = i + } + i[ino.index] = watch +} + +// Must run within the I/O thread. +func (w *Watcher) addWatch(pathname string, flags uint64) error { + dir, err := w.getDir(pathname) + if err != nil { + return err + } + + ino, err := w.getIno(dir) + if err != nil { + return err + } + w.mu.Lock() + watchEntry := w.watches.get(ino) + w.mu.Unlock() + if watchEntry == nil { + _, err := windows.CreateIoCompletionPort(ino.handle, w.port, 0, 0) + if err != nil { + windows.CloseHandle(ino.handle) + return os.NewSyscallError("CreateIoCompletionPort", err) + } + watchEntry = &watch{ + ino: ino, + path: dir, + names: make(map[string]uint64), + } + w.mu.Lock() + w.watches.set(ino, watchEntry) + w.mu.Unlock() + flags |= provisional + } else { + windows.CloseHandle(ino.handle) + } + if pathname == dir { + watchEntry.mask |= flags + } else { + watchEntry.names[filepath.Base(pathname)] |= flags + } + + err = w.startRead(watchEntry) + if err != nil { + return err + } + + if pathname == dir { + watchEntry.mask &= ^provisional + } else { + watchEntry.names[filepath.Base(pathname)] &= ^provisional + } + return nil +} + +// Must run within the I/O thread. +func (w *Watcher) remWatch(pathname string) error { + dir, err := w.getDir(pathname) + if err != nil { + return err + } + ino, err := w.getIno(dir) + if err != nil { + return err + } + + w.mu.Lock() + watch := w.watches.get(ino) + w.mu.Unlock() + + err = windows.CloseHandle(ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + if watch == nil { + return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) + } + if pathname == dir { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + watch.mask = 0 + } else { + name := filepath.Base(pathname) + w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + return w.startRead(watch) +} + +// Must run within the I/O thread. +func (w *Watcher) deleteWatch(watch *watch) { + for name, mask := range watch.names { + if mask&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) + } + delete(watch.names, name) + } + if watch.mask != 0 { + if watch.mask&provisional == 0 { + w.sendEvent(watch.path, watch.mask&sysFSIGNORED) + } + watch.mask = 0 + } +} + +// Must run within the I/O thread. +func (w *Watcher) startRead(watch *watch) error { + err := windows.CancelIo(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CancelIo", err)) + w.deleteWatch(watch) + } + mask := w.toWindowsFlags(watch.mask) + for _, m := range watch.names { + mask |= w.toWindowsFlags(m) + } + if mask == 0 { + err := windows.CloseHandle(watch.ino.handle) + if err != nil { + w.sendError(os.NewSyscallError("CloseHandle", err)) + } + w.mu.Lock() + delete(w.watches[watch.ino.volume], watch.ino.index) + w.mu.Unlock() + return nil + } + + rdErr := windows.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], + uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) + if rdErr != nil { + err := os.NewSyscallError("ReadDirectoryChanges", rdErr) + if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + err = nil + } + w.deleteWatch(watch) + w.startRead(watch) + return err + } + return nil +} + +// readEvents reads from the I/O completion port, converts the +// received events into Event objects and sends them via the Events channel. +// Entry point to the I/O thread. +func (w *Watcher) readEvents() { + var ( + n uint32 + key uintptr + ov *windows.Overlapped + ) + runtime.LockOSThread() + + for { + qErr := windows.GetQueuedCompletionStatus(w.port, &n, &key, &ov, windows.INFINITE) + // This error is handled after the watch == nil check below. NOTE: this + // seems odd, note sure if it's correct. + + watch := (*watch)(unsafe.Pointer(ov)) + if watch == nil { + select { + case ch := <-w.quit: + w.mu.Lock() + var indexes []indexMap + for _, index := range w.watches { + indexes = append(indexes, index) + } + w.mu.Unlock() + for _, index := range indexes { + for _, watch := range index { + w.deleteWatch(watch) + w.startRead(watch) + } + } + + err := windows.CloseHandle(w.port) + if err != nil { + err = os.NewSyscallError("CloseHandle", err) + } + close(w.Events) + close(w.Errors) + ch <- err + return + case in := <-w.input: + switch in.op { + case opAddWatch: + in.reply <- w.addWatch(in.path, uint64(in.flags)) + case opRemoveWatch: + in.reply <- w.remWatch(in.path) + } + default: + } + continue + } + + switch qErr { + case windows.ERROR_MORE_DATA: + if watch == nil { + w.sendError(errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")) + } else { + // The i/o succeeded but the buffer is full. + // In theory we should be building up a full packet. + // In practice we can get away with just carrying on. + n = uint32(unsafe.Sizeof(watch.buf)) + } + case windows.ERROR_ACCESS_DENIED: + // Watched directory was probably removed + w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) + w.deleteWatch(watch) + w.startRead(watch) + continue + case windows.ERROR_OPERATION_ABORTED: + // CancelIo was called on this handle + continue + default: + w.sendError(os.NewSyscallError("GetQueuedCompletionPort", qErr)) + continue + case nil: + } + + var offset uint32 + for { + if n == 0 { + w.sendError(errors.New("short read in readEvents()")) + break + } + + // Point "raw" to the event in the buffer + raw := (*windows.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) + + // Create a buf that is the size of the path name + size := int(raw.FileNameLength / 2) + var buf []uint16 + // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973 + sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) + sh.Len = size + sh.Cap = size + name := windows.UTF16ToString(buf) + fullname := filepath.Join(watch.path, name) + + var mask uint64 + switch raw.Action { + case windows.FILE_ACTION_REMOVED: + mask = sysFSDELETESELF + case windows.FILE_ACTION_MODIFIED: + mask = sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + watch.rename = name + case windows.FILE_ACTION_RENAMED_NEW_NAME: + // Update saved path of all sub-watches. + old := filepath.Join(watch.path, watch.rename) + w.mu.Lock() + for _, watchMap := range w.watches { + for _, ww := range watchMap { + if strings.HasPrefix(ww.path, old) { + ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) + } + } + } + w.mu.Unlock() + + if watch.names[watch.rename] != 0 { + watch.names[name] |= watch.names[watch.rename] + delete(watch.names, watch.rename) + mask = sysFSMOVESELF + } + } + + sendNameEvent := func() { + w.sendEvent(fullname, watch.names[name]&mask) + } + if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME { + sendNameEvent() + } + if raw.Action == windows.FILE_ACTION_REMOVED { + w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) + delete(watch.names, name) + } + + w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action)) + if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { + fullname = filepath.Join(watch.path, watch.rename) + sendNameEvent() + } + + // Move to the next event in the buffer + if raw.NextEntryOffset == 0 { + break + } + offset += raw.NextEntryOffset + + // Error! + if offset >= n { + w.sendError(errors.New( + "Windows system assumed buffer larger than it is, events have likely been missed.")) + break + } + } + + if err := w.startRead(watch); err != nil { + w.sendError(err) + } + } +} + +func (w *Watcher) toWindowsFlags(mask uint64) uint32 { + var m uint32 + if mask&sysFSMODIFY != 0 { + m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE + } + if mask&sysFSATTRIB != 0 { + m |= windows.FILE_NOTIFY_CHANGE_ATTRIBUTES + } + if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { + m |= windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME + } + return m +} + +func (w *Watcher) toFSnotifyFlags(action uint32) uint64 { + switch action { + case windows.FILE_ACTION_ADDED: + return sysFSCREATE + case windows.FILE_ACTION_REMOVED: + return sysFSDELETE + case windows.FILE_ACTION_MODIFIED: + return sysFSMODIFY + case windows.FILE_ACTION_RENAMED_OLD_NAME: + return sysFSMOVEDFROM + case windows.FILE_ACTION_RENAMED_NEW_NAME: + return sysFSMOVEDTO + } + return 0 +} diff --git a/vendor/github.com/fsnotify/fsnotify/fen.go b/vendor/github.com/fsnotify/fsnotify/fen.go deleted file mode 100644 index b3ac3d8f5..000000000 --- a/vendor/github.com/fsnotify/fsnotify/fen.go +++ /dev/null @@ -1,38 +0,0 @@ -// 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. - -//go:build solaris -// +build solaris - -package fsnotify - -import ( - "errors" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - return nil -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - return nil -} diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go index 0f4ee52e8..30a5bf0f0 100644 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -1,29 +1,37 @@ -// Copyright 2012 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 !plan9 // +build !plan9 -// Package fsnotify provides a platform-independent interface for file system notifications. +// Package fsnotify provides a cross-platform interface for file system +// notifications. package fsnotify import ( - "bytes" "errors" "fmt" + "strings" ) -// Event represents a single file system notification. +// Event represents a file system notification. type Event struct { - Name string // Relative path to the file or directory. - Op Op // File operation that triggered the event. + // Path to the file or directory. + // + // Paths are relative to the input; for example with Add("dir") the Name + // will be set to "dir/file" if you create that file, but if you use + // Add("/path/to/dir") it will be "/path/to/dir/file". + Name string + + // File operation that triggered the event. + // + // This is a bitmask and some systems may send multiple operations at once. + // Use the Event.Has() method instead of comparing with ==. + Op Op } // Op describes a set of file operations. type Op uint32 -// These are the generalized file operations that can trigger a notification. +// The operations fsnotify can trigger; see the documentation on [Watcher] for a +// full description, and check them with [Event.Has]. const ( Create Op = 1 << iota Write @@ -32,38 +40,42 @@ const ( Chmod ) -func (op Op) String() string { - // Use a buffer for efficient string concatenation - var buffer bytes.Buffer +// Common errors that can be reported by a watcher +var ( + ErrNonExistentWatch = errors.New("can't remove non-existent watcher") + ErrEventOverflow = errors.New("fsnotify queue overflow") +) - if op&Create == Create { - buffer.WriteString("|CREATE") +func (op Op) String() string { + var b strings.Builder + if op.Has(Create) { + b.WriteString("|CREATE") } - if op&Remove == Remove { - buffer.WriteString("|REMOVE") + if op.Has(Remove) { + b.WriteString("|REMOVE") } - if op&Write == Write { - buffer.WriteString("|WRITE") + if op.Has(Write) { + b.WriteString("|WRITE") } - if op&Rename == Rename { - buffer.WriteString("|RENAME") + if op.Has(Rename) { + b.WriteString("|RENAME") } - if op&Chmod == Chmod { - buffer.WriteString("|CHMOD") + if op.Has(Chmod) { + b.WriteString("|CHMOD") } - if buffer.Len() == 0 { - return "" + if b.Len() == 0 { + return "[no events]" } - return buffer.String()[1:] // Strip leading pipe + return b.String()[1:] } -// String returns a string representation of the event in the form -// "file: REMOVE|WRITE|..." +// Has reports if this operation has the given operation. +func (o Op) Has(h Op) bool { return o&h == h } + +// Has reports if this event has the given operation. +func (e Event) Has(op Op) bool { return e.Op.Has(op) } + +// String returns a string representation of the event with their path. func (e Event) String() string { - return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) + return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name) } - -// Common errors that can be reported by a watcher -var ( - ErrEventOverflow = errors.New("fsnotify queue overflow") -) diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go b/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go deleted file mode 100644 index 596885598..000000000 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify_unsupported.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows -// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows - -package fsnotify - -import ( - "fmt" - "runtime" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct{} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS) -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - return nil -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - return nil -} diff --git a/vendor/github.com/fsnotify/fsnotify/go.mod b/vendor/github.com/fsnotify/fsnotify/go.mod deleted file mode 100644 index 48cfd07fe..000000000 --- a/vendor/github.com/fsnotify/fsnotify/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/fsnotify/fsnotify - -go 1.16 - -require golang.org/x/sys v0.0.0-20220412211240-33da011f77ad - -retract ( - v1.5.3 // Published an incorrect branch accidentally https://github.com/fsnotify/fsnotify/issues/445 - v1.5.0 // Contains symlink regression https://github.com/fsnotify/fsnotify/pull/394 -) diff --git a/vendor/github.com/fsnotify/fsnotify/go.sum b/vendor/github.com/fsnotify/fsnotify/go.sum deleted file mode 100644 index 7f2d82d5c..000000000 --- a/vendor/github.com/fsnotify/fsnotify/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/fsnotify/fsnotify/inotify.go b/vendor/github.com/fsnotify/fsnotify/inotify.go deleted file mode 100644 index a6d0e0ec8..000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify.go +++ /dev/null @@ -1,351 +0,0 @@ -// 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. - -//go:build linux -// +build linux - -package fsnotify - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "sync" - "unsafe" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - mu sync.Mutex // Map access - fd int - poller *fdPoller - watches map[string]*watch // Map of inotify watches (key: path) - paths map[int]string // Map of watched paths (key: watch descriptor) - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - doneResp chan struct{} // Channel to respond to Close -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - // Create inotify fd - fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC) - if fd == -1 { - return nil, errno - } - // Create epoll - poller, err := newFdPoller(fd) - if err != nil { - unix.Close(fd) - return nil, err - } - w := &Watcher{ - fd: fd, - poller: poller, - watches: make(map[string]*watch), - paths: make(map[int]string), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan struct{}), - doneResp: make(chan struct{}), - } - - go w.readEvents() - return w, nil -} - -func (w *Watcher) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed() { - return nil - } - - // Send 'close' signal to goroutine, and set the Watcher to closed. - close(w.done) - - // Wake up goroutine - w.poller.wake() - - // Wait for goroutine to close - <-w.doneResp - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - name = filepath.Clean(name) - if w.isClosed() { - return errors.New("inotify instance already closed") - } - - const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM | - unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY | - unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF - - var flags uint32 = agnosticEvents - - w.mu.Lock() - defer w.mu.Unlock() - watchEntry := w.watches[name] - if watchEntry != nil { - flags |= watchEntry.flags | unix.IN_MASK_ADD - } - wd, errno := unix.InotifyAddWatch(w.fd, name, flags) - if wd == -1 { - return errno - } - - if watchEntry == nil { - w.watches[name] = &watch{wd: uint32(wd), flags: flags} - w.paths[wd] = name - } else { - watchEntry.wd = uint32(wd) - watchEntry.flags = flags - } - - return nil -} - -// Remove stops watching the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - - // Fetch the watch. - w.mu.Lock() - defer w.mu.Unlock() - watch, ok := w.watches[name] - - // Remove it from inotify. - if !ok { - return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) - } - - // We successfully removed the watch if InotifyRmWatch doesn't return an - // error, we need to clean up our internal state to ensure it matches - // inotify's kernel state. - delete(w.paths, int(watch.wd)) - delete(w.watches, name) - - // inotify_rm_watch will return EINVAL if the file has been deleted; - // the inotify will already have been removed. - // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously - // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE - // so that EINVAL means that the wd is being rm_watch()ed or its file removed - // by another thread and we have not received IN_IGNORE event. - success, errno := unix.InotifyRmWatch(w.fd, watch.wd) - if success == -1 { - // TODO: Perhaps it's not helpful to return an error here in every case. - // the only two possible errors are: - // EBADF, which happens when w.fd is not a valid file descriptor of any kind. - // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. - // Watch descriptors are invalidated when they are removed explicitly or implicitly; - // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. - return errno - } - - return nil -} - -// WatchList returns the directories and files that are being monitered. -func (w *Watcher) WatchList() []string { - w.mu.Lock() - defer w.mu.Unlock() - - entries := make([]string, 0, len(w.watches)) - for pathname := range w.watches { - entries = append(entries, pathname) - } - - return entries -} - -type watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) -} - -// readEvents reads from the inotify file descriptor, converts the -// received events into Event objects and sends them via the Events channel -func (w *Watcher) readEvents() { - var ( - buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - n int // Number of bytes read with read() - errno error // Syscall errno - ok bool // For poller.wait - ) - - defer close(w.doneResp) - defer close(w.Errors) - defer close(w.Events) - defer unix.Close(w.fd) - defer w.poller.close() - - for { - // See if we have been closed. - if w.isClosed() { - return - } - - ok, errno = w.poller.wait() - if errno != nil { - select { - case w.Errors <- errno: - case <-w.done: - return - } - continue - } - - if !ok { - continue - } - - n, errno = unix.Read(w.fd, buf[:]) - // If a signal interrupted execution, see if we've been asked to close, and try again. - // http://man7.org/linux/man-pages/man7/signal.7.html : - // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" - if errno == unix.EINTR { - continue - } - - // unix.Read might have been woken up by Close. If so, we're done. - if w.isClosed() { - return - } - - if n < unix.SizeofInotifyEvent { - var err error - if n == 0 { - // If EOF is received. This should really never happen. - err = io.EOF - } else if n < 0 { - // If an error occurred while reading. - err = errno - } else { - // Read was too short. - err = errors.New("notify: short read in readEvents()") - } - select { - case w.Errors <- err: - case <-w.done: - return - } - continue - } - - var offset uint32 - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... - for offset <= uint32(n-unix.SizeofInotifyEvent) { - // Point "raw" to the event in the buffer - raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) - - mask := uint32(raw.Mask) - nameLen := uint32(raw.Len) - - if mask&unix.IN_Q_OVERFLOW != 0 { - select { - case w.Errors <- ErrEventOverflow: - case <-w.done: - return - } - } - - // If the event happened to the watched directory or the watched file, the kernel - // doesn't append the filename to the event, but we would like to always fill the - // the "Name" field with a valid filename. We retrieve the path of the watch from - // the "paths" map. - w.mu.Lock() - name, ok := w.paths[int(raw.Wd)] - // IN_DELETE_SELF occurs when the file/directory being watched is removed. - // This is a sign to clean up the maps, otherwise we are no longer in sync - // with the inotify kernel state which has already deleted the watch - // automatically. - if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { - delete(w.paths, int(raw.Wd)) - delete(w.watches, name) - } - w.mu.Unlock() - - if nameLen > 0 { - // Point "bytes" at the first byte of the filename - bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] - // The filename is padded with NULL bytes. TrimRight() gets rid of those. - name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") - } - - event := newEvent(name, mask) - - // Send the events that are not ignored on the events channel - if !event.ignoreLinux(mask) { - select { - case w.Events <- event: - case <-w.done: - return - } - } - - // Move to the next event in the buffer - offset += unix.SizeofInotifyEvent + nameLen - } - } -} - -// Certain types of events can be "ignored" and not sent over the Events -// channel. Such as events marked ignore by the kernel, or MODIFY events -// against files that do not exist. -func (e *Event) ignoreLinux(mask uint32) bool { - // Ignore anything the inotify API says to ignore - if mask&unix.IN_IGNORED == unix.IN_IGNORED { - return true - } - - // If the event is not a DELETE or RENAME, the file must exist. - // Otherwise the event is ignored. - // *Note*: this was put in place because it was seen that a MODIFY - // event was sent after the DELETE. This ignores that MODIFY and - // assumes a DELETE will come or has come if the file doesn't exist. - if !(e.Op&Remove == Remove || e.Op&Rename == Rename) { - _, statErr := os.Lstat(e.Name) - return os.IsNotExist(statErr) - } - return false -} - -// newEvent returns an platform-independent Event based on an inotify mask. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO { - e.Op |= Create - } - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE { - e.Op |= Remove - } - if mask&unix.IN_MODIFY == unix.IN_MODIFY { - e.Op |= Write - } - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM { - e.Op |= Rename - } - if mask&unix.IN_ATTRIB == unix.IN_ATTRIB { - e.Op |= Chmod - } - return e -} diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go b/vendor/github.com/fsnotify/fsnotify/inotify_poller.go deleted file mode 100644 index b572a37c3..000000000 --- a/vendor/github.com/fsnotify/fsnotify/inotify_poller.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 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 linux -// +build linux - -package fsnotify - -import ( - "errors" - - "golang.org/x/sys/unix" -) - -type fdPoller struct { - fd int // File descriptor (as returned by the inotify_init() syscall) - epfd int // Epoll file descriptor - pipe [2]int // Pipe for waking up -} - -func emptyPoller(fd int) *fdPoller { - poller := new(fdPoller) - poller.fd = fd - poller.epfd = -1 - poller.pipe[0] = -1 - poller.pipe[1] = -1 - return poller -} - -// Create a new inotify poller. -// This creates an inotify handler, and an epoll handler. -func newFdPoller(fd int) (*fdPoller, error) { - var errno error - poller := emptyPoller(fd) - defer func() { - if errno != nil { - poller.close() - } - }() - - // Create epoll fd - poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC) - if poller.epfd == -1 { - return nil, errno - } - // Create pipe; pipe[0] is the read end, pipe[1] the write end. - errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC) - if errno != nil { - return nil, errno - } - - // Register inotify fd with epoll - event := unix.EpollEvent{ - Fd: int32(poller.fd), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event) - if errno != nil { - return nil, errno - } - - // Register pipe fd with epoll - event = unix.EpollEvent{ - Fd: int32(poller.pipe[0]), - Events: unix.EPOLLIN, - } - errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event) - if errno != nil { - return nil, errno - } - - return poller, nil -} - -// Wait using epoll. -// Returns true if something is ready to be read, -// false if there is not. -func (poller *fdPoller) wait() (bool, error) { - // 3 possible events per fd, and 2 fds, makes a maximum of 6 events. - // I don't know whether epoll_wait returns the number of events returned, - // or the total number of events ready. - // I decided to catch both by making the buffer one larger than the maximum. - events := make([]unix.EpollEvent, 7) - for { - n, errno := unix.EpollWait(poller.epfd, events, -1) - if n == -1 { - if errno == unix.EINTR { - continue - } - return false, errno - } - if n == 0 { - // If there are no events, try again. - continue - } - if n > 6 { - // This should never happen. More events were returned than should be possible. - return false, errors.New("epoll_wait returned more events than I know what to do with") - } - ready := events[:n] - epollhup := false - epollerr := false - epollin := false - for _, event := range ready { - if event.Fd == int32(poller.fd) { - if event.Events&unix.EPOLLHUP != 0 { - // This should not happen, but if it does, treat it as a wakeup. - epollhup = true - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the file descriptor, we should pretend - // something is ready to read, and let unix.Read pick up the error. - epollerr = true - } - if event.Events&unix.EPOLLIN != 0 { - // There is data to read. - epollin = true - } - } - if event.Fd == int32(poller.pipe[0]) { - if event.Events&unix.EPOLLHUP != 0 { - // Write pipe descriptor was closed, by us. This means we're closing down the - // watcher, and we should wake up. - } - if event.Events&unix.EPOLLERR != 0 { - // If an error is waiting on the pipe file descriptor. - // This is an absolute mystery, and should never ever happen. - return false, errors.New("Error on the pipe descriptor.") - } - if event.Events&unix.EPOLLIN != 0 { - // This is a regular wakeup, so we have to clear the buffer. - err := poller.clearWake() - if err != nil { - return false, err - } - } - } - } - - if epollhup || epollerr || epollin { - return true, nil - } - return false, nil - } -} - -// Close the write end of the poller. -func (poller *fdPoller) wake() error { - buf := make([]byte, 1) - n, errno := unix.Write(poller.pipe[1], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is full, poller will wake. - return nil - } - return errno - } - return nil -} - -func (poller *fdPoller) clearWake() error { - // You have to be woken up a LOT in order to get to 100! - buf := make([]byte, 100) - n, errno := unix.Read(poller.pipe[0], buf) - if n == -1 { - if errno == unix.EAGAIN { - // Buffer is empty, someone else cleared our wake. - return nil - } - return errno - } - return nil -} - -// Close all poller file descriptors, but not the one passed to it. -func (poller *fdPoller) close() { - if poller.pipe[1] != -1 { - unix.Close(poller.pipe[1]) - } - if poller.pipe[0] != -1 { - unix.Close(poller.pipe[0]) - } - if poller.epfd != -1 { - unix.Close(poller.epfd) - } -} diff --git a/vendor/github.com/fsnotify/fsnotify/kqueue.go b/vendor/github.com/fsnotify/fsnotify/kqueue.go deleted file mode 100644 index 6fb8d8532..000000000 --- a/vendor/github.com/fsnotify/fsnotify/kqueue.go +++ /dev/null @@ -1,535 +0,0 @@ -// 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. - -//go:build freebsd || openbsd || netbsd || dragonfly || darwin -// +build freebsd openbsd netbsd dragonfly darwin - -package fsnotify - -import ( - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sync" - "time" - - "golang.org/x/sys/unix" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - - kq int // File descriptor (as returned by the kqueue() syscall). - - mu sync.Mutex // Protects access to watcher data - watches map[string]int // Map of watched file descriptors (key: path). - externalWatches map[string]bool // Map of watches added by user of the library. - dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue. - paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events. - fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events). - isClosed bool // Set to true when Close() is first called -} - -type pathInfo struct { - name string - isDir bool -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - kq, err := kqueue() - if err != nil { - return nil, err - } - - w := &Watcher{ - kq: kq, - watches: make(map[string]int), - dirFlags: make(map[string]uint32), - paths: make(map[int]pathInfo), - fileExists: make(map[string]bool), - externalWatches: make(map[string]bool), - Events: make(chan Event), - Errors: make(chan error), - done: make(chan struct{}), - } - - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return nil - } - w.isClosed = true - - // copy paths to remove while locked - var pathsToRemove = make([]string, 0, len(w.watches)) - for name := range w.watches { - pathsToRemove = append(pathsToRemove, name) - } - w.mu.Unlock() - // unlock before calling Remove, which also locks - - for _, name := range pathsToRemove { - w.Remove(name) - } - - // send a "quit" message to the reader goroutine - close(w.done) - - return nil -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - w.mu.Lock() - w.externalWatches[name] = true - w.mu.Unlock() - _, err := w.addWatch(name, noteAllEvents) - return err -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - name = filepath.Clean(name) - w.mu.Lock() - watchfd, ok := w.watches[name] - w.mu.Unlock() - if !ok { - return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) - } - - const registerRemove = unix.EV_DELETE - if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { - return err - } - - unix.Close(watchfd) - - w.mu.Lock() - isDir := w.paths[watchfd].isDir - delete(w.watches, name) - delete(w.paths, watchfd) - delete(w.dirFlags, name) - w.mu.Unlock() - - // Find all watched paths that are in this directory that are not external. - if isDir { - var pathsToRemove []string - w.mu.Lock() - for _, path := range w.paths { - wdir, _ := filepath.Split(path.name) - if filepath.Clean(wdir) == name { - if !w.externalWatches[path.name] { - pathsToRemove = append(pathsToRemove, path.name) - } - } - } - w.mu.Unlock() - for _, name := range pathsToRemove { - // Since these are internal, not much sense in propagating error - // to the user, as that will just confuse them with an error about - // a path they did not explicitly watch themselves. - w.Remove(name) - } - } - - return nil -} - -// WatchList returns the directories and files that are being monitered. -func (w *Watcher) WatchList() []string { - w.mu.Lock() - defer w.mu.Unlock() - - entries := make([]string, 0, len(w.watches)) - for pathname := range w.watches { - entries = append(entries, pathname) - } - - return entries -} - -// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE) -const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME - -// keventWaitTime to block on each read from kevent -var keventWaitTime = durationToTimespec(100 * time.Millisecond) - -// addWatch adds name to the watched file set. -// The flags are interpreted as described in kevent(2). -// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. -func (w *Watcher) addWatch(name string, flags uint32) (string, error) { - var isDir bool - // Make ./name and name equivalent - name = filepath.Clean(name) - - w.mu.Lock() - if w.isClosed { - w.mu.Unlock() - return "", errors.New("kevent instance already closed") - } - watchfd, alreadyWatching := w.watches[name] - // We already have a watch, but we can still override flags. - if alreadyWatching { - isDir = w.paths[watchfd].isDir - } - w.mu.Unlock() - - if !alreadyWatching { - fi, err := os.Lstat(name) - if err != nil { - return "", err - } - - // Don't watch sockets. - if fi.Mode()&os.ModeSocket == os.ModeSocket { - return "", nil - } - - // Don't watch named pipes. - if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { - return "", nil - } - - // Follow Symlinks - // Unfortunately, Linux can add bogus symlinks to watch list without - // issue, and Windows can't do symlinks period (AFAIK). To maintain - // consistency, we will act like everything is fine. There will simply - // be no file events for broken symlinks. - // Hence the returns of nil on errors. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { - name, err = filepath.EvalSymlinks(name) - if err != nil { - return "", nil - } - - w.mu.Lock() - _, alreadyWatching = w.watches[name] - w.mu.Unlock() - - if alreadyWatching { - return name, nil - } - - fi, err = os.Lstat(name) - if err != nil { - return "", nil - } - } - - watchfd, err = unix.Open(name, openMode, 0700) - if watchfd == -1 { - return "", err - } - - isDir = fi.IsDir() - } - - const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE - if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { - unix.Close(watchfd) - return "", err - } - - if !alreadyWatching { - w.mu.Lock() - w.watches[name] = watchfd - w.paths[watchfd] = pathInfo{name: name, isDir: isDir} - w.mu.Unlock() - } - - if isDir { - // Watch the directory if it has not been watched before, - // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) - w.mu.Lock() - - watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && - (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) - // Store flags so this watch can be updated later - w.dirFlags[name] = flags - w.mu.Unlock() - - if watchDir { - if err := w.watchDirectoryFiles(name); err != nil { - return "", err - } - } - } - return name, nil -} - -// readEvents reads from kqueue and converts the received kevents into -// Event values that it sends down the Events channel. -func (w *Watcher) readEvents() { - eventBuffer := make([]unix.Kevent_t, 10) - -loop: - for { - // See if there is a message on the "done" channel - select { - case <-w.done: - break loop - default: - } - - // Get new events - kevents, err := read(w.kq, eventBuffer, &keventWaitTime) - // EINTR is okay, the syscall was interrupted before timeout expired. - if err != nil && err != unix.EINTR { - select { - case w.Errors <- err: - case <-w.done: - break loop - } - continue - } - - // Flush the events we received to the Events channel - for len(kevents) > 0 { - kevent := &kevents[0] - watchfd := int(kevent.Ident) - mask := uint32(kevent.Fflags) - w.mu.Lock() - path := w.paths[watchfd] - w.mu.Unlock() - event := newEvent(path.name, mask) - - if path.isDir && !(event.Op&Remove == Remove) { - // Double check to make sure the directory exists. This can happen when - // we do a rm -fr on a recursively watched folders and we receive a - // modification event first but the folder has been deleted and later - // receive the delete event - if _, err := os.Lstat(event.Name); os.IsNotExist(err) { - // mark is as delete event - event.Op |= Remove - } - } - - if event.Op&Rename == Rename || event.Op&Remove == Remove { - w.Remove(event.Name) - w.mu.Lock() - delete(w.fileExists, event.Name) - w.mu.Unlock() - } - - if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { - w.sendDirectoryChangeEvents(event.Name) - } else { - // Send the event on the Events channel. - select { - case w.Events <- event: - case <-w.done: - break loop - } - } - - if event.Op&Remove == Remove { - // Look for a file that may have overwritten this. - // For example, mv f1 f2 will delete f2, then create f2. - if path.isDir { - fileDir := filepath.Clean(event.Name) - w.mu.Lock() - _, found := w.watches[fileDir] - w.mu.Unlock() - if found { - // make sure the directory exists before we watch for changes. When we - // do a recursive watch and perform rm -fr, the parent directory might - // have gone missing, ignore the missing directory and let the - // upcoming delete event remove the watch from the parent directory. - if _, err := os.Lstat(fileDir); err == nil { - w.sendDirectoryChangeEvents(fileDir) - } - } - } else { - filePath := filepath.Clean(event.Name) - if fileInfo, err := os.Lstat(filePath); err == nil { - w.sendFileCreatedEventIfNew(filePath, fileInfo) - } - } - } - - // Move to next event - kevents = kevents[1:] - } - } - - // cleanup - err := unix.Close(w.kq) - if err != nil { - // only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors. - select { - case w.Errors <- err: - default: - } - } - close(w.Events) - close(w.Errors) -} - -// newEvent returns an platform-independent Event based on kqueue Fflags. -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&unix.NOTE_DELETE == unix.NOTE_DELETE { - e.Op |= Remove - } - if mask&unix.NOTE_WRITE == unix.NOTE_WRITE { - e.Op |= Write - } - if mask&unix.NOTE_RENAME == unix.NOTE_RENAME { - e.Op |= Rename - } - if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB { - e.Op |= Chmod - } - return e -} - -func newCreateEvent(name string) Event { - return Event{Name: name, Op: Create} -} - -// watchDirectoryFiles to mimic inotify when adding a watch on a directory -func (w *Watcher) watchDirectoryFiles(dirPath string) error { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - return err - } - - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - } - - return nil -} - -// sendDirectoryEvents searches the directory for newly created files -// and sends them over the event channel. This functionality is to have -// the BSD version of fsnotify match Linux inotify which provides a -// create event for files created in a watched directory. -func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { - // Get all files - files, err := ioutil.ReadDir(dirPath) - if err != nil { - select { - case w.Errors <- err: - case <-w.done: - return - } - } - - // Search for new files - for _, fileInfo := range files { - filePath := filepath.Join(dirPath, fileInfo.Name()) - err := w.sendFileCreatedEventIfNew(filePath, fileInfo) - - if err != nil { - return - } - } -} - -// sendFileCreatedEvent sends a create event if the file isn't already being tracked. -func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) { - w.mu.Lock() - _, doesExist := w.fileExists[filePath] - w.mu.Unlock() - if !doesExist { - // Send create event - select { - case w.Events <- newCreateEvent(filePath): - case <-w.done: - return - } - } - - // like watchDirectoryFiles (but without doing another ReadDir) - filePath, err = w.internalWatch(filePath, fileInfo) - if err != nil { - return err - } - - w.mu.Lock() - w.fileExists[filePath] = true - w.mu.Unlock() - - return nil -} - -func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) { - if fileInfo.IsDir() { - // mimic Linux providing delete events for subdirectories - // but preserve the flags used if currently watching subdirectory - w.mu.Lock() - flags := w.dirFlags[name] - w.mu.Unlock() - - flags |= unix.NOTE_DELETE | unix.NOTE_RENAME - return w.addWatch(name, flags) - } - - // watch file to mimic Linux inotify - return w.addWatch(name, noteAllEvents) -} - -// kqueue creates a new kernel event queue and returns a descriptor. -func kqueue() (kq int, err error) { - kq, err = unix.Kqueue() - if kq == -1 { - return kq, err - } - return kq, nil -} - -// register events with the queue -func register(kq int, fds []int, flags int, fflags uint32) error { - changes := make([]unix.Kevent_t, len(fds)) - - for i, fd := range fds { - // SetKevent converts int to the platform-specific types: - unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags) - changes[i].Fflags = fflags - } - - // register the events - success, err := unix.Kevent(kq, changes, nil, nil) - if success == -1 { - return err - } - return nil -} - -// read retrieves pending events, or waits until an event occurs. -// A timeout of nil blocks indefinitely, while 0 polls the queue. -func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) { - n, err := unix.Kevent(kq, nil, events, timeout) - if err != nil { - return nil, err - } - return events[0:n], nil -} - -// durationToTimespec prepares a timeout value -func durationToTimespec(d time.Duration) unix.Timespec { - return unix.NsecToTimespec(d.Nanoseconds()) -} diff --git a/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh new file mode 100644 index 000000000..b09ef7683 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/mkdoc.zsh @@ -0,0 +1,208 @@ +#!/usr/bin/env zsh +[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1 +setopt err_exit no_unset pipefail extended_glob + +# Simple script to update the godoc comments on all watchers. Probably took me +# more time to write this than doing it manually, but ah well 🙃 + +watcher=$(</tmp/x + print -r -- $cmt >>/tmp/x + tail -n+$(( end + 1 )) $file >>/tmp/x + mv /tmp/x $file + done +} + +set-cmt '^type Watcher struct ' $watcher +set-cmt '^func NewWatcher(' $new +set-cmt '^func (w \*Watcher) Add(' $add +set-cmt '^func (w \*Watcher) Remove(' $remove +set-cmt '^func (w \*Watcher) Close(' $close +set-cmt '^func (w \*Watcher) WatchList(' $watchlist +set-cmt '^[[:space:]]*Events *chan Event$' $events +set-cmt '^[[:space:]]*Errors *chan error$' $errors diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go b/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go deleted file mode 100644 index 36cc3845b..000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 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 freebsd || openbsd || netbsd || dragonfly -// +build freebsd openbsd netbsd dragonfly - -package fsnotify - -import "golang.org/x/sys/unix" - -const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go b/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go deleted file mode 100644 index 98cd8476f..000000000 --- a/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2013 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 -// +build darwin - -package fsnotify - -import "golang.org/x/sys/unix" - -// note: this constant is not defined on BSD -const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/system_bsd.go b/vendor/github.com/fsnotify/fsnotify/system_bsd.go new file mode 100644 index 000000000..4322b0b88 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_bsd.go @@ -0,0 +1,8 @@ +//go:build freebsd || openbsd || netbsd || dragonfly +// +build freebsd openbsd netbsd dragonfly + +package fsnotify + +import "golang.org/x/sys/unix" + +const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/system_darwin.go b/vendor/github.com/fsnotify/fsnotify/system_darwin.go new file mode 100644 index 000000000..5da5ffa78 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/system_darwin.go @@ -0,0 +1,9 @@ +//go:build darwin +// +build darwin + +package fsnotify + +import "golang.org/x/sys/unix" + +// note: this constant is not defined on BSD +const openMode = unix.O_EVTONLY | unix.O_CLOEXEC diff --git a/vendor/github.com/fsnotify/fsnotify/windows.go b/vendor/github.com/fsnotify/fsnotify/windows.go deleted file mode 100644 index 02ce7deb0..000000000 --- a/vendor/github.com/fsnotify/fsnotify/windows.go +++ /dev/null @@ -1,586 +0,0 @@ -// Copyright 2011 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 windows -// +build windows - -package fsnotify - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "reflect" - "runtime" - "sync" - "syscall" - "unsafe" -) - -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { - Events chan Event - Errors chan error - isClosed bool // Set to true when Close() is first called - mu sync.Mutex // Map access - port syscall.Handle // Handle to completion port - watches watchMap // Map of watches (key: i-number) - input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error -} - -// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. -func NewWatcher() (*Watcher, error) { - port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0) - if e != nil { - return nil, os.NewSyscallError("CreateIoCompletionPort", e) - } - w := &Watcher{ - port: port, - watches: make(watchMap), - input: make(chan *input, 1), - Events: make(chan Event, 50), - Errors: make(chan error), - quit: make(chan chan<- error, 1), - } - go w.readEvents() - return w, nil -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - if w.isClosed { - return nil - } - w.isClosed = true - - // Send "quit" message to the reader goroutine - ch := make(chan error) - w.quit <- ch - if err := w.wakeupReader(); err != nil { - return err - } - return <-ch -} - -// Add starts watching the named file or directory (non-recursively). -func (w *Watcher) Add(name string) error { - if w.isClosed { - return errors.New("watcher already closed") - } - in := &input{ - op: opAddWatch, - path: filepath.Clean(name), - flags: sysFSALLEVENTS, - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -// Remove stops watching the the named file or directory (non-recursively). -func (w *Watcher) Remove(name string) error { - in := &input{ - op: opRemoveWatch, - path: filepath.Clean(name), - reply: make(chan error), - } - w.input <- in - if err := w.wakeupReader(); err != nil { - return err - } - return <-in.reply -} - -// WatchList returns the directories and files that are being monitered. -func (w *Watcher) WatchList() []string { - w.mu.Lock() - defer w.mu.Unlock() - - entries := make([]string, 0, len(w.watches)) - for _, entry := range w.watches { - for _, watchEntry := range entry { - entries = append(entries, watchEntry.path) - } - } - - return entries -} - -const ( - // Options for AddWatch - sysFSONESHOT = 0x80000000 - sysFSONLYDIR = 0x1000000 - - // Events - sysFSACCESS = 0x1 - sysFSALLEVENTS = 0xfff - sysFSATTRIB = 0x4 - sysFSCLOSE = 0x18 - sysFSCREATE = 0x100 - sysFSDELETE = 0x200 - sysFSDELETESELF = 0x400 - sysFSMODIFY = 0x2 - sysFSMOVE = 0xc0 - sysFSMOVEDFROM = 0x40 - sysFSMOVEDTO = 0x80 - sysFSMOVESELF = 0x800 - - // Special events - sysFSIGNORED = 0x8000 - sysFSQOVERFLOW = 0x4000 -) - -func newEvent(name string, mask uint32) Event { - e := Event{Name: name} - if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO { - e.Op |= Create - } - if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF { - e.Op |= Remove - } - if mask&sysFSMODIFY == sysFSMODIFY { - e.Op |= Write - } - if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM { - e.Op |= Rename - } - if mask&sysFSATTRIB == sysFSATTRIB { - e.Op |= Chmod - } - return e -} - -const ( - opAddWatch = iota - opRemoveWatch -) - -const ( - provisional uint64 = 1 << (32 + iota) -) - -type input struct { - op int - path string - flags uint32 - reply chan error -} - -type inode struct { - handle syscall.Handle - volume uint32 - index uint64 -} - -type watch struct { - ov syscall.Overlapped - ino *inode // i-number - path string // Directory path - mask uint64 // Directory itself is being watched with these notify flags - names map[string]uint64 // Map of names being watched and their notify flags - rename string // Remembers the old name while renaming a file - buf [4096]byte -} - -type indexMap map[uint64]*watch -type watchMap map[uint32]indexMap - -func (w *Watcher) wakeupReader() error { - e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil) - if e != nil { - return os.NewSyscallError("PostQueuedCompletionStatus", e) - } - return nil -} - -func getDir(pathname string) (dir string, err error) { - attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname)) - if e != nil { - return "", os.NewSyscallError("GetFileAttributes", e) - } - if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - dir = pathname - } else { - dir, _ = filepath.Split(pathname) - dir = filepath.Clean(dir) - } - return -} - -func getIno(path string) (ino *inode, err error) { - h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path), - syscall.FILE_LIST_DIRECTORY, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - nil, syscall.OPEN_EXISTING, - syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0) - if e != nil { - return nil, os.NewSyscallError("CreateFile", e) - } - var fi syscall.ByHandleFileInformation - if e = syscall.GetFileInformationByHandle(h, &fi); e != nil { - syscall.CloseHandle(h) - return nil, os.NewSyscallError("GetFileInformationByHandle", e) - } - ino = &inode{ - handle: h, - volume: fi.VolumeSerialNumber, - index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow), - } - return ino, nil -} - -// Must run within the I/O thread. -func (m watchMap) get(ino *inode) *watch { - if i := m[ino.volume]; i != nil { - return i[ino.index] - } - return nil -} - -// Must run within the I/O thread. -func (m watchMap) set(ino *inode, watch *watch) { - i := m[ino.volume] - if i == nil { - i = make(indexMap) - m[ino.volume] = i - } - i[ino.index] = watch -} - -// Must run within the I/O thread. -func (w *Watcher) addWatch(pathname string, flags uint64) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - if flags&sysFSONLYDIR != 0 && pathname != dir { - return nil - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watchEntry := w.watches.get(ino) - w.mu.Unlock() - if watchEntry == nil { - if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil { - syscall.CloseHandle(ino.handle) - return os.NewSyscallError("CreateIoCompletionPort", e) - } - watchEntry = &watch{ - ino: ino, - path: dir, - names: make(map[string]uint64), - } - w.mu.Lock() - w.watches.set(ino, watchEntry) - w.mu.Unlock() - flags |= provisional - } else { - syscall.CloseHandle(ino.handle) - } - if pathname == dir { - watchEntry.mask |= flags - } else { - watchEntry.names[filepath.Base(pathname)] |= flags - } - if err = w.startRead(watchEntry); err != nil { - return err - } - if pathname == dir { - watchEntry.mask &= ^provisional - } else { - watchEntry.names[filepath.Base(pathname)] &= ^provisional - } - return nil -} - -// Must run within the I/O thread. -func (w *Watcher) remWatch(pathname string) error { - dir, err := getDir(pathname) - if err != nil { - return err - } - ino, err := getIno(dir) - if err != nil { - return err - } - w.mu.Lock() - watch := w.watches.get(ino) - w.mu.Unlock() - if watch == nil { - return fmt.Errorf("can't remove non-existent watch for: %s", pathname) - } - if pathname == dir { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - watch.mask = 0 - } else { - name := filepath.Base(pathname) - w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - return w.startRead(watch) -} - -// Must run within the I/O thread. -func (w *Watcher) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED) - } - delete(watch.names, name) - } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, watch.mask&sysFSIGNORED) - } - watch.mask = 0 - } -} - -// Must run within the I/O thread. -func (w *Watcher) startRead(watch *watch) error { - if e := syscall.CancelIo(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CancelIo", e) - w.deleteWatch(watch) - } - mask := toWindowsFlags(watch.mask) - for _, m := range watch.names { - mask |= toWindowsFlags(m) - } - if mask == 0 { - if e := syscall.CloseHandle(watch.ino.handle); e != nil { - w.Errors <- os.NewSyscallError("CloseHandle", e) - } - w.mu.Lock() - delete(w.watches[watch.ino.volume], watch.ino.index) - w.mu.Unlock() - return nil - } - e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0], - uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0) - if e != nil { - err := os.NewSyscallError("ReadDirectoryChanges", e) - if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 { - // Watched directory was probably removed - if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - err = nil - } - w.deleteWatch(watch) - w.startRead(watch) - return err - } - return nil -} - -// readEvents reads from the I/O completion port, converts the -// received events into Event objects and sends them via the Events channel. -// Entry point to the I/O thread. -func (w *Watcher) readEvents() { - var ( - n, key uint32 - ov *syscall.Overlapped - ) - runtime.LockOSThread() - - for { - e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE) - watch := (*watch)(unsafe.Pointer(ov)) - - if watch == nil { - select { - case ch := <-w.quit: - w.mu.Lock() - var indexes []indexMap - for _, index := range w.watches { - indexes = append(indexes, index) - } - w.mu.Unlock() - for _, index := range indexes { - for _, watch := range index { - w.deleteWatch(watch) - w.startRead(watch) - } - } - var err error - if e := syscall.CloseHandle(w.port); e != nil { - err = os.NewSyscallError("CloseHandle", e) - } - close(w.Events) - close(w.Errors) - ch <- err - return - case in := <-w.input: - switch in.op { - case opAddWatch: - in.reply <- w.addWatch(in.path, uint64(in.flags)) - case opRemoveWatch: - in.reply <- w.remWatch(in.path) - } - default: - } - continue - } - - switch e { - case syscall.ERROR_MORE_DATA: - if watch == nil { - w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer") - } else { - // The i/o succeeded but the buffer is full. - // In theory we should be building up a full packet. - // In practice we can get away with just carrying on. - n = uint32(unsafe.Sizeof(watch.buf)) - } - case syscall.ERROR_ACCESS_DENIED: - // Watched directory was probably removed - w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) - w.deleteWatch(watch) - w.startRead(watch) - continue - case syscall.ERROR_OPERATION_ABORTED: - // CancelIo was called on this handle - continue - default: - w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e) - continue - case nil: - } - - var offset uint32 - for { - if n == 0 { - w.Events <- newEvent("", sysFSQOVERFLOW) - w.Errors <- errors.New("short read in readEvents()") - break - } - - // Point "raw" to the event in the buffer - raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset])) - // TODO: Consider using unsafe.Slice that is available from go1.17 - // https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang - // instead of using a fixed syscall.MAX_PATH buf, we create a buf that is the size of the path name - size := int(raw.FileNameLength / 2) - var buf []uint16 - sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) - sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) - sh.Len = size - sh.Cap = size - name := syscall.UTF16ToString(buf) - fullname := filepath.Join(watch.path, name) - - var mask uint64 - switch raw.Action { - case syscall.FILE_ACTION_REMOVED: - mask = sysFSDELETESELF - case syscall.FILE_ACTION_MODIFIED: - mask = sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - watch.rename = name - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - if watch.names[watch.rename] != 0 { - watch.names[name] |= watch.names[watch.rename] - delete(watch.names, watch.rename) - mask = sysFSMOVESELF - } - } - - sendNameEvent := func() { - if w.sendEvent(fullname, watch.names[name]&mask) { - if watch.names[name]&sysFSONESHOT != 0 { - delete(watch.names, name) - } - } - } - if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME { - sendNameEvent() - } - if raw.Action == syscall.FILE_ACTION_REMOVED { - w.sendEvent(fullname, watch.names[name]&sysFSIGNORED) - delete(watch.names, name) - } - if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) { - if watch.mask&sysFSONESHOT != 0 { - watch.mask = 0 - } - } - if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME { - fullname = filepath.Join(watch.path, watch.rename) - sendNameEvent() - } - - // Move to the next event in the buffer - if raw.NextEntryOffset == 0 { - break - } - offset += raw.NextEntryOffset - - // Error! - if offset >= n { - w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.") - break - } - } - - if err := w.startRead(watch); err != nil { - w.Errors <- err - } - } -} - -func (w *Watcher) sendEvent(name string, mask uint64) bool { - if mask == 0 { - return false - } - event := newEvent(name, uint32(mask)) - select { - case ch := <-w.quit: - w.quit <- ch - case w.Events <- event: - } - return true -} - -func toWindowsFlags(mask uint64) uint32 { - var m uint32 - if mask&sysFSACCESS != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS - } - if mask&sysFSMODIFY != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE - } - if mask&sysFSATTRIB != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES - } - if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 { - m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME - } - return m -} - -func toFSnotifyFlags(action uint32) uint64 { - switch action { - case syscall.FILE_ACTION_ADDED: - return sysFSCREATE - case syscall.FILE_ACTION_REMOVED: - return sysFSDELETE - case syscall.FILE_ACTION_MODIFIED: - return sysFSMODIFY - case syscall.FILE_ACTION_RENAMED_OLD_NAME: - return sysFSMOVEDFROM - case syscall.FILE_ACTION_RENAMED_NEW_NAME: - return sysFSMOVEDTO - } - return 0 -} diff --git a/vendor/github.com/fzipp/gocyclo/go.mod b/vendor/github.com/fzipp/gocyclo/go.mod deleted file mode 100644 index 1266f2f0d..000000000 --- a/vendor/github.com/fzipp/gocyclo/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/fzipp/gocyclo - -go 1.18 diff --git a/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go index 149f0ac88..d3d139a08 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/badCond_checker.go @@ -114,30 +114,43 @@ func (c *badCondChecker) checkForStmt(stmt *ast.ForStmt) { iter := astcast.ToIdent(init.Lhs[0]) cond := astcast.ToBinaryExpr(stmt.Cond) - if cond.Op != token.GTR || !astequal.Expr(iter, cond.X) { + + var i, n ast.Expr + var op token.Token + switch { + case cond.Op == token.GTR && astequal.Expr(iter, cond.X): + i = cond.X + n = cond.Y + op = token.LSS + case cond.Op == token.LSS && astequal.Expr(iter, cond.Y): + i = cond.Y + n = cond.X + op = token.GTR + default: return } - if !typep.SideEffectFree(c.ctx.TypesInfo, cond.Y) { + + if !typep.SideEffectFree(c.ctx.TypesInfo, n) { return } post := astcast.ToIncDecStmt(stmt.Post) - if post.Tok != token.INC || !astequal.Expr(iter, post.X) { + if post.Tok != token.INC || !astequal.Expr(iter, i) { return } - mutated := lintutil.CouldBeMutated(c.ctx.TypesInfo, stmt.Body, cond.Y) || + mutated := lintutil.CouldBeMutated(c.ctx.TypesInfo, stmt.Body, n) || lintutil.CouldBeMutated(c.ctx.TypesInfo, stmt.Body, iter) if mutated { return } - c.warnForStmt(stmt, cond) + c.warnForStmt(stmt, op, cond) } -func (c *badCondChecker) warnForStmt(cause ast.Node, cond *ast.BinaryExpr) { +func (c *badCondChecker) warnForStmt(cause ast.Node, op token.Token, cond *ast.BinaryExpr) { suggest := astcopy.BinaryExpr(cond) - suggest.Op = token.LSS + suggest.Op = op c.ctx.Warn(cause, "`%s` in loop; probably meant `%s`?", cond, suggest) } diff --git a/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go index e0d4b7487..8a359000a 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/badRegexp_checker.go @@ -365,7 +365,7 @@ func (c *badRegexpChecker) checkCharClassDups(cc syntax.Expr) { } // 2. Sort ranges, O(nlogn). - sort.Slice(ranges, func(i, j int) bool { + sort.SliceStable(ranges, func(i, j int) bool { return ranges[i].low < ranges[j].low }) diff --git a/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go b/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go index 83de50528..ad16e3b3f 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/dupBranchBody_checker.go @@ -54,5 +54,5 @@ func (c *dupBranchBodyChecker) checkIf(stmt *ast.IfStmt) { } func (c *dupBranchBodyChecker) warnIf(cause ast.Node) { - c.ctx.Warn(cause, "both branches in if statement has same body") + c.ctx.Warn(cause, "both branches in if statement have same body") } diff --git a/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go b/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go index 8a53ee5e5..b17178e09 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/embedded_rules.go +++ b/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/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go index 910be180b..742652a12 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/hugeParam_checker.go @@ -5,7 +5,6 @@ import ( "github.com/go-critic/go-critic/checkers/internal/astwalk" "github.com/go-critic/go-critic/framework/linter" - "golang.org/x/exp/typeparams" ) func init() { @@ -50,9 +49,6 @@ func (c *hugeParamChecker) checkParams(params []*ast.Field) { for _, p := range params { for _, id := range p.Names { typ := c.ctx.TypeOf(id) - if _, ok := typ.(*typeparams.TypeParam); ok { - continue - } size, ok := c.ctx.SizeOf(typ) if ok && size >= c.sizeThreshold { c.warn(id, size) diff --git a/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go b/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go index b1fcf4147..c3d127c56 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/ifElseChain_checker.go @@ -11,6 +11,12 @@ func init() { var info linter.CheckerInfo info.Name = "ifElseChain" info.Tags = []string{"style"} + info.Params = linter.CheckerParams{ + "minThreshold": { + Value: 2, + Usage: "min number of if-else blocks that makes the warning trigger", + }, + } info.Summary = "Detects repeated if-else statements and suggests to replace them with switch statement" info.Before = ` if cond1 { @@ -35,7 +41,10 @@ will trigger suggestion to use switch statement. See [EffectiveGo#switch](https://golang.org/doc/effective_go.html#switch).` collection.AddChecker(&info, func(ctx *linter.CheckerContext) (linter.FileWalker, error) { - return astwalk.WalkerForStmt(&ifElseChainChecker{ctx: ctx}), nil + return astwalk.WalkerForStmt(&ifElseChainChecker{ + ctx: ctx, + minThreshold: info.Params.Int("minThreshold"), + }), nil }) } @@ -45,6 +54,8 @@ type ifElseChainChecker struct { cause *ast.IfStmt visited map[*ast.IfStmt]bool + + minThreshold int } func (c *ifElseChainChecker) EnterFunc(fn *ast.FuncDecl) bool { @@ -66,8 +77,7 @@ func (c *ifElseChainChecker) VisitStmt(stmt ast.Stmt) { } func (c *ifElseChainChecker) checkIfStmt(stmt *ast.IfStmt) { - const minThreshold = 2 - if c.countIfelseLen(stmt) >= minThreshold { + if c.countIfelseLen(stmt) >= c.minThreshold { c.warn() } } @@ -75,11 +85,12 @@ func (c *ifElseChainChecker) checkIfStmt(stmt *ast.IfStmt) { func (c *ifElseChainChecker) countIfelseLen(stmt *ast.IfStmt) int { count := 0 for { + if stmt.Init != nil { + return 0 // Give up + } + switch e := stmt.Else.(type) { case *ast.IfStmt: - if e.Init != nil { - return 0 // Give up - } // Else if. stmt = e count++ diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go index 47de589a4..5fcce6a2a 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go +++ b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/local_def_visitor.go @@ -7,9 +7,9 @@ import ( // LocalDefVisitor visits every name definitions inside a function. // // Next elements are considered as name definitions: -// - Function parameters (input, output, receiver) -// - Every LHS of ":=" assignment that defines a new name -// - Every local var/const declaration. +// - Function parameters (input, output, receiver) +// - Every LHS of ":=" assignment that defines a new name +// - Every local var/const declaration. // // NOTE: this visitor is experimental. // This is also why it lives in a separate file. diff --git a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go b/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go index 9c198e733..bc9bdef47 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/internal/astwalk/type_expr_walker.go +++ b/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/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go b/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go index 7e564b70f..04a3474f9 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/newDeref_checker.go @@ -7,6 +7,7 @@ import ( "github.com/go-critic/go-critic/checkers/internal/lintutil" "github.com/go-critic/go-critic/framework/linter" "github.com/go-toolsmith/astcast" + "golang.org/x/exp/typeparams" "golang.org/x/tools/go/ast/astutil" ) @@ -33,6 +34,10 @@ func (c *newDerefChecker) VisitExpr(expr ast.Expr) { call := astcast.ToCallExpr(deref.X) if astcast.ToIdent(call.Fun).Name == "new" { typ := c.ctx.TypeOf(call.Args[0]) + // allow *new(T) if T is a type parameter, see #1272 for details + if typeparams.IsTypeParam(typ) { + return + } zv := lintutil.ZeroValueOf(astutil.Unparen(call.Args[0]), typ) if zv != nil { c.warn(expr, zv) diff --git a/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go b/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go index eafc549d6..37f469657 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/rangeValCopy_checker.go @@ -5,7 +5,6 @@ import ( "github.com/go-critic/go-critic/checkers/internal/astwalk" "github.com/go-critic/go-critic/framework/linter" - "golang.org/x/exp/typeparams" ) func init() { @@ -66,10 +65,8 @@ func (c *rangeValCopyChecker) VisitStmt(stmt ast.Stmt) { if typ == nil { return } - if _, ok := typ.(*typeparams.TypeParam); ok { - return - } - if size, ok := c.ctx.SizeOf(typ); ok && size >= c.sizeThreshold { + size, ok := c.ctx.SizeOf(typ) + if ok && size >= c.sizeThreshold { c.warn(rng, size) } } diff --git a/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go b/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go index 35c6a6449..000007a31 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go +++ b/vendor/github.com/go-critic/go-critic/checkers/ruleguard_checker.go @@ -274,7 +274,7 @@ func (c *ruleguardChecker) WalkFile(f *ast.File) { func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.Engine, runCtx *ruleguard.RunContext) { type ruleguardReport struct { - node ast.Node + pos token.Pos message string fix linter.QuickFix } @@ -284,7 +284,7 @@ func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.En // TODO(quasilyte): investigate whether we should add a rule name as // a message prefix here. r := ruleguardReport{ - node: data.Node, + pos: data.Node.Pos(), message: data.Message, } fix := data.Suggestion @@ -310,9 +310,9 @@ func runRuleguardEngine(ctx *linter.CheckerContext, f *ast.File, e *ruleguard.En }) for _, report := range reports { if report.fix.Replacement != nil { - ctx.WarnFixable(report.node, report.fix, "%s", report.message) + ctx.WarnFixableWithPos(report.pos, report.fix, "%s", report.message) } else { - ctx.Warn(report.node, "%s", report.message) + ctx.WarnWithPos(report.pos, "%s", report.message) } } } diff --git a/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go b/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go index fd63c9b14..f0b147a68 100644 --- a/vendor/github.com/go-critic/go-critic/checkers/rulesdata/rulesdata.go +++ b/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,31 +2354,88 @@ 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", }, }, }, + { + Line: 777, + Name: "uncheckedInlineErr", + MatcherName: "m", + DocTags: []string{"diagnostic", "experimental"}, + DocSummary: "Detects unchecked errors in if statements", + DocBefore: "if err := expr(); err2 != nil { /*...*/ }", + DocAfter: "if err := expr(); err != nil { /*...*/ }", + Rules: []ir.Rule{{ + Line: 778, + SyntaxPatterns: []ir.PatternString{ + {Line: 779, Value: "if $err := $_($*_); $err2 != nil { $*_ }"}, + {Line: 780, Value: "if $err = $_($*_); $err2 != nil { $*_ }"}, + {Line: 781, Value: "if $*_, $err := $_($*_); $err2 != nil { $*_ }"}, + {Line: 782, Value: "if $*_, $err = $_($*_); $err2 != nil { $*_ }"}, + }, + ReportTemplate: "$err error is unchecked, maybe intended to check it instead of $err2", + WhereExpr: ir.FilterExpr{ + Line: 783, + Op: ir.FilterAndOp, + Src: "m[\"err\"].Type.Implements(\"error\") && m[\"err2\"].Type.Implements(\"error\") &&\n\tm[\"err\"].Text != m[\"err2\"].Text", + Args: []ir.FilterExpr{ + { + Line: 783, + Op: ir.FilterAndOp, + Src: "m[\"err\"].Type.Implements(\"error\") && m[\"err2\"].Type.Implements(\"error\")", + Args: []ir.FilterExpr{ + { + Line: 783, + Op: ir.FilterVarTypeImplementsOp, + Src: "m[\"err\"].Type.Implements(\"error\")", + Value: "err", + Args: []ir.FilterExpr{{Line: 783, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, + }, + { + Line: 783, + Op: ir.FilterVarTypeImplementsOp, + Src: "m[\"err2\"].Type.Implements(\"error\")", + Value: "err2", + Args: []ir.FilterExpr{{Line: 783, Op: ir.FilterStringOp, Src: "\"error\"", Value: "error"}}, + }, + }, + }, + { + Line: 784, + Op: ir.FilterNeqOp, + Src: "m[\"err\"].Text != m[\"err2\"].Text", + Args: []ir.FilterExpr{ + {Line: 784, Op: ir.FilterVarTextOp, Src: "m[\"err\"].Text", Value: "err"}, + {Line: 784, Op: ir.FilterVarTextOp, Src: "m[\"err2\"].Text", Value: "err2"}, + }, + }, + }, + }, + LocationVar: "err", + }}, + }, }, } diff --git a/vendor/github.com/go-critic/go-critic/framework/linter/linter.go b/vendor/github.com/go-critic/go-critic/framework/linter/linter.go index 750ff7cd9..8573ace30 100644 --- a/vendor/github.com/go-critic/go-critic/framework/linter/linter.go +++ b/vendor/github.com/go-critic/go-critic/framework/linter/linter.go @@ -6,7 +6,6 @@ import ( "go/types" "github.com/go-toolsmith/astfmt" - "golang.org/x/exp/typeparams" ) // CheckerCollection provides additional information for a group of checkers. @@ -141,9 +140,7 @@ type QuickFix struct { // Warning represents issue that is found by checker. type Warning struct { - // Node is an AST node that caused warning to trigger. - // Can be used to obtain proper error location. - Node ast.Node + Pos token.Pos // Text is warning message without source location info. Text string @@ -279,17 +276,27 @@ type CheckerContext struct { // Warn adds a Warning to checker output. func (ctx *CheckerContext) Warn(node ast.Node, format string, args ...interface{}) { + ctx.WarnWithPos(node.Pos(), format, args...) +} + +// WarnFixable emits a warning with a fix suggestion provided by the caller. +func (ctx *CheckerContext) WarnFixable(node ast.Node, fix QuickFix, format string, args ...interface{}) { + ctx.WarnFixableWithPos(node.Pos(), fix, format, args...) +} + +// WarnWithPos adds a Warning to checker output. Useful for ruleguard's Report func. +func (ctx *CheckerContext) WarnWithPos(pos token.Pos, format string, args ...interface{}) { ctx.warnings = append(ctx.warnings, Warning{ Text: ctx.printer.Sprintf(format, args...), - Node: node, + Pos: pos, }) } -// WarnFixable emits a warning with a fix suggestion provided by the caller. -func (ctx *CheckerContext) WarnFixable(node ast.Node, fix QuickFix, format string, args ...interface{}) { +// WarnFixableWithPos adds a Warning to checker output. Useful for ruleguard's Report func. +func (ctx *CheckerContext) WarnFixableWithPos(pos token.Pos, fix QuickFix, format string, args ...interface{}) { ctx.warnings = append(ctx.warnings, Warning{ Text: ctx.printer.Sprintf(format, args...), - Node: node, + Pos: pos, Suggestion: fix, }) } @@ -319,7 +326,10 @@ func (ctx *CheckerContext) TypeOf(x ast.Expr) types.Type { // // Unlike SizesInfo.SizeOf, it will not panic on generic types. func (ctx *CheckerContext) SizeOf(typ types.Type) (int64, bool) { - if _, ok := typ.(*typeparams.TypeParam); ok { + if _, ok := typ.(*types.TypeParam); ok { + return 0, false + } + if named, ok := typ.(*types.Named); ok && named.TypeParams() != nil { return 0, false } return ctx.SizesInfo.Sizeof(typ), true diff --git a/vendor/github.com/go-toolsmith/astcast/.travis.yml b/vendor/github.com/go-toolsmith/astcast/.travis.yml deleted file mode 100644 index c32ac0062..000000000 --- a/vendor/github.com/go-toolsmith/astcast/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... diff --git a/vendor/github.com/go-toolsmith/astcast/README.md b/vendor/github.com/go-toolsmith/astcast/README.md index b618da461..19ca0e71d 100644 --- a/vendor/github.com/go-toolsmith/astcast/README.md +++ b/vendor/github.com/go-toolsmith/astcast/README.md @@ -1,15 +1,19 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/astcast)](https://goreportcard.com/report/github.com/go-toolsmith/astcast) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/astcast?status.svg)](https://godoc.org/github.com/go-toolsmith/astcast) - # astcast -Package astcast wraps type assertion operations in such way that you don't have +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `astcast` wraps type assertion operations in such way that you don't have to worry about nil pointer results anymore. ## Installation +Go version 1.16+ + ```bash -go get -v github.com/go-toolsmith/astcast +go get github.com/go-toolsmith/astcast ``` ## Example @@ -84,3 +88,16 @@ func main() { fmt.Printf("%T %s\n", bar, bar.Name) } ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/astcast/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/astcast/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/astcast +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/astcast +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/astcast +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/astcast +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/astcast +[version-url]: https://github.com/go-toolsmith/astcast/releases diff --git a/vendor/github.com/go-toolsmith/astcast/go.mod b/vendor/github.com/go-toolsmith/astcast/go.mod deleted file mode 100644 index 3e431993e..000000000 --- a/vendor/github.com/go-toolsmith/astcast/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module github.com/go-toolsmith/astcast - -require ( - github.com/go-toolsmith/astequal v1.0.0 // indirect - github.com/go-toolsmith/strparse v1.0.0 -) diff --git a/vendor/github.com/go-toolsmith/astcast/go.sum b/vendor/github.com/go-toolsmith/astcast/go.sum deleted file mode 100644 index aa0857030..000000000 --- a/vendor/github.com/go-toolsmith/astcast/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= diff --git a/vendor/github.com/go-toolsmith/astcopy/.travis.yml b/vendor/github.com/go-toolsmith/astcopy/.travis.yml deleted file mode 100644 index 8994d395c..000000000 --- a/vendor/github.com/go-toolsmith/astcopy/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... \ No newline at end of file diff --git a/vendor/github.com/go-toolsmith/astcopy/README.md b/vendor/github.com/go-toolsmith/astcopy/README.md index 4dae5c41b..7adc66525 100644 --- a/vendor/github.com/go-toolsmith/astcopy/README.md +++ b/vendor/github.com/go-toolsmith/astcopy/README.md @@ -1,13 +1,16 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/astcopy)](https://goreportcard.com/report/github.com/go-toolsmith/astcopy) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/astcopy?status.svg)](https://godoc.org/github.com/go-toolsmith/astcopy) -[![Build Status](https://travis-ci.org/go-toolsmith/astcopy.svg?branch=master)](https://travis-ci.org/go-toolsmith/astcopy) - # astcopy -Package astcopy implements Go AST reflection-free deep copy operations. +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `astcopy` implements Go AST reflection-free deep copy operations. ## Installation: +Go version 1.16+ + ```bash go get github.com/go-toolsmith/astcopy ``` @@ -39,3 +42,16 @@ func main() { fmt.Println(astequal.Expr(x, y)) // => false } ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/astp/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/astp/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/astp +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/astp +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/astp +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/astp +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/astp +[version-url]: https://github.com/go-toolsmith/astp/releases diff --git a/vendor/github.com/go-toolsmith/astcopy/astcopy.go b/vendor/github.com/go-toolsmith/astcopy/astcopy.go index 393c5cabc..72bc58ce6 100644 --- a/vendor/github.com/go-toolsmith/astcopy/astcopy.go +++ b/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 { @@ -334,21 +346,6 @@ func FieldList(x *ast.FieldList) *ast.FieldList { return &cp } -// FuncType returns x deep copy. -// Copy of nil argument is nil. -func FuncType(x *ast.FuncType) *ast.FuncType { - if x == nil { - return nil - } - cp := *x - cp.Params = FieldList(x.Params) - cp.Results = FieldList(x.Results) - if typeParams := typeparams.ForFuncType(x); typeParams != nil { - *typeparams.ForFuncType(&cp) = *FieldList(typeParams) - } - return &cp -} - // InterfaceType returns x deep copy. // Copy of nil argument is nil. func InterfaceType(x *ast.InterfaceType) *ast.InterfaceType { @@ -423,23 +420,6 @@ func ValueSpec(x *ast.ValueSpec) *ast.ValueSpec { return &cp } -// TypeSpec returns x deep copy. -// Copy of nil argument is nil. -func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec { - if x == nil { - return nil - } - cp := *x - cp.Name = Ident(x.Name) - cp.Type = copyExpr(x.Type) - cp.Doc = CommentGroup(x.Doc) - cp.Comment = CommentGroup(x.Comment) - if typeParams := typeparams.ForTypeSpec(x); typeParams != nil { - *typeparams.ForTypeSpec(&cp) = *FieldList(typeParams) - } - return &cp -} - // Spec returns x deep copy. // Copy of nil argument is nil. func Spec(x ast.Spec) ast.Spec { @@ -858,6 +838,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/vendor/github.com/go-toolsmith/astcopy/astcopy_go117.go b/vendor/github.com/go-toolsmith/astcopy/astcopy_go117.go new file mode 100644 index 000000000..1b748bae5 --- /dev/null +++ b/vendor/github.com/go-toolsmith/astcopy/astcopy_go117.go @@ -0,0 +1,30 @@ +//go:build !go1.18 +// +build !go1.18 + +package astcopy + +// FuncType returns x deep copy. +// Copy of nil argument is nil. +func FuncType(x *ast.FuncType) *ast.FuncType { + if x == nil { + return nil + } + cp := *x + cp.Params = FieldList(x.Params) + cp.Results = FieldList(x.Results) + return &cp +} + +// TypeSpec returns x deep copy. +// Copy of nil argument is nil. +func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec { + if x == nil { + return nil + } + cp := *x + cp.Name = Ident(x.Name) + cp.Type = copyExpr(x.Type) + cp.Doc = CommentGroup(x.Doc) + cp.Comment = CommentGroup(x.Comment) + return &cp +} diff --git a/vendor/github.com/go-toolsmith/astcopy/astcopy_go118.go b/vendor/github.com/go-toolsmith/astcopy/astcopy_go118.go new file mode 100644 index 000000000..72f800acc --- /dev/null +++ b/vendor/github.com/go-toolsmith/astcopy/astcopy_go118.go @@ -0,0 +1,36 @@ +//go:build go1.18 +// +build go1.18 + +package astcopy + +import ( + "go/ast" +) + +// FuncType returns x deep copy. +// Copy of nil argument is nil. +func FuncType(x *ast.FuncType) *ast.FuncType { + if x == nil { + return nil + } + cp := *x + cp.Params = FieldList(x.Params) + cp.Results = FieldList(x.Results) + cp.TypeParams = FieldList(x.TypeParams) + return &cp +} + +// TypeSpec returns x deep copy. +// Copy of nil argument is nil. +func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec { + if x == nil { + return nil + } + cp := *x + cp.Name = Ident(x.Name) + cp.Type = copyExpr(x.Type) + cp.Doc = CommentGroup(x.Doc) + cp.Comment = CommentGroup(x.Comment) + cp.TypeParams = FieldList(x.TypeParams) + return &cp +} diff --git a/vendor/github.com/go-toolsmith/astcopy/go.mod b/vendor/github.com/go-toolsmith/astcopy/go.mod deleted file mode 100644 index 8e34ca50f..000000000 --- a/vendor/github.com/go-toolsmith/astcopy/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/go-toolsmith/astcopy - -go 1.16 - -require ( - github.com/go-toolsmith/astequal v1.0.2 - github.com/go-toolsmith/strparse v1.0.0 - golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171 -) diff --git a/vendor/github.com/go-toolsmith/astcopy/go.sum b/vendor/github.com/go-toolsmith/astcopy/go.sum deleted file mode 100644 index 743006ed1..000000000 --- a/vendor/github.com/go-toolsmith/astcopy/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -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/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171 h1:DZhP7zSquENyG3Yb6ZpGqNEtgE8dfXhcLcheIF9RQHY= -golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= diff --git a/vendor/github.com/go-toolsmith/astequal/.travis.yml b/vendor/github.com/go-toolsmith/astequal/.travis.yml deleted file mode 100644 index 8994d395c..000000000 --- a/vendor/github.com/go-toolsmith/astequal/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... \ No newline at end of file diff --git a/vendor/github.com/go-toolsmith/astequal/README.md b/vendor/github.com/go-toolsmith/astequal/README.md index b14f80f6f..db5e3a8c9 100644 --- a/vendor/github.com/go-toolsmith/astequal/README.md +++ b/vendor/github.com/go-toolsmith/astequal/README.md @@ -1,14 +1,16 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/astequal)](https://goreportcard.com/report/github.com/go-toolsmith/astequal) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/astequal?status.svg)](https://godoc.org/github.com/go-toolsmith/astequal) -[![Build Status](https://travis-ci.org/go-toolsmith/astequal.svg?branch=master)](https://travis-ci.org/go-toolsmith/astequal) - - # astequal -Package astequal provides AST (deep) equallity check operations. +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `astequal` provides AST (deep) equallity check operations. ## Installation: +Go version 1.16+ + ```bash go get github.com/go-toolsmith/astequal ``` @@ -65,3 +67,16 @@ BenchmarkEqualExpr/astequal.Expr-8 5000000 298 ns/op 0 B/op 0 BenchmarkEqualExpr/astequal.Node-8 3000000 409 ns/op 0 B/op 0 allocs/op BenchmarkEqualExpr/reflect.DeepEqual-8 50000 38898 ns/op 10185 B/op 156 allocs/op ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/astequal/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/astequal/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/astequal +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/astequal +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/astequal +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/astequal +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/astequal +[version-url]: https://github.com/go-toolsmith/astequal/releases diff --git a/vendor/github.com/go-toolsmith/astequal/astequal.go b/vendor/github.com/go-toolsmith/astequal/astequal.go index b2ab0e640..3d8db4af9 100644 --- a/vendor/github.com/go-toolsmith/astequal/astequal.go +++ b/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/vendor/github.com/go-toolsmith/astequal/go.mod b/vendor/github.com/go-toolsmith/astequal/go.mod deleted file mode 100644 index f5a12599c..000000000 --- a/vendor/github.com/go-toolsmith/astequal/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/go-toolsmith/astequal - -go 1.16 - -require github.com/go-toolsmith/strparse v1.0.0 - -require golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171 // indirect diff --git a/vendor/github.com/go-toolsmith/astequal/go.sum b/vendor/github.com/go-toolsmith/astequal/go.sum deleted file mode 100644 index 74e570ff4..000000000 --- a/vendor/github.com/go-toolsmith/astequal/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171 h1:DZhP7zSquENyG3Yb6ZpGqNEtgE8dfXhcLcheIF9RQHY= -golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= diff --git a/vendor/github.com/go-toolsmith/astfmt/.travis.yml b/vendor/github.com/go-toolsmith/astfmt/.travis.yml deleted file mode 100644 index c32ac0062..000000000 --- a/vendor/github.com/go-toolsmith/astfmt/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... diff --git a/vendor/github.com/go-toolsmith/astfmt/README.md b/vendor/github.com/go-toolsmith/astfmt/README.md index 954c92bf4..00f790fd2 100644 --- a/vendor/github.com/go-toolsmith/astfmt/README.md +++ b/vendor/github.com/go-toolsmith/astfmt/README.md @@ -1,13 +1,16 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/strparse)](https://goreportcard.com/report/github.com/go-toolsmith/strparse) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/strparse?status.svg)](https://godoc.org/github.com/go-toolsmith/strparse) - - # astfmt -Package astfmt implements ast.Node formatting with fmt-like API. +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `astfmt` implements ast.Node formatting with fmt-like API. ## Installation +Go version 1.16+ + ```bash go get github.com/go-toolsmith/astfmt ``` @@ -37,3 +40,16 @@ func Example() { pp.Println(x) // => foo(bar(baz(1 + 2))) } ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/astfmt/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/astfmt/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/astfmt +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/astfmt +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/astfmt +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/astfmt +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/astfmt +[version-url]: https://github.com/go-toolsmith/astfmt/releases diff --git a/vendor/github.com/go-toolsmith/astfmt/go.mod b/vendor/github.com/go-toolsmith/astfmt/go.mod deleted file mode 100644 index d23db1566..000000000 --- a/vendor/github.com/go-toolsmith/astfmt/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module github.com/go-toolsmith/astfmt - -require ( - github.com/go-toolsmith/astequal v1.0.0 // indirect - github.com/go-toolsmith/strparse v1.0.0 -) diff --git a/vendor/github.com/go-toolsmith/astfmt/go.sum b/vendor/github.com/go-toolsmith/astfmt/go.sum deleted file mode 100644 index aa0857030..000000000 --- a/vendor/github.com/go-toolsmith/astfmt/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= diff --git a/vendor/github.com/go-toolsmith/astp/.gitignore b/vendor/github.com/go-toolsmith/astp/.gitignore deleted file mode 100644 index 1f6187ecd..000000000 --- a/vendor/github.com/go-toolsmith/astp/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -bin -pkg -src/main -tmp \ No newline at end of file diff --git a/vendor/github.com/go-toolsmith/astp/.travis.yml b/vendor/github.com/go-toolsmith/astp/.travis.yml deleted file mode 100644 index 8994d395c..000000000 --- a/vendor/github.com/go-toolsmith/astp/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... \ No newline at end of file diff --git a/vendor/github.com/go-toolsmith/astp/README.md b/vendor/github.com/go-toolsmith/astp/README.md index 7313c6ab8..cf5197e81 100644 --- a/vendor/github.com/go-toolsmith/astp/README.md +++ b/vendor/github.com/go-toolsmith/astp/README.md @@ -1,14 +1,16 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/astp)](https://goreportcard.com/report/github.com/go-toolsmith/astp) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/astp?status.svg)](https://godoc.org/github.com/go-toolsmith/astp) -[![Build Status](https://travis-ci.org/go-toolsmith/astp.svg?branch=master)](https://travis-ci.org/go-toolsmith/astp) - - # astp -Package astp provides AST predicates. +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `astp` provides AST predicates. ## Installation: +Go version 1.16+ + ```bash go get github.com/go-toolsmith/astp ``` @@ -37,3 +39,16 @@ func main() { } } ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/astp/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/astp/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/astp +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/astp +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/astp +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/astp +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/astp +[version-url]: https://github.com/go-toolsmith/astp/releases diff --git a/vendor/github.com/go-toolsmith/astp/go.mod b/vendor/github.com/go-toolsmith/astp/go.mod deleted file mode 100644 index 023a09392..000000000 --- a/vendor/github.com/go-toolsmith/astp/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module github.com/go-toolsmith/astp - -require ( - github.com/go-toolsmith/astequal v1.0.0 // indirect - github.com/go-toolsmith/strparse v1.0.0 -) diff --git a/vendor/github.com/go-toolsmith/astp/go.sum b/vendor/github.com/go-toolsmith/astp/go.sum deleted file mode 100644 index aa0857030..000000000 --- a/vendor/github.com/go-toolsmith/astp/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= diff --git a/vendor/github.com/go-toolsmith/strparse/.travis.yml b/vendor/github.com/go-toolsmith/strparse/.travis.yml deleted file mode 100644 index 8994d395c..000000000 --- a/vendor/github.com/go-toolsmith/strparse/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go tool vet . - - go test -v -race ./... \ No newline at end of file diff --git a/vendor/github.com/go-toolsmith/strparse/README.md b/vendor/github.com/go-toolsmith/strparse/README.md index ae80a5398..ac04d516f 100644 --- a/vendor/github.com/go-toolsmith/strparse/README.md +++ b/vendor/github.com/go-toolsmith/strparse/README.md @@ -1,15 +1,17 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/strparse)](https://goreportcard.com/report/github.com/go-toolsmith/strparse) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/strparse?status.svg)](https://godoc.org/github.com/go-toolsmith/strparse) -[![Build Status](https://travis-ci.org/go-toolsmith/strparse.svg?branch=master)](https://travis-ci.org/go-toolsmith/strparse) - - # strparse -Package strparse provides convenience wrappers around `go/parser` for simple +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `strparse` provides convenience wrappers around `go/parser` for simple expression, statement and declaretion parsing from string. ## Installation +Go version 1.16+ + ```bash go get github.com/go-toolsmith/strparse ``` @@ -20,8 +22,8 @@ go get github.com/go-toolsmith/strparse package main import ( - "go-toolsmith/astequal" - "go-toolsmith/strparse" + "github.com/go-toolsmith/astequal" + "github.com/go-toolsmith/strparse" ) func main() { @@ -30,5 +32,17 @@ func main() { y := strparse.Expr(` 1+f( v[0].X ) `) fmt.Println(astequal.Expr(x, y)) // => true } - ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/strparse/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/strparse/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/strparse +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/strparse +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/strparse +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/strparse +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/strparse +[version-url]: https://github.com/go-toolsmith/strparse/releases diff --git a/vendor/github.com/go-toolsmith/strparse/go.mod b/vendor/github.com/go-toolsmith/strparse/go.mod deleted file mode 100644 index ed9d88136..000000000 --- a/vendor/github.com/go-toolsmith/strparse/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/go-toolsmith/strparse diff --git a/vendor/github.com/go-toolsmith/typep/.travis.yml b/vendor/github.com/go-toolsmith/typep/.travis.yml deleted file mode 100644 index d3ff3cca8..000000000 --- a/vendor/github.com/go-toolsmith/typep/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go -go: - - 1.x -install: - - # Prevent default install action "go get -t -v ./...". -script: - - go get -t -v ./... - - go vet ./... - - go test -v -race ./... diff --git a/vendor/github.com/go-toolsmith/typep/README.md b/vendor/github.com/go-toolsmith/typep/README.md index f7979148f..77478c443 100644 --- a/vendor/github.com/go-toolsmith/typep/README.md +++ b/vendor/github.com/go-toolsmith/typep/README.md @@ -1,15 +1,18 @@ -[![Go Report Card](https://goreportcard.com/badge/github.com/go-toolsmith/typep)](https://goreportcard.com/report/github.com/go-toolsmith/typep) -[![GoDoc](https://godoc.org/github.com/go-toolsmith/typep?status.svg)](https://godoc.org/github.com/go-toolsmith/typep) -[![Build Status](https://travis-ci.org/go-toolsmith/typep.svg?branch=master)](https://travis-ci.org/go-toolsmith/typep) - # typep -Package typep provides type predicates. +[![build-img]][build-url] +[![pkg-img]][pkg-url] +[![reportcard-img]][reportcard-url] +[![version-img]][version-url] + +Package `typep` provides type predicates. ## Installation: +Go version 1.16+ + ```bash -go get -v github.com/go-toolsmith/typep +go get github.com/go-toolsmith/typep ``` ## Example @@ -29,9 +32,23 @@ func main() { intTyp := types.Typ[types.Int] ptr := types.NewPointer(intTyp) arr := types.NewArray(intTyp, 64) + fmt.Println(typep.HasFloatProp(floatTyp)) // => true fmt.Println(typep.HasFloatProp(intTyp)) // => false fmt.Println(typep.IsPointer(ptr)) // => true fmt.Println(typep.IsArray(arr)) // => true } ``` + +## License + +[MIT License](LICENSE). + +[build-img]: https://github.com/go-toolsmith/typep/workflows/build/badge.svg +[build-url]: https://github.com/go-toolsmith/typep/actions +[pkg-img]: https://pkg.go.dev/badge/go-toolsmith/typep +[pkg-url]: https://pkg.go.dev/github.com/go-toolsmith/typep +[reportcard-img]: https://goreportcard.com/badge/go-toolsmith/typep +[reportcard-url]: https://goreportcard.com/report/go-toolsmith/typep +[version-img]: https://img.shields.io/github/v/release/go-toolsmith/typep +[version-url]: https://github.com/go-toolsmith/typep/releases diff --git a/vendor/github.com/go-toolsmith/typep/go.mod b/vendor/github.com/go-toolsmith/typep/go.mod deleted file mode 100644 index 197a57d30..000000000 --- a/vendor/github.com/go-toolsmith/typep/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/go-toolsmith/typep diff --git a/vendor/github.com/go-toolsmith/typep/safeExpr.go b/vendor/github.com/go-toolsmith/typep/safeExpr.go deleted file mode 100644 index d5835d97b..000000000 --- a/vendor/github.com/go-toolsmith/typep/safeExpr.go +++ /dev/null @@ -1,73 +0,0 @@ -package typep - -import ( - "go/ast" - "go/token" - "go/types" -) - -// SideEffectFree reports whether expr is softly safe expression and contains -// no significant side-effects. As opposed to strictly safe expressions, -// soft safe expressions permit some forms of side-effects, like -// panic possibility during indexing or nil pointer dereference. -// -// Uses types info to determine type conversion expressions that -// are the only permitted kinds of call expressions. -// Note that is does not check whether called function really -// has any side effects. The analysis is very conservative. -func SideEffectFree(info *types.Info, expr ast.Expr) bool { - // This list switch is not comprehensive and uses - // whitelist to be on the conservative side. - // Can be extended as needed. - - if expr == nil { - return true - } - - switch expr := expr.(type) { - case *ast.StarExpr: - return SideEffectFree(info, expr.X) - case *ast.BinaryExpr: - return SideEffectFree(info, expr.X) && - SideEffectFree(info, expr.Y) - case *ast.UnaryExpr: - return expr.Op != token.ARROW && - SideEffectFree(info, expr.X) - case *ast.BasicLit, *ast.Ident: - return true - case *ast.SliceExpr: - return SideEffectFree(info, expr.X) && - SideEffectFree(info, expr.Low) && - SideEffectFree(info, expr.High) && - SideEffectFree(info, expr.Max) - case *ast.IndexExpr: - return SideEffectFree(info, expr.X) && - SideEffectFree(info, expr.Index) - case *ast.SelectorExpr: - return SideEffectFree(info, expr.X) - case *ast.ParenExpr: - return SideEffectFree(info, expr.X) - case *ast.TypeAssertExpr: - return SideEffectFree(info, expr.X) - case *ast.CompositeLit: - return SideEffectFreeList(info, expr.Elts) - case *ast.CallExpr: - return IsTypeExpr(info, expr.Fun) && - SideEffectFreeList(info, expr.Args) - - default: - return false - } -} - -// SideEffectFreeList reports whether every expr in list is safe. -// -// See SideEffectFree. -func SideEffectFreeList(info *types.Info, list []ast.Expr) bool { - for _, expr := range list { - if !SideEffectFree(info, expr) { - return false - } - } - return true -} diff --git a/vendor/github.com/go-toolsmith/typep/safe_expr.go b/vendor/github.com/go-toolsmith/typep/safe_expr.go new file mode 100644 index 000000000..d5835d97b --- /dev/null +++ b/vendor/github.com/go-toolsmith/typep/safe_expr.go @@ -0,0 +1,73 @@ +package typep + +import ( + "go/ast" + "go/token" + "go/types" +) + +// SideEffectFree reports whether expr is softly safe expression and contains +// no significant side-effects. As opposed to strictly safe expressions, +// soft safe expressions permit some forms of side-effects, like +// panic possibility during indexing or nil pointer dereference. +// +// Uses types info to determine type conversion expressions that +// are the only permitted kinds of call expressions. +// Note that is does not check whether called function really +// has any side effects. The analysis is very conservative. +func SideEffectFree(info *types.Info, expr ast.Expr) bool { + // This list switch is not comprehensive and uses + // whitelist to be on the conservative side. + // Can be extended as needed. + + if expr == nil { + return true + } + + switch expr := expr.(type) { + case *ast.StarExpr: + return SideEffectFree(info, expr.X) + case *ast.BinaryExpr: + return SideEffectFree(info, expr.X) && + SideEffectFree(info, expr.Y) + case *ast.UnaryExpr: + return expr.Op != token.ARROW && + SideEffectFree(info, expr.X) + case *ast.BasicLit, *ast.Ident: + return true + case *ast.SliceExpr: + return SideEffectFree(info, expr.X) && + SideEffectFree(info, expr.Low) && + SideEffectFree(info, expr.High) && + SideEffectFree(info, expr.Max) + case *ast.IndexExpr: + return SideEffectFree(info, expr.X) && + SideEffectFree(info, expr.Index) + case *ast.SelectorExpr: + return SideEffectFree(info, expr.X) + case *ast.ParenExpr: + return SideEffectFree(info, expr.X) + case *ast.TypeAssertExpr: + return SideEffectFree(info, expr.X) + case *ast.CompositeLit: + return SideEffectFreeList(info, expr.Elts) + case *ast.CallExpr: + return IsTypeExpr(info, expr.Fun) && + SideEffectFreeList(info, expr.Args) + + default: + return false + } +} + +// SideEffectFreeList reports whether every expr in list is safe. +// +// See SideEffectFree. +func SideEffectFreeList(info *types.Info, list []ast.Expr) bool { + for _, expr := range list { + if !SideEffectFree(info, expr) { + return false + } + } + return true +} diff --git a/vendor/github.com/go-toolsmith/typep/simplePredicates.go b/vendor/github.com/go-toolsmith/typep/simplePredicates.go deleted file mode 100644 index 3bc9c29c8..000000000 --- a/vendor/github.com/go-toolsmith/typep/simplePredicates.go +++ /dev/null @@ -1,359 +0,0 @@ -// Code generated by simplePredicates_generate.go; DO NOT EDIT - -package typep - -import ( - "go/types" -) - -// Simple 1-to-1 type predicates via type assertion. - -// IsBasic reports whether a given type has *types.Basic type. -func IsBasic(typ types.Type) bool { - _, ok := typ.(*types.Basic) - return ok -} - -// IsArray reports whether a given type has *types.Array type. -func IsArray(typ types.Type) bool { - _, ok := typ.(*types.Array) - return ok -} - -// IsSlice reports whether a given type has *types.Slice type. -func IsSlice(typ types.Type) bool { - _, ok := typ.(*types.Slice) - return ok -} - -// IsStruct reports whether a given type has *types.Struct type. -func IsStruct(typ types.Type) bool { - _, ok := typ.(*types.Struct) - return ok -} - -// IsPointer reports whether a given type has *types.Pointer type. -func IsPointer(typ types.Type) bool { - _, ok := typ.(*types.Pointer) - return ok -} - -// IsTuple reports whether a given type has *types.Tuple type. -func IsTuple(typ types.Type) bool { - _, ok := typ.(*types.Tuple) - return ok -} - -// IsSignature reports whether a given type has *types.Signature type. -func IsSignature(typ types.Type) bool { - _, ok := typ.(*types.Signature) - return ok -} - -// IsInterface reports whether a given type has *types.Interface type. -func IsInterface(typ types.Type) bool { - _, ok := typ.(*types.Interface) - return ok -} - -// IsMap reports whether a given type has *types.Map type. -func IsMap(typ types.Type) bool { - _, ok := typ.(*types.Map) - return ok -} - -// IsChan reports whether a given type has *types.Chan type. -func IsChan(typ types.Type) bool { - _, ok := typ.(*types.Chan) - return ok -} - -// IsNamed reports whether a given type has *types.Named type. -func IsNamed(typ types.Type) bool { - _, ok := typ.(*types.Named) - return ok -} - -// *types.Basic predicates for the info field. - -// HasBooleanProp reports whether typ is a *types.Basic has IsBoolean property. -func HasBooleanProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsBoolean != 0 - } - return false -} - -// HasIntegerProp reports whether typ is a *types.Basic has IsInteger property. -func HasIntegerProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsInteger != 0 - } - return false -} - -// HasUnsignedProp reports whether typ is a *types.Basic has IsUnsigned property. -func HasUnsignedProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsUnsigned != 0 - } - return false -} - -// HasFloatProp reports whether typ is a *types.Basic has IsFloat property. -func HasFloatProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsFloat != 0 - } - return false -} - -// HasComplexProp reports whether typ is a *types.Basic has IsComplex property. -func HasComplexProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsComplex != 0 - } - return false -} - -// HasStringProp reports whether typ is a *types.Basic has IsString property. -func HasStringProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsString != 0 - } - return false -} - -// HasUntypedProp reports whether typ is a *types.Basic has IsUntyped property. -func HasUntypedProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsUntyped != 0 - } - return false -} - -// HasOrderedProp reports whether typ is a *types.Basic has IsOrdered property. -func HasOrderedProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsOrdered != 0 - } - return false -} - -// HasNumericProp reports whether typ is a *types.Basic has IsNumeric property. -func HasNumericProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsNumeric != 0 - } - return false -} - -// HasConstTypeProp reports whether typ is a *types.Basic has IsConstType property. -func HasConstTypeProp(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Info()&types.IsConstType != 0 - } - return false -} - -// *types.Basic predicates for the kind field. - -// HasBoolKind reports whether typ is a *types.Basic with its kind set to types.Bool. -func HasBoolKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Bool - } - return false -} - -// HasIntKind reports whether typ is a *types.Basic with its kind set to types.Int. -func HasIntKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Int - } - return false -} - -// HasInt8Kind reports whether typ is a *types.Basic with its kind set to types.Int8. -func HasInt8Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Int8 - } - return false -} - -// HasInt16Kind reports whether typ is a *types.Basic with its kind set to types.Int16. -func HasInt16Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Int16 - } - return false -} - -// HasInt32Kind reports whether typ is a *types.Basic with its kind set to types.Int32. -func HasInt32Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Int32 - } - return false -} - -// HasInt64Kind reports whether typ is a *types.Basic with its kind set to types.Int64. -func HasInt64Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Int64 - } - return false -} - -// HasUintKind reports whether typ is a *types.Basic with its kind set to types.Uint. -func HasUintKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uint - } - return false -} - -// HasUint8Kind reports whether typ is a *types.Basic with its kind set to types.Uint8. -func HasUint8Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uint8 - } - return false -} - -// HasUint16Kind reports whether typ is a *types.Basic with its kind set to types.Uint16. -func HasUint16Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uint16 - } - return false -} - -// HasUint32Kind reports whether typ is a *types.Basic with its kind set to types.Uint32. -func HasUint32Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uint32 - } - return false -} - -// HasUint64Kind reports whether typ is a *types.Basic with its kind set to types.Uint64. -func HasUint64Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uint64 - } - return false -} - -// HasUintptrKind reports whether typ is a *types.Basic with its kind set to types.Uintptr. -func HasUintptrKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Uintptr - } - return false -} - -// HasFloat32Kind reports whether typ is a *types.Basic with its kind set to types.Float32. -func HasFloat32Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Float32 - } - return false -} - -// HasFloat64Kind reports whether typ is a *types.Basic with its kind set to types.Float64. -func HasFloat64Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Float64 - } - return false -} - -// HasComplex64Kind reports whether typ is a *types.Basic with its kind set to types.Complex64. -func HasComplex64Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Complex64 - } - return false -} - -// HasComplex128Kind reports whether typ is a *types.Basic with its kind set to types.Complex128. -func HasComplex128Kind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.Complex128 - } - return false -} - -// HasStringKind reports whether typ is a *types.Basic with its kind set to types.String. -func HasStringKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.String - } - return false -} - -// HasUnsafePointerKind reports whether typ is a *types.Basic with its kind set to types.UnsafePointer. -func HasUnsafePointerKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UnsafePointer - } - return false -} - -// HasUntypedBoolKind reports whether typ is a *types.Basic with its kind set to types.UntypedBool. -func HasUntypedBoolKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedBool - } - return false -} - -// HasUntypedIntKind reports whether typ is a *types.Basic with its kind set to types.UntypedInt. -func HasUntypedIntKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedInt - } - return false -} - -// HasUntypedRuneKind reports whether typ is a *types.Basic with its kind set to types.UntypedRune. -func HasUntypedRuneKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedRune - } - return false -} - -// HasUntypedFloatKind reports whether typ is a *types.Basic with its kind set to types.UntypedFloat. -func HasUntypedFloatKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedFloat - } - return false -} - -// HasUntypedComplexKind reports whether typ is a *types.Basic with its kind set to types.UntypedComplex. -func HasUntypedComplexKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedComplex - } - return false -} - -// HasUntypedStringKind reports whether typ is a *types.Basic with its kind set to types.UntypedString. -func HasUntypedStringKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedString - } - return false -} - -// HasUntypedNilKind reports whether typ is a *types.Basic with its kind set to types.UntypedNil. -func HasUntypedNilKind(typ types.Type) bool { - if typ, ok := typ.(*types.Basic); ok { - return typ.Kind() == types.UntypedNil - } - return false -} diff --git a/vendor/github.com/go-toolsmith/typep/simple_predicates.go b/vendor/github.com/go-toolsmith/typep/simple_predicates.go new file mode 100644 index 000000000..61e7d5b7f --- /dev/null +++ b/vendor/github.com/go-toolsmith/typep/simple_predicates.go @@ -0,0 +1,359 @@ +// Code generated by simple_predicates_generate.go; DO NOT EDIT + +package typep + +import ( + "go/types" +) + +// Simple 1-to-1 type predicates via type assertion. + +// IsBasic reports whether a given type has *types.Basic type. +func IsBasic(typ types.Type) bool { + _, ok := typ.(*types.Basic) + return ok +} + +// IsArray reports whether a given type has *types.Array type. +func IsArray(typ types.Type) bool { + _, ok := typ.(*types.Array) + return ok +} + +// IsSlice reports whether a given type has *types.Slice type. +func IsSlice(typ types.Type) bool { + _, ok := typ.(*types.Slice) + return ok +} + +// IsStruct reports whether a given type has *types.Struct type. +func IsStruct(typ types.Type) bool { + _, ok := typ.(*types.Struct) + return ok +} + +// IsPointer reports whether a given type has *types.Pointer type. +func IsPointer(typ types.Type) bool { + _, ok := typ.(*types.Pointer) + return ok +} + +// IsTuple reports whether a given type has *types.Tuple type. +func IsTuple(typ types.Type) bool { + _, ok := typ.(*types.Tuple) + return ok +} + +// IsSignature reports whether a given type has *types.Signature type. +func IsSignature(typ types.Type) bool { + _, ok := typ.(*types.Signature) + return ok +} + +// IsInterface reports whether a given type has *types.Interface type. +func IsInterface(typ types.Type) bool { + _, ok := typ.(*types.Interface) + return ok +} + +// IsMap reports whether a given type has *types.Map type. +func IsMap(typ types.Type) bool { + _, ok := typ.(*types.Map) + return ok +} + +// IsChan reports whether a given type has *types.Chan type. +func IsChan(typ types.Type) bool { + _, ok := typ.(*types.Chan) + return ok +} + +// IsNamed reports whether a given type has *types.Named type. +func IsNamed(typ types.Type) bool { + _, ok := typ.(*types.Named) + return ok +} + +// *types.Basic predicates for the info field. + +// HasBooleanProp reports whether typ is a *types.Basic has IsBoolean property. +func HasBooleanProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsBoolean != 0 + } + return false +} + +// HasIntegerProp reports whether typ is a *types.Basic has IsInteger property. +func HasIntegerProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsInteger != 0 + } + return false +} + +// HasUnsignedProp reports whether typ is a *types.Basic has IsUnsigned property. +func HasUnsignedProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsUnsigned != 0 + } + return false +} + +// HasFloatProp reports whether typ is a *types.Basic has IsFloat property. +func HasFloatProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsFloat != 0 + } + return false +} + +// HasComplexProp reports whether typ is a *types.Basic has IsComplex property. +func HasComplexProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsComplex != 0 + } + return false +} + +// HasStringProp reports whether typ is a *types.Basic has IsString property. +func HasStringProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsString != 0 + } + return false +} + +// HasUntypedProp reports whether typ is a *types.Basic has IsUntyped property. +func HasUntypedProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsUntyped != 0 + } + return false +} + +// HasOrderedProp reports whether typ is a *types.Basic has IsOrdered property. +func HasOrderedProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsOrdered != 0 + } + return false +} + +// HasNumericProp reports whether typ is a *types.Basic has IsNumeric property. +func HasNumericProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsNumeric != 0 + } + return false +} + +// HasConstTypeProp reports whether typ is a *types.Basic has IsConstType property. +func HasConstTypeProp(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Info()&types.IsConstType != 0 + } + return false +} + +// *types.Basic predicates for the kind field. + +// HasBoolKind reports whether typ is a *types.Basic with its kind set to types.Bool. +func HasBoolKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Bool + } + return false +} + +// HasIntKind reports whether typ is a *types.Basic with its kind set to types.Int. +func HasIntKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Int + } + return false +} + +// HasInt8Kind reports whether typ is a *types.Basic with its kind set to types.Int8. +func HasInt8Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Int8 + } + return false +} + +// HasInt16Kind reports whether typ is a *types.Basic with its kind set to types.Int16. +func HasInt16Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Int16 + } + return false +} + +// HasInt32Kind reports whether typ is a *types.Basic with its kind set to types.Int32. +func HasInt32Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Int32 + } + return false +} + +// HasInt64Kind reports whether typ is a *types.Basic with its kind set to types.Int64. +func HasInt64Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Int64 + } + return false +} + +// HasUintKind reports whether typ is a *types.Basic with its kind set to types.Uint. +func HasUintKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uint + } + return false +} + +// HasUint8Kind reports whether typ is a *types.Basic with its kind set to types.Uint8. +func HasUint8Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uint8 + } + return false +} + +// HasUint16Kind reports whether typ is a *types.Basic with its kind set to types.Uint16. +func HasUint16Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uint16 + } + return false +} + +// HasUint32Kind reports whether typ is a *types.Basic with its kind set to types.Uint32. +func HasUint32Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uint32 + } + return false +} + +// HasUint64Kind reports whether typ is a *types.Basic with its kind set to types.Uint64. +func HasUint64Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uint64 + } + return false +} + +// HasUintptrKind reports whether typ is a *types.Basic with its kind set to types.Uintptr. +func HasUintptrKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Uintptr + } + return false +} + +// HasFloat32Kind reports whether typ is a *types.Basic with its kind set to types.Float32. +func HasFloat32Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Float32 + } + return false +} + +// HasFloat64Kind reports whether typ is a *types.Basic with its kind set to types.Float64. +func HasFloat64Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Float64 + } + return false +} + +// HasComplex64Kind reports whether typ is a *types.Basic with its kind set to types.Complex64. +func HasComplex64Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Complex64 + } + return false +} + +// HasComplex128Kind reports whether typ is a *types.Basic with its kind set to types.Complex128. +func HasComplex128Kind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.Complex128 + } + return false +} + +// HasStringKind reports whether typ is a *types.Basic with its kind set to types.String. +func HasStringKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.String + } + return false +} + +// HasUnsafePointerKind reports whether typ is a *types.Basic with its kind set to types.UnsafePointer. +func HasUnsafePointerKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UnsafePointer + } + return false +} + +// HasUntypedBoolKind reports whether typ is a *types.Basic with its kind set to types.UntypedBool. +func HasUntypedBoolKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedBool + } + return false +} + +// HasUntypedIntKind reports whether typ is a *types.Basic with its kind set to types.UntypedInt. +func HasUntypedIntKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedInt + } + return false +} + +// HasUntypedRuneKind reports whether typ is a *types.Basic with its kind set to types.UntypedRune. +func HasUntypedRuneKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedRune + } + return false +} + +// HasUntypedFloatKind reports whether typ is a *types.Basic with its kind set to types.UntypedFloat. +func HasUntypedFloatKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedFloat + } + return false +} + +// HasUntypedComplexKind reports whether typ is a *types.Basic with its kind set to types.UntypedComplex. +func HasUntypedComplexKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedComplex + } + return false +} + +// HasUntypedStringKind reports whether typ is a *types.Basic with its kind set to types.UntypedString. +func HasUntypedStringKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedString + } + return false +} + +// HasUntypedNilKind reports whether typ is a *types.Basic with its kind set to types.UntypedNil. +func HasUntypedNilKind(typ types.Type) bool { + if typ, ok := typ.(*types.Basic); ok { + return typ.Kind() == types.UntypedNil + } + return false +} diff --git a/vendor/github.com/go-xmlfmt/xmlfmt/README.md b/vendor/github.com/go-xmlfmt/xmlfmt/README.md index 4eb6d69a0..9f661ea2d 100644 --- a/vendor/github.com/go-xmlfmt/xmlfmt/README.md +++ b/vendor/github.com/go-xmlfmt/xmlfmt/README.md @@ -3,7 +3,6 @@ [![MIT License](http://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Go Doc](https://img.shields.io/badge/godoc-reference-4b68a3.svg)](https://godoc.org/github.com/go-xmlfmt/xmlfmt) [![Go Report Card](https://goreportcard.com/badge/github.com/go-xmlfmt/xmlfmt)](https://goreportcard.com/report/github.com/go-xmlfmt/xmlfmt) -[![Codeship Status](https://codeship.com/projects/c49f02b0-a384-0134-fb20-2e0351080565/status?branch=master)](https://codeship.com/projects/190297) ## Synopsis @@ -15,9 +14,18 @@ package main import "github.com/go-xmlfmt/xmlfmt" func main() { - xml1 := `aSome org-or-otherWouldnt you like to knowPatCalifia` + xml1 := `aSome org-or-otherWouldnt you like to knowPatCalifia` x := xmlfmt.FormatXML(xml1, "\t", " ") print(x) + + // If the XML Comments have nested tags in them + xml1 = ` Fred + + 23456 ` + x = xmlfmt.FormatXML(xml1, "", " ", true) + print(x) } ``` @@ -27,48 +35,107 @@ Output: ```xml - a - + a - Some org-or-other - - Wouldnt you like to know - + Some org-or-other + Wouldnt you like to know - Pat - - Califia - + Pat + Califia + + + + Fred + + 23456 + ``` There is no XML decoding and encoding involved, only pure regular expression matching and replacing. So it is much faster than going through decoding and encoding procedures. Moreover, the exact XML source string is preserved, instead of being changed by the encoder. This is why this package exists in the first place. +Note that + +- the default line ending is handled by the package automatically now. For Windows it's `CRLF`, and standard for anywhere else. No need to change the default line ending now. +- the case of XML comments nested within XML comments is ***not*** supported. Please avoid them or use any other tools to correct them before using this package. +- don't turn on the `nestedTagsInComments` parameter blindly, as the code has become 10+ times more complicated because of it. + ## Command To use it on command line, check out [xmlfmt](https://github.com/AntonioSun/xmlfmt): ``` -$ xmlfmt -XML Formatter -built on 2019-12-08 +$ xmlfmt -V +xmlfmt - XML Formatter +Copyright (C) 2016-2022, Antonio Sun The xmlfmt will format the XML string without rewriting the document -Options: - - -h, --help display help information - -f, --file *The xml file to read from (or stdin) - -p, --prefix each element begins on a new line and this prefix - -i, --indent[= ] indent string for nested elements +Built on 2022-02-06 +Version 1.1.1 + +$ xmlfmt +the required flag `-f, --file' was not specified + +Usage: + xmlfmt [OPTIONS] + +Application Options: + -f, --file= The xml file to read from (or "-" for stdin) [$XMLFMT_FILEI] + -p, --prefix= Each element begins on a new line and this prefix [$XMLFMT_PREFIX] + -i, --indent= Indent string for nested elements (default: ) [$XMLFMT_INDENT] + -n, --nested Nested tags in comments [$XMLFMT_NESTED] + -v, --verbose Verbose mode (Multiple -v options increase the verbosity) + -V, --version Show program version and exit + +Help Options: + -h, --help Show this help message + + +$ curl -sL https://pastebin.com/raw/z3euQ5PR | xmlfmt -f - + + + + a + + + + + Some org-or-other + Wouldnt you like to know + + + Pat + Califia + + + + + +$ curl -sL https://pastebin.com/raw/Zs0qy0qz | tee /tmp/xmlfmt.xml | xmlfmt -f - -n + + + Fred + + 23456 + + +$ XMLFMT_NESTED=true XMLFMT_PREFIX='|' xmlfmt -f /tmp/xmlfmt.xml + +| +| +| Fred +| +| 23456 +| ``` @@ -76,7 +143,7 @@ Options: ### The format -The Go XML Formatter is not called XML Beautifier because the result is not *exactly* as what people would expect -- some, but not all, closing tags stays on the same line, just as shown above. Having been looking at the result and thinking over it, I now think it is actually a better way to present it, as those closing tags on the same line are better stay that way in my opinion. I.e., +The Go XML Formatter is not called XML Beautifier because the result is not *exactly* as what people would expect -- most of the closing tags stays on the same line, just as shown above. Having been looking at the result and thinking over it, I now think it is actually a better way to present it, as those closing tags on the same line are better stay that way in my opinion. I.e., When it comes to very big XML strings, which is what I’m dealing every day, saving spaces by not allowing those closing tags taking extra lines is plus instead of negative to me. @@ -175,4 +242,4 @@ echo ']+?)(/?)>`) - // NL is the newline string used in XML output, define for DOS-convenient. - NL = "\r\n" + // NL is the newline string used in XML output. + NL = "\n" ) -// FormatXML will (purly) reformat the XML string in a readable way, without any rewriting/altering the structure -func FormatXML(xmls, prefix, indent string) string { - src := regexp.MustCompile(`(?s)>\s+<`).ReplaceAllString(xmls, "><") +func init() { + // define NL for Windows + if runtime.GOOS == "windows" { + NL = "\r\n" + } +} +// FormatXML will (purly) reformat the XML string in a readable way, without any rewriting/altering the structure. +// If your XML Comments have nested tags in them, or you're not 100% sure otherwise, pass `true` as the third parameter to this function. But don't turn it on blindly, as the code has become ten times more complicated because of it. +func FormatXML(xmls, prefix, indent string, nestedTagsInComments ...bool) string { + nestedTagsInComment := false + if len(nestedTagsInComments) > 0 { + nestedTagsInComment = nestedTagsInComments[0] + } + reXmlComments := regexp.MustCompile(`(?s)()`) + src := regexp.MustCompile(`(?s)>\s+<`).ReplaceAllString(xmls, "><") + if nestedTagsInComment { + src = reXmlComments.ReplaceAllStringFunc(src, func(m string) string { + parts := reXmlComments.FindStringSubmatch(m) + p2 := regexp.MustCompile(`\r*\n`).ReplaceAllString(parts[2], " ") + return parts[1] + html.EscapeString(p2) + parts[3] + }) + } rf := replaceTag(prefix, indent) - return (prefix + reg.ReplaceAllStringFunc(src, rf)) + r := prefix + reg.ReplaceAllStringFunc(src, rf) + if nestedTagsInComment { + r = reXmlComments.ReplaceAllStringFunc(r, func(m string) string { + parts := reXmlComments.FindStringSubmatch(m) + return parts[1] + html.UnescapeString(parts[2]) + parts[3] + }) + } + + return r } // replaceTag returns a closure function to do 's/(?<=>)\s+(?=<)//g; s(<(/?)([^>]+?)(/?)>)($indent+=$3?0:$1?-1:1;"<$1$2$3>"."\n".(" "x$indent))ge' as in Perl // and deal with comments as well func replaceTag(prefix, indent string) func(string) string { indentLevel := 0 + lastEndElem := true return func(m string) string { // head elem if strings.HasPrefix(m, "") { + lastEndElem = true return NL + prefix + strings.Repeat(indent, indentLevel) + m } // comment elem @@ -45,12 +76,17 @@ func replaceTag(prefix, indent string) func(string) string { // end elem if strings.HasPrefix(m, " 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/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go b/vendor/github.com/golangci/gofmt/gofmt/internal/execabs/execabs.go new file mode 100644 index 000000000..9a05d971d --- /dev/null +++ b/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/vendor/github.com/golangci/gofmt/gofmt/readme.md b/vendor/github.com/golangci/gofmt/gofmt/readme.md new file mode 100644 index 000000000..36a716d81 --- /dev/null +++ b/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/vendor/github.com/golangci/gofmt/gofmt/rewrite.go b/vendor/github.com/golangci/gofmt/gofmt/rewrite.go index 73741e0a9..f1299a42b 100644 --- a/vendor/github.com/golangci/gofmt/gofmt/rewrite.go +++ b/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/vendor/github.com/golangci/gofmt/goimports/goimports.go b/vendor/github.com/golangci/gofmt/goimports/goimports.go index 8878b700d..1fa3328f8 100644 --- a/vendor/github.com/golangci/gofmt/goimports/goimports.go +++ b/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/vendor/github.com/golangci/gofmt/goimports/golangci.go b/vendor/github.com/golangci/gofmt/goimports/golangci.go index e9d013d58..7edc37937 100644 --- a/vendor/github.com/golangci/gofmt/goimports/golangci.go +++ b/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/vendor/github.com/golangci/gofmt/goimports/readme.md b/vendor/github.com/golangci/gofmt/goimports/readme.md new file mode 100644 index 000000000..6c793eb7d --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go b/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go index cc6606a39..e9638c8e1 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go +++ b/vendor/github.com/golangci/golangci-lint/internal/cache/cache.go @@ -51,14 +51,13 @@ 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 { return nil, err } if !info.IsDir() { - return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} + return nil, &os.PathError{Op: "open", Path: dir, Err: errors.New("not a directory")} } for i := 0; i < 256; i++ { name := filepath.Join(dir, fmt.Sprintf("%02x", i)) @@ -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,13 +497,13 @@ 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) if !bytes.Equal(sum, out[:]) { _ = f.Truncate(0) - return fmt.Errorf("file content changed underfoot") + return errors.New("file content changed underfoot") } // Commit cache file entry. diff --git a/vendor/github.com/golangci/golangci-lint/internal/cache/default.go b/vendor/github.com/golangci/golangci-lint/internal/cache/default.go index 669500629..399cc84cf 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/cache/default.go +++ b/vendor/github.com/golangci/golangci-lint/internal/cache/default.go @@ -12,6 +12,8 @@ import ( "sync" ) +const envGolangciLintCache = "GOLANGCI_LINT_CACHE" + // Default returns the default cache to use. func Default() (*Cache, error) { defaultOnce.Do(initDefaultCache) @@ -64,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 = fmt.Errorf("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/vendor/github.com/golangci/golangci-lint/internal/cache/readme.md b/vendor/github.com/golangci/golangci-lint/internal/cache/readme.md new file mode 100644 index 000000000..b469711ed --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md b/vendor/github.com/golangci/golangci-lint/internal/renameio/readme.md new file mode 100644 index 000000000..36ec6ed49 --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md b/vendor/github.com/golangci/golangci-lint/internal/robustio/readme.md new file mode 100644 index 000000000..7c7ba0483 --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go b/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go index ce3dbbde6..15b33773c 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio.go +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go b/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go index 1ac0d10d7..99fd8ebc2 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_darwin.go +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go b/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go index 6cc2f03d0..c56e36ca6 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_flaky.go +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go b/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go index b7d01b340..da9a46e4f 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_other.go +++ b/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/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go b/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go index a35237d44..fe1728954 100644 --- a/vendor/github.com/golangci/golangci-lint/internal/robustio/robustio_windows.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go index 904c2a1fc..6fdaebaed 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/cache.go @@ -8,7 +8,6 @@ import ( "github.com/spf13/cobra" "github.com/golangci/golangci-lint/internal/cache" - "github.com/golangci/golangci-lint/pkg/exitcodes" "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/logutils" ) @@ -17,64 +16,55 @@ func (e *Executor) initCache() { cacheCmd := &cobra.Command{ Use: "cache", Short: "Cache control and information", - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint cache") - } - if err := cmd.Help(); err != nil { - e.log.Fatalf("Can't run cache: %s", err) - } + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() }, } e.rootCmd.AddCommand(cacheCmd) cacheCmd.AddCommand(&cobra.Command{ - Use: "clean", - Short: "Clean cache", - Run: e.executeCleanCache, + Use: "clean", + Short: "Clean cache", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: e.executeCleanCache, }) cacheCmd.AddCommand(&cobra.Command{ - Use: "status", - Short: "Show cache status", - Run: e.executeCacheStatus, + Use: "status", + Short: "Show cache status", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + Run: e.executeCacheStatus, }) // TODO: add trim command? } -func (e *Executor) executeCleanCache(_ *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint cache clean") - } - +func (e *Executor) executeCleanCache(_ *cobra.Command, _ []string) error { cacheDir := cache.DefaultDir() if err := os.RemoveAll(cacheDir); err != nil { - e.log.Fatalf("Failed to remove dir %s: %s", cacheDir, err) + return fmt.Errorf("failed to remove dir %s: %w", cacheDir, err) } - os.Exit(exitcodes.Success) + return nil } -func (e *Executor) executeCacheStatus(_ *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint cache status") - } - +func (e *Executor) executeCacheStatus(_ *cobra.Command, _ []string) { cacheDir := cache.DefaultDir() fmt.Fprintf(logutils.StdOut, "Dir: %s\n", cacheDir) + cacheSizeBytes, err := dirSizeBytes(cacheDir) if err == nil { fmt.Fprintf(logutils.StdOut, "Size: %s\n", fsutils.PrettifyBytesCount(cacheSizeBytes)) } - - os.Exit(exitcodes.Success) } func dirSizeBytes(path string) (int64, error) { var size int64 err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { if err == nil && !info.IsDir() { - size = info.Size() + size += info.Size() } return err }) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go index e9546d328..a16ef6310 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/config.go @@ -15,21 +15,19 @@ func (e *Executor) initConfig() { cmd := &cobra.Command{ Use: "config", Short: "Config", - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint config") - } - if err := cmd.Help(); err != nil { - e.log.Fatalf("Can't run help: %s", err) - } + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() }, } e.rootCmd.AddCommand(cmd) pathCmd := &cobra.Command{ - Use: "path", - Short: "Print used config path", - Run: e.executePathCmd, + Use: "path", + Short: "Print used config path", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + Run: e.executePathCmd, } e.initRunConfiguration(pathCmd) // allow --config cmd.AddCommand(pathCmd) @@ -52,11 +50,7 @@ func (e *Executor) getUsedConfig() string { return prettyUsedConfigFile } -func (e *Executor) executePathCmd(_ *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint config path") - } - +func (e *Executor) executePathCmd(_ *cobra.Command, _ []string) { usedConfigFile := e.getUsedConfig() if usedConfigFile == "" { e.log.Warnf("No config file detected") @@ -64,5 +58,4 @@ func (e *Executor) executePathCmd(_ *cobra.Command, args []string) { } fmt.Println(usedConfigFile) - os.Exit(exitcodes.Success) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go index d9c747f6f..6dc3b74b6 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/executor.go +++ b/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) } @@ -117,28 +117,23 @@ func NewExecutor(version, commit, date string) *Executor { // recreate after getting config e.DBManager = lintersdb.NewManager(e.cfg, e.log).WithCustomLinters() - e.cfg.LintersSettings.Gocritic.InferEnabledChecks(e.log) - if err = e.cfg.LintersSettings.Gocritic.Validate(e.log); err != nil { - e.log.Fatalf("Invalid gocritic settings: %s", err) - } - // Slice options must be explicitly set for proper merging of config and command-line options. fixSlicesFlags(e.runCmd.Flags()) 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) @@ -174,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/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go index a6ed4c84f..61d362e7d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/help.go @@ -2,14 +2,12 @@ package commands import ( "fmt" - "os" "sort" "strings" "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/golangci/golangci-lint/pkg/exitcodes" "github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/logutils" ) @@ -18,21 +16,19 @@ func (e *Executor) initHelp() { helpCmd := &cobra.Command{ Use: "help", Short: "Help", - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint help") - } - if err := cmd.Help(); err != nil { - e.log.Fatalf("Can't run help: %s", err) - } + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() }, } e.rootCmd.SetHelpCommand(helpCmd) lintersHelpCmd := &cobra.Command{ - Use: "linters", - Short: "Help about linters", - Run: e.executeLintersHelp, + Use: "linters", + Short: "Help about linters", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + Run: e.executeLintersHelp, } helpCmd.AddCommand(lintersHelpCmd) } @@ -64,11 +60,7 @@ func printLinterConfigs(lcs []*linter.Config) { } } -func (e *Executor) executeLintersHelp(_ *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint help linters") - } - +func (e *Executor) executeLintersHelp(_ *cobra.Command, _ []string) { var enabledLCs, disabledLCs []*linter.Config for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() { if lc.EnabledByDefault { @@ -93,6 +85,4 @@ func (e *Executor) executeLintersHelp(_ *cobra.Command, args []string) { sort.Strings(linterNames) fmt.Fprintf(logutils.StdOut, "%s: %s\n", color.YellowString(p), strings.Join(linterNames, ", ")) } - - os.Exit(exitcodes.Success) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go index 63328e4e9..13bb944d8 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/linters.go @@ -1,35 +1,31 @@ package commands import ( - "log" - "os" + "fmt" "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/golangci/golangci-lint/pkg/exitcodes" "github.com/golangci/golangci-lint/pkg/lint/linter" ) func (e *Executor) initLinters() { e.lintersCmd = &cobra.Command{ - Use: "linters", - Short: "List current linters configuration", - Run: e.executeLinters, + Use: "linters", + Short: "List current linters configuration", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: e.executeLinters, } e.rootCmd.AddCommand(e.lintersCmd) e.initRunConfiguration(e.lintersCmd) } // executeLinters runs the 'linters' CLI command, which displays the supported linters. -func (e *Executor) executeLinters(_ *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint linters") - } - +func (e *Executor) executeLinters(_ *cobra.Command, _ []string) error { enabledLintersMap, err := e.EnabledLintersSet.GetEnabledLintersMap() if err != nil { - log.Fatalf("Can't get enabled linters: %s", err) + return fmt.Errorf("can't get enabled linters: %w", err) } color.Green("Enabled by your configuration linters:\n") @@ -49,5 +45,5 @@ func (e *Executor) executeLinters(_ *cobra.Command, args []string) { color.Red("\nDisabled by your configuration linters:\n") printLinterConfigs(disabledLCs) - os.Exit(exitcodes.Success) + return nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go index 141fc87f2..0fdcccff7 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/root.go @@ -16,10 +16,16 @@ import ( "github.com/golangci/golangci-lint/pkg/logutils" ) -func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) { +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) - os.Exit(exitcodes.Success) + _, _ = fmt.Fprintf(logutils.StdOut, "golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) + os.Exit(exitcodes.Success) // a return nil is not enough to stop the process because we are inside the `preRun`. } runtime.GOMAXPROCS(e.cfg.Run.Concurrency) @@ -27,15 +33,15 @@ func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) { if e.cfg.Run.CPUProfilePath != "" { f, err := os.Create(e.cfg.Run.CPUProfilePath) if err != nil { - e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.CPUProfilePath, err) + return fmt.Errorf("can't create file %s: %w", e.cfg.Run.CPUProfilePath, err) } if err := pprof.StartCPUProfile(f); err != nil { - e.log.Fatalf("Can't start CPU profiling: %s", err) + return fmt.Errorf("can't start CPU profiling: %w", err) } } if e.cfg.Run.MemProfilePath != "" { - if rate := os.Getenv("GL_MEMPROFILE_RATE"); rate != "" { + if rate := os.Getenv(envMemProfileRate); rate != "" { runtime.MemProfileRate, _ = strconv.Atoi(rate) } } @@ -43,22 +49,25 @@ func (e *Executor) persistentPreRun(_ *cobra.Command, _ []string) { if e.cfg.Run.TracePath != "" { f, err := os.Create(e.cfg.Run.TracePath) if err != nil { - e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.TracePath, err) + return fmt.Errorf("can't create file %s: %w", e.cfg.Run.TracePath, err) } if err = trace.Start(f); err != nil { - e.log.Fatalf("Can't start tracing: %s", err) + return fmt.Errorf("can't start tracing: %w", err) } } + + return nil } -func (e *Executor) persistentPostRun(_ *cobra.Command, _ []string) { +func (e *Executor) persistentPostRun(_ *cobra.Command, _ []string) error { if e.cfg.Run.CPUProfilePath != "" { pprof.StopCPUProfile() } + if e.cfg.Run.MemProfilePath != "" { f, err := os.Create(e.cfg.Run.MemProfilePath) if err != nil { - e.log.Fatalf("Can't create file %s: %s", e.cfg.Run.MemProfilePath, err) + return fmt.Errorf("can't create file %s: %w", e.cfg.Run.MemProfilePath, err) } var ms runtime.MemStats @@ -66,15 +75,18 @@ func (e *Executor) persistentPostRun(_ *cobra.Command, _ []string) { printMemStats(&ms, e.log) if err := pprof.WriteHeapProfile(f); err != nil { - e.log.Fatalf("Can't write heap profile: %s", err) + return fmt.Errorf("cCan't write heap profile: %w", err) } - f.Close() + _ = f.Close() } + if e.cfg.Run.TracePath != "" { trace.Stop() } os.Exit(e.exitCode) + + return nil } func printMemStats(ms *runtime.MemStats, logger logutils.Log) { @@ -106,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 @@ -119,17 +131,13 @@ 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`, - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - e.log.Fatalf("Usage: golangci-lint") - } - if err := cmd.Help(); err != nil { - e.log.Fatalf("Can't run help: %s", err) - } + Long: `Smart, fast linters runner.`, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() }, - PersistentPreRun: e.persistentPreRun, - PersistentPostRun: e.persistentPostRun, + PersistentPreRunE: e.persistentPreRun, + PersistentPostRunE: e.persistentPostRun, } initRootFlagSet(rootCmd.PersistentFlags(), e.cfg, e.needVersionOption()) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go index f4716d184..8106dbdbd 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/run.go +++ b/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 { @@ -279,10 +286,11 @@ func (e *Executor) initRun() { Use: "run", Short: "Run the linters", Run: e.executeRun, - PreRun: func(_ *cobra.Command, _ []string) { + PreRunE: func(_ *cobra.Command, _ []string) error { if ok := e.acquireFileLock(); !ok { - e.log.Fatalf("Parallel golangci-lint is running") + return errors.New("parallel golangci-lint is running") } + return nil }, PostRun: func(_ *cobra.Command, _ []string) { e.releaseFileLock() @@ -349,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 @@ -389,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() @@ -473,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: @@ -544,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 @@ -568,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/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go b/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go index 8b48e515b..93e4a8ed9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/commands/version.go @@ -3,6 +3,7 @@ package commands import ( "encoding/json" "fmt" + "os" "strings" "github.com/spf13/cobra" @@ -31,27 +32,28 @@ func initVersionFlagSet(fs *pflag.FlagSet, cfg *config.Config) { func (e *Executor) initVersion() { versionCmd := &cobra.Command{ - Use: "version", - Short: "Version", + Use: "version", + Short: "Version", + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, RunE: func(cmd *cobra.Command, _ []string) error { switch strings.ToLower(e.cfg.Version.Format) { case "short": fmt.Println(e.version) + return nil + case "json": ver := jsonVersion{ Version: e.version, Commit: e.commit, Date: e.date, } - data, err := json.Marshal(&ver) - if err != nil { - return err - } - fmt.Println(string(data)) + return json.NewEncoder(os.Stdout).Encode(&ver) + default: fmt.Printf("golangci-lint has version %s built from %s on %s\n", e.version, e.commit, e.date) + return nil } - return nil }, } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go b/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go index 0f9ac5f61..b2437ec97 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/issues.go @@ -97,7 +97,7 @@ var DefaultExcludePatterns = []ExcludePattern{ }, { ID: "EXC0015", - Pattern: `should have a package comment, unless it's in another file for this package`, + Pattern: `should have a package comment`, Linter: "revive", Why: "Annoying issue about not having a comment. The rare codebase has such comments", }, @@ -188,15 +188,16 @@ func GetDefaultExcludePatternsStrings() []string { return ret } +// TODO(ldez): this behavior must be changed in v2, because this is confusing. func GetExcludePatterns(include []string) []ExcludePattern { - includeMap := make(map[string]bool, len(include)) + includeMap := make(map[string]struct{}, len(include)) for _, inc := range include { - includeMap[inc] = true + includeMap[inc] = struct{}{} } var ret []ExcludePattern for _, p := range DefaultExcludePatterns { - if !includeMap[p.ID] { + if _, ok := includeMap[p.ID]; !ok { ret = append(ret, p) } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go b/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go index b0bc1ac82..76a16b87d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings.go @@ -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, @@ -40,8 +43,8 @@ var defaultLintersSettings = LintersSettings{ Gocognit: GocognitSettings{ MinComplexity: 30, }, - Gocritic: GocriticSettings{ - SettingsPerCheck: map[string]GocriticCheckSettings{}, + Gocritic: GoCriticSettings{ + SettingsPerCheck: map[string]GoCriticCheckSettings{}, }, Godox: GodoxSettings{ Keywords: []string{}, @@ -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, }, @@ -77,7 +92,6 @@ var defaultLintersSettings = LintersSettings{ }, NoLintLint: NoLintLintSettings{ RequireExplanation: false, - AllowLeadingSpace: true, RequireSpecific: false, AllowUnused: false, }, @@ -106,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, }, } @@ -123,6 +140,7 @@ type LintersSettings struct { Depguard DepGuardSettings Dogsled DogsledSettings Dupl DuplSettings + DupWord DupWordSettings Errcheck ErrcheckSettings ErrChkJSON ErrChkJSONSettings ErrorLint ErrorLintSettings @@ -132,9 +150,10 @@ type LintersSettings struct { Forbidigo ForbidigoSettings Funlen FunlenSettings Gci GciSettings + GinkgoLinter GinkgoLinterSettings Gocognit GocognitSettings Goconst GoConstSettings - Gocritic GocriticSettings + Gocritic GoCriticSettings Gocyclo GoCycloSettings Godot GodotSettings Godox GodoxSettings @@ -152,12 +171,15 @@ type LintersSettings struct { Grouper GrouperSettings Ifshort IfshortSettings ImportAs ImportAsSettings + InterfaceBloat InterfaceBloatSettings Ireturn IreturnSettings Lll LllSettings + LoggerCheck LoggerCheckSettings MaintIdx MaintIdxSettings Makezero MakezeroSettings Maligned MalignedSettings Misspell MisspellSettings + MustTag MustTagSettings Nakedret NakedretSettings Nestif NestifSettings NilNil NilNilSettings @@ -168,6 +190,7 @@ type LintersSettings struct { Prealloc PreallocSettings Predeclared PredeclaredSettings Promlinter PromlinterSettings + Reassign ReassignSettings Revive ReviveSettings RowsErrCheck RowsErrCheckSettings Staticcheck StaticCheckSettings @@ -179,6 +202,7 @@ type LintersSettings struct { Thelper ThelperSettings Unparam UnparamSettings Unused StaticCheckSettings + UseStdlibVars UseStdlibVarsSettings Varcheck VarCheckSettings Varnamelen VarnamelenSettings Whitespace WhitespaceSettings @@ -236,6 +260,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"` @@ -259,10 +287,14 @@ 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"` + IgnoreEnumTypes string `mapstructure:"ignore-enum-types"` + PackageScopeOnly bool `mapstructure:"package-scope-only"` + ExplicitExhaustiveMap bool `mapstructure:"explicit-exhaustive-map"` + ExplicitExhaustiveSwitch bool `mapstructure:"explicit-exhaustive-switch"` } type ExhaustiveStructSettings struct { @@ -288,6 +320,13 @@ type GciSettings struct { LocalPrefixes string `mapstructure:"local-prefixes"` // Deprecated Sections []string `mapstructure:"sections"` SkipGenerated bool `mapstructure:"skip-generated"` + CustomOrder bool `mapstructure:"custom-order"` +} + +type GinkgoLinterSettings struct { + SuppressLenAssertion bool `mapstructure:"suppress-len-assertion"` + SuppressNilAssertion bool `mapstructure:"suppress-nil-assertion"` + SuppressErrAssertion bool `mapstructure:"suppress-err-assertion"` } type GocognitSettings struct { @@ -305,6 +344,16 @@ type GoConstSettings struct { IgnoreCalls bool `mapstructure:"ignore-calls"` } +type GoCriticSettings struct { + EnabledChecks []string `mapstructure:"enabled-checks"` + DisabledChecks []string `mapstructure:"disabled-checks"` + EnabledTags []string `mapstructure:"enabled-tags"` + DisabledTags []string `mapstructure:"disabled-tags"` + SettingsPerCheck map[string]GoCriticCheckSettings `mapstructure:"settings"` +} + +type GoCriticCheckSettings map[string]interface{} + type GoCycloSettings struct { MinComplexity int `mapstructure:"min-complexity"` } @@ -324,7 +373,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 { @@ -443,6 +498,10 @@ type ImportAsAlias struct { Alias string } +type InterfaceBloatSettings struct { + Max int `mapstructure:"max"` +} + type IreturnSettings struct { Allow []string `mapstructure:"allow"` Reject []string `mapstructure:"reject"` @@ -453,6 +512,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"` } @@ -470,6 +539,14 @@ type MisspellSettings struct { IgnoreWords []string `mapstructure:"ignore-words"` } +type MustTagSettings struct { + Functions []struct { + Name string `mapstructure:"name"` + Tag string `mapstructure:"tag"` + ArgPos int `mapstructure:"arg-pos"` + } `mapstructure:"functions"` +} + type NakedretSettings struct { MaxFuncLines int `mapstructure:"max-func-lines"` } @@ -488,7 +565,6 @@ type NlreturnSettings struct { type NoLintLintSettings struct { RequireExplanation bool `mapstructure:"require-explanation"` - AllowLeadingSpace bool `mapstructure:"allow-leading-space"` RequireSpecific bool `mapstructure:"require-specific"` AllowNoExplanation []string `mapstructure:"allow-no-explanation"` AllowUnused bool `mapstructure:"allow-unused"` @@ -517,6 +593,10 @@ type PromlinterSettings struct { DisabledLinters []string `mapstructure:"disabled-linters"` } +type ReassignSettings struct { + Patterns []string `mapstructure:"patterns"` +} + type ReviveSettings struct { MaxOpenFiles int `mapstructure:"max-open-files"` IgnoreGeneratedHeader bool `mapstructure:"ignore-generated-header"` @@ -588,6 +668,21 @@ type TenvSettings struct { All bool `mapstructure:"all"` } +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"` + DefaultRPCPath bool `mapstructure:"default-rpc-path"` + OSDevNull bool `mapstructure:"os-dev-null"` + SQLIsolationLevel bool `mapstructure:"sql-isolation-level"` + TLSSignatureScheme bool `mapstructure:"tls-signature-scheme"` + ConstantKind bool `mapstructure:"constant-kind"` + SyslogPriority bool `mapstructure:"syslog-priority"` +} + type UnparamSettings struct { CheckExported bool `mapstructure:"check-exported"` Algo string @@ -624,16 +719,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:"force-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/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings_gocritic.go b/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings_gocritic.go deleted file mode 100644 index 7f6905f5f..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/linters_settings_gocritic.go +++ /dev/null @@ -1,366 +0,0 @@ -package config - -import ( - "fmt" - "sort" - "strings" - - _ "github.com/go-critic/go-critic/checkers" // this import register checkers - "github.com/go-critic/go-critic/framework/linter" - "github.com/pkg/errors" - - "github.com/golangci/golangci-lint/pkg/logutils" -) - -const gocriticDebugKey = "gocritic" - -var ( - gocriticDebugf = logutils.Debug(gocriticDebugKey) - isGocriticDebug = logutils.HaveDebugTag(gocriticDebugKey) - allGocriticCheckers = linter.GetCheckersInfo() - allGocriticCheckerMap = func() map[string]*linter.CheckerInfo { - checkInfoMap := make(map[string]*linter.CheckerInfo) - for _, checkInfo := range allGocriticCheckers { - checkInfoMap[checkInfo.Name] = checkInfo - } - return checkInfoMap - }() -) - -type GocriticCheckSettings map[string]interface{} - -type GocriticSettings struct { - EnabledChecks []string `mapstructure:"enabled-checks"` - DisabledChecks []string `mapstructure:"disabled-checks"` - EnabledTags []string `mapstructure:"enabled-tags"` - DisabledTags []string `mapstructure:"disabled-tags"` - SettingsPerCheck map[string]GocriticCheckSettings `mapstructure:"settings"` - - inferredEnabledChecks map[string]bool -} - -func debugChecksListf(checks []string, format string, args ...interface{}) { - if isGocriticDebug { - prefix := fmt.Sprintf(format, args...) - gocriticDebugf(prefix+" checks (%d): %s", len(checks), sprintStrings(checks)) - } -} - -func stringsSliceToSet(ss []string) map[string]bool { - ret := make(map[string]bool, len(ss)) - for _, s := range ss { - ret[s] = true - } - - return ret -} - -func buildGocriticTagToCheckersMap() map[string][]string { - tagToCheckers := map[string][]string{} - for _, checker := range allGocriticCheckers { - for _, tag := range checker.Tags { - tagToCheckers[tag] = append(tagToCheckers[tag], checker.Name) - } - } - return tagToCheckers -} - -func gocriticCheckerTagsDebugf() { - if !isGocriticDebug { - return - } - - tagToCheckers := buildGocriticTagToCheckersMap() - - allTags := make([]string, 0, len(tagToCheckers)) - for tag := range tagToCheckers { - allTags = append(allTags, tag) - } - sort.Strings(allTags) - - gocriticDebugf("All gocritic existing tags and checks:") - for _, tag := range allTags { - debugChecksListf(tagToCheckers[tag], " tag %q", tag) - } -} - -func (s *GocriticSettings) gocriticDisabledCheckersDebugf() { - if !isGocriticDebug { - return - } - - var disabledCheckers []string - for _, checker := range allGocriticCheckers { - if s.inferredEnabledChecks[strings.ToLower(checker.Name)] { - continue - } - - disabledCheckers = append(disabledCheckers, checker.Name) - } - - if len(disabledCheckers) == 0 { - gocriticDebugf("All checks are enabled") - } else { - debugChecksListf(disabledCheckers, "Final not used") - } -} - -func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) { - gocriticCheckerTagsDebugf() - - enabledByDefaultChecks := getDefaultEnabledGocriticCheckersNames() - debugChecksListf(enabledByDefaultChecks, "Enabled by default") - - disabledByDefaultChecks := getDefaultDisabledGocriticCheckersNames() - debugChecksListf(disabledByDefaultChecks, "Disabled by default") - - enabledChecks := make([]string, 0, len(s.EnabledTags)+len(enabledByDefaultChecks)) - - // EnabledTags - if len(s.EnabledTags) != 0 { - tagToCheckers := buildGocriticTagToCheckersMap() - for _, tag := range s.EnabledTags { - enabledChecks = append(enabledChecks, tagToCheckers[tag]...) - } - debugChecksListf(enabledChecks, "Enabled by config tags %s", sprintStrings(s.EnabledTags)) - } - - if !(len(s.EnabledTags) == 0 && len(s.EnabledChecks) != 0) { - // don't use default checks only if we have no enabled tags and enable some checks manually - enabledChecks = append(enabledChecks, enabledByDefaultChecks...) - } - - // DisabledTags - if len(s.DisabledTags) != 0 { - enabledChecks = filterByDisableTags(enabledChecks, s.DisabledTags, log) - } - - // EnabledChecks - if len(s.EnabledChecks) != 0 { - debugChecksListf(s.EnabledChecks, "Enabled by config") - - alreadyEnabledChecksSet := stringsSliceToSet(enabledChecks) - for _, enabledCheck := range s.EnabledChecks { - if alreadyEnabledChecksSet[enabledCheck] { - log.Warnf("No need to enable check %q: it's already enabled", enabledCheck) - continue - } - enabledChecks = append(enabledChecks, enabledCheck) - } - } - - // DisabledChecks - if len(s.DisabledChecks) != 0 { - debugChecksListf(s.DisabledChecks, "Disabled by config") - - 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) - continue - } - delete(enabledChecksSet, disabledCheck) - } - - enabledChecks = nil - for enabledCheck := range enabledChecksSet { - enabledChecks = append(enabledChecks, enabledCheck) - } - } - - s.inferredEnabledChecks = map[string]bool{} - for _, check := range enabledChecks { - s.inferredEnabledChecks[strings.ToLower(check)] = true - } - - debugChecksListf(enabledChecks, "Final used") - s.gocriticDisabledCheckersDebugf() -} - -func validateStringsUniq(ss []string) error { - set := map[string]bool{} - for _, s := range ss { - _, ok := set[s] - if ok { - return fmt.Errorf("%q occurs multiple times in list", s) - } - set[s] = true - } - - return nil -} - -func intersectStringSlice(s1, s2 []string) []string { - s1Map := make(map[string]struct{}, len(s1)) - for _, s := range s1 { - s1Map[s] = struct{}{} - } - - result := make([]string, 0) - for _, s := range s2 { - if _, exists := s1Map[s]; exists { - result = append(result, s) - } - } - - return result -} - -func (s *GocriticSettings) Validate(log logutils.Log) 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") - } - } else { - if err := validateStringsUniq(s.EnabledTags); err != nil { - return errors.Wrap(err, "validate enabled tags") - } - - tagToCheckers := buildGocriticTagToCheckersMap() - for _, tag := range s.EnabledTags { - if _, ok := tagToCheckers[tag]; !ok { - return fmt.Errorf("gocritic [enabled]tag %q doesn't exist", tag) - } - } - } - - if len(s.DisabledTags) > 0 { - tagToCheckers := buildGocriticTagToCheckersMap() - for _, tag := range s.EnabledTags { - if _, ok := tagToCheckers[tag]; !ok { - return fmt.Errorf("gocritic [disabled]tag %q doesn't exist", tag) - } - } - } - - if err := validateStringsUniq(s.EnabledChecks); err != nil { - return errors.Wrap(err, "validate enabled checks") - } - if err := validateStringsUniq(s.DisabledChecks); err != nil { - return errors.Wrap(err, "validate disabled checks") - } - - if err := s.validateCheckerNames(log); err != nil { - return errors.Wrap(err, "validation failed") - } - - return nil -} - -func (s *GocriticSettings) IsCheckEnabled(name string) bool { - return s.inferredEnabledChecks[strings.ToLower(name)] -} - -func sprintAllowedCheckerNames(allowedNames map[string]bool) string { - namesSlice := make([]string, 0, len(allowedNames)) - for name := range allowedNames { - namesSlice = append(namesSlice, name) - } - return sprintStrings(namesSlice) -} - -func sprintStrings(ss []string) string { - sort.Strings(ss) - return fmt.Sprint(ss) -} - -// getAllCheckerNames returns a map containing all checker names supported by gocritic. -func getAllCheckerNames() map[string]bool { - allCheckerNames := make(map[string]bool, len(allGocriticCheckers)) - for _, checker := range allGocriticCheckers { - allCheckerNames[strings.ToLower(checker.Name)] = true - } - - return allCheckerNames -} - -func isEnabledByDefaultGocriticCheck(info *linter.CheckerInfo) bool { - return !info.HasTag("experimental") && - !info.HasTag("opinionated") && - !info.HasTag("performance") -} - -func getDefaultEnabledGocriticCheckersNames() []string { - var enabled []string - for _, info := range allGocriticCheckers { - enable := isEnabledByDefaultGocriticCheck(info) - if enable { - enabled = append(enabled, info.Name) - } - } - - return enabled -} - -func getDefaultDisabledGocriticCheckersNames() []string { - var disabled []string - for _, info := range allGocriticCheckers { - enable := isEnabledByDefaultGocriticCheck(info) - if !enable { - disabled = append(disabled, info.Name) - } - } - - return disabled -} - -func (s *GocriticSettings) validateCheckerNames(log logutils.Log) error { - allowedNames := getAllCheckerNames() - - for _, name := range s.EnabledChecks { - if !allowedNames[strings.ToLower(name)] { - return fmt.Errorf("enabled checker %s doesn't exist, all existing checkers: %s", - name, sprintAllowedCheckerNames(allowedNames)) - } - } - - for _, name := range s.DisabledChecks { - if !allowedNames[strings.ToLower(name)] { - return fmt.Errorf("disabled checker %s doesn't exist, all existing checkers: %s", - name, sprintAllowedCheckerNames(allowedNames)) - } - } - - for checkName := range s.SettingsPerCheck { - if _, ok := allowedNames[checkName]; !ok { - return fmt.Errorf("invalid setting, checker %s doesn't exist, all existing checkers: %s", - checkName, sprintAllowedCheckerNames(allowedNames)) - } - if !s.IsCheckEnabled(checkName) { - log.Warnf("Gocritic settings were provided for not enabled check %q", checkName) - } - } - - return nil -} - -func (s *GocriticSettings) GetLowercasedParams() map[string]GocriticCheckSettings { - ret := make(map[string]GocriticCheckSettings, len(s.SettingsPerCheck)) - for checker, params := range s.SettingsPerCheck { - ret[strings.ToLower(checker)] = params - } - return ret -} - -func filterByDisableTags(enabledChecks, disableTags []string, log logutils.Log) []string { - enabledChecksSet := stringsSliceToSet(enabledChecks) - for _, enabledCheck := range enabledChecks { - checkInfo, checkInfoExists := allGocriticCheckerMap[enabledCheck] - if !checkInfoExists { - log.Warnf("Gocritic check %q was not exists via filtering disabled tags", enabledCheck) - continue - } - hitTags := intersectStringSlice(checkInfo.Tags, disableTags) - if len(hitTags) != 0 { - delete(enabledChecksSet, enabledCheck) - } - } - debugChecksListf(enabledChecks, "Disabled by config tags %s", sprintStrings(disableTags)) - - enabledChecks = nil - for enabledCheck := range enabledChecksSet { - enabledChecks = append(enabledChecks, enabledCheck) - } - return enabledChecks -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go b/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go index c2c73e6f6..2dfd3c06c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/config/reader.go @@ -79,7 +79,7 @@ func (r *FileReader) parseConfig() error { r.log.Infof("Used config file %s", usedConfigFile) usedConfigDir := filepath.Dir(usedConfigFile) if usedConfigDir, err = filepath.Abs(usedConfigDir); err != nil { - return fmt.Errorf("can't get config directory") + return errors.New("can't get config directory") } r.cfg.cfgDir = usedConfigDir @@ -216,7 +216,7 @@ func (r *FileReader) parseConfigOption() (string, error) { configFile := cfg.Run.Config if cfg.Run.NoConfig && configFile != "" { - return "", fmt.Errorf("can't combine option --config and --no-config") + return "", errors.New("can't combine option --config and --no-config") } if cfg.Run.NoConfig { @@ -225,7 +225,7 @@ func (r *FileReader) parseConfigOption() (string, error) { configFile, err := homedir.Expand(configFile) if err != nil { - return "", fmt.Errorf("failed to expand configuration path") + return "", errors.New("failed to expand configuration path") } return configFile, nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go b/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go new file mode 100644 index 000000000..2a171ecc0 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_unix.go @@ -0,0 +1,8 @@ +//go:build !windows + +package fsutils + +// NormalizePathInRegex it's a noop function on Unix. +func NormalizePathInRegex(path string) string { + return path +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go b/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go new file mode 100644 index 000000000..650aae1e1 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/fsutils/path_windows.go @@ -0,0 +1,28 @@ +//go:build windows + +package fsutils + +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 { + // remove redundant character escape "\/" https://github.com/golangci/golangci-lint/issues/3277 + clean := regexp.MustCompile(`\\+/`). + ReplaceAllStringFunc(path, func(s string) string { + if strings.Count(s, "\\")%2 == 0 { + return s + } + return s[1:] + }) + + return strings.ReplaceAll(clean, "/", separatorToReplace) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go index a4c3913f7..3b40e59bf 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/commons.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go index 38ede810d..f54192a18 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/contextcheck.go @@ -1,17 +1,22 @@ 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" + "github.com/golangci/golangci-lint/pkg/lint/linter" ) func NewContextCheck() *goanalysis.Linter { + analyzer := contextcheck.NewAnalyzer(contextcheck.Configuration{}) + return goanalysis.NewLinter( - "contextcheck", - "check the function whether use a non-inherited context", - []*analysis.Analyzer{contextcheck.NewAnalyzer()}, + analyzer.Name, + analyzer.Doc, + []*analysis.Analyzer{analyzer}, nil, - ).WithLoadMode(goanalysis.LoadModeTypesInfo) + ).WithContextSetter(func(lintCtx *linter.Context) { + analyzer.Run = contextcheck.NewRun(lintCtx.Packages, false) + }).WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go index b9241d183..eb7b0f330 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/depguard.go @@ -10,6 +10,7 @@ import ( "golang.org/x/tools/go/loader" //nolint:staticcheck // require changes in github.com/OpenPeeDeeP/depguard "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" "github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/result" @@ -110,10 +111,15 @@ type guardian struct { } func newGuardian(settings *config.DepGuardSettings) (*guardian, error) { + var ignoreFileRules []string + for _, rule := range settings.IgnoreFileRules { + ignoreFileRules = append(ignoreFileRules, fsutils.NormalizePathInRegex(rule)) + } + dg := &depguard.Depguard{ Packages: settings.Packages, IncludeGoRoot: settings.IncludeGoRoot, - IgnoreFileRules: settings.IgnoreFileRules, + IgnoreFileRules: ignoreFileRules, } var err error diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl.go index 8c8d8fe4f..fe7b12773 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupl.go @@ -55,11 +55,7 @@ func NewDupl(settings *config.DuplSettings) *goanalysis.Linter { } func runDupl(pass *analysis.Pass, settings *config.DuplSettings) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } + fileNames := getFileNames(pass) issues, err := duplAPI.Run(fileNames, settings.Threshold) if err != nil { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/dupword.go new file mode 100644 index 000000000..ae85a6d00 --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go index 778dc004b..a66f95190 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/exhaustive.go @@ -15,10 +15,14 @@ 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.IgnoreEnumTypesFlag: settings.IgnoreEnumTypes, exhaustive.PackageScopeOnlyFlag: settings.PackageScopeOnly, + exhaustive.ExplicitExhaustiveMapFlag: settings.ExplicitExhaustiveMap, + exhaustive.ExplicitExhaustiveSwitchFlag: settings.ExplicitExhaustiveSwitch, }, } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo.go index a8c256b9e..95fb47e47 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/forbidigo.go @@ -64,7 +64,7 @@ func runForbidigo(pass *analysis.Pass, settings *config.ForbidigoSettings) ([]go var issues []goanalysis.Issue for _, file := range pass.Files { - hints, err := forbid.Run(pass.Fset, file) + hints, err := forbid.RunWithConfig(forbidigo.RunConfig{Fset: pass.Fset}, file) if err != nil { return nil, errors.Wrapf(err, "forbidigo linter failed on file %q", file.Name.String()) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go index 72c1776fd..d07c2126d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gci.go @@ -7,6 +7,11 @@ import ( gcicfg "github.com/daixiang0/gci/pkg/config" "github.com/daixiang0/gci/pkg/gci" + "github.com/daixiang0/gci/pkg/io" + "github.com/daixiang0/gci/pkg/log" + "github.com/hexops/gotextdiff" + "github.com/hexops/gotextdiff/myers" + "github.com/hexops/gotextdiff/span" "github.com/pkg/errors" "golang.org/x/tools/go/analysis" @@ -32,6 +37,7 @@ func NewGci(settings *config.GciSettings) *goanalysis.Linter { rawCfg := gcicfg.YamlConfig{ Cfg: gcicfg.BoolConfig{ SkipGenerated: settings.SkipGenerated, + CustomOrder: settings.CustomOrder, }, SectionStrings: settings.Sections, } @@ -41,7 +47,11 @@ func NewGci(settings *config.GciSettings) *goanalysis.Linter { rawCfg.SectionStrings = prefix } - cfg, _ = rawCfg.Parse() + var err error + cfg, err = rawCfg.Parse() + if err != nil { + linterLogger.Fatalf("gci: configuration parsing: %v", err) + } } var lock sync.Mutex @@ -74,14 +84,10 @@ func NewGci(settings *config.GciSettings) *goanalysis.Linter { } func runGci(pass *analysis.Pass, lintCtx *linter.Context, cfg *gcicfg.Config, lock *sync.Mutex) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } + fileNames := getFileNames(pass) var diffs []string - err := gci.DiffFormattedFilesToArray(fileNames, *cfg, &diffs, lock) + err := diffFormattedFilesToArray(fileNames, *cfg, &diffs, lock) if err != nil { return nil, err } @@ -106,6 +112,25 @@ func runGci(pass *analysis.Pass, lintCtx *linter.Context, cfg *gcicfg.Config, lo return issues, nil } +// diffFormattedFilesToArray is a copy of gci.DiffFormattedFilesToArray without io.StdInGenerator. +// gci.DiffFormattedFilesToArray uses gci.processStdInAndGoFilesInPaths that uses io.StdInGenerator but stdin is not active on CI. +// https://github.com/daixiang0/gci/blob/6f5cb16718ba07f0342a58de9b830ec5a6d58790/pkg/gci/gci.go#L63-L75 +// https://github.com/daixiang0/gci/blob/6f5cb16718ba07f0342a58de9b830ec5a6d58790/pkg/gci/gci.go#L80 +func diffFormattedFilesToArray(paths []string, cfg gcicfg.Config, diffs *[]string, lock *sync.Mutex) error { + log.InitLogger() + defer func() { _ = log.L().Sync() }() + + return gci.ProcessFiles(io.GoFilesInPathsGenerator(paths), cfg, func(filePath string, unmodifiedFile, formattedFile []byte) error { + fileURI := span.URIFromPath(filePath) + edits := myers.ComputeEdits(fileURI, string(unmodifiedFile), string(formattedFile)) + unifiedEdits := gotextdiff.ToUnified(filePath, filePath, string(unmodifiedFile), edits) + lock.Lock() + *diffs = append(*diffs, fmt.Sprint(unifiedEdits)) + lock.Unlock() + return nil + }) +} + func getErrorTextForGci(settings config.GciSettings) string { text := "File is not `gci`-ed" @@ -117,7 +142,7 @@ func getErrorTextForGci(settings config.GciSettings) string { text += " with" if settings.SkipGenerated { - text += " -skip-generated" + text += " --skip-generated" } if len(settings.Sections) > 0 { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go new file mode 100644 index 000000000..d97050c2e --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/ginkgolinter.go @@ -0,0 +1,29 @@ +package golinters + +import ( + "github.com/nunnatsa/ginkgolinter" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewGinkgoLinter(cfg *config.GinkgoLinterSettings) *goanalysis.Linter { + a := ginkgolinter.NewAnalyzer() + + cfgMap := make(map[string]map[string]interface{}) + if cfg != nil { + cfgMap[a.Name] = map[string]interface{}{ + "suppress-len-assertion": cfg.SuppressLenAssertion, + "suppress-nil-assertion": cfg.SuppressNilAssertion, + "suppress-err-assertion": cfg.SuppressErrAssertion, + } + } + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + cfgMap, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go index eb27130cc..50a4ca088 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/linter.go @@ -108,7 +108,7 @@ func (lnt *Linter) configureAnalyzer(a *analysis.Analyzer, cfg map[string]interf if f == nil { validFlagNames := allFlagNames(&a.Flags) if len(validFlagNames) == 0 { - return fmt.Errorf("analyzer doesn't have settings") + return errors.New("analyzer doesn't have settings") } return fmt.Errorf("analyzer doesn't have setting %q, valid settings: %v", diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go index c52998fbf..4a52c1100 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go index 50ea64c5c..d6f40a0c4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_action.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage.go index 0a9653b8d..e76b6ab6e 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage.go @@ -121,7 +121,15 @@ func (lp *loadingPackage) loadFromSource(loadMode LoadMode) error { pkg.IllTyped = true - pkg.TypesInfo = newTypesInfo() + pkg.TypesInfo = &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Instances: make(map[*ast.Ident]types.Instance), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Scopes: make(map[ast.Node]*types.Scope), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + } importer := func(path string) (*types.Package, error) { if path == unsafePkgName { @@ -426,6 +434,7 @@ func (lp *loadingPackage) convertError(err error) []packages.Error { // If you see this error message, please file a bug. lp.log.Warnf("Internal error: error %q (%T) without position", err, err) } + return errs } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti.go deleted file mode 100644 index 798add627..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package goanalysis - -import ( - "go/ast" - "go/types" -) - -func newTypesInfo() *types.Info { - return &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Instances: make(map[*ast.Ident]types.Instance), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Scopes: make(map[ast.Node]*types.Scope), - Selections: make(map[*ast.SelectorExpr]*types.Selection), - } -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti_go117.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti_go117.go deleted file mode 100644 index 096ac97c5..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runner_loadingpackage_ti_go117.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build go1.17 && !go1.18 -// +build go1.17,!go1.18 - -package goanalysis - -import ( - "go/ast" - "go/types" -) - -func newTypesInfo() *types.Info { - return &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Scopes: make(map[ast.Node]*types.Scope), - Selections: make(map[*ast.SelectorExpr]*types.Selection), - } -} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go index 7e4cf902e..559fb1392 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goanalysis/runners.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives.go new file mode 100644 index 000000000..2592c8994 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocheckcompilerdirectives.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "4d63.com/gocheckcompilerdirectives/checkcompilerdirectives" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewGoCheckCompilerDirectives() *goanalysis.Linter { + a := checkcompilerdirectives.Analyzer() + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go index 0732bc6aa..0fe67e2b0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gochecknoglobals.go @@ -25,5 +25,5 @@ func NewGochecknoglobals() *goanalysis.Linter { gochecknoglobals.Doc, []*analysis.Analyzer{gochecknoglobals}, linterConfig, - ).WithLoadMode(goanalysis.LoadModeSyntax) + ).WithLoadMode(goanalysis.LoadModeTypesInfo) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go index a53d57662..41fd60090 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gocritic.go @@ -11,31 +11,36 @@ import ( "strings" "sync" + "github.com/go-critic/go-critic/checkers" gocriticlinter "github.com/go-critic/go-critic/framework/linter" + "github.com/pkg/errors" "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/result" ) -const gocriticName = "gocritic" +const goCriticName = "gocritic" -func NewGocritic(settings *config.GocriticSettings, cfg *config.Config) *goanalysis.Linter { +var ( + goCriticDebugf = logutils.Debug(logutils.DebugKeyGoCritic) + isGoCriticDebug = logutils.HaveDebugTag(logutils.DebugKeyGoCritic) +) + +func NewGoCritic(settings *config.GoCriticSettings, cfg *config.Config) *goanalysis.Linter { var mu sync.Mutex var resIssues []goanalysis.Issue - sizes := types.SizesFor("gc", runtime.GOARCH) - - wrapper := goCriticWrapper{ - settings: settings, - cfg: cfg, - sizes: sizes, + wrapper := &goCriticWrapper{ + cfg: cfg, + sizes: types.SizesFor("gc", runtime.GOARCH), } analyzer := &analysis.Analyzer{ - Name: gocriticName, + Name: goCriticName, Doc: goanalysis.TheOnlyanalyzerDoc, Run: func(pass *analysis.Pass) (interface{}, error) { issues, err := wrapper.run(pass) @@ -56,24 +61,56 @@ func NewGocritic(settings *config.GocriticSettings, cfg *config.Config) *goanaly } return goanalysis.NewLinter( - gocriticName, + goCriticName, `Provides diagnostics that check for bugs, performance and style issues. Extensible without recompilation through dynamic rules. Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`, []*analysis.Analyzer{analyzer}, nil, - ).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { - return resIssues - }).WithLoadMode(goanalysis.LoadModeTypesInfo) + ). + WithContextSetter(func(context *linter.Context) { + wrapper.init(settings, context.Log) + }). + WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { + return resIssues + }).WithLoadMode(goanalysis.LoadModeTypesInfo) } type goCriticWrapper struct { - settings *config.GocriticSettings - cfg *config.Config - sizes types.Sizes + settingsWrapper *goCriticSettingsWrapper + cfg *config.Config + sizes types.Sizes + once sync.Once +} + +func (w *goCriticWrapper) init(settings *config.GoCriticSettings, logger logutils.Log) { + if settings == nil { + return + } + + 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() + + 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) { +func (w *goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { + if w.settingsWrapper == nil { + return nil, fmt.Errorf("the settings wrapper is nil") + } + linterCtx := gocriticlinter.NewContext(pass.Fset, w.sizes) enabledCheckers, err := w.buildEnabledCheckers(linterCtx) @@ -93,12 +130,12 @@ func (w goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) { return issues, nil } -func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { - allParams := w.settings.GetLowercasedParams() +func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { + allParams := w.settingsWrapper.getLowerCasedParams() var enabledCheckers []*gocriticlinter.Checker for _, info := range gocriticlinter.GetCheckersInfo() { - if !w.settings.IsCheckEnabled(info.Name) { + if !w.settingsWrapper.isCheckEnabled(info.Name) { continue } @@ -116,38 +153,38 @@ func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) return enabledCheckers, nil } -func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checkers []*gocriticlinter.Checker, +func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checks []*gocriticlinter.Checker, files []*ast.File) []result.Issue { var res []result.Issue for _, f := range files { filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename) linterCtx.SetFileInfo(filename, f) - issues := runGocriticOnFile(linterCtx, f, checkers) + issues := runGocriticOnFile(linterCtx, f, checks) res = append(res, issues...) } return res } -func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers []*gocriticlinter.Checker) []result.Issue { +func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checks []*gocriticlinter.Checker) []result.Issue { var res []result.Issue - for _, c := range checkers { + for _, c := range checks { // All checkers are expected to use *lint.Context // as read-only structure, so no copying is required. for _, warn := range c.Check(f) { - pos := linterCtx.FileSet.Position(warn.Node.Pos()) + pos := linterCtx.FileSet.Position(warn.Pos) issue := result.Issue{ Pos: pos, Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text), - FromLinter: gocriticName, + FromLinter: goCriticName, } if warn.HasQuickFix() { issue.Replacement = &result.Replacement{ Inline: &result.InlineFix{ StartCol: pos.Column - 1, - Length: int(warn.Node.End() - warn.Node.Pos()), + Length: int(warn.Suggestion.To - warn.Suggestion.From), NewString: string(warn.Suggestion.Replacement), }, } @@ -160,7 +197,7 @@ func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers return res } -func (w goCriticWrapper) configureCheckerInfo(info *gocriticlinter.CheckerInfo, allParams map[string]config.GocriticCheckSettings) error { +func (w *goCriticWrapper) configureCheckerInfo(info *gocriticlinter.CheckerInfo, allParams map[string]config.GoCriticCheckSettings) error { params := allParams[strings.ToLower(info.Name)] if params == nil { // no config for this checker return nil @@ -208,7 +245,7 @@ func normalizeCheckerInfoParams(info *gocriticlinter.CheckerInfo) gocriticlinter // but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type. // then we have to convert value types into the expected value types. // Maybe in the future, this kind of conversion will be done in go-critic itself. -func (w goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} { +func (w *goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} { rv := reflect.ValueOf(p) switch rv.Type().Kind() { case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: @@ -222,3 +259,381 @@ func (w goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} return p } } + +// TODO(ldez): rewrite and simplify goCriticSettingsWrapper. + +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, logger logutils.Log) *goCriticSettingsWrapper { + allCheckers := gocriticlinter.GetCheckersInfo() + + allCheckerMap := make(map[string]*gocriticlinter.CheckerInfo) + for _, checkInfo := range allCheckers { + allCheckerMap[checkInfo.Name] = checkInfo + } + + return &goCriticSettingsWrapper{ + GoCriticSettings: settings, + logger: logger, + allCheckers: allCheckers, + allCheckerMap: allCheckerMap, + inferredEnabledChecks: map[string]bool{}, + } +} + +func (s *goCriticSettingsWrapper) buildTagToCheckersMap() map[string][]string { + tagToCheckers := map[string][]string{} + + for _, checker := range s.allCheckers { + for _, tag := range checker.Tags { + tagToCheckers[tag] = append(tagToCheckers[tag], checker.Name) + } + } + + return tagToCheckers +} + +func (s *goCriticSettingsWrapper) checkerTagsDebugf() { + if !isGoCriticDebug { + return + } + + tagToCheckers := s.buildTagToCheckersMap() + + allTags := make([]string, 0, len(tagToCheckers)) + for tag := range tagToCheckers { + allTags = append(allTags, tag) + } + + sort.Strings(allTags) + + goCriticDebugf("All gocritic existing tags and checks:") + for _, tag := range allTags { + debugChecksListf(tagToCheckers[tag], " tag %q", tag) + } +} + +func (s *goCriticSettingsWrapper) disabledCheckersDebugf() { + if !isGoCriticDebug { + return + } + + var disabledCheckers []string + for _, checker := range s.allCheckers { + if s.inferredEnabledChecks[strings.ToLower(checker.Name)] { + continue + } + + disabledCheckers = append(disabledCheckers, checker.Name) + } + + if len(disabledCheckers) == 0 { + goCriticDebugf("All checks are enabled") + } else { + debugChecksListf(disabledCheckers, "Final not used") + } +} + +func (s *goCriticSettingsWrapper) inferEnabledChecks() { + s.checkerTagsDebugf() + + enabledByDefaultChecks := s.getDefaultEnabledCheckersNames() + debugChecksListf(enabledByDefaultChecks, "Enabled by default") + + disabledByDefaultChecks := s.getDefaultDisabledCheckersNames() + debugChecksListf(disabledByDefaultChecks, "Disabled by default") + + enabledChecks := make([]string, 0, len(s.EnabledTags)+len(enabledByDefaultChecks)) + + // EnabledTags + if len(s.EnabledTags) != 0 { + tagToCheckers := s.buildTagToCheckersMap() + for _, tag := range s.EnabledTags { + enabledChecks = append(enabledChecks, tagToCheckers[tag]...) + } + + debugChecksListf(enabledChecks, "Enabled by config tags %s", sprintStrings(s.EnabledTags)) + } + + if !(len(s.EnabledTags) == 0 && len(s.EnabledChecks) != 0) { + // don't use default checks only if we have no enabled tags and enable some checks manually + enabledChecks = append(enabledChecks, enabledByDefaultChecks...) + } + + // DisabledTags + if len(s.DisabledTags) != 0 { + enabledChecks = s.filterByDisableTags(enabledChecks, s.DisabledTags) + } + + // EnabledChecks + if len(s.EnabledChecks) != 0 { + debugChecksListf(s.EnabledChecks, "Enabled by config") + + alreadyEnabledChecksSet := stringsSliceToSet(enabledChecks) + for _, enabledCheck := range s.EnabledChecks { + if alreadyEnabledChecksSet[enabledCheck] { + s.logger.Warnf("%s: no need to enable check %q: it's already enabled", goCriticName, enabledCheck) + continue + } + enabledChecks = append(enabledChecks, enabledCheck) + } + } + + // DisabledChecks + if len(s.DisabledChecks) != 0 { + debugChecksListf(s.DisabledChecks, "Disabled by config") + + enabledChecksSet := stringsSliceToSet(enabledChecks) + for _, disabledCheck := range s.DisabledChecks { + if !enabledChecksSet[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) + } + + enabledChecks = nil + for enabledCheck := range enabledChecksSet { + enabledChecks = append(enabledChecks, enabledCheck) + } + } + + s.inferredEnabledChecks = map[string]bool{} + for _, check := range enabledChecks { + s.inferredEnabledChecks[strings.ToLower(check)] = true + } + + debugChecksListf(enabledChecks, "Final used") + + s.disabledCheckersDebugf() +} + +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") + } + } else { + if err := validateStringsUniq(s.EnabledTags); err != nil { + return errors.Wrap(err, "validate enabled tags") + } + + tagToCheckers := s.buildTagToCheckersMap() + + for _, tag := range s.EnabledTags { + if _, ok := tagToCheckers[tag]; !ok { + return fmt.Errorf("gocritic [enabled]tag %q doesn't exist", tag) + } + } + } + + if len(s.DisabledTags) > 0 { + tagToCheckers := s.buildTagToCheckersMap() + for _, tag := range s.EnabledTags { + if _, ok := tagToCheckers[tag]; !ok { + return fmt.Errorf("gocritic [disabled]tag %q doesn't exist", tag) + } + } + } + + if err := validateStringsUniq(s.EnabledChecks); err != nil { + return errors.Wrap(err, "validate enabled checks") + } + + if err := validateStringsUniq(s.DisabledChecks); err != nil { + return errors.Wrap(err, "validate disabled checks") + } + + if err := s.validateCheckerNames(); err != nil { + return errors.Wrap(err, "validation failed") + } + + return nil +} + +func (s *goCriticSettingsWrapper) isCheckEnabled(name string) bool { + return s.inferredEnabledChecks[strings.ToLower(name)] +} + +// getAllCheckerNames returns a map containing all checker names supported by gocritic. +func (s *goCriticSettingsWrapper) getAllCheckerNames() map[string]bool { + allCheckerNames := make(map[string]bool, len(s.allCheckers)) + + for _, checker := range s.allCheckers { + allCheckerNames[strings.ToLower(checker.Name)] = true + } + + return allCheckerNames +} + +func (s *goCriticSettingsWrapper) getDefaultEnabledCheckersNames() []string { + var enabled []string + + for _, info := range s.allCheckers { + enable := s.isEnabledByDefaultCheck(info) + if enable { + enabled = append(enabled, info.Name) + } + } + + return enabled +} + +func (s *goCriticSettingsWrapper) getDefaultDisabledCheckersNames() []string { + var disabled []string + + for _, info := range s.allCheckers { + enable := s.isEnabledByDefaultCheck(info) + if !enable { + disabled = append(disabled, info.Name) + } + } + + return disabled +} + +func (s *goCriticSettingsWrapper) validateCheckerNames() error { + allowedNames := s.getAllCheckerNames() + + for _, name := range s.EnabledChecks { + if !allowedNames[strings.ToLower(name)] { + return fmt.Errorf("enabled checker %s doesn't exist, all existing checkers: %s", + name, sprintAllowedCheckerNames(allowedNames)) + } + } + + for _, name := range s.DisabledChecks { + if !allowedNames[strings.ToLower(name)] { + return fmt.Errorf("disabled checker %s doesn't exist, all existing checkers: %s", + name, sprintAllowedCheckerNames(allowedNames)) + } + } + + for checkName := range s.SettingsPerCheck { + if _, ok := allowedNames[checkName]; !ok { + return fmt.Errorf("invalid setting, checker %s doesn't exist, all existing checkers: %s", + checkName, sprintAllowedCheckerNames(allowedNames)) + } + + if !s.isCheckEnabled(checkName) { + s.logger.Warnf("%s: settings were provided for not enabled check %q", goCriticName, checkName) + } + } + + return nil +} + +func (s *goCriticSettingsWrapper) getLowerCasedParams() map[string]config.GoCriticCheckSettings { + ret := make(map[string]config.GoCriticCheckSettings, len(s.SettingsPerCheck)) + + for checker, params := range s.SettingsPerCheck { + ret[strings.ToLower(checker)] = params + } + + return ret +} + +func (s *goCriticSettingsWrapper) filterByDisableTags(enabledChecks, disableTags []string) []string { + enabledChecksSet := stringsSliceToSet(enabledChecks) + + for _, enabledCheck := range enabledChecks { + checkInfo, checkInfoExists := s.allCheckerMap[enabledCheck] + if !checkInfoExists { + s.logger.Warnf("%s: check %q was not exists via filtering disabled tags", goCriticName, enabledCheck) + continue + } + + hitTags := intersectStringSlice(checkInfo.Tags, disableTags) + if len(hitTags) != 0 { + delete(enabledChecksSet, enabledCheck) + } + } + + debugChecksListf(enabledChecks, "Disabled by config tags %s", sprintStrings(disableTags)) + + enabledChecks = nil + for enabledCheck := range enabledChecksSet { + enabledChecks = append(enabledChecks, enabledCheck) + } + + return enabledChecks +} + +func (s *goCriticSettingsWrapper) isEnabledByDefaultCheck(info *gocriticlinter.CheckerInfo) bool { + return !info.HasTag("experimental") && + !info.HasTag("opinionated") && + !info.HasTag("performance") +} + +func validateStringsUniq(ss []string) error { + set := map[string]bool{} + + for _, s := range ss { + _, ok := set[s] + if ok { + return fmt.Errorf("%q occurs multiple times in list", s) + } + set[s] = true + } + + return nil +} + +func intersectStringSlice(s1, s2 []string) []string { + s1Map := make(map[string]struct{}, len(s1)) + + for _, s := range s1 { + s1Map[s] = struct{}{} + } + + results := make([]string, 0) + for _, s := range s2 { + if _, exists := s1Map[s]; exists { + results = append(results, s) + } + } + + return results +} + +func sprintAllowedCheckerNames(allowedNames map[string]bool) string { + namesSlice := make([]string, 0, len(allowedNames)) + + for name := range allowedNames { + namesSlice = append(namesSlice, name) + } + + return sprintStrings(namesSlice) +} + +func sprintStrings(ss []string) string { + sort.Strings(ss) + return fmt.Sprint(ss) +} + +func debugChecksListf(checks []string, format string, args ...interface{}) { + if !isGoCriticDebug { + return + } + + goCriticDebugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), sprintStrings(checks)) +} + +func stringsSliceToSet(ss []string) map[string]bool { + ret := make(map[string]bool, len(ss)) + for _, s := range ss { + ret[s] = true + } + + return ret +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go index 72322fa71..93ca7577a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/godot.go @@ -30,7 +30,7 @@ func NewGodot(settings *config.GodotSettings) *goanalysis.Linter { // Convert deprecated setting // todo(butuzov): remove on v2 release - if settings.CheckAll { // nolint:staticcheck // Keep for retro-compatibility. + if settings.CheckAll { //nolint:staticcheck // Keep for retro-compatibility. dotSettings.Scope = godot.AllScope } } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go index 1d50bfc55..112f422ff 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt.go @@ -53,16 +53,17 @@ func NewGofmt(settings *config.GoFmtSettings) *goanalysis.Linter { } func runGofmt(lintCtx *linter.Context, pass *analysis.Pass, settings *config.GoFmtSettings) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) + 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/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go index e92417429..59f4f4590 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofmt_common.go +++ b/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 != "" { @@ -239,7 +242,7 @@ func extractIssuesFromPatch(patch string, lintCtx *linter.Context, linterName st } if len(diffs) == 0 { - return nil, fmt.Errorf("got no diffs from patch parser: %v", diffs) + return nil, fmt.Errorf("got no diffs from patch parser: %v", patch) } var issues []result.Issue diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go index 60d97b944..312dfd6d9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gofumpt.go @@ -73,11 +73,7 @@ func NewGofumpt(settings *config.GofumptSettings) *goanalysis.Linter { } func runGofumpt(lintCtx *linter.Context, pass *analysis.Pass, diff differ, options format.Options) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } + fileNames := getFileNames(pass) var issues []goanalysis.Issue diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go index e59ee3dd5..97ad6d460 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/goimports.go @@ -27,14 +27,15 @@ func NewGoimports(settings *config.GoImportsSettings) *goanalysis.Linter { return goanalysis.NewLinter( goimportsName, - "In addition to fixing imports, goimports also formats your code in the same style as gofmt.", + "Check import statements are formatted according to the 'goimport' command. "+ + "Reformat imports in autofix mode.", []*analysis.Analyzer{analyzer}, nil, ).WithContextSetter(func(lintCtx *linter.Context) { 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,12 +55,8 @@ func NewGoimports(settings *config.GoImportsSettings) *goanalysis.Linter { }).WithLoadMode(goanalysis.LoadModeSyntax) } -func runGoiImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } +func runGoImports(lintCtx *linter.Context, pass *analysis.Pass) ([]goanalysis.Issue, error) { + fileNames := getFileNames(pass) var issues []goanalysis.Issue diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go index 76dd67012..e21658d5d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/gomodguard.go @@ -73,12 +73,7 @@ func NewGomodguard(settings *config.GoModGuardSettings) *goanalysis.Linter { } analyzer.Run = func(pass *analysis.Pass) (interface{}, error) { - var files []string - for _, file := range pass.Files { - files = append(files, pass.Fset.PositionFor(file.Pos(), false).Filename) - } - - gomodguardIssues := processor.ProcessFiles(files) + gomodguardIssues := processor.ProcessFiles(getFileNames(pass)) mu.Lock() defer mu.Unlock() diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go index 3f005c1d5..afed08214 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/govet.go @@ -37,6 +37,7 @@ import ( "golang.org/x/tools/go/analysis/passes/structtag" "golang.org/x/tools/go/analysis/passes/testinggoroutine" "golang.org/x/tools/go/analysis/passes/tests" + "golang.org/x/tools/go/analysis/passes/timeformat" "golang.org/x/tools/go/analysis/passes/unmarshal" "golang.org/x/tools/go/analysis/passes/unreachable" "golang.org/x/tools/go/analysis/passes/unsafeptr" @@ -80,6 +81,7 @@ var ( structtag.Analyzer, testinggoroutine.Analyzer, tests.Analyzer, + timeformat.Analyzer, unmarshal.Analyzer, unreachable.Analyzer, unsafeptr.Analyzer, @@ -87,7 +89,7 @@ var ( unusedwrite.Analyzer, } - // https://github.com/golang/go/blob/879db69ce2de814bc3203c39b45617ba51cc5366/src/cmd/vet/main.go#L40-L68 + // https://github.com/golang/go/blob/9f834a559c9ed6cdf883e29b36e21e5f956df74f/src/cmd/vet/main.go#L46-L76 defaultAnalyzers = []*analysis.Analyzer{ asmdecl.Analyzer, assign.Analyzer, @@ -112,6 +114,7 @@ var ( structtag.Analyzer, testinggoroutine.Analyzer, tests.Analyzer, + timeformat.Analyzer, unmarshal.Analyzer, unreachable.Analyzer, unsafeptr.Analyzer, @@ -155,11 +158,6 @@ func analyzersFromConfig(settings *config.GovetSettings) []*analysis.Analyzer { } func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers []*analysis.Analyzer) bool { - if (name == nilness.Analyzer.Name || name == unusedwrite.Analyzer.Name) && - config.IsGreaterThanOrEqualGo118(cfg.Go) { - return false - } - if cfg.EnableAll { for _, n := range cfg.Disable { if n == name { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas.go index d1f042829..1917bbb0c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/importas.go @@ -4,7 +4,7 @@ import ( "fmt" "strconv" - "github.com/julz/importas" // nolint: misspell + "github.com/julz/importas" //nolint:misspell "golang.org/x/tools/go/analysis" "github.com/golangci/golangci-lint/pkg/config" @@ -25,7 +25,7 @@ func NewImportAs(settings *config.ImportAsSettings) *goanalysis.Linter { return } if len(settings.Alias) == 0 { - lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") // nolint: misspell + lintCtx.Log.Infof("importas settings found, but no aliases listed. List aliases under alias: key.") //nolint:misspell } if err := analyzer.Flags.Set("no-unaliased", strconv.FormatBool(settings.NoUnaliased)); err != nil { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go new file mode 100644 index 000000000..044c96f3b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/interfacebloat.go @@ -0,0 +1,29 @@ +package golinters + +import ( + "github.com/sashamelentyev/interfacebloat/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewInterfaceBloat(settings *config.InterfaceBloatSettings) *goanalysis.Linter { + a := analyzer.New() + + var cfg map[string]map[string]interface{} + if settings != nil { + cfg = map[string]map[string]interface{}{ + a.Name: { + analyzer.InterfaceMaxMethodsFlag: settings.Max, + }, + } + } + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + cfg, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll.go index 65d4c15a3..551ff98a2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/lll.go @@ -56,11 +56,7 @@ func NewLLL(settings *config.LllSettings) *goanalysis.Linter { } func runLll(pass *analysis.Pass, settings *config.LllSettings) ([]goanalysis.Issue, error) { - var fileNames []string - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } + fileNames := getFileNames(pass) spaces := strings.Repeat(" ", settings.TabWidth) @@ -88,11 +84,29 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r } defer f.Close() - lineNumber := 1 + lineNumber := 0 + multiImportEnabled := false + scanner := bufio.NewScanner(f) for scanner.Scan() { + lineNumber++ + line := scanner.Text() - line = strings.Replace(line, "\t", tabSpaces, -1) + line = strings.ReplaceAll(line, "\t", tabSpaces) + + if strings.HasPrefix(line, "import") { + multiImportEnabled = strings.HasSuffix(line, "(") + continue + } + + if multiImportEnabled { + if line == ")" { + multiImportEnabled = false + } + + continue + } + lineLen := utf8.RuneCountInString(line) if lineLen > maxLineLen { res = append(res, result.Issue{ @@ -104,7 +118,6 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r FromLinter: lllName, }) } - lineNumber++ } if err := scanner.Err(); err != nil { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/loggercheck.go new file mode 100644 index 000000000..fc29127c3 --- /dev/null +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go index 47eb7a7b9..b5cc5c8a8 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/misspell.go @@ -61,12 +61,7 @@ func NewMisspell(settings *config.MisspellSettings) *goanalysis.Linter { } func runMisspell(lintCtx *linter.Context, pass *analysis.Pass, replacer *misspell.Replacer) ([]goanalysis.Issue, error) { - var fileNames []string - - for _, f := range pass.Files { - pos := pass.Fset.PositionFor(f.Pos(), false) - fileNames = append(fileNames, pos.Filename) - } + fileNames := getFileNames(pass) var issues []goanalysis.Issue for _, filename := range fileNames { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag.go new file mode 100644 index 000000000..75500b5ab --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/musttag.go @@ -0,0 +1,29 @@ +package golinters + +import ( + "github.com/junk1tm/musttag" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewMustTag(setting *config.MustTagSettings) *goanalysis.Linter { + var funcs []musttag.Func + + if setting != nil { + for _, fn := range setting.Functions { + funcs = append(funcs, musttag.Func{ + Name: fn.Name, + Tag: fn.Tag, + ArgPos: fn.ArgPos, + }) + } + } + + a := musttag.New(funcs...) + + return goanalysis. + NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint.go index 62b8064ba..a809f4499 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint.go @@ -57,9 +57,6 @@ func runNoLintLint(pass *analysis.Pass, settings *config.NoLintLintSettings) ([] if settings.RequireExplanation { needs |= nolintlint.NeedsExplanation } - if !settings.AllowLeadingSpace { - needs |= nolintlint.NeedsMachineOnly - } if settings.RequireSpecific { needs |= nolintlint.NeedsSpecific } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/README.md b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/README.md index 3d440d5a5..1643df7a5 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/README.md +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/README.md @@ -1,17 +1,17 @@ # nolintlint -nolintlint is a Go static analysis tool to find ill-formed or insufficiently explained `// nolint` directives for golangci -(or any other linter, using th ) +nolintlint is a Go static analysis tool to find ill-formed or insufficiently explained `//nolint` directives for golangci-lint +(or any other linter, using this package) ## Purpose To ensure that lint exceptions have explanations. Consider the case below: ```Go -import "crypto/md5" //nolint +import "crypto/md5" //nolint:all func hash(data []byte) []byte { - return md5.New().Sum(data) //nolint + return md5.New().Sum(data) //nolint:all } ``` @@ -27,5 +27,5 @@ func hash(data []byte) []byte { ``` `nolintlint` can also identify cases where you may have written `// nolint`. Finally `nolintlint`, can also enforce that you -use the machine-readable nolint directive format `//nolint` and that you mention what linter is being suppressed, as shown above when we write `//nolint:gosec`. +use the machine-readable nolint directive format `//nolint:all` and that you mention what linter is being suppressed, as shown above when we write `//nolint:gosec`. diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go index 064fd61a6..9c6b10f38 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/nolintlint/nolintlint.go @@ -152,7 +152,7 @@ func NewLinter(needs Needs, excludes []string) (*Linter, error) { } return &Linter{ - needs: needs, + needs: needs | NeedsMachineOnly, excludeByLinter: excludeByName, }, nil } @@ -184,12 +184,14 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { leadingSpace = leadingSpaceMatches[1] } - directiveWithOptionalLeadingSpace := comment.Text + directiveWithOptionalLeadingSpace := "//" if len(leadingSpace) > 0 { - split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], "//") - directiveWithOptionalLeadingSpace = "// " + strings.TrimSpace(split[1]) + directiveWithOptionalLeadingSpace += " " } + split := strings.Split(strings.SplitN(comment.Text, ":", 2)[0], "//") + directiveWithOptionalLeadingSpace += strings.TrimSpace(split[1]) + pos := fset.Position(comment.Pos()) end := fset.Position(comment.End()) @@ -227,8 +229,9 @@ func (l Linter) Run(fset *token.FileSet, nodes ...ast.Node) ([]Issue, error) { } lintersText, explanation := fullMatches[1], fullMatches[2] + var linters []string - if len(lintersText) > 0 { + if len(lintersText) > 0 && !strings.HasPrefix(lintersText, "all") { lls := strings.Split(lintersText, ",") linters = make([]string, 0, len(lls)) rangeStart := (pos.Column - 1) + len("//") + len(leadingSpace) + len("nolint:") diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go index 5f50a3940..55af7350a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/paralleltest.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go new file mode 100644 index 000000000..bc1b93a54 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/reassign.go @@ -0,0 +1,32 @@ +package golinters + +import ( + "fmt" + "strings" + + "github.com/curioswitch/go-reassign" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewReassign(settings *config.ReassignSettings) *goanalysis.Linter { + a := reassign.NewAnalyzer() + + var cfg map[string]map[string]interface{} + if settings != nil && len(settings.Patterns) > 0 { + cfg = map[string]map[string]interface{}{ + a.Name: { + reassign.FlagPattern: fmt.Sprintf("^(%s)$", strings.Join(settings.Patterns, "|")), + }, + } + } + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + cfg, + ).WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go index 6384f502c..faa9e0243 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/revive.go +++ b/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 { @@ -74,11 +74,7 @@ func NewRevive(settings *config.ReviveSettings) *goanalysis.Linter { } func runRevive(lintCtx *linter.Context, pass *analysis.Pass, settings *config.ReviveSettings) ([]goanalysis.Issue, error) { - var files []string - for _, file := range pass.Files { - files = append(files, pass.Fset.PositionFor(file.Pos(), false).Filename) - } - packages := [][]string{files} + packages := [][]string{getFileNames(pass)} conf, err := getReviveConfig(settings) if err != nil { @@ -325,6 +321,7 @@ var allRules = append([]lint.Rule{ &rule.TimeEqualRule{}, &rule.BannedCharsRule{}, &rule.OptimizeOperandsOrderRule{}, + &rule.DataRaceRule{}, }, defaultRules...) const defaultConfidence = 0.8 diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go index e54cf8e8b..0eb21ec9c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/staticcheck_common.go +++ b/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 @@ -98,7 +98,8 @@ func staticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config { } // https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477 -// nolint // Keep the original source code. +// +//nolint:gocritic // Keep the original source code. func filterAnalyzerNames(analyzers []string, checks []string) map[string]bool { allowedChecks := map[string]bool{} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle.go index 275670e10..67c14cbd4 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/tagliatelle.go @@ -11,8 +11,9 @@ import ( func NewTagliatelle(settings *config.TagliatelleSettings) *goanalysis.Linter { cfg := tagliatelle.Config{ Rules: map[string]string{ - "json": "camel", - "yaml": "camel", + "json": "camel", + "yaml": "camel", + "header": "header", }, } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go new file mode 100644 index 000000000..3333593a6 --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/testableexamples.go @@ -0,0 +1,19 @@ +package golinters + +import ( + "github.com/maratori/testableexamples/pkg/testableexamples" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewTestableexamples() *goanalysis.Linter { + a := testableexamples.NewAnalyzer() + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + nil, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go index 35b436011..d46469054 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/unused.go @@ -63,25 +63,19 @@ func runUnused(pass *analysis.Pass) ([]goanalysis.Issue, error) { return nil, err } - sr := unused.Serialize(pass, res.(unused.Result), pass.Fset) - used := make(map[string]bool) - for _, obj := range sr.Used { + for _, obj := range res.(unused.Result).Used { used[fmt.Sprintf("%s %d %s", obj.Position.Filename, obj.Position.Line, obj.Name)] = true } var issues []goanalysis.Issue // Inspired by https://github.com/dominikh/go-tools/blob/d694aadcb1f50c2d8ac0a1dd06217ebb9f654764/lintcmd/lint.go#L177-L197 - for _, object := range sr.Unused { + for _, object := range res.(unused.Result).Unused { if object.Kind == "type param" { continue } - if object.InGenerated { - continue - } - key := fmt.Sprintf("%s %d %s", object.Position.Filename, object.Position.Line, object.Name) if used[key] { continue diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go new file mode 100644 index 000000000..0ea4b563b --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/usestdlibvars.go @@ -0,0 +1,38 @@ +package golinters + +import ( + "github.com/sashamelentyev/usestdlibvars/pkg/analyzer" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewUseStdlibVars(cfg *config.UseStdlibVarsSettings) *goanalysis.Linter { + a := analyzer.New() + + cfgMap := make(map[string]map[string]interface{}) + if cfg != nil { + cfgMap[a.Name] = map[string]interface{}{ + analyzer.ConstantKindFlag: cfg.ConstantKind, + analyzer.CryptoHashFlag: cfg.CryptoHash, + analyzer.HTTPMethodFlag: cfg.HTTPMethod, + analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode, + analyzer.OSDevNullFlag: cfg.OSDevNull, + analyzer.RPCDefaultPathFlag: cfg.DefaultRPCPath, + analyzer.SQLIsolationLevelFlag: cfg.SQLIsolationLevel, + analyzer.SyslogPriorityFlag: cfg.SyslogPriority, + analyzer.TimeLayoutFlag: cfg.TimeLayout, + analyzer.TimeMonthFlag: cfg.TimeMonth, + analyzer.TimeWeekdayFlag: cfg.TimeWeekday, + analyzer.TLSSignatureSchemeFlag: cfg.TLSSignatureScheme, + } + } + + return goanalysis.NewLinter( + a.Name, + a.Doc, + []*analysis.Analyzer{a}, + cfgMap, + ).WithLoadMode(goanalysis.LoadModeSyntax) +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/util.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/util.go index 1940f30e3..1044567a9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/util.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/util.go @@ -2,8 +2,11 @@ package golinters import ( "fmt" + "path/filepath" "strings" + "golang.org/x/tools/go/analysis" + "github.com/golangci/golangci-lint/pkg/config" ) @@ -22,3 +25,17 @@ func formatCodeBlock(code string, _ *config.Config) string { return fmt.Sprintf("```\n%s\n```", code) } + +func getFileNames(pass *analysis.Pass) []string { + var fileNames []string + for _, f := range pass.Files { + fileName := pass.Fset.PositionFor(f.Pos(), true).Filename + ext := filepath.Ext(fileName) + if ext != "" && ext != ".go" { + // position has been adjusted to a non-go file, revert to original file + fileName = pass.Fset.PositionFor(f.Pos(), false).Filename + } + fileNames = append(fileNames, fileName) + } + return fileNames +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go b/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go index 0b10798eb..4bc702447 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/golinters/wsl.go @@ -19,22 +19,21 @@ 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.AllowCuddleDeclaration = settings.AllowCuddleDeclaration + conf.AllowCuddleWithCalls = settings.AllowCuddleWithCalls + conf.AllowCuddleWithRHS = settings.AllowCuddleWithRHS conf.ForceCuddleErrCheckAndAssign = settings.ForceCuddleErrCheckAndAssign - conf.ForceCaseTrailingWhitespaceLimit = settings.ForceCaseTrailingWhitespaceLimit + conf.ErrorVariableNames = settings.ErrorVariableNames conf.ForceExclusiveShortDeclarations = settings.ForceExclusiveShortDeclarations } @@ -42,7 +41,7 @@ func NewWSL(settings *config.WSLSettings) *goanalysis.Linter { 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 @@ -67,15 +66,11 @@ func NewWSL(settings *config.WSLSettings) *goanalysis.Linter { } func runWSL(pass *analysis.Pass, conf *wsl.Configuration) []goanalysis.Issue { - var files = make([]string, 0, len(pass.Files)) - for _, file := range pass.Files { - files = append(files, pass.Fset.PositionFor(file.Pos(), false).Filename) - } - if conf == nil { return nil } + files := getFileNames(pass) wslErrors, _ := wsl.NewProcessorWithConfig(*conf).ProcessFiles(files) if len(wslErrors) == 0 { return nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go b/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go index 1c05b9805..4873f3f96 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/goutil/env.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go index 01e219691..7d3b2260a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/linter/linter.go @@ -21,8 +21,8 @@ type Noop struct { } func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) { - lintCtx.Log.Warnf("%s is disabled because of go1.18."+ - " You can track the evolution of the go1.18 support by following the https://github.com/golangci/golangci-lint/issues/2649.", n.name) + lintCtx.Log.Warnf("%s is disabled because of generics."+ + " You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649.", n.name) return nil, nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go index 907c1c4db..92615b57a 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/enabled_set.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go index b55d05a4e..6f406f7d2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/manager.go @@ -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 @@ -117,9 +118,10 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { forbidigoCfg *config.ForbidigoSettings funlenCfg *config.FunlenSettings gciCfg *config.GciSettings + ginkgolinterCfg *config.GinkgoLinterSettings gocognitCfg *config.GocognitSettings goconstCfg *config.GoConstSettings - gocriticCfg *config.GocriticSettings + gocriticCfg *config.GoCriticSettings gocycloCfg *config.GoCycloSettings godotCfg *config.GodotSettings godoxCfg *config.GodoxSettings @@ -137,12 +139,15 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { grouperCfg *config.GrouperSettings ifshortCfg *config.IfshortSettings importAsCfg *config.ImportAsSettings + interfaceBloatCfg *config.InterfaceBloatSettings ireturnCfg *config.IreturnSettings lllCfg *config.LllSettings + loggerCheckCfg *config.LoggerCheckSettings maintIdxCfg *config.MaintIdxSettings makezeroCfg *config.MakezeroSettings malignedCfg *config.MalignedSettings misspellCfg *config.MisspellSettings + musttagCfg *config.MustTagSettings nakedretCfg *config.NakedretSettings nestifCfg *config.NestifSettings nilNilCfg *config.NilNilSettings @@ -153,6 +158,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { preallocCfg *config.PreallocSettings predeclaredCfg *config.PredeclaredSettings promlinterCfg *config.PromlinterSettings + reassignCfg *config.ReassignSettings reviveCfg *config.ReviveSettings rowserrcheckCfg *config.RowsErrCheckSettings staticcheckCfg *config.StaticCheckSettings @@ -164,6 +170,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { thelperCfg *config.ThelperSettings unparamCfg *config.UnparamSettings unusedCfg *config.StaticCheckSettings + usestdlibvars *config.UseStdlibVarsSettings varcheckCfg *config.VarCheckSettings varnamelenCfg *config.VarnamelenSettings whitespaceCfg *config.WhitespaceSettings @@ -179,6 +186,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 @@ -188,6 +196,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { forbidigoCfg = &m.cfg.LintersSettings.Forbidigo funlenCfg = &m.cfg.LintersSettings.Funlen gciCfg = &m.cfg.LintersSettings.Gci + ginkgolinterCfg = &m.cfg.LintersSettings.GinkgoLinter gocognitCfg = &m.cfg.LintersSettings.Gocognit goconstCfg = &m.cfg.LintersSettings.Goconst gocriticCfg = &m.cfg.LintersSettings.Gocritic @@ -208,12 +217,15 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { grouperCfg = &m.cfg.LintersSettings.Grouper ifshortCfg = &m.cfg.LintersSettings.Ifshort importAsCfg = &m.cfg.LintersSettings.ImportAs + 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 misspellCfg = &m.cfg.LintersSettings.Misspell + musttagCfg = &m.cfg.LintersSettings.MustTag nakedretCfg = &m.cfg.LintersSettings.Nakedret nestifCfg = &m.cfg.LintersSettings.Nestif nilNilCfg = &m.cfg.LintersSettings.NilNil @@ -224,6 +236,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { parallelTestCfg = &m.cfg.LintersSettings.ParallelTest predeclaredCfg = &m.cfg.LintersSettings.Predeclared promlinterCfg = &m.cfg.LintersSettings.Promlinter + reassignCfg = &m.cfg.LintersSettings.Reassign reviveCfg = &m.cfg.LintersSettings.Revive rowserrcheckCfg = &m.cfg.LintersSettings.RowsErrCheck staticcheckCfg = &m.cfg.LintersSettings.Staticcheck @@ -288,8 +301,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.18.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetPerformance, linter.PresetBugs). - WithURL("https://github.com/timakin/bodyclose"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/timakin/bodyclose"), linter.NewConfig(golinters.NewContainedCtx()). WithSince("1.44.0"). @@ -300,8 +312,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.43.0"). WithPresets(linter.PresetBugs). WithLoadForGoAnalysis(). - WithURL("https://github.com/sylvia7788/contextcheck"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/kkHAIKE/contextcheck"), linter.NewConfig(golinters.NewCyclop(cyclopCfg)). WithSince("v1.37.0"). @@ -318,7 +329,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.0.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetUnused). - WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode"), + WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode"). + Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), linter.NewConfig(golinters.NewDepguard(depGuardCfg)). WithSince("v1.4.0"). @@ -335,6 +347,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). @@ -416,15 +434,26 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetFormatting, linter.PresetImport). WithURL("https://github.com/daixiang0/gci"), + linter.NewConfig(golinters.NewGinkgoLinter(ginkgolinterCfg)). + WithSince("v1.51.0"). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/nunnatsa/ginkgolinter"), + + linter.NewConfig(golinters.NewGoCheckCompilerDirectives()). + WithSince("v1.51.0"). + WithPresets(linter.PresetBugs). + WithURL("https://github.com/leighmcculloch/gocheckcompilerdirectives"), + linter.NewConfig(golinters.NewGochecknoglobals()). WithSince("v1.12.0"). WithPresets(linter.PresetStyle). + WithLoadForGoAnalysis(). WithURL("https://github.com/leighmcculloch/gochecknoglobals"), linter.NewConfig(golinters.NewGochecknoinits()). WithSince("v1.12.0"). - WithPresets(linter.PresetStyle). - WithURL("https://github.com/leighmcculloch/gochecknoinits"), + WithPresets(linter.PresetStyle), linter.NewConfig(golinters.NewGocognit(gocognitCfg)). WithSince("v1.20.0"). @@ -436,7 +465,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithURL("https://github.com/jgautheron/goconst"), - linter.NewConfig(golinters.NewGocritic(gocriticCfg, m.cfg)). + linter.NewConfig(golinters.NewGoCritic(gocriticCfg, m.cfg)). WithSince("v1.12.0"). WithPresets(linter.PresetStyle, linter.PresetMetaLinter). WithLoadForGoAnalysis(). @@ -468,7 +497,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.0.0"). WithPresets(linter.PresetFormatting). WithAutoFix(). - WithURL("https://golang.org/cmd/gofmt/"), + WithURL("https://pkg.go.dev/cmd/gofmt"), linter.NewConfig(golinters.NewGofumpt(gofumptCfg)). WithSince("v1.28.0"). @@ -485,7 +514,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.20.0"). WithPresets(linter.PresetFormatting, linter.PresetImport). WithAutoFix(). - WithURL("https://godoc.org/golang.org/x/tools/cmd/goimports"), + WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"), linter.NewConfig(golinters.NewGolint(golintCfg)). WithSince("v1.0.0"). @@ -533,7 +562,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithLoadForGoAnalysis(). WithPresets(linter.PresetBugs, linter.PresetMetaLinter). WithAlternativeNames("vet", "vetshadow"). - WithURL("https://golang.org/cmd/vet/"), + WithURL("https://pkg.go.dev/cmd/vet"), linter.NewConfig(golinters.NewGrouper(grouperCfg)). WithSince("v1.44.0"). @@ -543,7 +572,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewIfshort(ifshortCfg)). WithSince("v1.36.0"). WithPresets(linter.PresetStyle). - WithURL("https://github.com/esimonov/ifshort"), + WithURL("https://github.com/esimonov/ifshort"). + Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""), linter.NewConfig(golinters.NewImportAs(importAsCfg)). WithSince("v1.38.0"). @@ -556,13 +586,17 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetUnused). WithURL("https://github.com/gordonklaus/ineffassign"), + linter.NewConfig(golinters.NewInterfaceBloat(interfaceBloatCfg)). + WithSince("v1.49.0"). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/sashamelentyev/interfacebloat"), + linter.NewConfig(golinters.NewInterfacer()). WithSince("v1.0.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetStyle). WithURL("https://github.com/mvdan/interfacer"). - Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", ""). - WithNoopFallback(m.cfg), + Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", ""), linter.NewConfig(golinters.NewIreturn(ireturnCfg)). WithSince("v1.43.0"). @@ -574,6 +608,13 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.8.0"). WithPresets(linter.PresetStyle), + linter.NewConfig(golinters.NewLoggerCheck(loggerCheckCfg)). + WithSince("v1.49.0"). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetStyle, linter.PresetBugs). + WithAlternativeNames("logrlint"). + WithURL("https://github.com/timonwong/loggercheck"), + linter.NewConfig(golinters.NewMaintIdx(maintIdxCfg)). WithSince("v1.44.0"). WithPresets(linter.PresetComplexity). @@ -598,6 +639,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithAutoFix(). WithURL("https://github.com/client9/misspell"), + linter.NewConfig(golinters.NewMustTag(musttagCfg)). + WithSince("v1.51.0"). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetStyle, linter.PresetBugs). + WithURL("https://github.com/junk1tm/musttag"), + linter.NewConfig(golinters.NewNakedret(nakedretCfg)). WithSince("v1.19.0"). WithPresets(linter.PresetStyle). @@ -612,8 +659,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.38.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetBugs). - WithURL("https://github.com/gostaticanalysis/nilerr"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/gostaticanalysis/nilerr"), linter.NewConfig(golinters.NewNilNil(nilNilCfg)). WithSince("v1.43.0"). @@ -630,8 +676,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.28.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetPerformance, linter.PresetBugs). - WithURL("https://github.com/sonatard/noctx"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/sonatard/noctx"), linter.NewConfig(golinters.NewNoNamedReturns(noNamedReturnsCfg)). WithSince("v1.46.0"). @@ -642,7 +687,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.NewNoSnakeCase()). WithSince("v1.47.0"). WithPresets(linter.PresetStyle). - WithURL("https://github.com/sivchari/nosnakecase"), + WithURL("https://github.com/sivchari/nosnakecase"). + Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive(var-naming)"), linter.NewConfig(golinters.NewNoSprintfHostPort()). WithSince("v1.46.0"). @@ -670,6 +716,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithPresets(linter.PresetStyle). WithURL("https://github.com/yeya24/promlinter"), + 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)). WithSince("v1.37.0"). WithPresets(linter.PresetStyle, linter.PresetMetaLinter). @@ -693,8 +745,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.28.0"). WithPresets(linter.PresetBugs, linter.PresetSQL). WithLoadForGoAnalysis(). - WithURL("https://github.com/ryanrolds/sqlclosecheck"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/ryanrolds/sqlclosecheck"), linter.NewConfig(golinters.NewStaticcheck(staticcheckCfg)). WithSince("v1.0.0"). @@ -708,6 +759,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithLoadForGoAnalysis(). WithPresets(linter.PresetUnused). WithURL("https://github.com/opennota/check"). + Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"). WithNoopFallback(m.cfg), linter.NewConfig(golinters.NewStylecheck(stylecheckCfg)). @@ -727,6 +779,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). @@ -742,8 +799,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.32.0"). WithPresets(linter.PresetStyle, linter.PresetTest). WithLoadForGoAnalysis(). - WithURL("https://github.com/moricho/tparallel"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/moricho/tparallel"), linter.NewConfig(golinters.NewTypecheck()). WithSince("v1.3.0"). @@ -761,8 +817,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSince("v1.9.0"). WithPresets(linter.PresetUnused). WithLoadForGoAnalysis(). - WithURL("https://github.com/mvdan/unparam"). - WithNoopFallback(m.cfg), + WithURL("https://github.com/mvdan/unparam"), linter.NewConfig(golinters.NewUnused(unusedCfg)). WithSince("v1.20.0"). @@ -773,11 +828,17 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithChangeTypes(). WithURL("https://github.com/dominikh/go-tools/tree/master/unused"), + linter.NewConfig(golinters.NewUseStdlibVars(usestdlibvars)). + WithSince("v1.48.0"). + WithPresets(linter.PresetStyle). + WithURL("https://github.com/sashamelentyev/usestdlibvars"), + linter.NewConfig(golinters.NewVarcheck(varcheckCfg)). WithSince("v1.0.0"). WithLoadForGoAnalysis(). WithPresets(linter.PresetUnused). - WithURL("https://github.com/opennota/check"), + WithURL("https://github.com/opennota/check"). + Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"), linter.NewConfig(golinters.NewVarnamelen(varnamelenCfg)). WithSince("v1.43.0"). @@ -822,10 +883,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { golinters.NewStaticcheck(staticcheckCfg).Name(): true, golinters.NewUnused(unusedCfg).Name(): true, golinters.NewGosimple(gosimpleCfg).Name(): true, - golinters.NewStructcheck(structcheckCfg).Name(): true, - golinters.NewVarcheck(varcheckCfg).Name(): true, golinters.NewIneffassign().Name(): true, - golinters.NewDeadcode().Name(): true, golinters.NewTypecheck().Name(): true, } return enableLinterConfigs(lcs, func(lc *linter.Config) bool { @@ -857,6 +915,10 @@ func linterConfigsToMap(lcs []*linter.Config) map[string]*linter.Config { func (m Manager) GetAllLinterConfigsForPreset(p string) []*linter.Config { var ret []*linter.Config for _, lc := range m.GetAllSupportedLinterConfigs() { + if lc.IsDeprecated() { + continue + } + for _, ip := range lc.InPresets { if p == ip { ret = append(ret, lc) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go index 2f0035185..52a70d859 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/lint/lintersdb/validator.go @@ -1,6 +1,7 @@ package lintersdb import ( + "errors" "fmt" "strings" @@ -47,7 +48,7 @@ func (v Validator) validatePresets(cfg *config.Linters) error { } if len(cfg.Presets) != 0 && cfg.EnableAll { - return fmt.Errorf("--presets is incompatible with --enable-all") + return errors.New("--presets is incompatible with --enable-all") } return nil @@ -55,12 +56,12 @@ func (v Validator) validatePresets(cfg *config.Linters) error { func (v Validator) validateAllDisableEnableOptions(cfg *config.Linters) error { if cfg.EnableAll && cfg.DisableAll { - return fmt.Errorf("--enable-all and --disable-all options must not be combined") + return errors.New("--enable-all and --disable-all options must not be combined") } if cfg.DisableAll { if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 { - return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one") + return errors.New("all linters were disabled, but no one linter was enabled: must enable at least one") } if len(cfg.Disable) != 0 { diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go index 8935134e1..c4e1e1765 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/load.go +++ b/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 } @@ -160,7 +160,17 @@ func (cl *ContextLoader) debugPrintLoadedPackages(pkgs []*packages.Package) { func (cl *ContextLoader) parseLoadedPackagesErrors(pkgs []*packages.Package) error { for _, pkg := range pkgs { + var errs []packages.Error for _, err := range pkg.Errors { + // quick fix: skip error related to `go list` invocation by packages.Load() + // The behavior has been changed between go1.19 and go1.20, the error is now inside the JSON content. + // https://github.com/golangci/golangci-lint/pull/3414#issuecomment-1364756303 + if strings.Contains(err.Msg, "# command-line-arguments") { + continue + } + + errs = append(errs, err) + if strings.Contains(err.Msg, "no Go files") { return errors.Wrapf(exitcodes.ErrNoGoFiles, "package %s", pkg.PkgPath) } @@ -169,6 +179,8 @@ func (cl *ContextLoader) parseLoadedPackagesErrors(pkgs []*packages.Package) err return errors.Wrap(exitcodes.ErrFailure, err.Msg) } } + + pkg.Errors = errs } return nil diff --git a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go b/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go index e1a77c7d6..f285b731b 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/lint/runner.go +++ b/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 } @@ -58,7 +58,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env, es *lint var extra string if lc.Deprecation.Replacement != "" { - extra = fmt.Sprintf(" Replaced by %s.", lc.Deprecation.Replacement) + extra = fmt.Sprintf("Replaced by %s.", lc.Deprecation.Replacement) } log.Warnf("The linter '%s' is deprecated (since %s) due to: %s %s", name, lc.Deprecation.Since, lc.Deprecation.Message, extra) @@ -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), @@ -208,6 +208,7 @@ func (r Runner) Run(ctx context.Context, linters []*linter.Config, lintCtx *lint return } + issues = append(issues, linterIssues...) }) } @@ -288,13 +289,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 +322,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/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go b/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go index 57c35c784..2c9609d89 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/log.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go b/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go index 93c9873d9..62c521eac 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/logutils.go +++ b/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" // Debugs a filter excluding autogenerated source code. + DebugKeyBinSalt = "bin_salt" + DebugKeyConfigReader = "config_reader" + DebugKeyEmpty = "" + DebugKeyEnabledLinters = "enabled_linters" + DebugKeyEnv = "env" // Debugs `go env` command. + DebugKeyExcludeRules = "exclude_rules" + DebugKeyExec = "exec" + DebugKeyFilenameUnadjuster = "filename_unadjuster" + DebugKeyGoEnv = "goenv" + DebugKeyLinter = "linter" + DebugKeyLintersContext = "linters_context" + DebugKeyLintersDB = "lintersdb" + DebugKeyLintersOutput = "linters_output" + DebugKeyLoader = "loader" // Debugs packages loading (including `go/packages` internal debugging). + 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" // Debugs `go-critic` linter. + DebugKeyMegacheck = "megacheck" // Debugs `staticcheck` related linters. + DebugKeyNolint = "nolint" // Debugs a filter excluding issues by `//nolint` comments. + DebugKeyRevive = "revive" // Debugs `revice` linter. +) + 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/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go b/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go index b87060d6c..a68215e70 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/logutils/stderr_log.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go index bb347bd2b..307a8e7a0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/checkstyle.go @@ -12,6 +12,8 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) +const defaultCheckstyleSeverity = "error" + type checkstyleOutput struct { XMLName xml.Name `xml:"checkstyle"` Version string `xml:"version,attr"` @@ -31,8 +33,6 @@ type checkstyleError struct { Source string `xml:"source,attr"` } -const defaultCheckstyleSeverity = "error" - type Checkstyle struct { w io.Writer } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go index 8127632e7..8a90f145d 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/codeclimate.go @@ -9,8 +9,12 @@ import ( "github.com/golangci/golangci-lint/pkg/result" ) -// CodeClimateIssue is a subset of the Code Climate spec - https://github.com/codeclimate/spec/blob/master/SPEC.md#data-types -// It is just enough to support GitLab CI Code Quality - https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html +const defaultCodeClimateSeverity = "critical" + +// CodeClimateIssue is a subset of the Code Climate spec. +// https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types +// It is just enough to support GitLab CI Code Quality. +// https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html type CodeClimateIssue struct { Description string `json:"description"` Severity string `json:"severity,omitempty"` @@ -40,6 +44,7 @@ func (p CodeClimate) Print(ctx context.Context, issues []result.Issue) error { codeClimateIssue.Location.Path = issue.Pos.Filename codeClimateIssue.Location.Lines.Begin = issue.Pos.Line codeClimateIssue.Fingerprint = issue.Fingerprint() + codeClimateIssue.Severity = defaultCodeClimateSeverity if issue.Severity != "" { codeClimateIssue.Severity = issue.Severity diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go index 4a126bde6..ffef49108 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/tab.go @@ -26,7 +26,7 @@ func NewTab(printLinterName bool, log logutils.Log, w io.Writer) *Tab { } } -func (p Tab) SprintfColored(ca color.Attribute, format string, args ...interface{}) string { +func (p *Tab) SprintfColored(ca color.Attribute, format string, args ...interface{}) string { c := color.New(ca) return c.Sprintf(format, args...) } @@ -45,7 +45,7 @@ func (p *Tab) Print(ctx context.Context, issues []result.Issue) error { return nil } -func (p Tab) printIssue(i *result.Issue, w io.Writer) { +func (p *Tab) printIssue(i *result.Issue, w io.Writer) { text := p.SprintfColored(color.FgRed, "%s", i.Text) if p.printLinterName { text = fmt.Sprintf("%s\t%s", i.FromLinter, text) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go b/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go index c8960e0e9..d59391b29 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/printers/text.go @@ -31,7 +31,7 @@ func NewText(printIssuedLine, useColors, printLinterName bool, log logutils.Log, } } -func (p Text) SprintfColored(ca color.Attribute, format string, args ...interface{}) string { +func (p *Text) SprintfColored(ca color.Attribute, format string, args ...interface{}) string { if !p.useColors { return fmt.Sprintf(format, args...) } @@ -55,7 +55,7 @@ func (p *Text) Print(ctx context.Context, issues []result.Issue) error { return nil } -func (p Text) printIssue(i *result.Issue) { +func (p *Text) printIssue(i *result.Issue) { text := p.SprintfColored(color.FgRed, "%s", strings.TrimSpace(i.Text)) if p.printLinterName { text += fmt.Sprintf(" (%s)", i.FromLinter) @@ -67,7 +67,7 @@ func (p Text) printIssue(i *result.Issue) { fmt.Fprintf(p.w, "%s: %s\n", pos, text) } -func (p Text) printSourceCode(i *result.Issue) { +func (p *Text) printSourceCode(i *result.Issue) { for _, line := range i.SourceLines { fmt.Fprintln(p.w, line) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go index 57388f64f..5e41fd6a9 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/autogenerated_exclude.go @@ -1,7 +1,6 @@ package processors import ( - "fmt" "go/parser" "go/token" "path/filepath" @@ -13,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 @@ -33,7 +32,7 @@ func NewAutogeneratedExclude() *AutogeneratedExclude { var _ Processor = &AutogeneratedExclude{} -func (p AutogeneratedExclude) Name() string { +func (p *AutogeneratedExclude) Name() string { return "autogenerated_exclude" } @@ -71,7 +70,7 @@ func (p *AutogeneratedExclude) shouldPassIssue(i *result.Issue) (bool, error) { } // isGenerated reports whether the source file is generated code. -// Using a bit laxer rules than https://golang.org/s/generatedcode to +// Using a bit laxer rules than https://go.dev/s/generatedcode to // match more generated code. See #48 and #72. func isGeneratedFileByComment(doc string) bool { const ( @@ -103,7 +102,7 @@ func (p *AutogeneratedExclude) getOrCreateFileSummary(i *result.Issue) (*ageFile p.fileSummaryCache[i.FilePath()] = fs if i.FilePath() == "" { - return nil, fmt.Errorf("no file path for issue") + return nil, errors.New("no file path for issue") } doc, err := getDoc(i.FilePath()) @@ -131,4 +130,4 @@ func getDoc(filePath string) (string, error) { return strings.Join(docLines, "\n"), nil } -func (p AutogeneratedExclude) Finish() {} +func (p *AutogeneratedExclude) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go index b6ce4f215..6958b9f2f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/base_rule.go @@ -58,7 +58,7 @@ func (r *baseRule) matchLinter(issue *result.Issue) bool { return false } -func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { // nolint:interfacer +func (r *baseRule) matchSource(issue *result.Issue, lineCache *fsutils.LineCache, log logutils.Log) bool { //nolint:interfacer sourceLine, errSourceLine := lineCache.GetLine(issue.FilePath(), issue.Line()) if errSourceLine != nil { log.Warnf("Failed to get line %s:%d from line cache: %s", issue.FilePath(), issue.Line(), errSourceLine) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go index 65e01785b..67104bab0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/diff.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go index d4d6569f4..62533b811 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/exclude_rules.go +++ b/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 := fsutils.NormalizePathInRegex(rule.Path) + parsedRule.path = regexp.MustCompile(path) } parsedRules = append(parsedRules, parsedRule) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go index 96540245b..2aaafbf58 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/filename_unadjuster.go @@ -97,7 +97,7 @@ func NewFilenameUnadjuster(pkgs []*packages.Package, log logutils.Log) *Filename } } -func (p FilenameUnadjuster) Name() string { +func (p *FilenameUnadjuster) Name() string { return "filename_unadjuster" } @@ -128,4 +128,4 @@ func (p *FilenameUnadjuster) Process(issues []result.Issue) ([]result.Issue, err }), nil } -func (FilenameUnadjuster) Finish() {} +func (p *FilenameUnadjuster) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go index 17f519e32..d125e1579 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/fixer.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go new file mode 100644 index 000000000..8bc3d847d --- /dev/null +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/issues.go @@ -0,0 +1,46 @@ +package processors + +import ( + "github.com/pkg/errors" + + "github.com/golangci/golangci-lint/pkg/result" +) + +func filterIssues(issues []result.Issue, filter func(i *result.Issue) bool) []result.Issue { + retIssues := make([]result.Issue, 0, len(issues)) + for i := range issues { + if filter(&issues[i]) { + retIssues = append(retIssues, issues[i]) + } + } + + return retIssues +} + +func filterIssuesErr(issues []result.Issue, filter func(i *result.Issue) (bool, error)) ([]result.Issue, error) { + retIssues := make([]result.Issue, 0, len(issues)) + for i := range issues { + ok, err := filter(&issues[i]) + if err != nil { + return nil, errors.Wrapf(err, "can't filter issue %#v", issues[i]) + } + + if ok { + retIssues = append(retIssues, issues[i]) + } + } + + return retIssues, nil +} + +func transformIssues(issues []result.Issue, transform func(i *result.Issue) *result.Issue) []result.Issue { + retIssues := make([]result.Issue, 0, len(issues)) + for i := range issues { + newI := transform(&issues[i]) + if newI != nil { + retIssues = append(retIssues, *newI) + } + } + + return retIssues +} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go index c58666c56..649ed86ae 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_from_linter.go @@ -24,7 +24,7 @@ func NewMaxFromLinter(limit int, log logutils.Log, cfg *config.Config) *MaxFromL } } -func (p MaxFromLinter) Name() string { +func (p *MaxFromLinter) Name() string { return "max_from_linter" } @@ -44,7 +44,7 @@ func (p *MaxFromLinter) Process(issues []result.Issue) ([]result.Issue, error) { }), nil } -func (p MaxFromLinter) Finish() { +func (p *MaxFromLinter) Finish() { walkStringToIntMapSortedByValue(p.lc, func(linter string, count int) { if count > p.limit { p.log.Infof("%d/%d issues from linter %s were hidden, use --max-issues-per-linter", diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go index e36446c9f..64182e3e2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_per_file_from_linter.go @@ -31,7 +31,7 @@ func NewMaxPerFileFromLinter(cfg *config.Config) *MaxPerFileFromLinter { } } -func (p MaxPerFileFromLinter) Name() string { +func (p *MaxPerFileFromLinter) Name() string { return "max_per_file_from_linter" } @@ -56,4 +56,4 @@ func (p *MaxPerFileFromLinter) Process(issues []result.Issue) ([]result.Issue, e }), nil } -func (p MaxPerFileFromLinter) Finish() {} +func (p *MaxPerFileFromLinter) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go index 84fdf0c05..391ae5fa7 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/max_same_issues.go @@ -28,7 +28,7 @@ func NewMaxSameIssues(limit int, log logutils.Log, cfg *config.Config) *MaxSameI } } -func (MaxSameIssues) Name() string { +func (p *MaxSameIssues) Name() string { return "max_same_issues" } @@ -48,7 +48,7 @@ func (p *MaxSameIssues) Process(issues []result.Issue) ([]result.Issue, error) { }), nil } -func (p MaxSameIssues) Finish() { +func (p *MaxSameIssues) Finish() { walkStringToIntMapSortedByValue(p.tc, func(text string, count int) { if count > p.limit { p.log.Infof("%d/%d issues with text %q were hidden, use --max-same-issues", diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go index 01f597e94..181d3bf1f 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/nolint.go @@ -1,7 +1,7 @@ package processors import ( - "fmt" + "errors" "go/ast" "go/parser" "go/token" @@ -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 { @@ -85,7 +85,7 @@ func NewNolint(log logutils.Log, dbManager *lintersdb.Manager, enabledLinters ma var _ Processor = &Nolint{} -func (p Nolint) Name() string { +func (p *Nolint) Name() string { return "nolint" } @@ -105,7 +105,7 @@ func (p *Nolint) getOrCreateFileData(i *result.Issue) (*fileData, error) { p.cache[i.FilePath()] = fd if i.FilePath() == "" { - return nil, fmt.Errorf("no file path for issue") + return nil, errors.New("no file path for issue") } // TODO: migrate this parsing to go/analysis facts @@ -252,7 +252,7 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to } } - if !strings.HasPrefix(text, "nolint:") { + if strings.HasPrefix(text, "nolint:all") || !strings.HasPrefix(text, "nolint:") { return buildRange(nil) // ignore all linters } @@ -260,8 +260,12 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to var linters []string text = strings.Split(text, "//")[0] // allow another comment after this comment linterItems := strings.Split(strings.TrimPrefix(text, "nolint:"), ",") - for _, linter := range linterItems { - linterName := strings.ToLower(strings.TrimSpace(linter)) + for _, item := range linterItems { + linterName := strings.ToLower(strings.TrimSpace(item)) + if linterName == "all" { + p.unknownLintersSet = map[string]bool{} + return buildRange(nil) + } lcs := p.dbManager.GetLinterConfigs(linterName) if lcs == nil { @@ -280,7 +284,7 @@ func (p *Nolint) extractInlineRangeFromComment(text string, g ast.Node, fset *to return buildRange(linters) } -func (p Nolint) Finish() { +func (p *Nolint) Finish() { if len(p.unknownLintersSet) == 0 { return } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go index 5ce940b39..04ed83126 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_prefixer.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go index 484f7f1f1..6b66bea8b 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/path_shortener.go @@ -31,8 +31,8 @@ func (p PathShortener) Name() string { func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) { return transformIssues(issues, func(i *result.Issue) *result.Issue { newI := i - newI.Text = strings.Replace(newI.Text, p.wd+"/", "", -1) - newI.Text = strings.Replace(newI.Text, p.wd, "", -1) + newI.Text = strings.ReplaceAll(newI.Text, p.wd+"/", "") + newI.Text = strings.ReplaceAll(newI.Text, p.wd, "") return newI }), nil } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go index 7c9a4c1d6..85c1866a2 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/severity_rules.go +++ b/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 := fsutils.NormalizePathInRegex(rule.Path) + parsedRule.path = regexp.MustCompile(path) } parsedRules = append(parsedRules, parsedRule) } diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go index d657c5a04..11ab99104 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_dirs.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" + "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/result" ) @@ -31,7 +32,7 @@ const goFileSuffix = ".go" func NewSkipDirs(patterns []string, log logutils.Log, runArgs []string) (*SkipDirs, error) { var patternsRe []*regexp.Regexp for _, p := range patterns { - p = normalizePathInRegex(p) + p = fsutils.NormalizePathInRegex(p) patternRe, err := regexp.Compile(p) if err != nil { return nil, errors.Wrapf(err, "can't compile regexp %q", p) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go index 1e2ca7aeb..b7b86bed0 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/skip_files.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" + "github.com/golangci/golangci-lint/pkg/fsutils" "github.com/golangci/golangci-lint/pkg/result" ) @@ -16,7 +17,7 @@ var _ Processor = (*SkipFiles)(nil) func NewSkipFiles(patterns []string) (*SkipFiles, error) { var patternsRe []*regexp.Regexp for _, p := range patterns { - p = normalizePathInRegex(p) + p = fsutils.NormalizePathInRegex(p) patternRe, err := regexp.Compile(p) if err != nil { return nil, fmt.Errorf("can't compile regexp %q: %s", p, err) diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go index f93059590..740c4fa8c 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/sort_results.go +++ b/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/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go index 17167dde5..dc0e1e8cf 100644 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go +++ b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/uniq_by_line.go @@ -22,7 +22,7 @@ func NewUniqByLine(cfg *config.Config) *UniqByLine { var _ Processor = &UniqByLine{} -func (p UniqByLine) Name() string { +func (p *UniqByLine) Name() string { return "uniq_by_line" } @@ -55,4 +55,4 @@ func (p *UniqByLine) Process(issues []result.Issue) ([]result.Issue, error) { }), nil } -func (p UniqByLine) Finish() {} +func (p *UniqByLine) Finish() {} diff --git a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go b/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go deleted file mode 100644 index 7108fd3b3..000000000 --- a/vendor/github.com/golangci/golangci-lint/pkg/result/processors/utils.go +++ /dev/null @@ -1,62 +0,0 @@ -package processors - -import ( - "path/filepath" - "regexp" - "strings" - - "github.com/pkg/errors" - - "github.com/golangci/golangci-lint/pkg/result" -) - -func filterIssues(issues []result.Issue, filter func(i *result.Issue) bool) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - if filter(&issues[i]) { - retIssues = append(retIssues, issues[i]) - } - } - - return retIssues -} - -func filterIssuesErr(issues []result.Issue, filter func(i *result.Issue) (bool, error)) ([]result.Issue, error) { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - ok, err := filter(&issues[i]) - if err != nil { - return nil, errors.Wrapf(err, "can't filter issue %#v", issues[i]) - } - - if ok { - retIssues = append(retIssues, issues[i]) - } - } - - return retIssues, nil -} - -func transformIssues(issues []result.Issue, transform func(i *result.Issue) *result.Issue) []result.Issue { - retIssues := make([]result.Issue, 0, len(issues)) - for i := range issues { - newI := transform(&issues[i]) - if newI != nil { - retIssues = append(retIssues, *newI) - } - } - - 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/vendor/github.com/golangci/lint-1/go.mod b/vendor/github.com/golangci/lint-1/go.mod deleted file mode 100644 index fafbd340b..000000000 --- a/vendor/github.com/golangci/lint-1/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/golangci/lint-1 - -require golang.org/x/tools v0.0.0-20190311212946-11955173bddd diff --git a/vendor/github.com/golangci/lint-1/go.sum b/vendor/github.com/golangci/lint-1/go.sum deleted file mode 100644 index 7d0e2e618..000000000 --- a/vendor/github.com/golangci/lint-1/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/vendor/github.com/golangci/misspell/.gitignore b/vendor/github.com/golangci/misspell/.gitignore index b1b707e32..5e5c368f8 100644 --- a/vendor/github.com/golangci/misspell/.gitignore +++ b/vendor/github.com/golangci/misspell/.gitignore @@ -2,6 +2,9 @@ dist/ bin/ vendor/ +.idea/ +/misspell + # editor turds *~ *.gz diff --git a/vendor/github.com/golangci/misspell/.golangci.yml b/vendor/github.com/golangci/misspell/.golangci.yml new file mode 100644 index 000000000..1a53216ae --- /dev/null +++ b/vendor/github.com/golangci/misspell/.golangci.yml @@ -0,0 +1,106 @@ +run: + timeout: 2m + skip-files: [] + +linters-settings: + govet: + enable-all: true + disable: + - fieldalignment + - shadow # FIXME(ldez) must be fixed + gocyclo: + min-complexity: 16 + goconst: + min-len: 3 + min-occurrences: 3 + misspell: + locale: US + funlen: + lines: -1 + statements: 40 + gofumpt: + extra-rules: true + depguard: + list-type: blacklist + include-go-root: false + packages: + - github.com/pkg/errors + godox: + keywords: + - FIXME + gocritic: + enabled-tags: + - diagnostic + - style + - performance + disabled-checks: + - sloppyReassign + - rangeValCopy + - octalLiteral + - paramTypeCombine # already handle by gofumpt.extra-rules + - exitAfterDefer # FIXME(ldez) must be fixed + - ifElseChain # FIXME(ldez) must be fixed + settings: + hugeParam: + sizeThreshold: 100 + forbidigo: + forbid: + - '^print(ln)?$' + - '^panic$' + - '^spew\.Print(f|ln)?$' + - '^spew\.Dump$' + +linters: + enable-all: true + disable: + - deadcode # deprecated + - exhaustivestruct # deprecated + - golint # deprecated + - ifshort # deprecated + - interfacer # deprecated + - maligned # deprecated + - nosnakecase # deprecated + - scopelint # deprecated + - scopelint # deprecated + - structcheck # deprecated + - varcheck # deprecated + - execinquery # not relevant (SQL) + - rowserrcheck # not relevant (SQL) + - sqlclosecheck # not relevant (SQL) + - cyclop # duplicate of gocyclo + - dupl + - exhaustive + - exhaustruct + - forbidigo + - gochecknoglobals + - gochecknoinits + - goerr113 + - gomnd + - lll + - nilnil + - nlreturn + - paralleltest + - prealloc + - testpackage + - tparallel + - varnamelen + - wrapcheck + - wsl + - misspell + - gosec # FIXME(ldez) must be fixed + - errcheck # FIXME(ldez) must be fixed + - nonamedreturns # FIXME(ldez) must be fixed + - nakedret # FIXME(ldez) must be fixed + +issues: + exclude-use-default: false + max-per-linter: 0 + max-same-issues: 0 + exclude: + - 'ST1000: at least one file in a package should have a package comment' + - 'package-comments: should have a package comment' + exclude-rules: + - path: .*_test.go + linters: + - funlen + - goconst diff --git a/vendor/github.com/golangci/misspell/.travis.yml b/vendor/github.com/golangci/misspell/.travis.yml deleted file mode 100644 index e63e6c2bd..000000000 --- a/vendor/github.com/golangci/misspell/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -sudo: required -dist: trusty -group: edge -language: go -go: - - "1.10" -git: - depth: 1 - -script: - - ./scripts/travis.sh - -# calls goreleaser when a new tag is pushed -deploy: -- provider: script - skip_cleanup: true - script: curl -sL http://git.io/goreleaser | bash - on: - tags: true - condition: $TRAVIS_OS_NAME = linux diff --git a/vendor/github.com/golangci/misspell/Dockerfile b/vendor/github.com/golangci/misspell/Dockerfile index b8ea37b4c..ce55fe61b 100644 --- a/vendor/github.com/golangci/misspell/Dockerfile +++ b/vendor/github.com/golangci/misspell/Dockerfile @@ -8,9 +8,6 @@ RUN apk add --no-cache git make # these are my standard testing / linting tools RUN /bin/true \ - && go get -u github.com/golang/dep/cmd/dep \ - && go get -u github.com/alecthomas/gometalinter \ - && gometalinter --install \ && rm -rf /go/src /go/pkg # # * SCOWL word list diff --git a/vendor/github.com/golangci/misspell/Gopkg.lock b/vendor/github.com/golangci/misspell/Gopkg.lock deleted file mode 100644 index 90ed45115..000000000 --- a/vendor/github.com/golangci/misspell/Gopkg.lock +++ /dev/null @@ -1,24 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/gobwas/glob" - packages = [ - ".", - "compiler", - "match", - "syntax", - "syntax/ast", - "syntax/lexer", - "util/runes", - "util/strings" - ] - revision = "5ccd90ef52e1e632236f7326478d4faa74f99438" - version = "v0.2.3" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "087ea4c49358ea8258ad9edfe514cd5ce9975c889c258e5ec7b5d2b720aae113" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/golangci/misspell/Gopkg.toml b/vendor/github.com/golangci/misspell/Gopkg.toml deleted file mode 100644 index e9b8e6a45..000000000 --- a/vendor/github.com/golangci/misspell/Gopkg.toml +++ /dev/null @@ -1,34 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/gobwas/glob" - version = "0.2.3" - -[prune] - go-tests = true - unused-packages = true diff --git a/vendor/github.com/golangci/misspell/LICENSE b/vendor/github.com/golangci/misspell/LICENSE index 423e1f9e0..bfcfcd301 100644 --- a/vendor/github.com/golangci/misspell/LICENSE +++ b/vendor/github.com/golangci/misspell/LICENSE @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/github.com/golangci/misspell/Makefile b/vendor/github.com/golangci/misspell/Makefile index 862ab77b0..e64a84b55 100644 --- a/vendor/github.com/golangci/misspell/Makefile +++ b/vendor/github.com/golangci/misspell/Makefile @@ -1,13 +1,18 @@ CONTAINER=nickg/misspell +default: lint test build + install: ## install misspell into GOPATH/bin go install ./cmd/misspell -build: hooks ## build and lint misspell - ./scripts/build.sh +build: ## build and lint misspell + go build ./cmd/misspell test: ## run all tests - go test . + go test -v . + +lint: ## run linter + golangci-lint run # real publishing is done only by travis publish: ## test goreleaser @@ -39,8 +44,8 @@ clean: ## clean up time ci: ## run test like travis-ci does, requires docker docker run --rm \ - -v $(PWD):/go/src/github.com/client9/misspell \ - -w /go/src/github.com/client9/misspell \ + -v $(PWD):/go/src/github.com/golangci/misspell \ + -w /go/src/github.com/golangci/misspell \ ${CONTAINER} \ make build falsepositives @@ -52,16 +57,10 @@ docker-pull: ## pull latest test image docker-console: ## log into the test image docker run --rm -it \ - -v $(PWD):/go/src/github.com/client9/misspell \ - -w /go/src/github.com/client9/misspell \ + -v $(PWD):/go/src/github.com/golangci/misspell \ + -w /go/src/github.com/golangci/misspell \ ${CONTAINER} sh -.git/hooks/pre-commit: scripts/pre-commit.sh - cp -f scripts/pre-commit.sh .git/hooks/pre-commit -.git/hooks/commit-msg: scripts/commit-msg.sh - cp -f scripts/commit-msg.sh .git/hooks/commit-msg -hooks: .git/hooks/pre-commit .git/hooks/commit-msg ## install git precommit hooks - .PHONY: help ci console docker-build bench # https://www.client9.com/self-documenting-makefiles/ @@ -69,6 +68,6 @@ help: @awk -F ':|##' '/^[^\t].+?:.*?##/ {\ printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) -.DEFAULT_GOAL=help +.DEFAULT_GOAL=default .PHONY=help diff --git a/vendor/github.com/golangci/misspell/README.md b/vendor/github.com/golangci/misspell/README.md index 5b68af04d..cccd04996 100644 --- a/vendor/github.com/golangci/misspell/README.md +++ b/vendor/github.com/golangci/misspell/README.md @@ -19,7 +19,7 @@ Both will install as `./bin/misspell`. You can adjust the download location usi If you use [Go](https://golang.org/), the best way to run `misspell` is by using [gometalinter](#gometalinter). Otherwise, install `misspell` the old-fashioned way: ``` -go get -u github.com/client9/misspell/cmd/misspell +go install github.com/client9/misspell/cmd/misspell@latest ``` and misspell will be in your `GOPATH` diff --git a/vendor/github.com/golangci/misspell/ascii.go b/vendor/github.com/golangci/misspell/ascii.go index 1430718d6..d60af5a8d 100644 --- a/vendor/github.com/golangci/misspell/ascii.go +++ b/vendor/github.com/golangci/misspell/ascii.go @@ -1,7 +1,7 @@ package misspell -// ByteToUpper converts an ascii byte to upper cases -// Uses a branchless algorithm +// ByteToUpper converts an ascii byte to upper cases. +// Uses a branch-less algorithm. func ByteToUpper(x byte) byte { b := byte(0x80) | x c := b - byte(0x61) @@ -10,8 +10,8 @@ func ByteToUpper(x byte) byte { return x - (e >> 2) } -// ByteToLower converts an ascii byte to lower case -// uses a branchless algorithm +// ByteToLower converts an ascii byte to lower case. +// Uses a branch-less algorithm. func ByteToLower(eax byte) byte { ebx := eax&byte(0x7f) + byte(0x25) ebx = ebx&byte(0x7f) + byte(0x1a) @@ -19,7 +19,7 @@ func ByteToLower(eax byte) byte { return eax + ebx } -// ByteEqualFold does ascii compare, case insensitive +// ByteEqualFold does ascii compare, case insensitive. func ByteEqualFold(a, b byte) bool { return a == b || ByteToLower(a) == ByteToLower(b) } @@ -27,7 +27,7 @@ func ByteEqualFold(a, b byte) bool { // StringEqualFold ASCII case-insensitive comparison // golang toUpper/toLower for both bytes and strings // appears to be Unicode based which is super slow -// based from https://codereview.appspot.com/5180044/patch/14007/21002 +// based from https://codereview.appspot.com/5180044/patch/14007/21002. func StringEqualFold(s1, s2 string) bool { if len(s1) != len(s2) { return false @@ -47,9 +47,7 @@ func StringEqualFold(s1, s2 string) bool { return true } -// StringHasPrefixFold is similar to strings.HasPrefix but comparison -// is done ignoring ASCII case. -// / +// StringHasPrefixFold is similar to strings.HasPrefix but comparison is done ignoring ASCII case. func StringHasPrefixFold(s1, s2 string) bool { // prefix is bigger than input --> false if len(s1) < len(s2) { diff --git a/vendor/github.com/golangci/misspell/case.go b/vendor/github.com/golangci/misspell/case.go index 2ea3850df..88ad44fa8 100644 --- a/vendor/github.com/golangci/misspell/case.go +++ b/vendor/github.com/golangci/misspell/case.go @@ -4,10 +4,10 @@ import ( "strings" ) -// WordCase is an enum of various word casing styles +// WordCase is an enum of various word casing styles. type WordCase int -// Various WordCase types.. likely to be not correct +// Various WordCase types... likely to be not correct. const ( CaseUnknown WordCase = iota CaseLower @@ -15,7 +15,7 @@ const ( CaseTitle ) -// CaseStyle returns what case style a word is in +// CaseStyle returns what case style a word is in. func CaseStyle(word string) WordCase { upperCount := 0 lowerCount := 0 @@ -42,11 +42,10 @@ func CaseStyle(word string) WordCase { return CaseUnknown } -// CaseVariations returns -// If AllUpper or First-Letter-Only is upcased: add the all upper case version -// If AllLower, add the original, the title and upcase forms -// If Mixed, return the original, and the all upcase form -// +// CaseVariations returns: +// If AllUpper or First-Letter-Only is upcased: add the all upper case version. +// If AllLower, add the original, the title and upcase forms. +// If Mixed, return the original, and the all upcase form. func CaseVariations(word string, style WordCase) []string { switch style { case CaseLower: diff --git a/vendor/github.com/golangci/misspell/goreleaser.yml b/vendor/github.com/golangci/misspell/goreleaser.yml index 560cb3810..b4c8c099c 100644 --- a/vendor/github.com/golangci/misspell/goreleaser.yml +++ b/vendor/github.com/golangci/misspell/goreleaser.yml @@ -1,6 +1,3 @@ -# goreleaser.yml -# https://github.com/goreleaser/goreleaser - project_name: misspell builds: @@ -14,22 +11,18 @@ builds: - windows goarch: - amd64 + - arm64 env: - CGO_ENABLED=0 - ignore: - - goos: darwin - goarch: 386 - - goos: windows - goarch: 386 -archive: - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - replacements: - amd64: 64bit - 386: 32bit - darwin: mac - files: - - none* +archives: + - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + replacements: + amd64: 64bit + 386: 32bit + darwin: mac + files: + - LICENSE checksum: name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" diff --git a/vendor/github.com/golangci/misspell/legal.go b/vendor/github.com/golangci/misspell/legal.go index 20076974b..4f9bcfc67 100644 --- a/vendor/github.com/golangci/misspell/legal.go +++ b/vendor/github.com/golangci/misspell/legal.go @@ -3,7 +3,7 @@ package misspell // Legal provides licensing info. const Legal = ` -Execept where noted below, the source code for misspell is +Except where noted below, the source code for misspell is copyright Nick Galbreath and distribution is allowed under a MIT license. See the following for details: @@ -44,5 +44,4 @@ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -` +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.` diff --git a/vendor/github.com/golangci/misspell/mime.go b/vendor/github.com/golangci/misspell/mime.go index 9db4902b3..76a96cfd1 100644 --- a/vendor/github.com/golangci/misspell/mime.go +++ b/vendor/github.com/golangci/misspell/mime.go @@ -4,21 +4,18 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/http" "os" "path/filepath" "strings" ) -// The number of possible binary formats is very large -// items that might be checked into a repo or be an -// artifact of a build. Additions welcome. +// The number of possible binary formats is very large items that might be checked into a repo or be an artifact of a build. +// Additions welcome. // -// Golang's internal table is very small and can't be -// relied on. Even then things like ".js" have a mime -// type of "application/javascipt" which isn't very helpful. -// "[x]" means we have sniff test and suffix test should be eliminated +// Golang's internal table is very small and can't be relied on. +// Even then things like ".js" have a mime type of "application/javascript" which isn't very helpful. +// "[x]" means we have sniff test and suffix test should be eliminated. var binary = map[string]bool{ ".a": true, // [ ] archive ".bin": true, // [ ] binary @@ -52,12 +49,10 @@ var binary = map[string]bool{ ".zip": true, // [x] archive } -// isBinaryFilename returns true if the file is likely to be binary +// isBinaryFilename returns true if the file is likely to be binary. // -// Better heuristics could be done here, in particular a binary -// file is unlikely to be UTF-8 encoded. However this is cheap -// and will solve the immediate need of making sure common -// binary formats are not corrupted by mistake. +// Better heuristics could be done here, in particular a binary file is unlikely to be UTF-8 encoded. +// However, this is cheap and will solve the immediate need of making sure common binary formats are not corrupted by mistake. func isBinaryFilename(s string) bool { return binary[strings.ToLower(filepath.Ext(s))] } @@ -70,8 +65,8 @@ var scm = map[string]bool{ "CVS": true, } -// isSCMPath returns true if the path is likely part of a (private) SCM -// directory. E.g. ./git/something = true +// isSCMPath returns true if the path is likely part of a (private) SCM directory. +// E.g. ./git/something = true. func isSCMPath(s string) bool { // hack for .git/COMMIT_EDITMSG and .git/TAG_EDITMSG // normally we don't look at anything in .git @@ -128,29 +123,30 @@ func isTextFile(raw []byte) bool { } } - // allow any text/ type with utf-8 encoding - // DetectContentType sometimes returns charset=utf-16 for XML stuff - // in which case ignore. + // allow any text/ type with utf-8 encoding. + // DetectContentType sometimes returns charset=utf-16 for XML stuff in which case ignore. mime := http.DetectContentType(raw) return strings.HasPrefix(mime, "text/") && strings.HasSuffix(mime, "charset=utf-8") } -// ReadTextFile returns the contents of a file, first testing if it is a text file -// returns ("", nil) if not a text file -// returns ("", error) if error -// returns (string, nil) if text +// ReadTextFile returns the contents of a file, first testing if it is a text file: // -// unfortunately, in worse case, this does -// 1 stat -// 1 open,read,close of 512 bytes -// 1 more stat,open, read everything, close (via ioutil.ReadAll) -// This could be kinder to the filesystem. +// returns ("", nil) if not a text file +// returns ("", error) if error +// returns (string, nil) if text +// +// unfortunately, in worse case, this does: +// +// 1 stat +// 1 open,read,close of 512 bytes +// 1 more stat,open, read everything, close (via io.ReadAll) +// This could be kinder to the filesystem. // // This uses some heuristics of the file's extension (e.g. .zip, .txt) and // uses a sniffer to determine if the file is text or not. // Using file extensions isn't great, but probably // good enough for real-world use. -// Golang's built in sniffer is problematic for differnet reasons. It's +// Golang's built-in sniffer is problematic for different reasons. It's // optimized for HTML, and is very limited in detection. It would be good // to explicitly add some tests for ELF/DWARF formats to make sure we never // corrupt binary files. @@ -164,9 +160,8 @@ func ReadTextFile(filename string) (string, error) { } fstat, err := os.Stat(filename) - if err != nil { - return "", fmt.Errorf("Unable to stat %q: %s", filename, err) + return "", fmt.Errorf("unable to stat %q: %w", filename, err) } // directory: nothing to do. @@ -181,26 +176,26 @@ func ReadTextFile(filename string) (string, error) { if fstat.Size() > 50000 { fin, err := os.Open(filename) if err != nil { - return "", fmt.Errorf("Unable to open large file %q: %s", filename, err) + return "", fmt.Errorf("unable to open large file %q: %w", filename, err) } defer fin.Close() buf := make([]byte, 512) _, err = io.ReadFull(fin, buf) if err != nil { - return "", fmt.Errorf("Unable to read 512 bytes from %q: %s", filename, err) + return "", fmt.Errorf("unable to read 512 bytes from %q: %w", filename, err) } if !isTextFile(buf) { return "", nil } - // set so we don't double check this file + // set so we don't double-check this file isText = true } // read in whole file - raw, err := ioutil.ReadFile(filename) + raw, err := os.ReadFile(filename) if err != nil { - return "", fmt.Errorf("Unable to read all %q: %s", filename, err) + return "", fmt.Errorf("unable to read all %q: %w", filename, err) } if !isText && !isTextFile(raw) { diff --git a/vendor/github.com/golangci/misspell/notwords.go b/vendor/github.com/golangci/misspell/notwords.go index 06d0d5a5a..a250cf7f6 100644 --- a/vendor/github.com/golangci/misspell/notwords.go +++ b/vendor/github.com/golangci/misspell/notwords.go @@ -13,10 +13,10 @@ var ( ) // RemovePath attempts to strip away embedded file system paths, e.g. -// /foo/bar or /static/myimg.png // -// TODO: windows style +// /foo/bar or /static/myimg.png // +// TODO: windows style. func RemovePath(s string) string { out := bytes.Buffer{} var idx int @@ -57,28 +57,28 @@ func RemovePath(s string) string { return out.String() } -// replaceWithBlanks returns a string with the same number of spaces as the input +// replaceWithBlanks returns a string with the same number of spaces as the input. func replaceWithBlanks(s string) string { return strings.Repeat(" ", len(s)) } -// RemoveEmail remove email-like strings, e.g. "nickg+junk@xfoobar.com", "nickg@xyz.abc123.biz" +// RemoveEmail remove email-like strings, e.g. "nickg+junk@xfoobar.com", "nickg@xyz.abc123.biz". func RemoveEmail(s string) string { return reEmail.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveHost removes host-like strings "foobar.com" "abc123.fo1231.biz" +// RemoveHost removes host-like strings "foobar.com" "abc123.fo1231.biz". func RemoveHost(s string) string { return reHost.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveBackslashEscapes removes characters that are preceeded by a backslash -// commonly found in printf format stringd "\nto" +// RemoveBackslashEscapes removes characters that are preceded by a backslash. +// commonly found in printf format string "\nto". func removeBackslashEscapes(s string) string { return reBackslash.ReplaceAllStringFunc(s, replaceWithBlanks) } -// RemoveNotWords blanks out all the not words +// RemoveNotWords blanks out all the not words. func RemoveNotWords(s string) string { // do most selective/specific first return removeBackslashEscapes(RemoveHost(RemoveEmail(RemovePath(StripURL(s))))) diff --git a/vendor/github.com/golangci/misspell/replace.go b/vendor/github.com/golangci/misspell/replace.go index a99bbcc58..68d904b0d 100644 --- a/vendor/github.com/golangci/misspell/replace.go +++ b/vendor/github.com/golangci/misspell/replace.go @@ -27,7 +27,7 @@ func inArray(haystack []string, needle string) bool { var wordRegexp = regexp.MustCompile(`[a-zA-Z0-9']+`) -// Diff is datastructure showing what changed in a single line +// Diff is datastructures showing what changed in a single line. type Diff struct { Filename string FullLine string @@ -37,7 +37,7 @@ type Diff struct { Corrected string } -// Replacer is the main struct for spelling correction +// Replacer is the main struct for spelling correction. type Replacer struct { Replacements []string Debug bool @@ -45,7 +45,7 @@ type Replacer struct { corrected map[string]string } -// New creates a new default Replacer using the main rule list +// New creates a new default Replacer using the main rule list. func New() *Replacer { r := Replacer{ Replacements: DictMain, @@ -54,31 +54,31 @@ func New() *Replacer { return &r } -// RemoveRule deletes existings rules. -// TODO: make inplace to save memory +// RemoveRule deletes existing rules. +// TODO: make in place to save memory. func (r *Replacer) RemoveRule(ignore []string) { - newwords := make([]string, 0, len(r.Replacements)) + newWords := make([]string, 0, len(r.Replacements)) for i := 0; i < len(r.Replacements); i += 2 { if inArray(ignore, r.Replacements[i]) { continue } - newwords = append(newwords, r.Replacements[i:i+2]...) + newWords = append(newWords, r.Replacements[i:i+2]...) } r.engine = nil - r.Replacements = newwords + r.Replacements = newWords } // AddRuleList appends new rules. // Input is in the same form as Strings.Replacer: [ old1, new1, old2, new2, ....] -// Note: does not check for duplictes +// Note: does not check for duplicates. func (r *Replacer) AddRuleList(additions []string) { r.engine = nil r.Replacements = append(r.Replacements, additions...) } -// Compile compiles the rules. Required before using the Replace functions +// Compile compiles the rules. +// Required before using the Replace functions. func (r *Replacer) Compile() { - r.corrected = make(map[string]string, len(r.Replacements)/2) for i := 0; i < len(r.Replacements); i += 2 { r.corrected[r.Replacements[i]] = r.Replacements[i+1] @@ -92,11 +92,14 @@ extract words from each line1 replace word -> newword if word == new-word - continue + + continue + if new-word in list of replacements - continue -new word not original, and not in list of replacements - some substring got mixed up. UNdo + + continue + +new word not original, and not in list of replacements some substring got mixed up. UNdo. */ func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(Diff)) { first := 0 @@ -136,9 +139,8 @@ func (r *Replacer) recheckLine(s string, lineNum int, buf io.Writer, next func(D io.WriteString(buf, s[first:]) } -// ReplaceGo is a specialized routine for correcting Golang source -// files. Currently only checks comments, not identifiers for -// spelling. +// ReplaceGo is a specialized routine for correcting Golang source files. +// Currently only checks comments, not identifiers for spelling. func (r *Replacer) ReplaceGo(input string) (string, []Diff) { var s scanner.Scanner s.Init(strings.NewReader(input)) @@ -169,7 +171,7 @@ Loop: return input, nil } if lastPos < len(input) { - output = output + input[lastPos:] + output += input[lastPos:] } diffs := make([]Diff, 0, 8) buf := bytes.NewBuffer(make([]byte, 0, max(len(input), len(output))+100)) @@ -187,11 +189,9 @@ Loop: } return buf.String(), diffs - } -// Replace is corrects misspellings in input, returning corrected version -// along with a list of diffs. +// Replace is corrects misspellings in input, returning corrected version along with a list of diffs. func (r *Replacer) Replace(input string) (string, []Diff) { output := r.engine.Replace(input) if input == output { @@ -215,8 +215,8 @@ func (r *Replacer) Replace(input string) (string, []Diff) { return buf.String(), diffs } -// ReplaceReader applies spelling corrections to a reader stream. Diffs are -// emitted through a callback. +// ReplaceReader applies spelling corrections to a reader stream. +// Diffs are emitted through a callback. func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) error { var ( err error @@ -239,7 +239,7 @@ func (r *Replacer) ReplaceReader(raw io.Reader, w io.Writer, next func(Diff)) er io.WriteString(w, line) continue } - // but it can be inaccurate, so we need to double check + // but it can be inaccurate, so we need to double-check r.recheckLine(line, lineNum, w, next) } return nil diff --git a/vendor/github.com/golangci/misspell/stringreplacer.go b/vendor/github.com/golangci/misspell/stringreplacer.go index 3151eceb7..73ca9a56a 100644 --- a/vendor/github.com/golangci/misspell/stringreplacer.go +++ b/vendor/github.com/golangci/misspell/stringreplacer.go @@ -6,7 +6,6 @@ package misspell import ( "io" - // "log" "strings" ) @@ -38,7 +37,7 @@ func (r *StringReplacer) Replace(s string) string { } // WriteString writes s to w with all replacements performed. -func (r *StringReplacer) WriteString(w io.Writer, s string) (n int, err error) { +func (r *StringReplacer) WriteString(w io.Writer, s string) (int, error) { return r.r.WriteString(w, s) } @@ -46,14 +45,14 @@ func (r *StringReplacer) WriteString(w io.Writer, s string) (n int, err error) { // and values may be empty. For example, the trie containing keys "ax", "ay", // "bcbc", "x" and "xy" could have eight nodes: // -// n0 - -// n1 a- -// n2 .x+ -// n3 .y+ -// n4 b- -// n5 .cbc+ -// n6 x+ -// n7 .y+ +// n0 - +// n1 a- +// n2 .x+ +// n3 .y+ +// n4 b- +// n5 .cbc+ +// n6 x+ +// n7 .y+ // // n0 is the root node, and its children are n1, n4 and n6; n1's children are // n2 and n3; n4's child is n5; n6's child is n7. Nodes n0, n1 and n4 (marked @@ -103,6 +102,7 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { return } + //nolint:nestif // TODO(ldez) must be fixed. if t.prefix != "" { // Need to split the prefix among multiple nodes. var n int // length of the longest common prefix @@ -157,42 +157,6 @@ func (t *trieNode) add(key, val string, priority int, r *genericReplacer) { } } -func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { - // Iterate down the trie to the end, and grab the value and keylen with - // the highest priority. - bestPriority := 0 - node := &r.root - n := 0 - for node != nil { - if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { - bestPriority = node.priority - val = node.value - keylen = n - found = true - } - - if s == "" { - break - } - if node.table != nil { - index := r.mapping[ByteToLower(s[0])] - if int(index) == r.tableSize { - break - } - node = node.table[index] - s = s[1:] - n++ - } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { - n += len(node.prefix) - s = s[len(node.prefix):] - node = node.next - } else { - break - } - } - return -} - // genericReplacer is the fully generic algorithm. // It's used as a fallback when nothing faster can be used. type genericReplacer struct { @@ -236,38 +200,40 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { return r } -type appendSliceWriter []byte - -// Write writes to the buffer to satisfy io.Writer. -func (w *appendSliceWriter) Write(p []byte) (int, error) { - *w = append(*w, p...) - return len(p), nil -} - -// WriteString writes to the buffer without string->[]byte->string allocations. -func (w *appendSliceWriter) WriteString(s string) (int, error) { - *w = append(*w, s...) - return len(s), nil -} - -type stringWriterIface interface { - WriteString(string) (int, error) -} - -type stringWriter struct { - w io.Writer -} - -func (w stringWriter) WriteString(s string) (int, error) { - return w.w.Write([]byte(s)) -} +func (r *genericReplacer) lookup(s string, ignoreRoot bool) (val string, keylen int, found bool) { + // Iterate down the trie to the end, and grab the value and keylen with + // the highest priority. + bestPriority := 0 + node := &r.root + n := 0 + for node != nil { + if node.priority > bestPriority && !(ignoreRoot && node == &r.root) { + bestPriority = node.priority + val = node.value + keylen = n + found = true + } -func getStringWriter(w io.Writer) stringWriterIface { - sw, ok := w.(stringWriterIface) - if !ok { - sw = stringWriter{w} + if s == "" { + break + } + if node.table != nil { + index := r.mapping[ByteToLower(s[0])] + if int(index) == r.tableSize { + break + } + node = node.table[index] + s = s[1:] + n++ + } else if node.prefix != "" && StringHasPrefixFold(s, node.prefix) { + n += len(node.prefix) + s = s[len(node.prefix):] + node = node.next + } else { + break + } } - return sw + return } func (r *genericReplacer) Replace(s string) string { @@ -276,6 +242,7 @@ func (r *genericReplacer) Replace(s string) string { return string(buf) } +//nolint:gocognit // TODO(ldez) must be fixed. func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) { sw := getStringWriter(w) var last, wn int @@ -316,7 +283,7 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) if err != nil { return } - //log.Printf("%d: Going to correct %q with %q", i, s[i:i+keylen], val) + // debug helper: log.Printf("%d: Going to correct %q with %q", i, s[i:i+keylen], val) wn, err = sw.WriteString(val) n += wn if err != nil { @@ -334,3 +301,33 @@ func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) } return } + +type appendSliceWriter []byte + +// Write writes to the buffer to satisfy io.Writer. +func (w *appendSliceWriter) Write(p []byte) (int, error) { + *w = append(*w, p...) + return len(p), nil +} + +// WriteString writes to the buffer without string->[]byte->string allocations. +func (w *appendSliceWriter) WriteString(s string) (int, error) { + *w = append(*w, s...) + return len(s), nil +} + +type stringWriter struct { + w io.Writer +} + +func (w stringWriter) WriteString(s string) (int, error) { + return w.w.Write([]byte(s)) +} + +func getStringWriter(w io.Writer) io.StringWriter { + sw, ok := w.(io.StringWriter) + if !ok { + sw = stringWriter{w} + } + return sw +} diff --git a/vendor/github.com/golangci/misspell/url.go b/vendor/github.com/golangci/misspell/url.go index 1a259f5f9..203b91a79 100644 --- a/vendor/github.com/golangci/misspell/url.go +++ b/vendor/github.com/golangci/misspell/url.go @@ -7,11 +7,12 @@ import ( // Regexp for URL https://mathiasbynens.be/demo/url-regex // // original @imme_emosol (54 chars) has trouble with dashes in hostname -// @(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS -var reURL = regexp.MustCompile(`(?i)(https?|ftp)://(-\.)?([^\s/?\.#]+\.?)+(/[^\s]*)?`) +// @(https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS. +var reURL = regexp.MustCompile(`(?i)(https?|ftp)://(-\.)?([^\s/?.#]+\.?)+(/\S*)?`) // StripURL attemps to replace URLs with blank spaces, e.g. -// "xxx http://foo.com/ yyy -> "xxx yyyy" +// +// "xxx http://foo.com/ yyy -> "xxx yyyy". func StripURL(s string) string { return reURL.ReplaceAllStringFunc(s, replaceWithBlanks) } diff --git a/vendor/github.com/golangci/revgrep/go.mod b/vendor/github.com/golangci/revgrep/go.mod deleted file mode 100644 index 25d884a5b..000000000 --- a/vendor/github.com/golangci/revgrep/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/golangci/revgrep - -go 1.17 diff --git a/vendor/github.com/golangci/revgrep/go.sum b/vendor/github.com/golangci/revgrep/go.sum deleted file mode 100644 index e69de29bb..000000000 diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go index fd2b3a42b..087320da7 100644 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/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/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go index bc196b16c..a248e5436 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go +++ b/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/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go deleted file mode 100644 index 9147a2997..000000000 --- a/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/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index e57b9eb53..1f9ca9c48 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/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/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go index c71003463..a0a588502 100644 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ b/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/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go index 1ef65ac1d..2050bf6b4 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ b/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/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 287b89358..2ab41fad3 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/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/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go index 68b5c1ae1..23e444f62 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ b/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/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go index 0fd46d7ff..388fcf571 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_text.go +++ b/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/vendor/github.com/google/pprof/profile/encode.go b/vendor/github.com/google/pprof/profile/encode.go index 96aa271e5..c8a1beb8a 100644 --- a/vendor/github.com/google/pprof/profile/encode.go +++ b/vendor/github.com/google/pprof/profile/encode.go @@ -184,12 +184,13 @@ var profileDecoder = []decoder{ // repeated Location location = 4 func(b *buffer, m message) error { x := new(Location) - x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer + x.Line = b.tmpLines[:0] // Use shared space temporarily pp := m.(*Profile) pp.Location = append(pp.Location, x) err := decodeMessage(b, x) - var tmp []Line - x.Line = append(tmp, x.Line...) // Shrink to allocated size + b.tmpLines = x.Line[:0] + // Copy to shrink size and detach from shared space. + x.Line = append([]Line(nil), x.Line...) return err }, // repeated Function function = 5 @@ -307,41 +308,52 @@ func (p *Profile) postDecode() error { st.Unit, err = getString(p.stringTable, &st.unitX, err) } + // Pre-allocate space for all locations. + numLocations := 0 for _, s := range p.Sample { - labels := make(map[string][]string, len(s.labelX)) - numLabels := make(map[string][]int64, len(s.labelX)) - numUnits := make(map[string][]string, len(s.labelX)) - for _, l := range s.labelX { - var key, value string - key, err = getString(p.stringTable, &l.keyX, err) - if l.strX != 0 { - value, err = getString(p.stringTable, &l.strX, err) - labels[key] = append(labels[key], value) - } else if l.numX != 0 || l.unitX != 0 { - numValues := numLabels[key] - units := numUnits[key] - if l.unitX != 0 { - var unit string - unit, err = getString(p.stringTable, &l.unitX, err) - units = padStringArray(units, len(numValues)) - numUnits[key] = append(units, unit) + numLocations += len(s.locationIDX) + } + locBuffer := make([]*Location, numLocations) + + for _, s := range p.Sample { + if len(s.labelX) > 0 { + labels := make(map[string][]string, len(s.labelX)) + numLabels := make(map[string][]int64, len(s.labelX)) + numUnits := make(map[string][]string, len(s.labelX)) + for _, l := range s.labelX { + var key, value string + key, err = getString(p.stringTable, &l.keyX, err) + if l.strX != 0 { + value, err = getString(p.stringTable, &l.strX, err) + labels[key] = append(labels[key], value) + } else if l.numX != 0 || l.unitX != 0 { + numValues := numLabels[key] + units := numUnits[key] + if l.unitX != 0 { + var unit string + unit, err = getString(p.stringTable, &l.unitX, err) + units = padStringArray(units, len(numValues)) + numUnits[key] = append(units, unit) + } + numLabels[key] = append(numLabels[key], l.numX) } - numLabels[key] = append(numLabels[key], l.numX) } - } - if len(labels) > 0 { - s.Label = labels - } - if len(numLabels) > 0 { - s.NumLabel = numLabels - for key, units := range numUnits { - if len(units) > 0 { - numUnits[key] = padStringArray(units, len(numLabels[key])) + if len(labels) > 0 { + s.Label = labels + } + if len(numLabels) > 0 { + s.NumLabel = numLabels + for key, units := range numUnits { + if len(units) > 0 { + numUnits[key] = padStringArray(units, len(numLabels[key])) + } } + s.NumUnit = numUnits } - s.NumUnit = numUnits } - s.Location = make([]*Location, len(s.locationIDX)) + + s.Location = locBuffer[:len(s.locationIDX)] + locBuffer = locBuffer[len(s.locationIDX):] for i, lid := range s.locationIDX { if lid < uint64(len(locationIds)) { s.Location[i] = locationIds[lid] diff --git a/vendor/github.com/google/pprof/profile/filter.go b/vendor/github.com/google/pprof/profile/filter.go index ea8e66c68..c794b9390 100644 --- a/vendor/github.com/google/pprof/profile/filter.go +++ b/vendor/github.com/google/pprof/profile/filter.go @@ -22,6 +22,10 @@ import "regexp" // samples where at least one frame matches focus but none match ignore. // Returns true is the corresponding regexp matched at least one sample. func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) { + if focus == nil && ignore == nil && hide == nil && show == nil { + fm = true // Missing focus implies a match + return + } focusOrIgnore := make(map[uint64]bool) hidden := make(map[uint64]bool) for _, l := range p.Location { diff --git a/vendor/github.com/google/pprof/profile/legacy_profile.go b/vendor/github.com/google/pprof/profile/legacy_profile.go index 9ba9a77c9..8d07fd6c2 100644 --- a/vendor/github.com/google/pprof/profile/legacy_profile.go +++ b/vendor/github.com/google/pprof/profile/legacy_profile.go @@ -865,7 +865,6 @@ func parseThread(b []byte) (*Profile, error) { // Recognize each thread and populate profile samples. for !isMemoryMapSentinel(line) { if strings.HasPrefix(line, "---- no stack trace for") { - line = "" break } if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { diff --git a/vendor/github.com/google/pprof/profile/merge.go b/vendor/github.com/google/pprof/profile/merge.go index 6fcd11de1..4b66282cb 100644 --- a/vendor/github.com/google/pprof/profile/merge.go +++ b/vendor/github.com/google/pprof/profile/merge.go @@ -15,6 +15,7 @@ package profile import ( + "encoding/binary" "fmt" "sort" "strconv" @@ -58,7 +59,7 @@ func Merge(srcs []*Profile) (*Profile, error) { for _, src := range srcs { // Clear the profile-specific hash tables - pm.locationsByID = make(map[uint64]*Location, len(src.Location)) + pm.locationsByID = makeLocationIDMap(len(src.Location)) pm.functionsByID = make(map[uint64]*Function, len(src.Function)) pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping)) @@ -136,7 +137,7 @@ type profileMerger struct { p *Profile // Memoization tables within a profile. - locationsByID map[uint64]*Location + locationsByID locationIDMap functionsByID map[uint64]*Function mappingsByID map[uint64]mapInfo @@ -153,6 +154,16 @@ type mapInfo struct { } func (pm *profileMerger) mapSample(src *Sample) *Sample { + // Check memoization table + k := pm.sampleKey(src) + if ss, ok := pm.samples[k]; ok { + for i, v := range src.Value { + ss.Value[i] += v + } + return ss + } + + // Make new sample. s := &Sample{ Location: make([]*Location, len(src.Location)), Value: make([]int64, len(src.Value)), @@ -177,52 +188,98 @@ func (pm *profileMerger) mapSample(src *Sample) *Sample { s.NumLabel[k] = vv s.NumUnit[k] = uu } - // Check memoization table. Must be done on the remapped location to - // account for the remapped mapping. Add current values to the - // existing sample. - k := s.key() - if ss, ok := pm.samples[k]; ok { - for i, v := range src.Value { - ss.Value[i] += v - } - return ss - } copy(s.Value, src.Value) pm.samples[k] = s pm.p.Sample = append(pm.p.Sample, s) return s } -// key generates sampleKey to be used as a key for maps. -func (sample *Sample) key() sampleKey { - ids := make([]string, len(sample.Location)) - for i, l := range sample.Location { - ids[i] = strconv.FormatUint(l.ID, 16) +func (pm *profileMerger) sampleKey(sample *Sample) sampleKey { + // Accumulate contents into a string. + var buf strings.Builder + buf.Grow(64) // Heuristic to avoid extra allocs + + // encode a number + putNumber := func(v uint64) { + var num [binary.MaxVarintLen64]byte + n := binary.PutUvarint(num[:], v) + buf.Write(num[:n]) + } + + // encode a string prefixed with its length. + putDelimitedString := func(s string) { + putNumber(uint64(len(s))) + buf.WriteString(s) + } + + for _, l := range sample.Location { + // Get the location in the merged profile, which may have a different ID. + if loc := pm.mapLocation(l); loc != nil { + putNumber(loc.ID) + } } + putNumber(0) // Delimiter - labels := make([]string, 0, len(sample.Label)) - for k, v := range sample.Label { - labels = append(labels, fmt.Sprintf("%q%q", k, v)) + for _, l := range sortedKeys1(sample.Label) { + putDelimitedString(l) + values := sample.Label[l] + putNumber(uint64(len(values))) + for _, v := range values { + putDelimitedString(v) + } } - sort.Strings(labels) - numlabels := make([]string, 0, len(sample.NumLabel)) - for k, v := range sample.NumLabel { - numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k])) + for _, l := range sortedKeys2(sample.NumLabel) { + putDelimitedString(l) + values := sample.NumLabel[l] + putNumber(uint64(len(values))) + for _, v := range values { + putNumber(uint64(v)) + } + units := sample.NumUnit[l] + putNumber(uint64(len(units))) + for _, v := range units { + putDelimitedString(v) + } } - sort.Strings(numlabels) - return sampleKey{ - strings.Join(ids, "|"), - strings.Join(labels, ""), - strings.Join(numlabels, ""), + return sampleKey(buf.String()) +} + +type sampleKey string + +// sortedKeys1 returns the sorted keys found in a string->[]string map. +// +// Note: this is currently non-generic since github pprof runs golint, +// which does not support generics. When that issue is fixed, it can +// be merged with sortedKeys2 and made into a generic function. +func sortedKeys1(m map[string][]string) []string { + if len(m) == 0 { + return nil } + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys } -type sampleKey struct { - locations string - labels string - numlabels string +// sortedKeys2 returns the sorted keys found in a string->[]int64 map. +// +// Note: this is currently non-generic since github pprof runs golint, +// which does not support generics. When that issue is fixed, it can +// be merged with sortedKeys1 and made into a generic function. +func sortedKeys2(m map[string][]int64) []string { + if len(m) == 0 { + return nil + } + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys } func (pm *profileMerger) mapLocation(src *Location) *Location { @@ -230,7 +287,7 @@ func (pm *profileMerger) mapLocation(src *Location) *Location { return nil } - if l, ok := pm.locationsByID[src.ID]; ok { + if l := pm.locationsByID.get(src.ID); l != nil { return l } @@ -249,10 +306,10 @@ func (pm *profileMerger) mapLocation(src *Location) *Location { // account for the remapped mapping ID. k := l.key() if ll, ok := pm.locations[k]; ok { - pm.locationsByID[src.ID] = ll + pm.locationsByID.set(src.ID, ll) return ll } - pm.locationsByID[src.ID] = l + pm.locationsByID.set(src.ID, l) pm.locations[k] = l pm.p.Location = append(pm.p.Location, l) return l @@ -480,3 +537,131 @@ func (p *Profile) compatible(pb *Profile) error { func equalValueType(st1, st2 *ValueType) bool { return st1.Type == st2.Type && st1.Unit == st2.Unit } + +// locationIDMap is like a map[uint64]*Location, but provides efficiency for +// ids that are densely numbered, which is often the case. +type locationIDMap struct { + dense []*Location // indexed by id for id < len(dense) + sparse map[uint64]*Location // indexed by id for id >= len(dense) +} + +func makeLocationIDMap(n int) locationIDMap { + return locationIDMap{ + dense: make([]*Location, n), + sparse: map[uint64]*Location{}, + } +} + +func (lm locationIDMap) get(id uint64) *Location { + if id < uint64(len(lm.dense)) { + return lm.dense[int(id)] + } + return lm.sparse[id] +} + +func (lm locationIDMap) set(id uint64, loc *Location) { + if id < uint64(len(lm.dense)) { + lm.dense[id] = loc + return + } + lm.sparse[id] = loc +} + +// CompatibilizeSampleTypes makes profiles compatible to be compared/merged. It +// keeps sample types that appear in all profiles only and drops/reorders the +// sample types as necessary. +// +// In the case of sample types order is not the same for given profiles the +// order is derived from the first profile. +// +// Profiles are modified in-place. +// +// It returns an error if the sample type's intersection is empty. +func CompatibilizeSampleTypes(ps []*Profile) error { + sTypes := commonSampleTypes(ps) + if len(sTypes) == 0 { + return fmt.Errorf("profiles have empty common sample type list") + } + for _, p := range ps { + if err := compatibilizeSampleTypes(p, sTypes); err != nil { + return err + } + } + return nil +} + +// commonSampleTypes returns sample types that appear in all profiles in the +// order how they ordered in the first profile. +func commonSampleTypes(ps []*Profile) []string { + if len(ps) == 0 { + return nil + } + sTypes := map[string]int{} + for _, p := range ps { + for _, st := range p.SampleType { + sTypes[st.Type]++ + } + } + var res []string + for _, st := range ps[0].SampleType { + if sTypes[st.Type] == len(ps) { + res = append(res, st.Type) + } + } + return res +} + +// compatibilizeSampleTypes drops sample types that are not present in sTypes +// list and reorder them if needed. +// +// It sets DefaultSampleType to sType[0] if it is not in sType list. +// +// It assumes that all sample types from the sTypes list are present in the +// given profile otherwise it returns an error. +func compatibilizeSampleTypes(p *Profile, sTypes []string) error { + if len(sTypes) == 0 { + return fmt.Errorf("sample type list is empty") + } + defaultSampleType := sTypes[0] + reMap, needToModify := make([]int, len(sTypes)), false + for i, st := range sTypes { + if st == p.DefaultSampleType { + defaultSampleType = p.DefaultSampleType + } + idx := searchValueType(p.SampleType, st) + if idx < 0 { + return fmt.Errorf("%q sample type is not found in profile", st) + } + reMap[i] = idx + if idx != i { + needToModify = true + } + } + if !needToModify && len(sTypes) == len(p.SampleType) { + return nil + } + p.DefaultSampleType = defaultSampleType + oldSampleTypes := p.SampleType + p.SampleType = make([]*ValueType, len(sTypes)) + for i, idx := range reMap { + p.SampleType[i] = oldSampleTypes[idx] + } + values := make([]int64, len(sTypes)) + for _, s := range p.Sample { + for i, idx := range reMap { + values[i] = s.Value[idx] + } + s.Value = s.Value[:len(values)] + copy(s.Value, values) + } + return nil +} + +func searchValueType(vts []*ValueType, s string) int { + for i, vt := range vts { + if vt.Type == s { + return i + } + } + return -1 +} diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go index 5a3807f97..60ef7e926 100644 --- a/vendor/github.com/google/pprof/profile/profile.go +++ b/vendor/github.com/google/pprof/profile/profile.go @@ -21,7 +21,6 @@ import ( "compress/gzip" "fmt" "io" - "io/ioutil" "math" "path/filepath" "regexp" @@ -73,9 +72,23 @@ type ValueType struct { type Sample struct { Location []*Location Value []int64 - Label map[string][]string + // Label is a per-label-key map to values for string labels. + // + // In general, having multiple values for the given label key is strongly + // discouraged - see docs for the sample label field in profile.proto. The + // main reason this unlikely state is tracked here is to make the + // decoding->encoding roundtrip not lossy. But we expect that the value + // slices present in this map are always of length 1. + Label map[string][]string + // NumLabel is a per-label-key map to values for numeric labels. See a note + // above on handling multiple values for a label. NumLabel map[string][]int64 - NumUnit map[string][]string + // NumUnit is a per-label-key map to the unit names of corresponding numeric + // label values. The unit info may be missing even if the label is in + // NumLabel, see the docs in profile.proto for details. When the value is + // slice is present and not nil, its length must be equal to the length of + // the corresponding value slice in NumLabel. + NumUnit map[string][]string locationIDX []uint64 labelX []label @@ -153,7 +166,7 @@ type Function struct { // may be a gzip-compressed encoded protobuf or one of many legacy // profile formats which may be unsupported in the future. func Parse(r io.Reader) (*Profile, error) { - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return nil, err } @@ -168,7 +181,7 @@ func ParseData(data []byte) (*Profile, error) { if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err == nil { - data, err = ioutil.ReadAll(gz) + data, err = io.ReadAll(gz) } if err != nil { return nil, fmt.Errorf("decompressing profile: %v", err) @@ -716,6 +729,35 @@ func (s *Sample) HasLabel(key, value string) bool { return false } +// SetNumLabel sets the specified key to the specified value for all samples in the +// profile. "unit" is a slice that describes the units that each corresponding member +// of "values" is measured in (e.g. bytes or seconds). If there is no relevant +// unit for a given value, that member of "unit" should be the empty string. +// "unit" must either have the same length as "value", or be nil. +func (p *Profile) SetNumLabel(key string, value []int64, unit []string) { + for _, sample := range p.Sample { + if sample.NumLabel == nil { + sample.NumLabel = map[string][]int64{key: value} + } else { + sample.NumLabel[key] = value + } + if sample.NumUnit == nil { + sample.NumUnit = map[string][]string{key: unit} + } else { + sample.NumUnit[key] = unit + } + } +} + +// RemoveNumLabel removes all numerical labels associated with the specified key for all +// samples in the profile. +func (p *Profile) RemoveNumLabel(key string) { + for _, sample := range p.Sample { + delete(sample.NumLabel, key) + delete(sample.NumUnit, key) + } +} + // DiffBaseSample returns true if a sample belongs to the diff base and false // otherwise. func (s *Sample) DiffBaseSample() bool { diff --git a/vendor/github.com/google/pprof/profile/proto.go b/vendor/github.com/google/pprof/profile/proto.go index 539ad3ab3..a15696ba1 100644 --- a/vendor/github.com/google/pprof/profile/proto.go +++ b/vendor/github.com/google/pprof/profile/proto.go @@ -39,11 +39,12 @@ import ( ) type buffer struct { - field int // field tag - typ int // proto wire type code for field - u64 uint64 - data []byte - tmp [16]byte + field int // field tag + typ int // proto wire type code for field + u64 uint64 + data []byte + tmp [16]byte + tmpLines []Line // temporary storage used while decoding "repeated Line". } type decoder func(*buffer, message) error @@ -286,7 +287,6 @@ func decodeInt64s(b *buffer, x *[]int64) error { if b.typ == 2 { // Packed encoding data := b.data - tmp := make([]int64, 0, len(data)) // Maximally sized for len(data) > 0 { var u uint64 var err error @@ -294,9 +294,8 @@ func decodeInt64s(b *buffer, x *[]int64) error { if u, data, err = decodeVarint(data); err != nil { return err } - tmp = append(tmp, int64(u)) + *x = append(*x, int64(u)) } - *x = append(*x, tmp...) return nil } var i int64 @@ -319,7 +318,6 @@ func decodeUint64s(b *buffer, x *[]uint64) error { if b.typ == 2 { data := b.data // Packed encoding - tmp := make([]uint64, 0, len(data)) // Maximally sized for len(data) > 0 { var u uint64 var err error @@ -327,9 +325,8 @@ func decodeUint64s(b *buffer, x *[]uint64) error { if u, data, err = decodeVarint(data); err != nil { return err } - tmp = append(tmp, u) + *x = append(*x, u) } - *x = append(*x, tmp...) return nil } var u uint64 diff --git a/vendor/github.com/google/pprof/profile/prune.go b/vendor/github.com/google/pprof/profile/prune.go index 02d21a818..b2f9fd546 100644 --- a/vendor/github.com/google/pprof/profile/prune.go +++ b/vendor/github.com/google/pprof/profile/prune.go @@ -62,15 +62,31 @@ func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) { prune := make(map[uint64]bool) pruneBeneath := make(map[uint64]bool) + // simplifyFunc can be expensive, so cache results. + // Note that the same function name can be encountered many times due + // different lines and addresses in the same function. + pruneCache := map[string]bool{} // Map from function to whether or not to prune + pruneFromHere := func(s string) bool { + if r, ok := pruneCache[s]; ok { + return r + } + funcName := simplifyFunc(s) + if dropRx.MatchString(funcName) { + if keepRx == nil || !keepRx.MatchString(funcName) { + pruneCache[s] = true + return true + } + } + pruneCache[s] = false + return false + } + for _, loc := range p.Location { var i int for i = len(loc.Line) - 1; i >= 0; i-- { if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { - funcName := simplifyFunc(fn.Name) - if dropRx.MatchString(funcName) { - if keepRx == nil || !keepRx.MatchString(funcName) { - break - } + if pruneFromHere(fn.Name) { + break } } } diff --git a/vendor/github.com/google/safehtml/CONTRIBUTING.md b/vendor/github.com/google/safehtml/CONTRIBUTING.md new file mode 100644 index 000000000..22b241cb7 --- /dev/null +++ b/vendor/github.com/google/safehtml/CONTRIBUTING.md @@ -0,0 +1,29 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement (CLA). You (or your employer) retain the copyright to your +contribution; this simply gives us permission to use and redistribute your +contributions as part of the project. Head over to + to see your current agreements on file or +to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google/conduct/). diff --git a/vendor/github.com/google/safehtml/LICENSE b/vendor/github.com/google/safehtml/LICENSE new file mode 100644 index 000000000..dec93b16e --- /dev/null +++ b/vendor/github.com/google/safehtml/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google LLC nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/google/safehtml/README.md b/vendor/github.com/google/safehtml/README.md new file mode 100644 index 000000000..d3c9676d1 --- /dev/null +++ b/vendor/github.com/google/safehtml/README.md @@ -0,0 +1,17 @@ +# Safe HTML for Go + +`safehtml` provides immutable string-like types that wrap web types such as +HTML, JavaScript and CSS. These wrappers are safe by construction against XSS +and similar web vulnerabilities, and they can only be interpolated in safe ways. +You can read more about our approach to web security in our +[whitepaper](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/42934.pdf), +or this [OWASP talk](https://www.youtube.com/watch?v=ccfEu-Jj0as). + +Additional subpackages provide APIs for managing exceptions to the +safety rules, and a template engine with a syntax and interface that closely +matches [`html/template`](https://golang.org/pkg/html/template/). You can refer +to the [godoc](https://pkg.go.dev/github.com/google/safehtml?tab=doc) +for each (sub)package for the API documentation and code examples. +More end-to-end demos are available in `example_test.go`. + +This is not an officially supported Google product. diff --git a/vendor/github.com/google/safehtml/doc.go b/vendor/github.com/google/safehtml/doc.go new file mode 100644 index 000000000..4c5c1bf78 --- /dev/null +++ b/vendor/github.com/google/safehtml/doc.go @@ -0,0 +1,11 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +// Package safehtml provides immutable string-like types which represent values that +// are guaranteed to be safe, by construction or by escaping or sanitization, to use +// in various HTML contexts and with various DOM APIs. +// +package safehtml diff --git a/vendor/github.com/google/safehtml/html.go b/vendor/github.com/google/safehtml/html.go new file mode 100644 index 000000000..27c0f337d --- /dev/null +++ b/vendor/github.com/google/safehtml/html.go @@ -0,0 +1,117 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "bytes" + "html" + "unicode" + + "golang.org/x/text/unicode/rangetable" +) + +// An HTML is an immutable string-like type that is safe to use in HTML +// contexts in DOM APIs and HTML documents. +// +// HTML guarantees that its value as a string will not cause untrusted script +// execution when evaluated as HTML in a browser. +// +// Values of this type are guaranteed to be safe to use in HTML contexts, +// such as assignment to the innerHTML DOM property, or interpolation into an +// HTML template in HTML PC_DATA context, in the sense that the use will not +// result in a Cross-site Scripting (XSS) vulnerability. +type HTML struct { + // We declare an HTML not as a string but as a struct wrapping a string + // to prevent construction of HTML values through string conversion. + str string +} + +// HTMLer is implemented by any value that has an HTML method, which defines the +// safe HTML format for that value. +type HTMLer interface { + HTML() HTML +} + +// HTMLEscaped returns an HTML whose value is text, with the characters [&<>"'] escaped. +// +// text is coerced to interchange valid, so the resulting HTML contains only +// valid UTF-8 characters which are legal in HTML and XML. +// +func HTMLEscaped(text string) HTML { + return HTML{escapeAndCoerceToInterchangeValid(text)} +} + +// HTMLConcat returns an HTML which contains, in order, the string representations +// of the given htmls. +func HTMLConcat(htmls ...HTML) HTML { + var b bytes.Buffer + for _, html := range htmls { + b.WriteString(html.String()) + } + return HTML{b.String()} +} + +// String returns the string form of the HTML. +func (h HTML) String() string { + return h.str +} + +// escapeAndCoerceToInterchangeValid coerces the string to interchange-valid +// UTF-8 and then HTML-escapes it. +func escapeAndCoerceToInterchangeValid(str string) string { + return html.EscapeString(coerceToUTF8InterchangeValid(str)) +} + +// coerceToUTF8InterchangeValid coerces a string to interchange-valid UTF-8. +// Illegal UTF-8 bytes are replaced with the Unicode replacement character +// ('\uFFFD'). C0 and C1 control codes (other than CR LF HT FF) and +// non-characters are also replaced with the Unicode replacement character. +func coerceToUTF8InterchangeValid(s string) string { + // TODO: Replace this entire function with stdlib function if https://golang.org/issue/25805 gets addressed. + runes := make([]rune, 0, len(s)) + // If s contains any invalid UTF-8 byte sequences, range will have rune + // contain the Unicode replacement character and there's no need to call + // utf8.ValidRune. I.e. iteration over the string implements + // CoerceToStructurallyValid() from C++/Java. + // See https://blog.golang.org/strings. + for _, rune := range s { + if unicode.Is(controlAndNonCharacter, rune) { + runes = append(runes, unicode.ReplacementChar) + } else { + runes = append(runes, rune) + } + } + return string(runes) +} + +// controlAndNonCharacters contains the non-interchange-valid codepoints. +// +// See http://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream +// +// safehtml functions do a lot of lookups on these tables, so merging them is probably +// worth it to avoid comparing against both tables each time. +var controlAndNonCharacter = rangetable.Merge(unicode.Noncharacter_Code_Point, controlChar) + +// controlChar contains Unicode control characters disallowed in interchange +// valid UTF-8. This table is slightly different from unicode.Cc: +// - Disallows null. +// - Allows LF, CR, HT, and FF. +// +// unicode.C is mentioned in unicode.IsControl; it contains "special" characters +// which includes at least control characters, surrogate code points, and +// formatting codepoints (e.g. word joiner). We don't need to exclude all of +// those. In particular, surrogates are handled by the for loop converting +// invalid UTF-8 byte sequences to the Unicode replacement character. +var controlChar = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x0000, 0x0008, 1}, + {0x000B, 0x000B, 1}, + {0x000E, 0x001F, 1}, + {0x007F, 0x009F, 1}, + }, + LatinOffset: 4, +} diff --git a/vendor/github.com/google/safehtml/identifier.go b/vendor/github.com/google/safehtml/identifier.go new file mode 100644 index 000000000..ffad26423 --- /dev/null +++ b/vendor/github.com/google/safehtml/identifier.go @@ -0,0 +1,83 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "fmt" + "regexp" +) + +// A Identifier is an immutable string-like type that is safe to use in HTML +// contexts as an identifier for HTML elements. For example, it is unsafe to +// insert an untrusted string into a +// +// +// +// context since the string may be controlled by an attacker who can assign it +// a value that masks existing DOM properties (i.e. DOM Clobbering). An +// attacker may also be able to force legitimate Javascript code, which uses +// document.getElementsByName(...) to read DOM elements, to refer to this +// element. This may lead to unintended side effects, particularly if that +// element contains attacker-controlled data. It is, however, safe to use an +// Identifier in this context since its value is known to be partially or fully +// under application control. +// +// In order to ensure that an attacker cannot influence the Identifier value, +// an Identifier can only be instantiated from a compile-time constant string +// literal prefix. +// +// Note that Identifier is Go-specific and therefore does not have a Proto form +// for cross-language use. +type Identifier struct { + // We declare a Identifier not as a string but as a struct wrapping a string + // to prevent construction of Identifier values through string conversion. + str string +} + +// To minimize the risk of parsing errors, Identifier values must start with an +// alphabetical rune, and comprise of only alphanumeric, '-', and '_' runes. + +// startsWithAlphabetPattern matches strings that start with an alphabetical rune. +var startsWithAlphabetPattern = regexp.MustCompile(`^[a-zA-Z]`) + +// onlyAlphanumericsOrHyphenPattern matches strings that only contain alphanumeric, +// '-' and '_' runes. +var onlyAlphanumericsOrHyphenPattern = regexp.MustCompile(`^[-_a-zA-Z0-9]*$`) + +// IdentifierFromConstant constructs an Identifier with its underlying identifier +// set to the given string value, which must be an untyped string constant. It +// panics if value does not start with an alphabetic rune or contains any +// non-alphanumeric runes other than '-' and '_'. +func IdentifierFromConstant(value stringConstant) Identifier { + if !startsWithAlphabetPattern.MatchString(string(value)) || + !onlyAlphanumericsOrHyphenPattern.MatchString(string(value)) { + panic(fmt.Sprintf("invalid identifier %q", string(value))) + } + return Identifier{string(value)} +} + +// IdentifierFromConstantPrefix constructs an Identifier with its underlying string +// set to the string formed by joining prefix, which must be an untyped string +// constant, and value with a hyphen. It panics if prefix or value contain any +// non-alphanumeric runes other than '-' and '_', or if prefix does not start with +// an alphabetic rune. +func IdentifierFromConstantPrefix(prefix stringConstant, value string) Identifier { + prefixString := string(prefix) + if !startsWithAlphabetPattern.MatchString(string(prefix)) || + !onlyAlphanumericsOrHyphenPattern.MatchString(string(prefix)) { + panic(fmt.Sprintf("invalid prefix %q", string(prefix))) + } + if !onlyAlphanumericsOrHyphenPattern.MatchString(value) { + panic(fmt.Sprintf("value %q contains non-alphanumeric runes", value)) + } + return Identifier{prefixString + "-" + value} +} + +// String returns the string form of the Identifier. +func (i Identifier) String() string { + return i.str +} diff --git a/vendor/github.com/google/safehtml/init.go b/vendor/github.com/google/safehtml/init.go new file mode 100644 index 000000000..d37547d72 --- /dev/null +++ b/vendor/github.com/google/safehtml/init.go @@ -0,0 +1,58 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "github.com/google/safehtml/internal/raw" +) + +// stringConstant is an unexported string type. Users of this package cannot +// create values of this type except by passing an untyped string constant to +// functions which expect a stringConstant. This type should only be used in +// function and method parameters. +type stringConstant string + +// The following functions are used by package uncheckedconversions +// (via package raw) to create safe HTML types from plain strings. + +func htmlRaw(s string) HTML { + return HTML{s} +} + +func scriptRaw(s string) Script { + return Script{s} +} + +func style(s string) Style { + return Style{s} +} + +func styleSheetRaw(s string) StyleSheet { + return StyleSheet{s} +} + +func urlRaw(s string) URL { + return URL{s} +} + +func trustedResourceURLRaw(s string) TrustedResourceURL { + return TrustedResourceURL{s} +} + +func identifierRaw(s string) Identifier { + return Identifier{s} +} + +func init() { + raw.HTML = htmlRaw + raw.Script = scriptRaw + raw.Style = style + raw.StyleSheet = styleSheetRaw + raw.URL = urlRaw + raw.TrustedResourceURL = trustedResourceURLRaw + raw.Identifier = identifierRaw +} diff --git a/vendor/github.com/google/safehtml/internal/raw/raw.go b/vendor/github.com/google/safehtml/internal/raw/raw.go new file mode 100644 index 000000000..3bedb6a6d --- /dev/null +++ b/vendor/github.com/google/safehtml/internal/raw/raw.go @@ -0,0 +1,31 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +// Package raw provides a coordination point for package safehtml, package +// uncheckedconversions, package legacyconversions, and package testconversions. +// raw must only be imported by these four packages. +package raw + +// HTML is the raw constructor for a safehtml.HTML. +var HTML interface{} + +// Script is the raw constructor for a safehtml.Script. +var Script interface{} + +// Style is the raw constructor for a safehtml.Style. +var Style interface{} + +// StyleSheet is the raw constructor for a safehtml.StyleSheet. +var StyleSheet interface{} + +// URL is the raw constructor for a safehtml.URL. +var URL interface{} + +// TrustedResourceURL is the raw constructor for a safehtml.TrustedResourceURL. +var TrustedResourceURL interface{} + +// Identifier is the raw constructor for a safehtml.Identifier. +var Identifier interface{} diff --git a/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go b/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go new file mode 100644 index 000000000..dd8e7fe36 --- /dev/null +++ b/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go @@ -0,0 +1,180 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +// Package safehtmlutil contains functions shared by package safehtml and safehtml/template. +package safehtmlutil + +import ( + "bytes" + "fmt" + "reflect" + "regexp" +) + +// IsSafeTrustedResourceURLPrefix returns whether the given prefix is safe to use as a +// TrustedResourceURL prefix. +// +// TrustedResourceURL prefixes must start with one of the following: +// * `https:///` +// * `///` +// * `/` +// * `about:blank#` +// +// `` must contain only alphanumerics, '.', ':', '[', ']', or '-'. +// These restrictions do not enforce a well-formed domain name, so '.' and '1.2' are valid. +// +// `` is any character except `/` and `\`. Based on +// https://url.spec.whatwg.org/commit-snapshots/56b74ce7cca8883eab62e9a12666e2fac665d03d/#url-parsing, +// an initial / which is not followed by another / or \ will end up in the "path state" and from there +// it can only go to the "fragment state" and "query state". +func IsSafeTrustedResourceURLPrefix(prefix string) bool { + return safeTrustedResourceURLPrefixPattern.MatchString(prefix) +} + +var safeTrustedResourceURLPrefixPattern = regexp.MustCompile(`(?i)^(?:` + + `(?:https:)?//[0-9a-z.:\[\]-]+/|` + + `/[^/\\]|` + + `about:blank#)`) + +// URLContainsDoubleDotSegment returns whether the given URL or URL substring +// contains the double dot-segment ".." (RFC3986 3.3) in its percent-encoded or +// unencoded form. +func URLContainsDoubleDotSegment(url string) bool { + return urlDoubleDotSegmentPattern.MatchString(url) +} + +var urlDoubleDotSegmentPattern = regexp.MustCompile(`(?i)(?:\.|%2e)(?:\.|%2e)`) + +// QueryEscapeURL produces an output that can be embedded in a URL query. +// The output can be embedded in an HTML attribute without further escaping. +func QueryEscapeURL(args ...interface{}) string { + return urlProcessor(false, Stringify(args...)) +} + +// NormalizeURL normalizes URL content so it can be embedded in a quote-delimited +// string or parenthesis delimited url(...). +// The normalizer does not encode all HTML specials. Specifically, it does not +// encode '&' so correct embedding in an HTML attribute requires escaping of +// '&' to '&'. +func NormalizeURL(args ...interface{}) string { + return urlProcessor(true, Stringify(args...)) +} + +// urlProcessor normalizes (when norm is true) or escapes its input to produce +// a valid hierarchical or opaque URL part. +func urlProcessor(norm bool, s string) string { + var b bytes.Buffer + written := 0 + // The byte loop below assumes that all URLs use UTF-8 as the + // content-encoding. This is similar to the URI to IRI encoding scheme + // defined in section 3.1 of RFC 3987, and behaves the same as the + // EcmaScript builtin encodeURIComponent. + // It should not cause any misencoding of URLs in pages with + // Content-type: text/html;charset=UTF-8. + for i, n := 0, len(s); i < n; i++ { + c := s[i] + switch c { + // Single quote and parens are sub-delims in RFC 3986, but we + // escape them so the output can be embedded in single + // quoted attributes and unquoted CSS url(...) constructs. + // Single quotes are reserved in URLs, but are only used in + // the obsolete "mark" rule in an appendix in RFC 3986 + // so can be safely encoded. + case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']': + if norm { + continue + } + // Unreserved according to RFC 3986 sec 2.3 + // "For consistency, percent-encoded octets in the ranges of + // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), + // period (%2E), underscore (%5F), or tilde (%7E) should not be + // created by URI producers + case '-', '.', '_', '~': + continue + case '%': + // When normalizing do not re-encode valid escapes. + if norm && i+2 < len(s) && isHex(s[i+1]) && isHex(s[i+2]) { + continue + } + default: + // Unreserved according to RFC 3986 sec 2.3 + if 'a' <= c && c <= 'z' { + continue + } + if 'A' <= c && c <= 'Z' { + continue + } + if '0' <= c && c <= '9' { + continue + } + } + b.WriteString(s[written:i]) + fmt.Fprintf(&b, "%%%02x", c) + written = i + 1 + } + if written == 0 { + return s + } + b.WriteString(s[written:]) + return b.String() +} + +// isHex reports whether the given character is a hex digit. +func isHex(c byte) bool { + return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' +} + +// Stringify converts its arguments to a string. It is equivalent to +// fmt.Sprint(args...), except that it deferences all pointers. +func Stringify(args ...interface{}) string { + // Optimization for simple common case of a single string argument. + if len(args) == 1 { + if s, ok := args[0].(string); ok { + return s + } + } + for i, arg := range args { + args[i] = indirectToStringerOrError(arg) + } + return fmt.Sprint(args...) +} + +var ( + errorType = reflect.TypeOf((*error)(nil)).Elem() + fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() +) + +// indirectToStringerOrError dereferences a as many times +// as necessary to reach the base type, an implementation of fmt.Stringer, +// or an implementation of error, and returns a value of that type. It returns +// nil if a is nil. +func indirectToStringerOrError(a interface{}) interface{} { + if a == nil { + return nil + } + v := reflect.ValueOf(a) + for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v.Interface() +} + +// Indirect returns the value, after dereferencing as many times +// as necessary to reach the base type (or nil). +func Indirect(a interface{}) interface{} { + if a == nil { + return nil + } + if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { + // Avoid creating a reflect.Value if it's not a pointer. + return a + } + v := reflect.ValueOf(a) + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v.Interface() +} diff --git a/vendor/github.com/google/safehtml/internal/template/raw/raw.go b/vendor/github.com/google/safehtml/internal/template/raw/raw.go new file mode 100644 index 000000000..b69599bd2 --- /dev/null +++ b/vendor/github.com/google/safehtml/internal/template/raw/raw.go @@ -0,0 +1,16 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +// Package raw provides a coordination point for package safehtml/template and +// package safehtml/template/uncheckedconversions. raw must be imported only by +// these two packages. +package raw + +// TrustedSource is the raw constructor for a template.TrustedSource. +var TrustedSource interface{} + +// TrustedTemplate is the raw constructor for a template.TrustedTemplate. +var TrustedTemplate interface{} diff --git a/vendor/github.com/google/safehtml/script.go b/vendor/github.com/google/safehtml/script.go new file mode 100644 index 000000000..c9e0fd298 --- /dev/null +++ b/vendor/github.com/google/safehtml/script.go @@ -0,0 +1,90 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "encoding/json" + "fmt" + "regexp" +) + +// A Script is an immutable string-like type which represents JavaScript +// code and guarantees that its value, as a string, will not cause execution +// of unconstrained attacker controlled code (cross-site scripting) when +// evaluated as JavaScript in a browser. +// +// Script's string representation can safely be interpolated as the +// content of a script element within HTML, and can safely be passed to DOM +// properties and functions which expect JavaScript. In these cases, the Script +// string should not be escaped. Script's string representation can also be safely +// used as the value for on* attribute handlers in HTML, though the Script string +// must be escaped before such use. +// +// Note that the Script might contain text that is attacker-controlled but +// that text should have been interpolated with appropriate escaping, +// sanitization and/or validation into the right location in the script, such +// that it is highly constrained in its effect (for example, it had to match a +// set of allowed words). +// +// In order to ensure that an attacker cannot influence the Script +// value, a Script can only be instantiated from compile-time +// constant string literals or security-reviewed unchecked conversions, +// but never from arbitrary string values potentially representing untrusted +// user input. +type Script struct { + // We declare a Script not as a string but as a struct wrapping a string + // to prevent construction of Script values through string conversion. + str string +} + +// ScriptFromConstant constructs a Script with its underlying script set +// to the given script, which must be an untyped string constant. +// +// No runtime validation or sanitization is performed on script; being under +// application control, it is simply assumed to comply with the Script +// contract. +func ScriptFromConstant(script stringConstant) Script { + return Script{string(script)} +} + +// ScriptFromDataAndConstant constructs a Script of the form +// +// var name = data; script +// +// where name is the supplied variable name, data is the supplied data value +// encoded as JSON using encoding/json.Marshal, and script is the supplied +// JavaScript statement or sequence of statements. The supplied name and script +// must both be untyped string constants. It returns an error if name is not a +// valid Javascript identifier or JSON encoding fails. +// +// No runtime validation or sanitization is performed on script; being under +// application control, it is simply assumed to comply with the Script +// contract. +func ScriptFromDataAndConstant(name stringConstant, data interface{}, script stringConstant) (Script, error) { + if !jsIdentifierPattern.MatchString(string(name)) { + return Script{}, fmt.Errorf("variable name %q is an invalid Javascript identifier", string(name)) + } + json, err := json.Marshal(data) + if err != nil { + return Script{}, err + } + return Script{fmt.Sprintf("var %s = %s;\n%s", name, json, string(script))}, nil +} + +// jsIdentifierPattern matches strings that are valid Javascript identifiers. +// +// This pattern accepts only a subset of valid identifiers defined in +// https://tc39.github.io/ecma262/#sec-names-and-keywords. In particular, +// it does not match identifiers that contain non-ASCII letters, Unicode +// escape sequences, and the Unicode format-control characters +// \u200C (zero-width non-joiner) and \u200D (zero-width joiner). +var jsIdentifierPattern = regexp.MustCompile(`^[$_a-zA-Z][$_a-zA-Z0-9]+$`) + +// String returns the string form of the Script. +func (s Script) String() string { + return s.str +} diff --git a/vendor/github.com/google/safehtml/style.go b/vendor/github.com/google/safehtml/style.go new file mode 100644 index 000000000..c11ac9d96 --- /dev/null +++ b/vendor/github.com/google/safehtml/style.go @@ -0,0 +1,304 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "bytes" + "fmt" + "regexp" + "strings" +) + +// A Style is an immutable string-like type which represents a sequence of CSS +// declarations (property_name1: property_value1; property_name2: property_value2; ...) +// and guarantees that its value will not cause untrusted script execution +// (cross-site scripting) when evaluated as CSS in a browser. +// +// Style's string representation can safely be: +// * Interpolated as the content of a quoted HTML style attribute. However, the +// Style string must be HTML-attribute-escaped before interpolation. +// * Interpolated as the content of a {}-wrapped block within a StyleSheet. +// '<' runes in the Style string must be CSS-escaped before interpolation. +// The Style string is also guaranteed not to be able to introduce new +// properties or elide existing ones. +// * Interpolated as the content of a {}-wrapped block within an HTML `. Escape this in case the Style user forgets to. + c == '"', c == '\\', // Must be CSS-escaped in . U+000A line feed is handled in the next case. + c <= '\u001F', c == '\u007F', // C0 control codes + c >= '\u0080' && c <= '\u009F', // C1 control codes + c == '\u2028', c == '\u2029': // Unicode newline characters + // See CSS escape sequence syntax at https://www.w3.org/TR/css-syntax-3/#escape-diagram. + fmt.Fprintf(&b, "\\%06X", c) + default: + b.WriteRune(c) + } + } + return b.String() +} diff --git a/vendor/github.com/google/safehtml/stylesheet.go b/vendor/github.com/google/safehtml/stylesheet.go new file mode 100644 index 000000000..17de8a517 --- /dev/null +++ b/vendor/github.com/google/safehtml/stylesheet.go @@ -0,0 +1,111 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "container/list" + "fmt" + "regexp" + "strings" +) + +// A StyleSheet is an immutable string-like type which represents a CSS +// style sheet and guarantees that its value, as a string, will not cause +// untrusted script execution (cross-site scripting) when evaluated as CSS +// in a browser. +// +// StyleSheet's string representation can safely be interpolated as the +// content of a style element within HTML. The StyleSheet string should +// not be escaped before interpolation. +type StyleSheet struct { + // We declare a StyleSheet not as a string but as a struct wrapping a string + // to prevent construction of StyleSheet values through string conversion. + str string +} + +// StyleSheetFromConstant constructs a StyleSheet with the +// underlying stylesheet set to the given styleSheet, which must be an untyped string +// constant. +// +// No runtime validation or sanitization is performed on script; being under +// application control, it is simply assumed to comply with the StyleSheet +// contract. +func StyleSheetFromConstant(styleSheet stringConstant) StyleSheet { + return StyleSheet{string(styleSheet)} +} + +// CSSRule constructs a StyleSheet containng a CSS rule of the form: +// selector{style} +// It returns an error if selector contains disallowed characters or unbalanced +// brackets. +// +// The constructed StyleSheet value is guaranteed to fulfill its type contract, +// but is not guaranteed to be semantically valid CSS. +func CSSRule(selector string, style Style) (StyleSheet, error) { + if strings.ContainsRune(selector, '<') { + return StyleSheet{}, fmt.Errorf("selector %q contains '<'", selector) + } + selectorWithoutStrings := cssStringPattern.ReplaceAllString(selector, "") + if matches := invalidCSSSelectorRune.FindStringSubmatch(selectorWithoutStrings); matches != nil { + return StyleSheet{}, fmt.Errorf("selector %q contains %q, which is disallowed outside of CSS strings", selector, matches[0]) + } + if !hasBalancedBrackets(selectorWithoutStrings) { + return StyleSheet{}, fmt.Errorf("selector %q contains unbalanced () or [] brackets", selector) + } + return StyleSheet{fmt.Sprintf("%s{%s}", selector, style.String())}, nil +} + +var ( + // cssStringPattern matches a single- or double-quoted CSS string. + cssStringPattern = regexp.MustCompile( + `"([^"\r\n\f\\]|\\[\s\S])*"|` + // Double-quoted string literal + `'([^'\r\n\f\\]|\\[\s\S])*'`) // Single-quoted string literal + + // invalidCSSSelectorRune matches a rune that is not allowed in a CSS3 + // selector that does not contain string literals. + // See https://w3.org/TR/css3-selectors/#selectors. + invalidCSSSelectorRune = regexp.MustCompile(`[^-_a-zA-Z0-9#.:* ,>+~[\]()=^$|]`) +) + +// hasBalancedBrackets returns whether s has balanced () and [] brackets. +func hasBalancedBrackets(s string) bool { + stack := list.New() + for i := 0; i < len(s); i++ { + c := s[i] + if expected, ok := matchingBrackets[c]; ok { + e := stack.Back() + if e == nil { + return false + } + // Skip success check for this type assertion since it is trivial to + // see that only bytes are pushed onto this stack. + if v := e.Value.(byte); v != expected { + return false + } + stack.Remove(e) + continue + } + for _, openBracket := range matchingBrackets { + if c == openBracket { + stack.PushBack(c) + break + } + } + } + return stack.Len() == 0 +} + +// matchingBrackets[x] is the opening bracket that matches closing bracket x. +var matchingBrackets = map[byte]byte{ + ')': '(', + ']': '[', +} + +// String returns the string form of the StyleSheet. +func (s StyleSheet) String() string { + return s.str +} diff --git a/vendor/github.com/google/safehtml/template/context.go b/vendor/github.com/google/safehtml/template/context.go new file mode 100644 index 000000000..dd7886dc6 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/context.go @@ -0,0 +1,183 @@ +// 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 template + +import ( + "strings" +) + +// context describes the state an HTML parser must be in when it reaches the +// portion of HTML produced by evaluating a particular template node. +// +// The zero value of type Context is the start context for a template that +// produces an HTML fragment as defined at +// http://www.w3.org/TR/html5/syntax.html#the-end +// where the context element is null. +type context struct { + state state + delim delim + element element + attr attr + err *Error + // scriptType is the lowercase value of the "type" attribute inside the current "script" + // element (see https://dev.w3.org/html5/spec-preview/the-script-element.html#attr-script-type). + // This field will be empty if the parser is currently not in a script element, + // the type attribute has not already been parsed in the current element, or if the + // value of the type attribute cannot be determined at parse time. + scriptType string + // linkRel is the value of the "rel" attribute inside the current "link" + // element (see https://html.spec.whatwg.org/multipage/semantics.html#attr-link-rel). + // This value has been normalized to lowercase with exactly one space between tokens + // and exactly one space at start and end, so that a lookup of any token foo can + // be performed by searching for the substring " foo ". + // This field will be empty if the parser is currently not in a link element, + // the rel attribute has not already been parsed in the current element, or if the + // value of the rel attribute cannot be determined at parse time. + linkRel string +} + +// eq returns whether Context c is equal to Context d. +func (c context) eq(d context) bool { + return c.state == d.state && + c.delim == d.delim && + c.element.eq(d.element) && + c.attr.eq(d.attr) && + c.err == d.err && + c.scriptType == d.scriptType && + c.linkRel == d.linkRel +} + +// state describes a high-level HTML parser state. +// +// It bounds the top of the element stack, and by extension the HTML insertion +// mode, but also contains state that does not correspond to anything in the +// HTML5 parsing algorithm because a single token production in the HTML +// grammar may contain embedded actions in a template. For instance, the quoted +// HTML attribute produced by +//
+// is a single token in HTML's grammar but in a template spans several nodes. +type state uint8 + +//go:generate stringer -type state + +const ( + // stateText is parsed character data. An HTML parser is in + // this state when its parse position is outside an HTML tag, + // directive, comment, and special element body. + stateText state = iota + // stateSpecialElementBody occurs inside a specal HTML element body. + stateSpecialElementBody + // stateTag occurs before an HTML attribute or the end of a tag. + stateTag + // stateAttrName occurs inside an attribute name. + // It occurs between the ^'s in ` ^name^ = value`. + stateAttrName + // stateAfterName occurs after an attr name has ended but before any + // equals sign. It occurs between the ^'s in ` name^ ^= value`. + stateAfterName + // stateBeforeValue occurs after the equals sign but before the value. + // It occurs between the ^'s in ` name =^ ^value`. + stateBeforeValue + // stateHTMLCmt occurs inside an . + stateHTMLCmt + // stateAttr occurs inside an HTML attribute whose content is text. + stateAttr + // stateError is an infectious error state outside any valid + // HTML/CSS/JS construct. + stateError +) + +// isComment reports whether a state contains content meant for template +// authors & maintainers, not for end-users or machines. +func isComment(s state) bool { + switch s { + case stateHTMLCmt: + return true + } + return false +} + +// isInTag reports whether s occurs solely inside an HTML tag. +func isInTag(s state) bool { + switch s { + case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr: + return true + } + return false +} + +// delim is the delimiter that will end the current HTML attribute. +type delim uint8 + +//go:generate stringer -type delim + +const ( + // delimNone occurs outside any attribute. + delimNone delim = iota + // delimDoubleQuote occurs when a double quote (") closes the attribute. + delimDoubleQuote + // delimSingleQuote occurs when a single quote (') closes the attribute. + delimSingleQuote + // delimSpaceOrTagEnd occurs when a space or right angle bracket (>) + // closes the attribute. + delimSpaceOrTagEnd +) + +type element struct { + // name is the lowercase name of the element. If context joining has occurred, name + // will be arbitrarily assigned the element name from one of the joined contexts. + name string + // names contains all possible names the element could assume because of context joining. + // For example, after joining the contexts in the "if" and "else" branches of + // {{if .C}}`, + // names will contain "img" and "audio". + // names can also contain empty strings, which represent joined contexts with no element name. + // names will be empty if no context joining occurred. + names []string +} + +// eq reports whether a and b have the same name. All other fields are ignored. +func (e element) eq(d element) bool { + return e.name == d.name +} + +// String returns the string representation of the element. +func (e element) String() string { + return "element" + strings.Title(e.name) +} + +// attr represents the attribute that the parser is in, that is, +// starting from stateAttrName until stateTag/stateText (exclusive). +type attr struct { + // name is the lowercase name of the attribute. If context joining has occurred, name + // will be arbitrarily assigned the attribute name from one of the joined contexts. + name string + // value is the value of the attribute. If context joining has occurred, value + // will be arbitrarily assigned the attribute value from one of the joined contexts. + // If there are multiple actions in the attribute value, value will contain the + // concatenation of all values seen so far. For example, in + // + // value is "foo" at "{{.X}}" and "foobar" at "{{.Y}}". + value string + // ambiguousValue indicates whether value contains an ambiguous value due to context-joining. + ambiguousValue bool + // names contains all possible names the attribute could assume because of context joining. + // For example, after joining the contexts in the "if" and "else" branches of + // + // names will contain "title" and "name". + // names can also contain empty strings, which represent joined contexts with no attribute name. + // names will be empty if no context joining occurred. + names []string +} + +// eq reports whether a and b have the same name. All other fields are ignored. +func (a attr) eq(b attr) bool { + return a.name == b.name +} + +// String returns the string representation of the attr. +func (a attr) String() string { + return "attr" + strings.Title(a.name) +} diff --git a/vendor/github.com/google/safehtml/template/delim_string.go b/vendor/github.com/google/safehtml/template/delim_string.go new file mode 100644 index 000000000..0ef2c2510 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/delim_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type Delim"; DO NOT EDIT + +package template + +import "fmt" + +const _Delim_name = "DelimNoneDelimDoubleQuoteDelimSingleQuoteDelimSpaceOrTagEnd" + +var _Delim_index = [...]uint8{0, 9, 25, 41, 59} + +func (i delim) String() string { + if i >= delim(len(_Delim_index)-1) { + return fmt.Sprintf("delim(%d)", i) + } + return _Delim_name[_Delim_index[i]:_Delim_index[i+1]] +} diff --git a/vendor/github.com/google/safehtml/template/doc.go b/vendor/github.com/google/safehtml/template/doc.go new file mode 100644 index 000000000..fab552b25 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/doc.go @@ -0,0 +1,291 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +/* +Package template (safehtml/template) implements data-driven templates for +generating HTML output safe against code injection. It provides an interface +similar to that of package html/template, but produces HTML output that is more +secure. Therefore, it should be used instead of html/template to render HTML. + +The documentation here focuses on the security features of the package. For +information about how to program the templates themselves, see the +documentation for text/template. + + +Basic usage + +This package provides an API almost identical to that of text/template and +html/template to parse and execute HTML templates safely. + + tmpl := template.Must(template.New("name").Parse(`
Hello {{.}}
`)) + err := tmpl.Execute(out, data) + +If successful, out will contain code-injection-safe HTML. Otherwise, err's +string representation will describe the error that occurred. + +Elements of data might be modified at run time before being included in out, or +rejected completely if such a conversion is not possible. Pass values of +appropriate types from package safehtml to ensure that they are included in the +template's HTML output in their expected form. More details are provided below +in "Contextual autosanitization" and "Sanitization contexts". + + +Security improvements + +safehtml/template produces HTML more resistant to code injection than +html/template because it: + * Allows values of types only from package safehtml to bypass run-time + sanitization. These types represent values that are known---by construction + or by run-time sanitization---to be safe for use in various HTML contexts + without being processed by certain sanitization functions. + * Does not attempt to escape CSS or JavaScript. Instead of attempting to + parse and escape these complex languages, safehtml/template allows values + of only the appropriate types from package safehtml (e.g. safehtml.Style, + safehtml.Script) to be used in these contexts, since they are already + guaranteed to be safe. + * Emits an error if user data is interpolated in unsafe contexts, such as + within disallowed elements or unquoted attribute values. + * Only loads templates from trusted sources. This ensures that the contents + of the template are always under programmer control. More details are + provided below in "Trusted template sources". + * Differentiates between URLs that load code and those that do not. URLs in + the former category must be supplied to the template as values of type + safehtml.TrustedResourceURL, whose type contract promises that the URL + identifies a trustworthy resource. URLs in the latter category can be + sanitized at run time. + + +Threat model + +safehtml/template assumes that programmers are trustworthy. Therefore, data +fully under programmer control, such as string literals, are considered safe. +The types from package safehtml are designed around this same assumption, so +their type contracts are trusted by this package. + +safehtml/template considers all other data values untrustworthy and +conservatively assumes that such values could result in a code-injection +vulnerability if included verbatim in HTML. + + +Trusted template sources + +safehtml/template loads templates only from trusted sources. Therefore, template +text, file paths, and file patterns passed to Parse* functions and methods must +be entirely under programmer control. + +This constraint is enforced by using unexported string types for the parameters +of Parse* functions and methods, such as trustedFilePattern for ParseGlob. +The only values that may be assigned to these types (and thus provided as +arguments) are untyped string constants such as string literals, which are +always under programmer control. + + +Contextual autosanitization + +Code injection vulnerabilities, such as cross-site scripting (XSS), occur when +untrusted data values are embedded in a HTML document. For example, + + import "text/template" + ... + var t = template.Must(template.New("foo").Parse(`
{{ .Y }}`)) + func renderHTML(x, y string) string { + var out bytes.Buffer + err := t.Execute(&out, struct{ X, Y string }{x, y}) + // Error checking elided + return out.String() + } + +If x and y originate from user-provided data, an attacker who controls these +strings could arrange for them to contain the following values: + + x = "javascript:evil()" + y = "" + +which will cause renderHTML to return the following unsafe HTML: + + + +To prevent such vulnerabilities, untrusted data must be sanitized before being +included in HTML. A sanitization function takes untrusted data and returns a +string that will not create a code-injection vulnerability in the destination +context. The function might return the input unchanged if it deems it safe, +escape special runes in the input's string representation to prevent them from +triggering undesired state changes in the HTML parser, or entirely replace the +input by an innocuous string (also known as "filtering"). If none of these +conversions are possible, the sanitization function aborts template processing. + +safehtml/template contextually autosanitizes untrusted data by adding +appropriate sanitization functions to template actions to ensure that the +action output is safe to include in the HTML context in which the action +appears. For example, in + + import "safehtml/template" + ... + var t = template.Must(template.New("foo").Parse(`{{ .Y }}`)) + func renderHTML(x, y string) string { + var out bytes.Buffer + err := t.Execute(&out, struct{ X, Y string }{x, y}) + // Error checking elided + return out.String() + } + +the contextual autosanitizer rewrites the template to + + {{ .Y | _sanitizeHTML }} + +so that the template produces the following safe, sanitized HTML output (split +across multiple lines for clarity): + + + </a><script>alert('pwned')</script><a> + + +Similar template systems such as html/template, Soy, and Angular, refer to this +functionality as "contextual autoescaping". safehtml/template uses the term +"autosanitization" instead of "autoescaping" since "sanitization" broadly +captures the operations of escaping and filtering. + + +Sanitization contexts + +The types of sanitization functions inserted into an action depend on the +action's sanitization context, which is determined by its surrounding text. +The following table describes these sanitization contexts. + + +--------------------+----------------------------------+------------------------------+-----------------------+ + | Context | Examples | Safe types | Run-time sanitizer | + |--------------------+----------------------------------+------------------------------+-----------------------+ + | HTMLContent | Hello {{.}} | safehtml.HTML | safehtml.HTMLEscaped | + | | {{.}} | | | + +--------------------------------------------------------------------------------------------------------------+ + | HTMLValOnly | | safehtml.HTML* | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | URL | Cite | safehtml.URL | safehtml.URLSanitized | + +--------------------------------------------------------------------------------------------------------------+ + | URL or | Link | safehtml.URL | safehtml.URLSanitized | + | TrustedResourceURL | | safehtml.TrustedResourceURL | | + +--------------------------------------------------------------------------------------------------------------+ + | TrustedResourceURL | | safehtml.TrustedResourceURL† | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | Script | | safehtml.Script* | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | Style |

Paragraph

| safehtml.Style* | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | Stylesheet | | safehtml.StyleSheet* | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | Identifier |

Hello

| safehtml.Identifier* | N/A | + +--------------------------------------------------------------------------------------------------------------+ + | Enumerated value | Link | Allowed string values | N/A | + | | | ("_self" or "_blank" for | | + | | | the given example) | | + +--------------------------------------------------------------------------------------------------------------+ + | None |

Hello

| N/A (any type allowed) | N/A (any type | + | | | | allowed) | + +--------------------+----------------------------------+------------------------------+-----------------------+ + *: Values only of this type are allowed in this context. Other values will trigger a run-time error. + †: If the action is a prefix of the attribute value, values only of this type are allowed. + Otherwise, values of any type are allowed. See "Substitutions in URLs" for more details. + +For each context, the function named in "Run-time sanitizer" is called to +sanitize the output of the action. However, if the action outputs a value of +any of the types listed in "Safe types", the run-time sanitizer is not called. +For example, in + + {{ .X }} + +if X is a string value, a HTML sanitizer that calls safehtml.HTMLEscaped will be +added to the action to sanitize X. + + // _sanitizeHTML calls safehtml.HTMLEscaped. + {{ .X | _sanitizeHTML }} + +However, if X is a safehtml.HTML value, _sanitizeHTML will not change its +value, since safehtml.HTML values are already safe to use in HTML contexts. +Therefore, the string contents of X will bypass context-specific +sanitization (in this case, HTML escaping) and appear unchanged in the +template's HTML output. Note that in attribute value contexts, HTML escaping +will always take place, whether or not context-specific sanitization is +performed. More details can be found at the end of this section. + +In certain contexts, the autosanitizer allows values only of that context's +"Safe types". Any other values will trigger an error and abort template +processing. For example, the template + + + +triggers a run-time error if X is not a safehtml.StyleSheet. Otherwise, the +string form of X will appear unchanged in the output. The only exception to +this behavior is in TrustedResourceURL sanitization contexts, where actions may +output data of any type if the action occurs after a safe attribute value prefix. +More details can be found below in "Substitutions in URLs". + + +Unconditional sanitization + +In attribute value contexts, action outputs are always HTML-escaped after +context-specific sanitization to ensure that the attribute values cannot change +change the structure of the surrounding HTML tag. In URL or TrustedResourceURL +sanitization contexts, action outputs are additionally URL-normalized to reduce +the likelihood of downstream URL-parsing bugs. For example, the template + + Link +

Text

+ +is rewritten by the autosanitizer into + + // _sanitizeHTML calls safehtml.HTMLEscaped. + Link +

Text

+ +Even if X is a safehtml.URL or safehtml.TrustedResourceURL value, which +remains unchanged after _sanitizeTrustedResourceURLOrURL, X will still be +URL-normalized and HTML-escaped. Likewise, Y will still be HTML-escaped even if +its string form is left unchanged by _sanitizeIdentifier. + + +Substitutions in URLs + +Values of any type may be substituted into attribute values in URL and +TrustedResourceURL sanitization contexts only if the action is preceded by a +safe URL prefix. For example, in + + foo + +Since "http://www.foo.com/" is a safe URL prefix, PathComponent can safely be +interpolated into this URL sanitization context after URL normalization. +Similarly, in + + + +Since "https://www.bar.com/" is a safe TrustedResourceURL prefix, PathComponent +can safely be interpolated into this TrustedResourceURL sanitization context +after URL escaping. Substitutions after a safe TrustedResourceURL prefix are +escaped instead of normalized to prevent the injection of any new URL +components, including additional path components. URL escaping also takes place +in URL sanitization contexts where the substitutions occur in the query or +fragment part of the URL, such as in: + + Link + +A URL prefix is considered safe in a URL sanitization context if it does +not end in an incomplete HTML character reference (e.g. https) or incomplete +percent-encoding character triplet (e.g. /fo%6), does not contain whitespace or control +characters, and one of the following is true: + * The prefix has a safe scheme (i.e. http, https, mailto, or ftp). + * The prefix has the data scheme with base64 encoding and an allowed audio, image, + or video MIME type (e.g. data:img/jpeg;base64, data:video/mp4;base64). + * The prefix has no scheme at all, and cannot be interpreted as a scheme prefix (e.g. /path). + +A URL prefix is considered safe in a TrustedResourceURL sanitization context if it does +not end in an incomplete HTML character reference (e.g. https) or incomplete +percent-encoding character triplet (e.g. /fo%6), does not contain white space or control +characters, and one of the following is true: + * The prefix has the https scheme and contains a domain name (e.g. https://www.foo.com). + * The prefix is scheme-relative and contains a domain name (e.g. //www.foo.com/). + * The prefix is path-absolute and contains a path (e.g. /path). + * The prefix is "about:blank". +*/ +package template diff --git a/vendor/github.com/google/safehtml/template/error.go b/vendor/github.com/google/safehtml/template/error.go new file mode 100644 index 000000000..fe7821433 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/error.go @@ -0,0 +1,280 @@ +// 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 template + +import ( + "fmt" + "text/template/parse" +) + +// Error describes a problem encountered during template Escaping. +type Error struct { + // ErrorCode describes the kind of error. + ErrorCode ErrorCode + // Node is the node that caused the problem, if known. + // If not nil, it overrides Name and Line. + Node parse.Node + // Name is the name of the template in which the error was encountered. + Name string + // Line is the line number of the error in the template source or 0. + Line int + // Description is a human-readable description of the problem. + Description string +} + +// ErrorCode is a code for a kind of error. +type ErrorCode int + +// We define codes for each error that manifests while escaping templates, but +// escaped templates may also fail at runtime. +// +// Output: "ZgotmplZ" +// Example: +// +// where {{.X}} evaluates to `javascript:...` +// Discussion: +// "ZgotmplZ" is a special value that indicates that unsafe content reached a +// CSS or URL context at runtime. The output of the example will be +// +// If the data comes from a trusted source, use content types to exempt it +// from filtering: URL(`javascript:...`). +const ( + // OK indicates the lack of an error. + OK ErrorCode = iota + + // ErrAmbigContext: "... appears in an ambiguous context within a URL" + // Example: + // + // Discussion: + // {{.X}} is in an ambiguous URL context since, depending on {{.C}}, + // it may be either a URL suffix or a query parameter. + // Moving {{.X}} into the condition removes the ambiguity: + // + ErrAmbigContext + + // ErrBadHTML: "expected space, attr name, or end of tag, but got ...", + // "... in unquoted attr", "... in attribute name" + // Example: + // + // + //
+ //
{{end}} + // {{define "attrs"}}href="{{.URL}}"{{end}} + // Discussion: + // Package html/template looks through template calls to compute the + // context. + // Here the {{.URL}} in "attrs" must be treated as a URL when called + // from "main", but you will get this error if "attrs" is not defined + // when "main" is parsed. + ErrNoSuchTemplate + + // ErrOutputContext: "cannot compute output context for template ..." + // Examples: + // {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}} + // Discussion: + // A recursive template does not end in the same context in which it + // starts, and a reliable output context cannot be computed. + // Look for typos in the named template. + // If the template should not be called in the named start context, + // look for calls to that template in unexpected contexts. + // Maybe refactor recursive templates to not be recursive. + ErrOutputContext + + // ErrPartialCharset: "unfinished JS regexp charset in ..." + // Example: + // + // Discussion: + // Package html/template does not support interpolation into regular + // expression literal character sets. + ErrPartialCharset + + // ErrPartialEscape: "unfinished escape sequence in ..." + // Example: + // + // Discussion: + // Package html/template does not support actions following a + // backslash. + // This is usually an error and there are better solutions; for + // example + // + // should work, and if {{.X}} is a partial escape sequence such as + // "xA0", mark the whole sequence as safe content: JSStr(`\xA0`) + ErrPartialEscape + + // ErrRangeLoopReentry: "on range loop re-entry: ..." + // Example: + // + // Discussion: + // If an iteration through a range would cause it to end in a + // different context than an earlier pass, there is no single context. + // In the example, there is missing a quote, so it is not clear + // whether {{.}} is meant to be inside a JS string or in a JS value + // context. The second iteration would produce something like + // + // + ErrRangeLoopReentry + + // ErrSlashAmbig: '/' could start a division or regexp. + // Example: + // + // Discussion: + // The example above could produce `var x = 1/-2/i.test(s)...` + // in which the first '/' is a mathematical division operator or it + // could produce `/-2/i.test(s)` in which the first '/' starts a + // regexp literal. + // Look for missing semicolons inside branches, and maybe add + // parentheses to make it clear which interpretation you intend. + ErrSlashAmbig + + // ErrPredefinedEscaper: "predefined escaper ... disallowed in template" + // Example: + //
Hello
+ // Discussion: + // Package html/template already contextually escapes all pipelines to + // produce HTML output safe against code injection. Manually escaping + // pipeline output using the predefined escapers "html" or "urlquery" is + // unnecessary, and may affect the correctness or safety of the escaped + // pipeline output in Go 1.8 and earlier. + // + // In most cases, such as the given example, this error can be resolved by + // simply removing the predefined escaper from the pipeline and letting the + // contextual autoescaper handle the escaping of the pipeline. In other + // instances, where the predefined escaper occurs in the middle of a + // pipeline where subsequent commands expect escaped input, e.g. + // {{.X | html | makeALink}} + // where makeALink does + // return `link` + // consider refactoring the surrounding template to make use of the + // contextual autoescaper, i.e. + // link + // + // To ease migration to Go 1.9 and beyond, "html" and "urlquery" will + // continue to be allowed as the last command in a pipeline. However, if the + // pipeline occurs in an unquoted attribute value context, "html" is + // disallowed. Avoid using "html" and "urlquery" entirely in new templates. + ErrPredefinedEscaper + + // ErrEscapeAction: "cannot escape action ..." + // Discussion: + // Error returned while escaping an action using EscaperForContext. + // Refer to error message for more details. + // TODO: remove this error type and replace it with more informative sanitization errors. + ErrEscapeAction + + // ErrCSPCompatibility: `"javascript:" URI disallowed for CSP compatibility`, + // "inline event handler ... is disallowed for CSP compatibility + // Examples: + // A thing. + // foo + // Discussion: + // Inline event handlers (onclick="...", onerror="...") and + // links can be used to run scripts, + // so an attacker who finds an XSS bug could inject such HTML + // and execute malicious JavaScript. These patterns must be + // refactored into safer alternatives for compatibility with + // Content Security Policy (CSP). + // + // For example, the following HTML that contains an inline event handler: + // + // A thing. + // can be refactored into: + // A thing. + // + // + // Likewise, the following HTML containng a javascript: URI: + // foo + // can be refactored into: + // foo + // + ErrCSPCompatibility + // All JS templates inside script literals have to be balanced; otherwise a concatenation such as + // can contain XSS if data contains user-controlled escaped strings (e.g. as JSON). + ErrUnbalancedJsTemplate +) + +func (e *Error) Error() string { + switch { + case e.Node != nil: + loc, _ := (*parse.Tree)(nil).ErrorContext(e.Node) + return fmt.Sprintf("html/template:%s: %s", loc, e.Description) + case e.Line != 0: + return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description) + case e.Name != "": + return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description) + } + return "html/template: " + e.Description +} + +// errorf creates an error given a format string f and args. +// The template Name still needs to be supplied. +func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error { + return &Error{k, node, "", line, fmt.Sprintf(f, args...)} +} diff --git a/vendor/github.com/google/safehtml/template/escape.go b/vendor/github.com/google/safehtml/template/escape.go new file mode 100644 index 000000000..8a9d53dd5 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/escape.go @@ -0,0 +1,884 @@ +// Copyright 2011 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 template + +import ( + "bytes" + "fmt" + "html" + "reflect" + "strings" + "text/template" + "text/template/parse" +) + +// TODO: remove all unused escaping logic inherited from html/template. +// TODO: replace "escape" with "sanitize" in file names and contents to maintain consistency with safehtml/template docs. + +// escapeTemplate rewrites the named template, which must be +// associated with t, to guarantee that the output of any of the named +// templates is properly escaped. If no error is returned, then the named templates have +// been modified. Otherwise the named templates have been rendered +// unusable. +func escapeTemplate(tmpl *Template, node parse.Node, name string) error { + c, _ := tmpl.esc.escapeTree(context{}, node, name, 0) + var err error + if c.err != nil { + err, c.err.Name = c.err, name + } else if c.state != stateText { + err = &Error{ErrEndContext, nil, name, 0, fmt.Sprintf("ends in a non-text context: %+v", c)} + } + if err != nil { + // Prevent execution of unsafe templates. + if t := tmpl.set[name]; t != nil { + t.escapeErr = err + t.text.Tree = nil + t.Tree = nil + } + return err + } + tmpl.esc.commit() + if t := tmpl.set[name]; t != nil { + t.escapeErr = errEscapeOK + t.Tree = t.text.Tree + } + return nil +} + +// evalArgs formats the list of arguments into a string. It is equivalent to +// fmt.Sprint(args...), except that it deferences all pointers. +func evalArgs(args ...interface{}) string { + // Optimization for simple common case of a single string argument. + if len(args) == 1 { + if s, ok := args[0].(string); ok { + return s + } + } + for i, arg := range args { + args[i] = indirectToStringerOrError(arg) + } + return fmt.Sprint(args...) +} + +// escaper collects type inferences about templates and changes needed to make +// templates injection safe. +type escaper struct { + // ns is the nameSpace that this escaper is associated with. + ns *nameSpace + // output[templateName] is the output context for a templateName that + // has been mangled to include its input context. + output map[string]context + // derived[c.mangle(name)] maps to a template derived from the template + // named name templateName for the start context c. + derived map[string]*template.Template + // called[templateName] is a set of called mangled template names. + called map[string]bool + // xxxNodeEdits are the accumulated edits to apply during commit. + // Such edits are not applied immediately in case a template set + // executes a given template in different escaping contexts. + actionNodeEdits map[*parse.ActionNode][]string + templateNodeEdits map[*parse.TemplateNode]string + textNodeEdits map[*parse.TextNode][]byte +} + +// makeEscaper creates a blank escaper for the given set. +func makeEscaper(n *nameSpace) escaper { + return escaper{ + n, + map[string]context{}, + map[string]*template.Template{}, + map[string]bool{}, + map[*parse.ActionNode][]string{}, + map[*parse.TemplateNode]string{}, + map[*parse.TextNode][]byte{}, + } +} + +// escape escapes a template node. +func (e *escaper) escape(c context, n parse.Node) context { + switch n := n.(type) { + case *parse.ActionNode: + return e.escapeAction(c, n) + case *parse.IfNode: + return e.escapeBranch(c, &n.BranchNode, "if") + case *parse.ListNode: + return e.escapeList(c, n) + case *parse.RangeNode: + return e.escapeBranch(c, &n.BranchNode, "range") + case *parse.TemplateNode: + return e.escapeTemplate(c, n) + case *parse.TextNode: + return e.escapeText(c, n) + case *parse.WithNode: + return e.escapeBranch(c, &n.BranchNode, "with") + } + panic("escaping " + n.String() + " is unimplemented") +} + +// escapeAction escapes an action template node. +func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { + if len(n.Pipe.Decl) != 0 { + // A local variable assignment, not an interpolation. + return c + } + c = nudge(c) + // Check for disallowed use of predefined escapers in the pipeline. + for pos, idNode := range n.Pipe.Cmds { + node, ok := idNode.Args[0].(*parse.IdentifierNode) + if !ok { + // A predefined escaper "esc" will never be found as an identifier in a + // Chain or Field node, since: + // - "esc.x ..." is invalid, since predefined escapers return strings, and + // strings do not have methods, keys or fields. + // - "... .esc" is invalid, since predefined escapers are global functions, + // not methods or fields of any types. + // Therefore, it is safe to ignore these two node types. + continue + } + ident := node.Ident + if _, ok := predefinedEscapers[ident]; ok { + if pos < len(n.Pipe.Cmds)-1 || + c.state == stateAttr && c.delim == delimSpaceOrTagEnd && ident == "html" { + return context{ + state: stateError, + err: errorf(ErrPredefinedEscaper, n, n.Line, "predefined escaper %q disallowed in template", ident), + } + } + } + } + switch c.state { + case stateError: + return c + case stateAttrName, stateTag: + c.state = stateAttrName + } + // TODO: integrate sanitizerForContext into escapeAction. + s, err := sanitizerForContext(c) + if err != nil { + return context{ + state: stateError, + // TODO: return sanitization-specific errors. + err: errorf(ErrEscapeAction, n, n.Line, "cannot escape action %v: %s", n, err), + } + } + e.editActionNode(n, s) + return c +} + +// ensurePipelineContains ensures that the pipeline ends with the commands with +// the identifiers in s in order. If the pipeline ends with a predefined escaper +// (i.e. "html" or "urlquery"), merge it with the identifiers in s.c +func ensurePipelineContains(p *parse.PipeNode, s []string) { + if len(s) == 0 { + // Do not rewrite pipeline if we have no escapers to insert. + return + } + // Precondition: p.Cmds contains at most one predefined escaper and the + // escaper will be present at p.Cmds[len(p.Cmds)-1]. This precondition is + // always true because of the checks in escapeAction. + pipelineLen := len(p.Cmds) + if pipelineLen > 0 { + lastCmd := p.Cmds[pipelineLen-1] + if idNode, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok { + if esc := idNode.Ident; predefinedEscapers[esc] { + // Pipeline ends with a predefined escaper. + if len(p.Cmds) == 1 && len(lastCmd.Args) > 1 { + // Special case: pipeline is of the form {{ esc arg1 arg2 ... argN }}, + // where esc is the predefined escaper, and arg1...argN are its arguments. + // Convert this into the equivalent form + // {{ _eval_args_ arg1 arg2 ... argN | esc }}, so that esc can be easily + // merged with the escapers in s. + lastCmd.Args[0] = parse.NewIdentifier(evalArgsFuncName).SetTree(nil).SetPos(lastCmd.Args[0].Position()) + p.Cmds = append(p.Cmds, newIdentCmd(esc, p.Position())) + pipelineLen++ + } + // If any of the commands in s that we are about to insert is equivalent + // to the predefined escaper, use the predefined escaper instead. + dup := false + for i, escaper := range s { + if escFnsEq(esc, escaper) { + s[i] = idNode.Ident + dup = true + } + } + if dup { + // The predefined escaper will already be inserted along with the + // escapers in s, so do not copy it to the rewritten pipeline. + pipelineLen-- + } + } + } + } + // Rewrite the pipeline, creating the escapers in s at the end of the pipeline. + newCmds := make([]*parse.CommandNode, pipelineLen, pipelineLen+len(s)) + copy(newCmds, p.Cmds) + for _, name := range s { + newCmds = append(newCmds, newIdentCmd(name, p.Position())) + } + p.Cmds = newCmds +} + +// predefinedEscapers contains template predefined escapers that are equivalent +// to some contextual escapers. Keep in sync with equivEscapers. +var predefinedEscapers = map[string]bool{ + "html": true, + "urlquery": true, +} + +// equivEscapers matches contextual escapers to equivalent predefined +// template escapers. +var equivEscapers = map[string]string{ + // The following pairs of HTML escapers provide equivalent security + // guarantees, since they all escape '\000', '\'', '"', '&', '<', and '>'. + sanitizeHTMLFuncName: "html", + sanitizeRCDATAFuncName: "html", + // These two URL escapers produce URLs safe for embedding in a URL query by + // percent-encoding all the reserved characters specified in RFC 3986 Section + // 2.2 + queryEscapeURLFuncName: "urlquery", + // The normalizer function is not actually equivalent to urlquery; urlquery is + // stricter as it escapes reserved characters (e.g. '#'), while the normalizer + // function does not. It is therefore only safe to replace the normalizer with + // with urlquery (this happens in ensurePipelineContains), but not the other + // way around. We keep this entry around to preserve the behavior of templates + // written before Go 1.9, which might depend on this substitution taking place. + normalizeURLFuncName: "urlquery", +} + +// escFnsEq reports whether the two escaping functions are equivalent. +func escFnsEq(a, b string) bool { + return normalizeEscFn(a) == normalizeEscFn(b) +} + +// normalizeEscFn(a) is equal to normalizeEscFn(b) for any pair of names of +// escaper functions a and b that are equivalent. +func normalizeEscFn(e string) string { + if norm := equivEscapers[e]; norm != "" { + return norm + } + return e +} + +// newIdentCmd produces a command containing a single identifier node. +func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode { + return &parse.CommandNode{ + NodeType: parse.NodeCommand, + Args: []parse.Node{parse.NewIdentifier(identifier).SetTree(nil).SetPos(pos)}, // TODO: SetTree. + Pos: pos, + } +} + +// nudge returns the context that would result from following empty string +// transitions from the input context. +// For example, parsing: +// `90% of the time. + e.output[t.Name()] = c + return e.escapeListConditionally(c, t.Tree.Root, filter) +} + +// delimEnds maps each delim to a string of characters that terminate it. +var delimEnds = [...]string{ + delimDoubleQuote: `"`, + delimSingleQuote: "'", + // Determined empirically by running the below in various browsers. + // var div = document.createElement("DIV"); + // for (var i = 0; i < 0x10000; ++i) { + // div.innerHTML = ""; + // if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0) + // document.write("

U+" + i.toString(16)); + // } + delimSpaceOrTagEnd: " \t\n\f\r>", +} + +var doctypeBytes = []byte("= i; j-- { + if s[j] == '<' { + end = j + break + } + } + } + for j := i; j < end; j++ { + if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) { + b.Write(s[written:j]) + b.WriteString("<") + written = j + 1 + } + } + } else if isComment(c.state) && c.delim == delimNone { + written = i1 + } + if c.state == stateSpecialElementBody && c.element.name == "script" { + if err := isJsTemplateBalanced(bytes.NewBuffer(s)); err != nil { + return context{ + state: stateError, + err: errorf(ErrUnbalancedJsTemplate, n, 0, "Mixing template systems can cause security vulnerabilites. Therefore, there can be no safehtml/template insertion points or actions inside an ES6 template, and all ES6 templates must be closed: %v", err.Error()), + } + } + } + + if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone { + // Preserve the portion between written and the comment start. + cs := i1 - 2 + if c1.state == stateHTMLCmt { + // "") + +// tText is the context transition function for the text state. +func tText(c context, s []byte) (context, int) { + k := 0 + for { + i := k + bytes.IndexByte(s[k:], '<') + if i < k || i+1 == len(s) { + return c, len(s) + } else if i+4 <= len(s) && bytes.Equal(commentStart, s[i:i+4]) { + return context{state: stateHTMLCmt}, i + 4 + } + i++ + end := false + if s[i] == '/' { + if i+1 == len(s) { + return c, len(s) + } + end, i = true, i+1 + } + j, e := eatTagName(s, i) + if j != i { + // We've found an HTML tag. + ret := context{state: stateTag} + // Element name not needed if we are at the end of the element. + if !end { + ret.element = e + } + return ret, j + } + k = j + } +} + +// specialElements contains the names of elements whose bodies are treated +// differently by the parser and escaper from stateText. +var specialElements = map[string]bool{ + "script": true, + "style": true, + "textarea": true, + "title": true, +} + +// voidElements contains the names of all void elements. +// https://www.w3.org/TR/html5/syntax.html#void-elements +var voidElements = map[string]bool{ + "area": true, + "base": true, + "br": true, + "col": true, + "embed": true, + "hr": true, + "img": true, + "input": true, + "keygen": true, + "link": true, + "meta": true, + "param": true, + "source": true, + "track": true, + "wbr": true, +} + +// tTag is the context transition function for the tag state. +func tTag(c context, s []byte) (context, int) { + // Find the attribute name. + i := eatWhiteSpace(s, 0) + if i == len(s) { + return c, len(s) + } + if s[i] == '>' { + ret := context{ + state: stateText, + element: c.element, + scriptType: c.scriptType, + linkRel: c.linkRel, + } + if specialElements[c.element.name] { + ret.state = stateSpecialElementBody + } + if c.element.name != "" && voidElements[c.element.name] { + // Special case: end of start tag of a void element. + // Discard unnecessary state, since this element have no content. + ret.element = element{} + ret.scriptType = "" + ret.linkRel = "" + } + return ret, i + 1 + } + j, err := eatAttrName(s, i) + if err != nil { + return context{state: stateError, err: err}, len(s) + } + state := stateTag + if i == j { + return context{ + state: stateError, + err: errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]), + }, len(s) + } + + if j == len(s) { + state = stateAttrName + } else { + state = stateAfterName + } + return context{ + state: state, + element: c.element, + attr: attr{name: strings.ToLower(string(s[i:j]))}, + linkRel: c.linkRel, + }, j +} + +// tAttrName is the context transition function for stateAttrName. +func tAttrName(c context, s []byte) (context, int) { + i, err := eatAttrName(s, 0) + if err != nil { + return context{state: stateError, err: err}, len(s) + } else if i != len(s) { + c.state = stateAfterName + } + return c, i +} + +// tAfterName is the context transition function for stateAfterName. +func tAfterName(c context, s []byte) (context, int) { + // Look for the start of the value. + i := eatWhiteSpace(s, 0) + if i == len(s) { + return c, len(s) + } else if s[i] != '=' { + // Occurs due to tag ending '>', and valueless attribute. + c.state = stateTag + return c, i + } + c.state = stateBeforeValue + // Consume the "=". + return c, i + 1 +} + +// tBeforeValue is the context transition function for stateBeforeValue. +func tBeforeValue(c context, s []byte) (context, int) { + i := eatWhiteSpace(s, 0) + if i == len(s) { + return c, len(s) + } + // Find the attribute delimiter. + // TODO: consider disallowing single-quoted or unquoted attribute values completely, even in hardcoded template text. + delim := delimSpaceOrTagEnd + switch s[i] { + case '\'': + delim, i = delimSingleQuote, i+1 + case '"': + delim, i = delimDoubleQuote, i+1 + } + c.state, c.delim = stateAttr, delim + return c, i +} + +// tHTMLCmt is the context transition function for stateHTMLCmt. +func tHTMLCmt(c context, s []byte) (context, int) { + if i := bytes.Index(s, commentEnd); i != -1 { + return context{}, i + 3 + } + return c, len(s) +} + +var ( + specialTagEndPrefix = []byte(" \t\n\f/") +) + +// tSpecialTagEnd is the context transition function for raw text, RCDATA +// script data, and stylesheet element states. +func tSpecialTagEnd(c context, s []byte) (context, int) { + if specialElements[c.element.name] { + if i := indexTagEnd(s, []byte(c.element.name)); i != -1 { + return context{}, i + } + } + return c, len(s) +} + +// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1 +func indexTagEnd(s []byte, tag []byte) int { + res := 0 + plen := len(specialTagEndPrefix) + for len(s) > 0 { + // Try to find the tag end prefix first + i := bytes.Index(s, specialTagEndPrefix) + if i == -1 { + return i + } + s = s[i+plen:] + // Try to match the actual tag if there is still space for it + if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) { + s = s[len(tag):] + // Check the tag is followed by a proper separator + if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 { + return res + i + } + res += len(tag) + } + res += i + plen + } + return -1 +} + +// tAttr is the context transition function for the attribute state. +func tAttr(c context, s []byte) (context, int) { + return c, len(s) +} + +// tError is the context transition function for the error state. +func tError(c context, s []byte) (context, int) { + return c, len(s) +} + +// eatAttrName returns the largest j such that s[i:j] is an attribute name. +// It returns an error if s[i:] does not look like it begins with an +// attribute name, such as encountering a quote mark without a preceding +// equals sign. +func eatAttrName(s []byte, i int) (int, *Error) { + for j := i; j < len(s); j++ { + switch s[j] { + case ' ', '\t', '\n', '\f', '\r', '=', '>': + return j, nil + case '\'', '"', '<': + // These result in a parse warning in HTML5 and are + // indicative of serious problems if seen in an attr + // name in a template. + return -1, errorf(ErrBadHTML, nil, 0, "%q in attribute name: %.32q", s[j:j+1], s) + default: + // No-op. + } + } + return len(s), nil +} + +// asciiAlpha reports whether c is an ASCII letter. +func asciiAlpha(c byte) bool { + return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' +} + +// asciiAlphaNum reports whether c is an ASCII letter or digit. +func asciiAlphaNum(c byte) bool { + return asciiAlpha(c) || '0' <= c && c <= '9' +} + +// eatTagName returns the largest j such that s[i:j] is a tag name and the tag name. +func eatTagName(s []byte, i int) (int, element) { + if i == len(s) || !asciiAlpha(s[i]) { + return i, element{} + } + j := i + 1 + for j < len(s) { + x := s[j] + if asciiAlphaNum(x) { + j++ + continue + } + // Allow "x-y" or "x:y" but not "x-", "-y", or "x--y". + if (x == ':' || x == '-') && j+1 < len(s) && asciiAlphaNum(s[j+1]) { + j += 2 + continue + } + break + } + return j, element{name: strings.ToLower(string(s[i:j]))} +} + +// eatWhiteSpace returns the largest j such that s[i:j] is white space. +func eatWhiteSpace(s []byte, i int) int { + for j := i; j < len(s); j++ { + switch s[j] { + case ' ', '\t', '\n', '\f', '\r': + // No-op. + default: + return j + } + } + return len(s) +} diff --git a/vendor/github.com/google/safehtml/template/trustedfs.go b/vendor/github.com/google/safehtml/template/trustedfs.go new file mode 100644 index 000000000..80db11824 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/trustedfs.go @@ -0,0 +1,98 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +//go:build go1.16 +// +build go1.16 + +package template + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path" +) + +// A TrustedFS is an immutable type referencing a filesystem (fs.FS) +// under application control. +// +// In order to ensure that an attacker cannot influence the TrustedFS value, a +// TrustedFS can be instantiated in only two ways. One way is from an embed.FS +// with TrustedFSFromEmbed. It is assumed that embedded filesystems are under +// the programmer's control. The other way is from a TrustedSource using +// TrustedFSFromTrustedSource, in which case the guarantees and caveats of +// TrustedSource apply. +type TrustedFS struct { + fsys fs.FS +} + +// TrustedFSFromEmbed constructs a TrustedFS from an embed.FS. +func TrustedFSFromEmbed(fsys embed.FS) TrustedFS { + return TrustedFS{fsys: fsys} +} + +// TrustedFSFromTrustedSource constructs a TrustedFS from the string in the +// TrustedSource, which should refer to a directory. +func TrustedFSFromTrustedSource(ts TrustedSource) TrustedFS { + return TrustedFS{fsys: os.DirFS(ts.src)} +} + +// Sub returns a TrustedFS at a subdirectory of the receiver. +// It works by calling fs.Sub on the receiver's fs.FS. +func (tf TrustedFS) Sub(dir TrustedSource) (TrustedFS, error) { + subfs, err := fs.Sub(tf.fsys, dir.String()) + return TrustedFS{fsys: subfs}, err +} + +// ParseFS is like ParseFiles or ParseGlob but reads from the TrustedFS +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +// +// The same behaviors listed for ParseFiles() apply to ParseFS too (e.g. using the base name +// of the file as the template name). +func ParseFS(tfs TrustedFS, patterns ...string) (*Template, error) { + return parseFS(nil, tfs.fsys, patterns) +} + +// ParseFS is like ParseFiles or ParseGlob but reads from the TrustedFS +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +// +// The same behaviors listed for ParseFiles() apply to ParseFS too (e.g. using the base name +// of the file as the template name). +func (t *Template) ParseFS(tfs TrustedFS, patterns ...string) (*Template, error) { + return parseFS(t, tfs.fsys, patterns) +} + +// Copied from +// https://go.googlesource.com/go/+/refs/tags/go1.17.1/src/text/template/helper.go. +func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { + var filenames []string + for _, pattern := range patterns { + list, err := fs.Glob(fsys, pattern) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) + } + filenames = append(filenames, list...) + } + return parseFiles(t, readFileFS(fsys), filenames...) +} + +// Copied with minor changes from +// https://go.googlesource.com/go/+/refs/tags/go1.17.1/src/text/template/helper.go. +func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { + return func(file string) (string, []byte, error) { + name := path.Base(file) + b, err := fs.ReadFile(fsys, file) + return name, b, err + } +} diff --git a/vendor/github.com/google/safehtml/template/trustedsource.go b/vendor/github.com/google/safehtml/template/trustedsource.go new file mode 100644 index 000000000..f64263948 --- /dev/null +++ b/vendor/github.com/google/safehtml/template/trustedsource.go @@ -0,0 +1,105 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package template + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "flag" +) + +// A TrustedSource is an immutable string-like type referencing +// trusted template files under application control. It can be passed to +// template-parsing functions and methods to safely load templates +// without the risk of untrusted template execution. +// +// In order to ensure that an attacker cannot influence the TrustedSource +// value, a TrustedSource can be instantiated only from untyped string +// constants, command-line flags, and other application-controlled strings, but +// never from arbitrary string values potentially representing untrusted user input. +// +// Note that TrustedSource's constructors cannot truly guarantee that the +// templates it references are not attacker-controlled; it can guarantee only that +// the path to the template itself is under application control. Users of these +// constructors must ensure themselves that TrustedSource never references +// attacker-controlled files or directories that contain such files. +type TrustedSource struct { + // We declare a TrustedSource not as a string but as a struct wrapping a string + // to prevent construction of TrustedSource values through string conversion. + src string +} + +// TrustedSourceFromConstant constructs a TrustedSource with its underlying +// src set to the given src, which must be an untyped string constant. +// +// No runtime validation or sanitization is performed on src; being under +// application control, it is simply assumed to comply with the TrustedSource type +// contract. +func TrustedSourceFromConstant(src stringConstant) TrustedSource { + return TrustedSource{string(src)} +} + +// TrustedSourceFromConstantDir constructs a TrustedSource calling path/filepath.Join on +// an application-controlled directory path, which must be an untyped string constant, +// a TrustedSource, and a dynamic filename. It returns an error if filename contains +// filepath or list separators, since this might cause the resulting path to reference a +// file outside of the given directory. +// +// dir or src may be empty if either of these path segments are not required. +func TrustedSourceFromConstantDir(dir stringConstant, src TrustedSource, filename string) (TrustedSource, error) { + if i := strings.IndexAny(filename, string([]rune{filepath.Separator, filepath.ListSeparator})); i != -1 { + return TrustedSource{}, fmt.Errorf("filename %q must not contain the separator %q", filename, filename[i]) + } + if filename == ".." { + return TrustedSource{}, fmt.Errorf("filename must not be the special name %q", filename) + } + return TrustedSource{filepath.Join(string(dir), src.String(), filename)}, nil +} + +// TrustedSourceJoin is a wrapper around path/filepath.Join that returns a +// TrustedSource formed by joining the given path elements into a single path, +// adding an OS-specific path separator if necessary. +func TrustedSourceJoin(elem ...TrustedSource) TrustedSource { + return TrustedSource{filepath.Join(trustedSourcesToStrings(elem)...)} +} + +// TrustedSourceFromFlag returns a TrustedSource containing the string +// representation of the retrieved value of the flag. +// +// In a server setting, flags are part of the application's deployment +// configuration and are hence considered application-controlled. +func TrustedSourceFromFlag(value flag.Value) TrustedSource { + return TrustedSource{fmt.Sprint(value.String())} +} + +// TrustedSourceFromEnvVar is a wrapper around os.Getenv that +// returns a TrustedSource containing the value of the environment variable +// named by the key. It returns the value, which will be empty if the variable +// is not present. To distinguish between an empty value and an unset value, +// use os.LookupEnv. +// +// In a server setting, environment variables are part of the application's +// deployment configuration and are hence considered application-controlled. +func TrustedSourceFromEnvVar(key stringConstant) TrustedSource { + return TrustedSource{os.Getenv(string(key))} +} + +// String returns the string form of the TrustedSource. +func (t TrustedSource) String() string { + return t.src +} + +func trustedSourcesToStrings(paths []TrustedSource) []string { + ret := make([]string, 0, len(paths)) + for _, p := range paths { + ret = append(ret, p.String()) + } + return ret +} diff --git a/vendor/github.com/google/safehtml/template/trustedtemplate.go b/vendor/github.com/google/safehtml/template/trustedtemplate.go new file mode 100644 index 000000000..bd3b1b46a --- /dev/null +++ b/vendor/github.com/google/safehtml/template/trustedtemplate.go @@ -0,0 +1,36 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package template + +// A TrustedTemplate is an immutable string-like type containing a +// safehtml/template template body. It can be safely loaded as template +// text without the risk of untrusted template execution. +// +// In order to ensure that an attacker cannot influence the TrustedTemplate +// value, a TrustedTemplate can be instantiated only from untyped string constants, +// and never from arbitrary string values potentially representing untrusted user input. +// +type TrustedTemplate struct { + // We declare a TrustedTemplate not as a string but as a struct wrapping a string + // to prevent construction of TrustedTemplate values through string conversion. + tmpl string +} + +// MakeTrustedTemplate constructs a TrustedTemplate with its underlying +// tmpl set to the given tmpl, which must be an untyped string constant. +// +// No runtime validation or sanitization is performed on tmpl; being under +// application control, it is simply assumed to comply with the TrustedTemplate type +// contract. +func MakeTrustedTemplate(tmpl stringConstant) TrustedTemplate { + return TrustedTemplate{string(tmpl)} +} + +// String returns the string form of the TrustedTemplate. +func (t TrustedTemplate) String() string { + return t.tmpl +} diff --git a/vendor/github.com/google/safehtml/template/url.go b/vendor/github.com/google/safehtml/template/url.go new file mode 100644 index 000000000..f63475fcf --- /dev/null +++ b/vendor/github.com/google/safehtml/template/url.go @@ -0,0 +1,122 @@ +// Copyright 2011 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 template + +import ( + "fmt" + "html" + "regexp" + "strings" + + "github.com/google/safehtml/internal/safehtmlutil" + "github.com/google/safehtml" +) + +// urlPrefixValidators maps URL and TrustedResourceURL sanitization contexts to functions return an error +// if the given string is unsafe to use as a URL prefix in that sanitization context. +var urlPrefixValidators = map[sanitizationContext]func(string) error{ + sanitizationContextURL: validateURLPrefix, + sanitizationContextTrustedResourceURLOrURL: validateURLPrefix, + sanitizationContextTrustedResourceURL: validateTrustedResourceURLPrefix, +} + +// startsWithFullySpecifiedSchemePattern matches strings that have a fully-specified scheme component. +// See RFC 3986 Section 3. +var startsWithFullySpecifiedSchemePattern = regexp.MustCompile( + `^[[:alpha:]](?:[[:alnum:]]|[+.-])*:`) + +// validateURLPrefix validates if the given non-empty prefix is a safe safehtml.URL prefix. +// +// Prefixes are considered unsafe if they end in an incomplete HTML character reference +// or percent-encoding character triplet. +// +// If the prefix contains a fully-specified scheme component, it is considered safe only if +// it starts with an allowed scheme. See safehtml.URLSanitized for more details. +// +// Otherwise, the prefix is safe only if it contains '/', '?', or '#', since the presence of any +// of these runes ensures that this prefix, when combined with some arbitrary suffix, cannot be +// interpreted as a part of a scheme. +func validateURLPrefix(prefix string) error { + decoded, err := decodeURLPrefix(prefix) + if err != nil { + return err + } + switch { + case startsWithFullySpecifiedSchemePattern.MatchString(decoded): + if safehtml.URLSanitized(decoded).String() != decoded { + return fmt.Errorf("URL prefix %q contains an unsafe scheme", prefix) + } + case !strings.ContainsAny(decoded, "/?#"): + // If the URL prefix does not already have a ':' scheme delimiter, and does not contain + // '/', '?', or '#', any ':' following this prefix will be intepreted as a scheme + // delimiter, causing this URL prefix to be interpreted as being part of a scheme. + // e.g. `` + return fmt.Errorf("URL prefix %q is unsafe; it might be interpreted as part of a scheme", prefix) + } + return nil +} + +// validateTrustedResourceURLPrefix validates if the given non-empty prefix is a safe +// safehtml.TrustedResourceURL prefix. +// +// Prefixes are considered unsafe if they end in an incomplete HTML character reference +// or percent-encoding character triplet. +// +// See safehtmlutil.IsSafeTrustedResourceURLPrefix for details on how the prefix is validated. +func validateTrustedResourceURLPrefix(prefix string) error { + decoded, err := decodeURLPrefix(prefix) + if err != nil { + return err + } + if !safehtmlutil.IsSafeTrustedResourceURLPrefix(decoded) { + return fmt.Errorf("%q is a disallowed TrustedResourceURL prefix", prefix) + } + return nil +} + +// endsWithPercentEncodingPrefixPattern matches strings that end in an incomplete +// URL percent encoding triplet. +// +// See https://tools.ietf.org/html/rfc3986#section-2.1. +var endsWithPercentEncodingPrefixPattern = regexp.MustCompile( + `%[[:xdigit:]]?$`) + +// containsWhitespaceOrControlPattern matches strings that contain ASCII whitespace +// or control characters. +var containsWhitespaceOrControlPattern = regexp.MustCompile(`[[:space:]]|[[:cntrl:]]`) + +// decodeURLPrefix returns the given prefix after it has been HTML-unescaped. +// It returns an error if the prefix: +// * ends in an incomplete HTML character reference before HTML-unescaping, +// * ends in an incomplete percent-encoding character triplet after HTML-unescaping, or +// * contains whitespace before or after HTML-unescaping. +func decodeURLPrefix(prefix string) (string, error) { + if containsWhitespaceOrControlPattern.MatchString(prefix) { + return "", fmt.Errorf("URL prefix %q contains whitespace or control characters", prefix) + } + if err := validateDoesNotEndsWithCharRefPrefix(prefix); err != nil { + return "", fmt.Errorf("URL %s", err) + } + decoded := html.UnescapeString(prefix) + // Check again for whitespace that might have previously been masked by a HTML reference, + // such as in "javascript ". + if containsWhitespaceOrControlPattern.MatchString(decoded) { + return "", fmt.Errorf("URL prefix %q contains whitespace or control characters", prefix) + } + if endsWithPercentEncodingPrefixPattern.MatchString(decoded) { + return "", fmt.Errorf("URL prefix %q ends with an incomplete percent-encoding character triplet", prefix) + } + return decoded, nil +} + +func validateTrustedResourceURLSubstitution(args ...interface{}) (string, error) { + input := safehtmlutil.Stringify(args...) + if safehtmlutil.URLContainsDoubleDotSegment(input) { + // Reject substitutions containing the ".." dot-segment to prevent the final TrustedResourceURL from referencing + // a resource higher up in the path name hierarchy than the path specified in the prefix. + return "", fmt.Errorf(`cannot substitute %q after TrustedResourceURL prefix: ".." is disallowed`, input) + } + return input, nil +} diff --git a/vendor/github.com/google/safehtml/trustedresourceurl.go b/vendor/github.com/google/safehtml/trustedresourceurl.go new file mode 100644 index 000000000..e31a2fd56 --- /dev/null +++ b/vendor/github.com/google/safehtml/trustedresourceurl.go @@ -0,0 +1,195 @@ +// Copyright (c) 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 or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "flag" + "github.com/google/safehtml/internal/safehtmlutil" +) + +// A TrustedResourceURL is an immutable string-like type referencing the +// application’s own, trusted resources. It can be used to safely load scripts, +// CSS and other sensitive resources without the risk of untrusted code execution. +// For example, it is unsafe to insert a plain string in a +// +// +// +// context since the URL may originate from untrusted user input and the +// script it is pointing to may thus be controlled by an attacker. It is, +// however, safe to use a TrustedResourceURL since its value is known to never +// have left application control. +// +// In order to ensure that an attacker cannot influence the TrustedResourceURL +// value, a TrustedResourceURL can only be instantiated from compile-time +// constant string literals, command-line flags or a combination of the two, +// but never from arbitrary string values potentially representing untrusted user input. +// +// Additionally, TrustedResourceURLs can be serialized and passed along within +// the application via protocol buffers. It is the application’s responsibility +// to ensure that the protocol buffers originate from within the application +// itself and not from an external entity outside its trust domain. +// +// Note that TrustedResourceURLs can also use absolute paths (starting with '/') +// and relative paths. This allows the same binary to be used for different +// hosts without hard-coding the hostname in a string literal. +type TrustedResourceURL struct { + // We declare a TrustedResourceURL not as a string but as a struct wrapping a string + // to prevent construction of TrustedResourceURL values through string conversion. + str string +} + +// TrustedResourceURLWithParams constructs a new TrustedResourceURL with the +// given key-value pairs added as query parameters. +// +// Map entries with empty keys or values are ignored. The order of appended +// keys is guaranteed to be stable but may differ from the order in input. +func TrustedResourceURLWithParams(t TrustedResourceURL, params map[string]string) TrustedResourceURL { + url := t.str + var fragment string + if i := strings.IndexByte(url, '#'); i != -1 { + // The fragment identifier component will always appear at the end + // of the URL after the query segment. It is therefore safe to + // trim the fragment from the tail of the URL and re-append it after + // all query parameters have been added. + // See https://tools.ietf.org/html/rfc3986#appendix-A. + fragment = url[i:] + url = url[:i] + } + sep := "?" + if i := strings.IndexRune(url, '?'); i != -1 { + // The first "?" in a URL indicates the start of the query component. + // See https://tools.ietf.org/html/rfc3986#section-3.4 + if i == len(url)-1 { + sep = "" + } else { + sep = "&" + } + } + stringParams := make([]string, 0, len(params)) + for k, v := range params { + if k == "" || v == "" { + continue + } + stringParam := safehtmlutil.QueryEscapeURL(k) + "=" + safehtmlutil.QueryEscapeURL(v) + stringParams = append(stringParams, stringParam) + } + if len(stringParams) > 0 { + sort.Strings(stringParams) + url += sep + strings.Join(stringParams, "&") + } + return TrustedResourceURL{url + fragment} +} + +// TrustedResourceURLFromConstant constructs a TrustedResourceURL with its underlying +// URL set to the given url, which must be an untyped string constant. +// +// No runtime validation or sanitization is performed on url; being under +// application control, it is simply assumed to comply with the TrustedResourceURL type +// contract. +func TrustedResourceURLFromConstant(url stringConstant) TrustedResourceURL { + return TrustedResourceURL{string(url)} +} + +// TrustedResourceURLFormatFromConstant constructs a TrustedResourceURL from a +// format string, which must be an untyped string constant, and string arguments. +// +// Arguments are specified as a map of labels, which must contain only alphanumeric +// and '_' runes, to string values. Each `%{