From 8158ff35f028a3300a870cc2a67c4d15457071cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 03:56:29 +0000 Subject: [PATCH] Update module github.com/golangci/golangci-lint/v2 to v2.13.1 --- go.mod | 97 +- go.sum | 210 +- .../checkcompilerdirectives.go | 1 + vendor/charm.land/lipgloss/v2/.golangci.yml | 3 + vendor/charm.land/lipgloss/v2/canvas.go | 5 +- vendor/charm.land/lipgloss/v2/position.go | 4 +- vendor/charm.land/lipgloss/v2/wrap.go | 6 + .../dev.gaijin.team/go/exhaustruct/v5/LICENSE | 21 + .../go/exhaustruct/v5/analyzer/analyzer.go | 112 + .../go/exhaustruct/v5/analyzer/config.go | 134 + .../v5/analyzer/missing-fields-visitor.go | 381 + .../v5/analyzer/tag-migration-visitor.go | 111 + .../v5/internal/astutil/file-parser.go | 213 + .../go/exhaustruct/v5/internal/cache/cache.go | 100 + .../v5/internal/directive/directive.go | 95 + .../v5/internal/directive/scanner.go | 189 + .../exhaustruct/v5/internal/pattern/list.go | 63 + .../v5/internal/structure/origin-scanner.go | 121 + .../v5/internal/structure/processor.go | 254 + .../v5/internal/structure/struct.go | 224 + .../dev.gaijin.team/go/golib/fields/field.go | 1 - .../dev.gaijin.team/go/golib/fields/list.go | 2 +- .../github.com/Abirdcfly/dupword/dupword.go | 41 +- .../AlwxSin/noinlineerr/noinlineerr.go | 17 +- .../passes/chbatchclose/chbatchclose.go | 77 +- .../alecthomas/chroma/v2/.golangci.yml | 179 +- .../github.com/alecthomas/chroma/v2/AGENTS.md | 2 +- .../github.com/alecthomas/chroma/v2/BUILD.bit | 93 + .../github.com/alecthomas/chroma/v2/Bitfile | 24 - .../alecthomas/chroma/v2/Dockerfile | 2 +- .../github.com/alecthomas/chroma/v2/Justfile | 6 +- .../github.com/alecthomas/chroma/v2/README.md | 16 +- .../github.com/alecthomas/chroma/v2/colour.go | 2 +- .../chroma/v2/formatters/html/html.go | 70 +- .../chroma/v2/lexers/embedded/arturo.xml | 119 + .../chroma/v2/lexers/embedded/dart.xml | 2 +- .../v2/lexers/embedded/gemfile_lock.xml | 81 + .../chroma/v2/lexers/embedded/java.xml | 19 +- .../chroma/v2/lexers/embedded/json.xml | 3 + .../chroma/v2/lexers/embedded/lilypond.xml | 133 + .../chroma/v2/lexers/embedded/nu.xml | 7 +- .../chroma/v2/lexers/embedded/postscript.xml | 6 +- .../v2/lexers/embedded/protocol_buffer.xml | 18 +- .../chroma/v2/lexers/embedded/ruby.xml | 4 + .../chroma/v2/lexers/embedded/templ.xml | 315 + .../chroma/v2/lexers/embedded/yaml.xml | 18 +- .../alecthomas/chroma/v2/lexers/go.go | 4 +- .../alecthomas/chroma/v2/lexers/http.go | 2 +- .../alecthomas/chroma/v2/lexers/markdown.go | 67 +- .../alecthomas/chroma/v2/lexers/markless.go | 4 +- .../alecthomas/chroma/v2/lexers/raku.go | 10 +- .../alecthomas/chroma/v2/lexers/yaml_jinja.go | 20 + .../github.com/alecthomas/chroma/v2/regexp.go | 19 +- .../alecthomas/chroma/v2/renovate.json5 | 1 + .../alecthomas/chroma/v2/serialise.go | 8 +- .../github.com/alecthomas/chroma/v2/style.go | 95 +- .../alecthomas/chroma/v2/styles/api.go | 29 + .../chroma/v2/styles/catppuccin-latte.xml | 2 +- .../chroma/v2/styles/catppuccin-mocha.xml | 2 +- .../chroma/v2/styles/github-dark.xml | 2 +- .../alecthomas/chroma/v2/styles/github.xml | 2 +- .../chroma/v2/styles/gruvbox-light.xml | 3 +- .../alecthomas/chroma/v2/styles/gruvbox.xml | 3 +- .../chroma/v2/styles/kanagawa-lotus.xml | 2 +- .../chroma/v2/styles/kanagawa-wave.xml | 2 +- .../chroma/v2/styles/modus-operandi.xml | 2 +- .../chroma/v2/styles/modus-vivendi.xml | 2 +- .../alecthomas/chroma/v2/styles/monokai.xml | 2 +- .../chroma/v2/styles/monokailight.xml | 2 +- .../chroma/v2/styles/paraiso-dark.xml | 2 +- .../chroma/v2/styles/paraiso-light.xml | 2 +- .../chroma/v2/styles/rose-pine-dawn.xml | 2 +- .../alecthomas/chroma/v2/styles/rose-pine.xml | 2 +- .../chroma/v2/styles/solarized-dark.xml | 2 +- .../chroma/v2/styles/solarized-light.xml | 2 +- .../chroma/v2/styles/tokyonight-day.xml | 2 +- .../chroma/v2/styles/tokyonight-night.xml | 2 +- .../chroma/v2/styles/xcode-dark.xml | 2 +- .../alecthomas/chroma/v2/styles/xcode.xml | 2 +- .../alecthomas/chroma/v2/test.jsonl | 2 + .../github.com/bombsimon/wsl/v5/.golangci.yml | 3 + .../github.com/bombsimon/wsl/v5/analyzer.go | 2 +- vendor/github.com/bombsimon/wsl/v5/wsl.go | 18 +- .../github.com/butuzov/mirror/.editorconfig | 3 - .../github.com/butuzov/mirror/.golangci.yaml | 26 + vendor/github.com/butuzov/mirror/Makefile | 132 - vendor/github.com/butuzov/mirror/Taskfile.yml | 54 +- vendor/github.com/butuzov/mirror/analyzer.go | 4 +- .../mirror/internal/checker/checker.go | 4 +- .../mirror/internal/checker/violation.go | 8 +- vendor/github.com/butuzov/mirror/readme.md | 70 +- .../charmbracelet/ultraviolet/.golangci.yml | 40 +- .../charmbracelet/ultraviolet/README.md | 173 +- .../charmbracelet/ultraviolet/TUTORIAL.md | 256 +- .../charmbracelet/ultraviolet/buffer.go | 362 +- .../charmbracelet/ultraviolet/cell.go | 6 + .../charmbracelet/ultraviolet/console.go | 219 + .../charmbracelet/ultraviolet/console_unix.go | 13 + .../ultraviolet/console_windows.go | 13 + .../charmbracelet/ultraviolet/decoder.go | 5 +- .../charmbracelet/ultraviolet/doc.go | 45 +- .../charmbracelet/ultraviolet/event.go | 8 +- .../charmbracelet/ultraviolet/layout.go | 137 - .../charmbracelet/ultraviolet/mouse.go | 70 +- .../charmbracelet/ultraviolet/poll.go | 38 + .../charmbracelet/ultraviolet/poll_bsd.go | 165 + .../charmbracelet/ultraviolet/poll_default.go | 12 + .../ultraviolet/poll_fallback.go | 158 + .../charmbracelet/ultraviolet/poll_linux.go | 175 + .../charmbracelet/ultraviolet/poll_select.go | 156 + .../charmbracelet/ultraviolet/poll_solaris.go | 12 + .../charmbracelet/ultraviolet/poll_windows.go | 217 + .../charmbracelet/ultraviolet/styled.go | 150 +- .../charmbracelet/ultraviolet/terminal.go | 1200 +- .../ultraviolet/terminal_other.go | 17 +- .../ultraviolet/terminal_reader.go | 75 +- .../ultraviolet/terminal_reader_windows.go | 16 +- .../ultraviolet/terminal_renderer.go | 302 +- .../terminal_renderer_hardscroll.go | 14 +- .../ultraviolet/terminal_renderer_hashmap.go | 14 +- .../ultraviolet/terminal_screen.go | 837 + .../ultraviolet/terminal_unix.go | 59 +- .../ultraviolet/terminal_windows.go | 50 +- .../charmbracelet/ultraviolet/tty.go | 26 +- .../charmbracelet/ultraviolet/tty_other.go | 14 +- .../charmbracelet/ultraviolet/tty_unix.go | 11 + .../charmbracelet/ultraviolet/tty_windows.go | 14 +- .../charmbracelet/ultraviolet/uv.go | 297 +- .../charmbracelet/ultraviolet/window.go | 147 + .../github.com/charmbracelet/x/ansi/color.go | 2 +- .../charmbracelet/x/ansi/kitty/options.go | 21 +- .../charmbracelet/x/ansi/kitty/writer.go | 7 +- .../github.com/charmbracelet/x/ansi/mouse.go | 2 +- .../x/ansi/parser/transition_table.go | 4 +- .../charmbracelet/x/ansi/parser_decode.go | 10 +- .../charmbracelet/x/ansi/wcwidth.go | 100 + .../github.com/charmbracelet/x/ansi/width.go | 12 + vendor/github.com/dlclark/regexp2/.travis.yml | 7 - vendor/github.com/dlclark/regexp2/README.md | 174 - vendor/github.com/dlclark/regexp2/regexp.go | 395 - vendor/github.com/dlclark/regexp2/replace.go | 177 - vendor/github.com/dlclark/regexp2/runner.go | 1614 -- .../dlclark/regexp2/syntax/charclass.go | 865 - .../github.com/dlclark/regexp2/syntax/code.go | 274 - .../github.com/dlclark/regexp2/syntax/tree.go | 654 - vendor/github.com/dlclark/regexp2/testoutput1 | 7061 ------- .../dlclark/regexp2/{ => v2}/.gitignore | 2 + .../dlclark/regexp2/{ => v2}/ATTRIB | 0 .../dlclark/regexp2/{ => v2}/LICENSE | 0 .../github.com/dlclark/regexp2/v2/README.md | 283 + .../dlclark/regexp2/v2/Taskfile.yml | 64 + .../dlclark/regexp2/v2/bufferpool.go | 76 + .../dlclark/regexp2/{ => v2}/fastclock.go | 0 .../dlclark/regexp2/v2/helpers/indexof.go | 394 + .../dlclark/regexp2/v2/helpers/math.go | 15 + .../dlclark/regexp2/v2/helpers/runes.go | 58 + .../regexp2/v2/helpers/searchvalues.go | 180 + .../dlclark/regexp2/{ => v2}/match.go | 158 +- .../github.com/dlclark/regexp2/v2/options.go | 157 + .../github.com/dlclark/regexp2/v2/regexp.go | 717 + .../dlclark/regexp2/v2/regexp_codegen.go | 70 + .../github.com/dlclark/regexp2/v2/replace.go | 357 + .../github.com/dlclark/regexp2/v2/runner.go | 2197 ++ vendor/github.com/dlclark/regexp2/v2/split.go | 67 + .../dlclark/regexp2/v2/stringprefixfilter.go | 375 + .../dlclark/regexp2/v2/syntax/charclass.go | 1507 ++ .../dlclark/regexp2/v2/syntax/code.go | 316 + .../dlclark/regexp2/{ => v2}/syntax/escape.go | 2 +- .../dlclark/regexp2/{ => v2}/syntax/fuzz.go | 3 +- .../regexp2/v2/syntax/optimizations.go | 672 + .../dlclark/regexp2/{ => v2}/syntax/parser.go | 691 +- .../dlclark/regexp2/{ => v2}/syntax/prefix.go | 277 +- .../regexp2/v2/syntax/prefixanalyzer.go | 1491 ++ .../regexp2/{ => v2}/syntax/replacerdata.go | 20 +- .../dlclark/regexp2/v2/syntax/tree.go | 2362 +++ .../regexp2/v2/syntax/unicode_alias_tables.go | 6058 ++++++ .../dlclark/regexp2/{ => v2}/syntax/writer.go | 228 +- vendor/github.com/ebitengine/purego/func.go | 9 +- .../internal/fakecgo/zsymbols_freebsd.go | 20 +- .../ebitengine/purego/syscall_sysv.go | 5 +- .../felixge/httpsnoop/capture_metrics.go | 37 +- .../felixge/httpsnoop/wrap_generated.go | 16179 +++++++++++++++ .../httpsnoop/wrap_generated_gteq_1.8.go | 436 - .../httpsnoop/wrap_generated_lt_1.8.go | 278 - .../nonamedreturns/analyzer/analyzer.go | 219 +- .../ghostiam/protogetter/flake.lock | 6 +- .../github.com/ghostiam/protogetter/flake.nix | 2 +- .../go-critic/go-critic/checkers/utils.go | 349 +- vendor/github.com/golangci/gofmt/Makefile | 9 + vendor/github.com/golangci/gofmt/gofmt.go | 73 + .../golangci/gofmt/gofmt/golangci.go | 133 - .../github.com/golangci/gofmt/gofmt/readme.md | 15 - .../golangci/gofmt/internal/.gitattributes | 1 + .../gofmt/{gofmt => internal}/LICENSE | 0 .../golangci/gofmt/{gofmt => internal}/doc.go | 2 +- .../gofmt/{gofmt => internal}/gofmt.go | 102 +- .../golangci/gofmt/internal/golangci.go | 51 + .../gofmt/{gofmt => internal}/internal.go | 9 +- .../gofmt/{gofmt => internal}/rewrite.go | 12 +- .../gofmt/{gofmt => internal}/simplify.go | 2 +- vendor/github.com/golangci/gofmt/readme.md | 46 + .../golangci-lint/v2/internal/cache/cache.go | 12 +- .../v2/internal/go/base/readme.md | 2 + .../v2/internal/go/cache/cache.go | 45 +- .../v2/internal/go/cache/default.go | 36 +- .../v2/internal/go/cache/hash.go | 3 + .../v2/internal/go/cache/readme.md | 6 +- .../v2/internal/go/cacheprog/cacheprog.go | 13 +- .../v2/internal/go/cacheprog/readme.md | 2 + .../golangci-lint/v2/internal/go/mmap/mmap.go | 19 + .../v2/internal/go/mmap/readme.md | 2 + .../v2/internal/go/quoted/readme.md | 2 + .../v2/internal/x/tools/diff/lcs/old.go | 17 +- .../v2/internal/x/tools/diff/lcs/sequence.go | 79 +- .../v2/internal/x/tools/diff/ndiff.go | 19 + .../v2/internal/x/tools/diff/readme.md | 2 + .../v2/internal/x/tools/diff/unified.go | 79 +- .../v2/internal/x/tools/driverutil/readme.md | 3 + .../v2/jsonschema/golangci.jsonschema.json | 143 +- .../jsonschema/golangci.next.jsonschema.json | 143 +- .../jsonschema/golangci.v2.12.jsonschema.json | 5438 +++++ .../golangci-lint/v2/pkg/commands/cache.go | 16 +- .../pkg/commands/internal/migrate/migrate.go | 3 +- .../internal/migrate/migrate_linters.go | 4 +- .../migrate/migrate_linters_exclusions.go | 10 +- .../migrate/migrate_linters_settings.go | 2 +- .../internal/migrate/migrate_output.go | 30 +- .../pkg/commands/internal/migrate/ptr/ptr.go | 2 - .../migrate/versionone/linters_settings.go | 2 +- .../internal/migrate/versionone/output.go | 6 +- .../golangci-lint/v2/pkg/commands/run.go | 6 +- .../v2/pkg/config/base_loader.go | 3 +- .../v2/pkg/config/formatters_settings.go | 13 +- .../v2/pkg/config/linters_settings.go | 44 +- .../v2/pkg/goanalysis/runner_action_cache.go | 49 +- .../pkg/goanalysis/runner_loadingpackage.go | 4 +- .../gci/internal/section/standard_list.go | 4 +- .../v2/pkg/goformatters/gofmt/gofmt.go | 2 +- .../v2/pkg/goformatters/gofumpt/gofumpt.go | 10 + .../v2/pkg/golinters/dupword/dupword.go | 7 +- .../golinters/exhaustruct/exhaustruct_v5.go | 34 + .../v2/pkg/golinters/fatcontext/fatcontext.go | 4 +- .../v2/pkg/golinters/funcorder/funcorder.go | 1 + .../v2/pkg/golinters/goconst/goconst.go | 48 +- .../v2/pkg/golinters/godoclint/godoclint.go | 18 +- .../v2/pkg/golinters/gofumpt/gofumpt.go | 2 +- .../gomoddirectives/gomoddirectives.go | 2 + .../v2/pkg/golinters/iface/iface.go | 10 +- .../v2/pkg/golinters/modernize/modernize.go | 10 + .../nonamedreturns/nonamedreturns.go | 3 +- .../v2/pkg/lint/lintersdb/builder_linter.go | 10 +- .../pkg/lint/lintersdb/builder_plugin_go.go | 6 + .../github.com/jgautheron/goconst/README.md | 32 +- vendor/github.com/jgautheron/goconst/api.go | 201 +- .../github.com/jgautheron/goconst/parser.go | 17 + .../github.com/jgautheron/goconst/visitor.go | 117 +- .../kisielk/errcheck/errcheck/errcheck.go | 25 +- .../kisielk/errcheck/errcheck/excludes.go | 3 + .../ldez/gomoddirectives/.golangci.yml | 2 + .../ldez/gomoddirectives/gomoddirectives.go | 5 + .../github.com/ldez/gomoddirectives/readme.md | 9 +- .../lucasb-eyer/go-colorful/CHANGELOG.md | 4 + .../lucasb-eyer/go-colorful/widegamut.go | 6 +- .../github.com/mattn/go-runewidth/SECURITY.md | 25 + .../mattn/go-runewidth/runewidth.go | 151 +- .../nunnatsa/ginkgolinter/config/config.go | 4 +- .../internal/expression/actual/actualarg.go | 33 +- .../expression/matcher/errormatchers.go | 2 +- .../internal/expression/value/value.go | 17 +- .../internal/reports/report-builder.go | 2 + .../internal/rules/errorequalnilrule.go | 2 +- .../internal/rules/haveoccurredrule.go | 12 +- .../internal/rules/succeedrule.go | 14 +- .../pelletier/go-toml/v2/.goreleaser.yaml | 32 +- .../github.com/pelletier/go-toml/v2/AGENTS.md | 11 +- .../pelletier/go-toml/v2/CONTRIBUTING.md | 19 + .../pelletier/go-toml/v2/Dockerfile | 7 +- .../github.com/pelletier/go-toml/v2/README.md | 341 +- .../go-toml/v2/capability_baseline.txt | 1 + .../github.com/pelletier/go-toml/v2/caps.sh | 101 + vendor/github.com/pelletier/go-toml/v2/ci.sh | 6 +- .../github.com/pelletier/go-toml/v2/decode.go | 767 +- .../pelletier/go-toml/v2/decode_fused.go | 362 + .../github.com/pelletier/go-toml/v2/errors.go | 282 +- .../go-toml/v2/internal/characters/ascii.go | 42 - .../go-toml/v2/internal/characters/utf8.go | 175 - .../v2/internal/parserbridge/parserbridge.go | 37 + .../go-toml/v2/internal/tracker/key.go | 3 +- .../go-toml/v2/internal/tracker/seen.go | 551 +- .../pelletier/go-toml/v2/localtime.go | 7 +- .../pelletier/go-toml/v2/marshaler.go | 2101 +- .../github.com/pelletier/go-toml/v2/strict.go | 94 +- .../github.com/pelletier/go-toml/v2/toml.abnf | 21 +- .../github.com/pelletier/go-toml/v2/types.go | 13 +- .../pelletier/go-toml/v2/unmarshaler.go | 2994 ++- .../pelletier/go-toml/v2/unstable/ast.go | 85 +- .../pelletier/go-toml/v2/unstable/bridge.go | 21 + .../pelletier/go-toml/v2/unstable/builder.go | 64 - .../pelletier/go-toml/v2/unstable/kind.go | 4 +- .../go-toml/v2/unstable/marshaler.go | 29 + .../pelletier/go-toml/v2/unstable/parser.go | 2299 ++- .../pelletier/go-toml/v2/unstable/scanner.go | 270 - .../go-toml/v2/unstable/unmarshaler.go | 31 +- .../raeperd/recvcheck/.golangci.yml | 18 +- vendor/github.com/raeperd/recvcheck/README.md | 142 +- .../github.com/raeperd/recvcheck/analyzer.go | 26 +- .../jsonschema/v6/.golangci.yml | 1 - .../santhosh-tekuri/jsonschema/v6/.swp | Bin 20480 -> 0 bytes .../santhosh-tekuri/jsonschema/v6/format.go | 2 +- .../santhosh-tekuri/jsonschema/v6/go.work.sum | 2 +- .../jsonschema/v6/kind/kind.go | 2 +- .../jsonschema/v6/objcompiler.go | 6 +- .../santhosh-tekuri/jsonschema/v6/schema.go | 31 +- .../santhosh-tekuri/jsonschema/v6/util.go | 3 + .../jsonschema/v6/validator.go | 6 +- .../santhosh-tekuri/jsonschema/v6/vocab.go | 4 + .../github.com/securego/gosec/v2/.env.example | 3 + .../github.com/securego/gosec/v2/.gitignore | 4 +- vendor/github.com/securego/gosec/v2/README.md | 60 +- .../github.com/securego/gosec/v2/action.yml | 2 +- .../github.com/securego/gosec/v2/analyzer.go | 109 +- .../gosec/v2/analyzers/context_propagation.go | 15 + .../gosec/v2/analyzers/range_analyzer.go | 4 +- vendor/github.com/securego/gosec/v2/config.go | 9 + .../securego/gosec/v2/renovate.json | 71 +- .../gosec/v2/rules/hardcoded_credentials.go | 17 + .../securego/gosec/v2/rules/rand.go | 8 +- .../shirou/gopsutil/v4/cpu/cpu_darwin.go | 4 +- .../shirou/gopsutil/v4/cpu/cpu_freebsd.go | 3 + .../shirou/gopsutil/v4/cpu/cpu_netbsd.go | 6 + .../shirou/gopsutil/v4/cpu/cpu_openbsd.go | 6 + .../shirou/gopsutil/v4/cpu/cpu_windows.go | 130 +- .../v4/internal/common/common_darwin.go | 133 +- .../shirou/gopsutil/v4/mem/mem_darwin.go | 2 +- .../shirou/gopsutil/v4/mem/mem_linux.go | 4 +- .../shirou/gopsutil/v4/mem/mem_openbsd_386.go | 7 +- .../gopsutil/v4/mem/mem_openbsd_amd64.go | 4 +- .../shirou/gopsutil/v4/mem/mem_openbsd_arm.go | 7 +- .../gopsutil/v4/mem/mem_openbsd_arm64.go | 7 +- .../gopsutil/v4/mem/mem_openbsd_riscv64.go | 7 +- .../shirou/gopsutil/v4/net/net_linux.go | 6 +- .../shirou/gopsutil/v4/net/net_windows.go | 16 +- .../shirou/gopsutil/v4/process/process.go | 8 +- .../gopsutil/v4/process/process_darwin.go | 107 +- .../gopsutil/v4/process/process_linux.go | 18 + .../gopsutil/v4/process/process_openbsd.go | 16 +- .../github.com/sirupsen/logrus/.golangci.yml | 48 +- vendor/github.com/sirupsen/logrus/.travis.yml | 15 - .../github.com/sirupsen/logrus/CHANGELOG.md | 239 +- vendor/github.com/sirupsen/logrus/README.md | 92 +- vendor/github.com/sirupsen/logrus/alt_exit.go | 4 +- .../github.com/sirupsen/logrus/buffer_pool.go | 22 +- vendor/github.com/sirupsen/logrus/doc.go | 26 +- vendor/github.com/sirupsen/logrus/entry.go | 412 +- vendor/github.com/sirupsen/logrus/exported.go | 169 +- .../github.com/sirupsen/logrus/formatter.go | 47 +- .../sirupsen/logrus/json_formatter.go | 37 +- vendor/github.com/sirupsen/logrus/level.go | 101 + vendor/github.com/sirupsen/logrus/logger.go | 156 +- vendor/github.com/sirupsen/logrus/logrus.go | 211 +- .../logrus/terminal_check_appengine.go | 8 +- .../sirupsen/logrus/terminal_check_bsd.go | 3 +- .../sirupsen/logrus/terminal_check_js.go | 7 - .../logrus/terminal_check_no_terminal.go | 8 +- .../logrus/terminal_check_notappengine.go | 8 +- .../sirupsen/logrus/terminal_check_solaris.go | 2 + .../sirupsen/logrus/terminal_check_unix.go | 5 +- .../sirupsen/logrus/terminal_check_wasi.go | 8 - .../sirupsen/logrus/terminal_check_wasip1.go | 8 - .../sirupsen/logrus/terminal_check_windows.go | 2 +- .../sirupsen/logrus/text_formatter.go | 489 +- vendor/github.com/sirupsen/logrus/writer.go | 6 +- .../testify/assert/assertion_format.go | 28 +- .../testify/assert/assertion_forward.go | 52 +- .../testify/assert/assertion_order.go | 14 +- .../stretchr/testify/assert/assertions.go | 147 +- .../github.com/stretchr/testify/assert/doc.go | 4 +- .../testify/assert/yaml/yaml_custom.go | 2 +- .../testify/assert/yaml/yaml_default.go | 6 +- .../stretchr/testify/assert/yaml/yaml_fail.go | 2 +- .../testify/internal/difflib}/LICENSE | 2 +- .../testify/internal}/difflib/difflib.go | 206 +- .../testify/internal/spew}/LICENSE | 0 .../stretchr/testify/internal/spew/README.md | 12 + .../testify/internal}/spew/bypass.go | 1 + .../testify/internal}/spew/bypasssafe.go | 1 + .../testify/internal}/spew/common.go | 0 .../testify/internal}/spew/config.go | 30 +- .../testify/internal}/spew/doc.go | 146 +- .../testify/internal}/spew/dump.go | 18 +- .../testify/internal}/spew/format.go | 0 .../testify/internal}/spew/spew.go | 0 .../github.com/stretchr/testify/mock/mock.go | 43 +- .../stretchr/testify/require/doc.go | 6 +- .../stretchr/testify/require/require.go | 102 +- .../stretchr/testify/require/require.go.tmpl | 2 +- .../testify/require/require_forward.go | 100 +- .../testify/require/require_forward.go.tmpl | 2 +- .../stretchr/testify/require/requirements.go | 8 +- .../uudashr/iface/identical/identical.go | 32 +- .../iface/internal/directive/directive.go | 9 + .../github.com/uudashr/iface/opaque/opaque.go | 228 +- .../uudashr/iface/unexported/unexported.go | 258 +- .../github.com/uudashr/iface/unused/unused.go | 95 +- .../uudashr/iface/unusedmethod/doc.go | 3 + .../iface/unusedmethod/unusedmethod.go | 226 + .../fatcontext/pkg/analyzer/analyzer.go | 31 +- .../net/http/otelhttp/handler.go | 17 +- .../http/otelhttp/internal/semconv/client.go | 45 +- .../http/otelhttp/internal/semconv/server.go | 39 +- .../http/otelhttp/internal/semconv/util.go | 2 +- .../net/http/otelhttp/transport.go | 3 +- .../net/http/otelhttp/version.go | 2 +- .../otel/semconv/v1.40.0/MIGRATION.md | 27 - .../otel/semconv/v1.40.0/README.md | 3 - .../otel/semconv/v1.40.0/attribute_group.go | 16865 ---------------- .../otel/semconv/v1.40.0/doc.go | 9 - .../otel/semconv/v1.40.0/error_type.go | 81 - .../otel/semconv/v1.40.0/exception.go | 9 - .../otel/semconv/v1.40.0/schema.go | 9 - .../{v1.40.0 => v1.41.0}/httpconv/metric.go | 323 +- .../x/crypto/internal/poly1305/mac_noasm.go | 2 +- .../x/crypto/internal/poly1305/sum_asm.go | 2 +- .../x/crypto/internal/poly1305/sum_riscv64.s | 158 + vendor/golang.org/x/crypto/ssh/certs.go | 15 +- vendor/golang.org/x/crypto/ssh/channel.go | 69 +- vendor/golang.org/x/crypto/ssh/client_auth.go | 2 +- vendor/golang.org/x/crypto/ssh/common.go | 8 +- vendor/golang.org/x/crypto/ssh/connection.go | 2 +- vendor/golang.org/x/crypto/ssh/handshake.go | 2 +- vendor/golang.org/x/crypto/ssh/keys.go | 17 +- vendor/golang.org/x/crypto/ssh/messages.go | 11 +- vendor/golang.org/x/crypto/ssh/mux.go | 13 +- vendor/golang.org/x/crypto/ssh/server.go | 79 +- vendor/golang.org/x/crypto/ssh/ssh_gss.go | 16 +- vendor/golang.org/x/crypto/ssh/streamlocal.go | 2 + vendor/golang.org/x/crypto/ssh/tcpip.go | 2 + vendor/golang.org/x/exp/typeparams/common.go | 11 +- .../golang.org/x/exp/typeparams/normalize.go | 6 - .../golang.org/x/exp/typeparams/termlist.go | 23 +- .../{typeparams_go118.go => typeparams.go} | 108 +- .../x/exp/typeparams/typeparams_go117.go | 201 - .../golang.org/x/exp/typeparams/typeterm.go | 11 +- .../passes/fieldalignment/fieldalignment.go | 141 +- .../tools/go/analysis/passes/modernize/any.go | 2 +- .../analysis/passes/modernize/atomictypes.go | 2 +- .../go/analysis/passes/modernize/bloop.go | 2 +- .../tools/go/analysis/passes/modernize/doc.go | 44 +- .../go/analysis/passes/modernize/embedlit.go | 33 +- .../analysis/passes/modernize/errorsastype.go | 7 +- .../analysis/passes/modernize/fmtappendf.go | 2 +- .../go/analysis/passes/modernize/forvar.go | 2 +- .../passes/modernize/importcomment.go | 2 +- .../go/analysis/passes/modernize/maps.go | 2 +- .../go/analysis/passes/modernize/minmax.go | 17 +- .../go/analysis/passes/modernize/modernize.go | 18 +- .../go/analysis/passes/modernize/newexpr.go | 2 +- .../go/analysis/passes/modernize/omitzero.go | 2 +- .../go/analysis/passes/modernize/plusbuild.go | 2 +- .../go/analysis/passes/modernize/rangeint.go | 45 +- .../go/analysis/passes/modernize/reflect.go | 2 +- .../passes/modernize/reflecttypeassert.go | 118 + .../go/analysis/passes/modernize/slices.go | 2 +- .../passes/modernize/slicesbackward.go | 20 +- .../analysis/passes/modernize/slicesclip.go | 81 + .../passes/modernize/slicescontains.go | 2 +- .../analysis/passes/modernize/slicesdelete.go | 2 +- .../go/analysis/passes/modernize/sortslice.go | 2 +- .../analysis/passes/modernize/stditerators.go | 2 +- .../passes/modernize/stringsbuilder.go | 2 +- .../analysis/passes/modernize/stringscut.go | 35 +- .../passes/modernize/stringscutprefix.go | 2 +- .../analysis/passes/modernize/stringsseq.go | 4 +- .../passes/modernize/testingcontext.go | 2 +- .../analysis/passes/modernize/unsafefuncs.go | 2 +- .../analysis/passes/modernize/waitgroupgo.go | 46 +- .../tools/go/analysis/passes/printf/printf.go | 9 - .../analysis/passes/stdversion/stdversion.go | 31 +- .../passes/unusedresult/unusedresult.go | 4 +- .../x/tools/go/ast/inspector/cursor.go | 41 + vendor/golang.org/x/tools/go/loader/loader.go | 2 + .../golang.org/x/tools/go/packages/visit.go | 33 +- vendor/golang.org/x/tools/go/ssa/builder.go | 5 +- vendor/golang.org/x/tools/go/ssa/methods.go | 12 +- vendor/golang.org/x/tools/go/ssa/util.go | 10 +- vendor/golang.org/x/tools/go/ssa/wrappers.go | 5 +- .../x/tools/go/types/typeutil/callee.go | 61 +- .../internal/analysis/analyzerutil/version.go | 2 +- .../x/tools/internal/moremaps/maps.go | 116 + .../tools/internal/packagepath/packagepath.go | 16 +- .../x/tools/internal/refactor/imports.go | 4 +- .../tools/internal/refactor/inline/callee.go | 30 + .../internal/refactor/inline/calleefx.go | 17 +- .../tools/internal/refactor/inline/falcon.go | 14 +- .../internal/typesinternal/assignedaddress.go | 128 + .../internal/typesinternal/classify_call.go | 77 +- .../x/tools/internal/typesinternal/element.go | 65 +- .../x/tools/internal/typesinternal/toonew.go | 44 +- .../x/tools/internal/typesinternal/types.go | 8 + .../x/tools/refactor/satisfy/find.go | 19 +- .../honnef.co/go/tools/analysis/code/code.go | 14 +- .../honnef.co/go/tools/analysis/code/visit.go | 4 +- .../go/tools/analysis/dfa/dense/flow.go | 60 + .../go/tools/analysis/dfa/dense/forward.go | 271 + vendor/honnef.co/go/tools/analysis/dfa/dot.go | 48 + .../go/tools/analysis/dfa/lattice.go | 147 + .../tools/analysis/facts/nilness/nilness.go | 871 +- .../analysis/facts/typedness/typedness.go | 253 - .../go/tools/analysis/report/report.go | 3 +- .../honnef.co/go/tools/go/ast/astutil/util.go | 11 - vendor/honnef.co/go/tools/go/ir/UPSTREAM | 9 - vendor/honnef.co/go/tools/go/ir/block.go | 133 + vendor/honnef.co/go/tools/go/ir/blockopt.go | 19 +- vendor/honnef.co/go/tools/go/ir/builder.go | 1427 +- vendor/honnef.co/go/tools/go/ir/const.go | 276 +- vendor/honnef.co/go/tools/go/ir/create.go | 167 +- vendor/honnef.co/go/tools/go/ir/doc.go | 68 +- vendor/honnef.co/go/tools/go/ir/dom.go | 385 +- vendor/honnef.co/go/tools/go/ir/emit.go | 205 +- vendor/honnef.co/go/tools/go/ir/func.go | 566 +- vendor/honnef.co/go/tools/go/ir/html.go | 1126 -- .../honnef.co/go/tools/go/ir/instantiate.go | 161 + .../honnef.co/go/tools/go/ir/irutil/load.go | 88 +- .../honnef.co/go/tools/go/ir/irutil/stub.go | 73 +- .../honnef.co/go/tools/go/ir/irutil/switch.go | 20 +- .../honnef.co/go/tools/go/ir/irutil/util.go | 63 +- .../honnef.co/go/tools/go/ir/irutil/visit.go | 154 +- vendor/honnef.co/go/tools/go/ir/lift.go | 952 +- vendor/honnef.co/go/tools/go/ir/lvalue.go | 2 +- vendor/honnef.co/go/tools/go/ir/methods.go | 311 +- vendor/honnef.co/go/tools/go/ir/mode.go | 40 +- vendor/honnef.co/go/tools/go/ir/print.go | 335 +- vendor/honnef.co/go/tools/go/ir/sanity.go | 253 +- vendor/honnef.co/go/tools/go/ir/scc.go | 106 + vendor/honnef.co/go/tools/go/ir/source.go | 96 +- vendor/honnef.co/go/tools/go/ir/ssa.go | 893 +- vendor/honnef.co/go/tools/go/ir/subst.go | 577 + vendor/honnef.co/go/tools/go/ir/task.go | 103 + vendor/honnef.co/go/tools/go/ir/typeset.go | 175 + vendor/honnef.co/go/tools/go/ir/util.go | 366 +- vendor/honnef.co/go/tools/go/ir/wrappers.go | 303 +- vendor/honnef.co/go/tools/go/ir/write.go | 5 - .../go/tools/go/types/typeutil/typeparams.go | 12 +- .../go/tools/go/types/typeutil/unify.go | 345 + .../go/tools/internal/iterutil/iterutil.go | 21 + .../tools/internal/passes/buildir/buildir.go | 17 +- .../go/tools/internal/sharedcheck/lint.go | 3 +- .../xtools-internal/aliases/aliases.go | 18 + .../analysis}/typeindex/typeindex.go | 6 +- .../internal/xtools-internal/astutil/clone.go | 71 + .../xtools-internal/astutil/comment.go | 143 + .../xtools-internal/astutil/cursor.go | 38 + .../internal/xtools-internal/astutil/equal.go | 107 + .../xtools-internal/astutil/fields.go | 35 + .../internal/xtools-internal/astutil/purge.go | 93 + .../xtools-internal/astutil/stringlit.go | 103 + .../xtools-internal/astutil/unpack.go | 61 + .../internal/xtools-internal/astutil/util.go | 261 + .../xtools-internal/graph/allpaths.go | 24 + .../internal/xtools-internal/graph/compact.go | 89 + .../internal/xtools-internal/graph/graph.go | 33 + .../internal/xtools-internal/graph/index.go | 96 + .../internal/xtools-internal/graph/order.go | 94 + .../xtools-internal/graph/reachable.go | 23 + .../internal/xtools-internal/graph/scc.go | 39 + .../xtools-internal/graph/shortest.go | 45 + .../xtools-internal/graph/transpose.go | 51 + .../xtools-internal/moreiters/iters.go | 63 + .../xtools-internal/typeparams/common.go | 68 + .../xtools-internal/typeparams/coretype.go | 157 + .../xtools-internal/typeparams/free.go | 129 + .../xtools-internal/typeparams/normalize.go | 214 + .../xtools-internal/typeparams/termlist.go | 169 + .../xtools-internal/typeparams/typeterm.go | 172 + .../typesinternal/classify_call.go | 137 + .../xtools-internal/typesinternal/element.go | 137 + .../typesinternal/errorcode.go | 1558 ++ .../typesinternal/errorcode_string.go | 179 + .../xtools-internal/typesinternal/fx.go | 88 + .../xtools-internal/typesinternal/isnamed.go | 71 + .../typesinternal/qualifier.go | 54 + .../xtools-internal/typesinternal/recv.go | 44 + .../typesinternal/typeindex/typeindex.go | 94 +- .../xtools-internal/typesinternal/types.go | 272 + .../xtools-internal/typesinternal/varkind.go | 23 + .../typesinternal/varkind_go124.go | 39 + .../typesinternal/zerovalue.go | 381 + .../xtools-internal/versions/features.go | 49 + .../xtools-internal/versions/gover.go | 172 + .../xtools-internal/versions/types.go | 33 + .../xtools-internal/versions/versions.go | 57 + vendor/honnef.co/go/tools/knowledge/arg.go | 2 + .../go/tools/knowledge/deprecated.go | 5 + .../go/tools/quickfix/qf1002/qf1002.go | 2 +- .../go/tools/quickfix/qf1003/qf1003.go | 2 +- .../go/tools/quickfix/qf1004/qf1004.go | 4 +- .../honnef.co/go/tools/simple/s1005/s1005.go | 10 +- .../go/tools/staticcheck/analysis.go | 4 +- .../go/tools/staticcheck/sa1002/sa1002.go | 5 +- .../go/tools/staticcheck/sa1012/sa1012.go | 5 +- .../go/tools/staticcheck/sa1014/sa1014.go | 6 +- .../go/tools/staticcheck/sa1019/sa1019.go | 82 +- .../go/tools/staticcheck/sa1020/sa1020.go | 7 +- .../go/tools/staticcheck/sa1025/sa1025.go | 2 +- .../go/tools/staticcheck/sa1026/sa1026.go | 2 + .../go/tools/staticcheck/sa1030/sa1030.go | 2 +- .../go/tools/staticcheck/sa2000/sa2000.go | 5 +- .../go/tools/staticcheck/sa2001/sa2001.go | 3 +- .../go/tools/staticcheck/sa2003/sa2003.go | 16 +- .../go/tools/staticcheck/sa4003/sa4003.go | 128 +- .../go/tools/staticcheck/sa4005/sa4005.go | 6 +- .../go/tools/staticcheck/sa4006/sa4006.go | 33 +- .../go/tools/staticcheck/sa4008/sa4008.go | 18 +- .../go/tools/staticcheck/sa4009/sa4009.go | 3 +- .../go/tools/staticcheck/sa4010/sa4010.go | 58 +- .../go/tools/staticcheck/sa4017/sa4017.go | 3 +- .../go/tools/staticcheck/sa4023/sa4023.go | 46 +- .../go/tools/staticcheck/sa4031/sa4031.go | 2 - .../go/tools/staticcheck/sa5007/sa5007.go | 9 +- .../go/tools/staticcheck/sa5008/jsonv2.go | 2 +- .../go/tools/staticcheck/sa5011/sa5011.go | 221 - .../go/tools/staticcheck/sa5012/sa5012.go | 5 +- .../go/tools/staticcheck/sa6001/sa6001.go | 29 +- .../go/tools/staticcheck/sa6005/sa6005.go | 7 +- .../go/tools/staticcheck/sa9005/sa9005.go | 2 + .../go/tools/staticcheck/sa9010/sa9010.go | 60 + .../honnef.co/go/tools/unused/implements.go | 75 +- vendor/honnef.co/go/tools/unused/unused.go | 16 +- vendor/modules.txt | 190 +- vendor/mvdan.cc/gofumpt/format/format.go | 360 +- vendor/mvdan.cc/gofumpt/format/rewrite.go | 15 +- vendor/mvdan.cc/gofumpt/format/simplify.go | 5 + .../internal/govendor/go/format/internal.go | 8 +- .../internal/govendor/go/printer/nodes.go | 12 +- .../internal/govendor/go/printer/printer.go | 18 +- vendor/mvdan.cc/unparam/check/check.go | 144 +- 636 files changed, 73945 insertions(+), 45411 deletions(-) create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/LICENSE create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/analyzer.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/config.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/missing-fields-visitor.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/tag-migration-visitor.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/astutil/file-parser.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/cache/cache.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/directive.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/scanner.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/pattern/list.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/origin-scanner.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/processor.go create mode 100644 vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/struct.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/BUILD.bit delete mode 100644 vendor/github.com/alecthomas/chroma/v2/Bitfile create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arturo.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gemfile_lock.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lilypond.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/embedded/templ.xml create mode 100644 vendor/github.com/alecthomas/chroma/v2/lexers/yaml_jinja.go create mode 100644 vendor/github.com/alecthomas/chroma/v2/test.jsonl create mode 100644 vendor/github.com/butuzov/mirror/.golangci.yaml delete mode 100644 vendor/github.com/butuzov/mirror/Makefile create mode 100644 vendor/github.com/charmbracelet/ultraviolet/console.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/console_unix.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/console_windows.go delete mode 100644 vendor/github.com/charmbracelet/ultraviolet/layout.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_bsd.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_default.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_fallback.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_linux.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_select.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_solaris.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/poll_windows.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/terminal_screen.go create mode 100644 vendor/github.com/charmbracelet/ultraviolet/window.go create mode 100644 vendor/github.com/charmbracelet/x/ansi/wcwidth.go delete mode 100644 vendor/github.com/dlclark/regexp2/.travis.yml delete mode 100644 vendor/github.com/dlclark/regexp2/README.md delete mode 100644 vendor/github.com/dlclark/regexp2/regexp.go delete mode 100644 vendor/github.com/dlclark/regexp2/replace.go delete mode 100644 vendor/github.com/dlclark/regexp2/runner.go delete mode 100644 vendor/github.com/dlclark/regexp2/syntax/charclass.go delete mode 100644 vendor/github.com/dlclark/regexp2/syntax/code.go delete mode 100644 vendor/github.com/dlclark/regexp2/syntax/tree.go delete mode 100644 vendor/github.com/dlclark/regexp2/testoutput1 rename vendor/github.com/dlclark/regexp2/{ => v2}/.gitignore (94%) rename vendor/github.com/dlclark/regexp2/{ => v2}/ATTRIB (100%) rename vendor/github.com/dlclark/regexp2/{ => v2}/LICENSE (100%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/README.md create mode 100644 vendor/github.com/dlclark/regexp2/v2/Taskfile.yml create mode 100644 vendor/github.com/dlclark/regexp2/v2/bufferpool.go rename vendor/github.com/dlclark/regexp2/{ => v2}/fastclock.go (100%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/helpers/indexof.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/helpers/math.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/helpers/runes.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/helpers/searchvalues.go rename vendor/github.com/dlclark/regexp2/{ => v2}/match.go (67%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/options.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/regexp.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/regexp_codegen.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/replace.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/runner.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/split.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/stringprefixfilter.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/charclass.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/code.go rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/escape.go (97%) rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/fuzz.go (80%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/optimizations.go rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/parser.go (75%) rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/prefix.go (73%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/prefixanalyzer.go rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/replacerdata.go (80%) create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/tree.go create mode 100644 vendor/github.com/dlclark/regexp2/v2/syntax/unicode_alias_tables.go rename vendor/github.com/dlclark/regexp2/{ => v2}/syntax/writer.go (63%) create mode 100644 vendor/github.com/felixge/httpsnoop/wrap_generated.go delete mode 100644 vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go delete mode 100644 vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go create mode 100644 vendor/github.com/golangci/gofmt/Makefile create mode 100644 vendor/github.com/golangci/gofmt/gofmt.go delete mode 100644 vendor/github.com/golangci/gofmt/gofmt/golangci.go delete mode 100644 vendor/github.com/golangci/gofmt/gofmt/readme.md create mode 100644 vendor/github.com/golangci/gofmt/internal/.gitattributes rename vendor/github.com/golangci/gofmt/{gofmt => internal}/LICENSE (100%) rename vendor/github.com/golangci/gofmt/{gofmt => internal}/doc.go (99%) rename vendor/github.com/golangci/gofmt/{gofmt => internal}/gofmt.go (89%) create mode 100644 vendor/github.com/golangci/gofmt/internal/golangci.go rename vendor/github.com/golangci/gofmt/{gofmt => internal}/internal.go (96%) rename vendor/github.com/golangci/gofmt/{gofmt => internal}/rewrite.go (96%) rename vendor/github.com/golangci/gofmt/{gofmt => internal}/simplify.go (99%) create mode 100644 vendor/github.com/golangci/gofmt/readme.md create mode 100644 vendor/github.com/golangci/golangci-lint/v2/jsonschema/golangci.v2.12.jsonschema.json create mode 100644 vendor/github.com/golangci/golangci-lint/v2/pkg/golinters/exhaustruct/exhaustruct_v5.go create mode 100644 vendor/github.com/mattn/go-runewidth/SECURITY.md create mode 100644 vendor/github.com/pelletier/go-toml/v2/capability_baseline.txt create mode 100644 vendor/github.com/pelletier/go-toml/v2/caps.sh create mode 100644 vendor/github.com/pelletier/go-toml/v2/decode_fused.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/internal/parserbridge/parserbridge.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/bridge.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/builder.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/marshaler.go delete mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go delete mode 100644 vendor/github.com/santhosh-tekuri/jsonschema/v6/.swp create mode 100644 vendor/github.com/securego/gosec/v2/.env.example delete mode 100644 vendor/github.com/sirupsen/logrus/.travis.yml create mode 100644 vendor/github.com/sirupsen/logrus/level.go delete mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_js.go delete mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_wasi.go delete mode 100644 vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go rename vendor/github.com/{pmezard/go-difflib => stretchr/testify/internal/difflib}/LICENSE (95%) rename vendor/github.com/{pmezard/go-difflib => stretchr/testify/internal}/difflib/difflib.go (77%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal/spew}/LICENSE (100%) create mode 100644 vendor/github.com/stretchr/testify/internal/spew/README.md rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/bypass.go (98%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/bypasssafe.go (96%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/common.go (100%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/config.go (95%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/doc.go (65%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/dump.go (96%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/format.go (100%) rename vendor/github.com/{davecgh/go-spew => stretchr/testify/internal}/spew/spew.go (100%) create mode 100644 vendor/github.com/uudashr/iface/unusedmethod/doc.go create mode 100644 vendor/github.com/uudashr/iface/unusedmethod/unusedmethod.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/MIGRATION.md delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/README.md delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/attribute_group.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/doc.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/error_type.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/exception.go delete mode 100644 vendor/go.opentelemetry.io/otel/semconv/v1.40.0/schema.go rename vendor/go.opentelemetry.io/otel/semconv/{v1.40.0 => v1.41.0}/httpconv/metric.go (83%) create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s rename vendor/golang.org/x/exp/typeparams/{typeparams_go118.go => typeparams.go} (67%) delete mode 100644 vendor/golang.org/x/exp/typeparams/typeparams_go117.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/reflecttypeassert.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesclip.go create mode 100644 vendor/golang.org/x/tools/internal/moremaps/maps.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/assignedaddress.go create mode 100644 vendor/honnef.co/go/tools/analysis/dfa/dense/flow.go create mode 100644 vendor/honnef.co/go/tools/analysis/dfa/dense/forward.go create mode 100644 vendor/honnef.co/go/tools/analysis/dfa/dot.go create mode 100644 vendor/honnef.co/go/tools/analysis/dfa/lattice.go delete mode 100644 vendor/honnef.co/go/tools/analysis/facts/typedness/typedness.go delete mode 100644 vendor/honnef.co/go/tools/go/ir/UPSTREAM create mode 100644 vendor/honnef.co/go/tools/go/ir/block.go delete mode 100644 vendor/honnef.co/go/tools/go/ir/html.go create mode 100644 vendor/honnef.co/go/tools/go/ir/instantiate.go create mode 100644 vendor/honnef.co/go/tools/go/ir/scc.go create mode 100644 vendor/honnef.co/go/tools/go/ir/subst.go create mode 100644 vendor/honnef.co/go/tools/go/ir/task.go create mode 100644 vendor/honnef.co/go/tools/go/ir/typeset.go delete mode 100644 vendor/honnef.co/go/tools/go/ir/write.go create mode 100644 vendor/honnef.co/go/tools/go/types/typeutil/unify.go create mode 100644 vendor/honnef.co/go/tools/internal/iterutil/iterutil.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/aliases/aliases.go rename vendor/honnef.co/go/tools/internal/{analysisinternal => xtools-internal/analysis}/typeindex/typeindex.go (80%) create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/clone.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/comment.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/cursor.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/equal.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/fields.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/purge.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/stringlit.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/unpack.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/astutil/util.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/moreiters/iters.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/common.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/coretype.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/free.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/normalize.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/termlist.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/typeterm.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/classify_call.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/element.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode_string.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/fx.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/isnamed.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/qualifier.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/recv.go rename vendor/honnef.co/go/tools/internal/{ => xtools-internal}/typesinternal/typeindex/typeindex.go (74%) create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/types.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind_go124.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/zerovalue.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/versions/features.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/versions/gover.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/versions/types.go create mode 100644 vendor/honnef.co/go/tools/internal/xtools-internal/versions/versions.go delete mode 100644 vendor/honnef.co/go/tools/staticcheck/sa5011/sa5011.go create mode 100644 vendor/honnef.co/go/tools/staticcheck/sa9010/sa9010.go diff --git a/go.mod b/go.mod index 2d5c7b7d..aec75124 100644 --- a/go.mod +++ b/go.mod @@ -21,20 +21,21 @@ require ( ) require ( - 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect + 4d63.com/gocheckcompilerdirectives v1.4.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect - charm.land/lipgloss/v2 v2.0.3 // indirect + charm.land/lipgloss/v2 v2.0.6 // indirect codeberg.org/chavacava/garif v0.2.0 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect dario.cat/mergo v1.0.2 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect - dev.gaijin.team/go/golib v0.6.0 // indirect + dev.gaijin.team/go/exhaustruct/v5 v5.0.3 // indirect + dev.gaijin.team/go/golib v0.8.1 // indirect github.com/4meepo/tagalign v1.4.3 // indirect - github.com/Abirdcfly/dupword v0.1.7 // indirect + github.com/Abirdcfly/dupword v0.1.8 // indirect github.com/AdminBenni/iota-mixing v1.0.0 // indirect - github.com/AlwxSin/noinlineerr v1.0.5 // indirect - github.com/Antonboom/errname v1.1.1 // indirect - github.com/Antonboom/nilnil v1.1.1 // indirect + github.com/AlwxSin/noinlineerr v1.0.6 // indirect + github.com/Antonboom/errname v1.1.2 // indirect + github.com/Antonboom/nilnil v1.1.2 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect @@ -46,14 +47,14 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect github.com/Azure/go-autorest/logger v0.2.2 // indirect github.com/Azure/go-autorest/tracing v0.6.1 // indirect - github.com/ClickHouse/clickhouse-go-linter v1.2.0 // indirect + github.com/ClickHouse/clickhouse-go-linter v1.2.1 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect github.com/Masterminds/semver/v3 v3.5.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/MirrexOne/unqueryvet v1.5.4 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/agext/levenshtein v1.2.3 // indirect - github.com/alecthomas/chroma/v2 v2.24.1 // indirect + github.com/alecthomas/chroma/v2 v2.27.0 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect github.com/alexkohler/prealloc v1.1.0 // indirect @@ -83,19 +84,19 @@ require ( github.com/bkielbasa/cyclop v1.2.3 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.8.0 // indirect + github.com/bombsimon/wsl/v5 v5.9.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/buildpacks/imgutil v0.0.0-20260415151438-73856e68b72b // indirect github.com/butuzov/ireturn v0.4.1 // indirect - github.com/butuzov/mirror v1.3.0 // indirect + github.com/butuzov/mirror v1.3.3 // indirect github.com/catenacyber/perfsprint v0.10.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/charithe/durationcheck v0.0.11 // indirect github.com/charmbracelet/colorprofile v0.4.3 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 // indirect - github.com/charmbracelet/x/ansi v0.11.7 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 // indirect + github.com/charmbracelet/x/ansi v0.11.8 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect @@ -114,11 +115,10 @@ require ( github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/dlclark/regexp2 v1.12.0 // indirect + github.com/dlclark/regexp2/v2 v2.2.1 // indirect github.com/docker/cli v29.6.2+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect @@ -126,16 +126,16 @@ require ( github.com/docker/go-connections v0.7.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ebitengine/purego v0.10.0 // indirect + github.com/ebitengine/purego v0.10.2 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.19.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/firefart/nonamedreturns v1.0.6 // indirect + github.com/felixge/httpsnoop v1.1.0 // indirect + github.com/firefart/nonamedreturns v1.0.8 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.20 // indirect - github.com/go-critic/go-critic v0.14.3 // indirect + github.com/ghostiam/protogetter v0.3.21 // indirect + github.com/go-critic/go-critic v0.14.4 // indirect github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect @@ -157,8 +157,8 @@ require ( github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect - github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect - github.com/golangci/golangci-lint/v2 v2.12.2 // indirect + github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792 // indirect + github.com/golangci/golangci-lint/v2 v2.13.1 // indirect github.com/golangci/golines v0.15.0 // indirect github.com/golangci/misspell v0.8.0 // indirect github.com/golangci/plugin-module-register v0.1.2 // indirect @@ -182,24 +182,24 @@ require ( github.com/heroku/color v0.0.6 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jgautheron/goconst v1.10.0 // indirect + github.com/jgautheron/goconst v1.11.0 // indirect github.com/jjti/go-spancheck v0.6.5 // indirect github.com/julz/importas v0.2.0 // indirect github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect - github.com/kisielk/errcheck v1.10.0 // indirect + github.com/kisielk/errcheck v1.20.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect github.com/klauspost/compress v1.19.1 // indirect github.com/kulti/thelper v0.7.1 // indirect github.com/kunwardeep/paralleltest v1.0.15 // indirect github.com/lasiar/canonicalheader v1.1.2 // indirect github.com/ldez/exptostd v0.4.5 // indirect - github.com/ldez/gomoddirectives v0.8.0 // indirect + github.com/ldez/gomoddirectives v0.9.0 // indirect github.com/ldez/grignotin v0.10.1 // indirect github.com/ldez/structtags v0.6.1 // indirect github.com/ldez/tagliatelle v0.7.2 // indirect github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/lucasb-eyer/go-colorful v1.4.0 // indirect + github.com/lucasb-eyer/go-colorful v1.4.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/macabu/inamedparam v0.2.0 // indirect github.com/magiconair/properties v1.8.10 // indirect @@ -210,7 +210,7 @@ require ( github.com/matoous/godox v1.1.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect - github.com/mattn/go-runewidth v0.0.23 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect github.com/mgechev/revive v1.15.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e // indirect @@ -230,13 +230,12 @@ require ( github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.23.0 // indirect + github.com/nunnatsa/ginkgolinter v0.24.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/pelletier/go-toml/v2 v2.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.4.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect @@ -247,21 +246,21 @@ require ( github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/raeperd/recvcheck v0.2.0 // indirect + github.com/raeperd/recvcheck v0.3.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rogpeppe/go-internal v1.16.0 // indirect github.com/ryancurrah/gomodguard v1.4.1 // indirect github.com/ryancurrah/gomodguard/v2 v2.1.3 // indirect github.com/ryanrolds/sqlclosecheck v0.6.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect - github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect - github.com/securego/gosec/v2 v2.26.1 // indirect - github.com/shirou/gopsutil/v4 v4.26.5 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/securego/gosec/v2 v2.28.0 // indirect + github.com/shirou/gopsutil/v4 v4.26.7 // indirect + github.com/sirupsen/logrus v1.10.1 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sonatard/noctx v0.5.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -273,7 +272,7 @@ require ( github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect github.com/stretchr/objx v0.5.3 // indirect - github.com/stretchr/testify v1.11.1 // indirect + github.com/stretchr/testify v1.12.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tetafro/godot v1.5.6 // indirect github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect @@ -286,7 +285,7 @@ require ( github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/uudashr/gocognit v1.2.1 // indirect - github.com/uudashr/iface v1.4.2 // indirect + github.com/uudashr/iface v1.5.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xen0n/gosmopolitan v1.3.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect @@ -298,9 +297,9 @@ require ( go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.12.0 // indirect go.augendre.info/arangolint v0.4.0 // indirect - go.augendre.info/fatcontext v0.9.0 // indirect + go.augendre.info/fatcontext v0.10.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect go.opentelemetry.io/otel/trace v1.44.0 // indirect @@ -308,20 +307,20 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect - golang.org/x/crypto v0.54.0 // indirect + golang.org/x/crypto v0.55.0 // indirect golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect - golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect - golang.org/x/mod v0.38.0 // indirect - golang.org/x/net v0.57.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f // indirect + golang.org/x/mod v0.40.0 // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect - golang.org/x/text v0.40.0 // indirect - golang.org/x/tools v0.48.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.49.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - honnef.co/go/tools v0.7.0 // indirect - mvdan.cc/gofumpt v0.9.2 // indirect - mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect + honnef.co/go/tools v0.8.0 // indirect + mvdan.cc/gofumpt v0.11.0 // indirect + mvdan.cc/unparam v0.0.0-20260818115549-3f964bcb5673 // indirect ) diff --git a/go.sum b/go.sum index 761aa0ec..eeb5c8d8 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= -4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= +4d63.com/gocheckcompilerdirectives v1.4.0 h1:ZLq62rbGWVmQhiZ8kuNVIT/M09xCSTdJz9K3xOdT/CY= +4d63.com/gocheckcompilerdirectives v1.4.0/go.mod h1:9ZOAiMOjqC/nRwci2fcUXVHUNLG/cH6r6rhUh+jTFtQ= 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= -charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= -charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= +charm.land/lipgloss/v2 v2.0.6 h1:EaGKeuA8FvF+v2BT5VmZd2LoYLaMZJXA5n34th8nCIQ= +charm.land/lipgloss/v2 v2.0.6/go.mod h1:ipDDJNSGa1hlwDtSfW1s2/xR8Vdhbut4PXh2zEKZd0Q= code.cloudfoundry.org/credhub-cli v0.0.0-20260727130059-9e78db728bcf h1:pHjgXWLqCCJpQvA7Cxo/TLILuoPfgrlUYxNLKXYV4IY= code.cloudfoundry.org/credhub-cli v0.0.0-20260727130059-9e78db728bcf/go.mod h1:v2Ksqa8pjAMN+2sDjuv0Dn649weA85Ge9i9Rgn6ICAI= codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= @@ -16,22 +16,24 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= -dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= -dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= +dev.gaijin.team/go/exhaustruct/v5 v5.0.3 h1:yOeA7DNjlT8y4yfmN6nWWYYggA13N523YAj9/TXbuTM= +dev.gaijin.team/go/exhaustruct/v5 v5.0.3/go.mod h1:KwtBsX8nHHH1YxhxkpiBq6bfsmw5WnazWpNvJPHgY9Y= +dev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E= +dev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= -github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= -github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= +github.com/Abirdcfly/dupword v0.1.8 h1:SrhcUuGsROBuChFxHALRYzyyPODWn9zwghmzPvD9Cd8= +github.com/Abirdcfly/dupword v0.1.8/go.mod h1:XZrhVnI7YGpsTiWZANSQaBJ4QpL/Tq5vIEdKJJAs9WI= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= -github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= -github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= -github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= -github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= -github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= -github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= +github.com/AlwxSin/noinlineerr v1.0.6 h1:KAvuxunTe9QxvqrFB7nZTdb/7Wzas4AvifslTnG0Ld8= +github.com/AlwxSin/noinlineerr v1.0.6/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= +github.com/Antonboom/errname v1.1.2 h1:dxwONZJua3VB8Xh/VaCjqAcqF645sWWv7xj26zy7tdQ= +github.com/Antonboom/errname v1.1.2/go.mod h1:YeZIpgLMxT+SNkruGgYkLhzq/9vs3fsolTZegKaKDZI= +github.com/Antonboom/nilnil v1.1.2 h1:aNlFuJhaEseXe4fHO3xbjXlSeEiQVYa2lEkWD2s2hAY= +github.com/Antonboom/nilnil v1.1.2/go.mod h1:0ynwvphOLmAuMwTNDyBnDZmSwZoDpcFXmUHmzoHH2WA= github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= @@ -66,8 +68,8 @@ github.com/Azure/go-autorest/tracing v0.6.1 h1:YUMSrC/CeD1ZnnXcNYU4a/fzsO35u2Fsf github.com/Azure/go-autorest/tracing v0.6.1/go.mod h1:/3EgjbsjraOqiicERAeu3m7/z0x1TzjQGAwDrJrXGkc= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/ClickHouse/clickhouse-go-linter v1.2.0 h1:zbm174up3hTKjp0wKZVnTzRiG7tSF5XZF0FJG/MuCBI= -github.com/ClickHouse/clickhouse-go-linter v1.2.0/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4= +github.com/ClickHouse/clickhouse-go-linter v1.2.1 h1:zGEKIyd5YL08ieWG/LOUmlau2DxbxPVOfAeo+4Jz3ck= +github.com/ClickHouse/clickhouse-go-linter v1.2.1/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -86,8 +88,8 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM= -github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI= +github.com/alecthomas/chroma/v2 v2.27.0 h1:FodwmyOBgJULFYmDqibcp9pvfDLWdtPRh9v/r5BXYZs= +github.com/alecthomas/chroma/v2 v2.27.0/go.mod h1:NjJ3ciIgrqBNeIkWZ4e46nseoLDslxU1LmfCoL+wcY8= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= @@ -159,8 +161,8 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.8.0 h1:JTkyfs4yl8SPejrCF2GdABXE+mO1WvM7iUYzRWlsxDs= -github.com/bombsimon/wsl/v5 v5.8.0/go.mod h1:AbOLsulgkqP4ZnitHf9gwPtCOGlrzkk0jb0uNxRSY0o= +github.com/bombsimon/wsl/v5 v5.9.0 h1:WCrgZ7RQnZO5oEwbVTlYgBdU3wL294kR1BSWV8vTfsU= +github.com/bombsimon/wsl/v5 v5.9.0/go.mod h1:kjo4HiAV5FDkHC8/uzJq9mBffEEd6WT/nvN7DoMovDM= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= @@ -173,8 +175,8 @@ github.com/buildpacks/pack v0.40.9 h1:DNgCI19uIZuuQL9QEZA30xBdCVGx8G4tl01dkHwKOw github.com/buildpacks/pack v0.40.9/go.mod h1:X+FKtQMkkWcRdKLmICxgetDlccor+zbbu3jVAMKHCDc= github.com/butuzov/ireturn v0.4.1 h1:vWb3NO4t77iku/sjCQ/2pHTQeOmxEhjIriJqRLg1Y+I= github.com/butuzov/ireturn v0.4.1/go.mod h1:q+DXKzTDV5guNuXLnIab9fKXizTn2miZHLhxH7V/GB4= -github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= -github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= +github.com/butuzov/mirror v1.3.3 h1:v0RsWBhfFc1RQqE/f3sHpSttKDtodFn0gFmtYyD4/hA= +github.com/butuzov/mirror v1.3.3/go.mod h1:h9BzzwYnTiHO0GzgvaTqIg7VSsOUhdIv51cHFFBmX1w= github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ= github.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= @@ -189,10 +191,10 @@ github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1Di github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 h1:OqDqxQZliC7C8adA7KjelW3OjtAxREfeHkNcd66wpeI= -github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318/go.mod h1:Y6kE2GzHfkyQQVCSL9r2hwokSrIlHGzZG+71+wDYSZI= -github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= -github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 h1:rdnVWKgJpTVXKuKuJyxDJ+NFJdUaUqGvyGy61OcvlbA= +github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886/go.mod h1:nAw0d9PhFp1qdzi2xhQU5YOu5sVpDIHWlaW2Uz/bCro= +github.com/charmbracelet/x/ansi v0.11.8 h1:JMFwp0CgDC2+jcOB162HH5k7I3FVbgFSMMYg7dSPBQQ= +github.com/charmbracelet/x/ansi v0.11.8/go.mod h1:ZNN+3mXny/516oTQPLMPIBeSINvNJJQ8uQXDgbeJxY0= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= @@ -250,6 +252,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2/v2 v2.2.1 h1:mf4KkFUj0gJuarK8P+LgiS+Lit7m9N1yAwEfPbee7R0= +github.com/dlclark/regexp2/v2 v2.2.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU= github.com/docker/cli v29.6.2+incompatible h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw= github.com/docker/cli v29.6.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= @@ -268,8 +272,8 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= -github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7gzE= +github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= @@ -279,10 +283,10 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= -github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= +github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= +github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= +github.com/firefart/nonamedreturns v1.0.8 h1:iB32Dl17zJl1zlVEj/WlUWgx0HiRyQ85OUw1WHa4/II= +github.com/firefart/nonamedreturns v1.0.8/go.mod h1:vxFNvm5AfP/8rgAKFzYmnqx0yp1HjrYsErZ9pHPTznA= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -294,16 +298,16 @@ github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uh github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= github.com/gdamore/tcell/v2 v2.13.10 h1:Afs3JKt83HnhuUKdZ3MnxUgOqQRWftj5JyDqv1LLynA= github.com/gdamore/tcell/v2 v2.13.10/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= -github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0= -github.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= +github.com/ghostiam/protogetter v0.3.21 h1:EeWTGvL/Eyosp653hiWb6Byx4b69iJC4/E+za7vQHoI= +github.com/ghostiam/protogetter v0.3.21/go.mod h1:iAKSpyoHwYzay+OpjoWgwzRtPFthEfuUvmlomTThck0= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= -github.com/go-critic/go-critic v0.14.3 h1:5R1qH2iFeo4I/RJU8vTezdqs08Egi4u5p6vOESA0pog= -github.com/go-critic/go-critic v0.14.3/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= +github.com/go-critic/go-critic v0.14.4 h1:dSX4C3pWSeuMVxvQh6yG8U0ReSf3YOmKi4nwX5q7n/8= +github.com/go-critic/go-critic v0.14.4/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= @@ -320,8 +324,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= +github.com/go-quicktest/qt v1.102.0 h1:HSQxCeh5YZH3EL3W39ixjtyaEhcWSXQHtHnMBzSs474= +github.com/go-quicktest/qt v1.102.0/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= @@ -377,10 +381,10 @@ github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 h1:CbTB8KpqnViI6lIXx github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= -github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= -github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.12.2 h1:7+d1uY0bq1MU2UV3R5pW5Q7QWdcoq4naMRXM+gsJKrs= -github.com/golangci/golangci-lint/v2 v2.12.2/go.mod h1:opqHHuIcTG2R+4akzWMd4o1BnD9/1LcjICWOujr91U8= +github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792 h1:WL8YKrt3UbOBqSRU7GpP5BTtQTMWtVtj+mfPijgZeIg= +github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792/go.mod h1:te5hX0dW4C5r6YbXs+6ysNr8Q5UTmdIqGbb+mlFiYmA= +github.com/golangci/golangci-lint/v2 v2.13.1 h1:RuM4OcluM4xFQcGuRE6R7jA33pqxK/W1EsBxpugdZjg= +github.com/golangci/golangci-lint/v2 v2.13.1/go.mod h1:HwX7mDzqHbcSxlhrTygjX1GJbAfQ3sJAqOx41qQlhDE= github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= @@ -450,8 +454,8 @@ github.com/jarcoal/httpmock v1.4.2 h1:dKwiP/9zITCPfBLsDn3kchbSOu16JrnxtVEmL0fPRc github.com/jarcoal/httpmock v1.4.2/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jgautheron/goconst v1.10.0 h1:Ptt+OoE4NaEWKhLrWrrN3IpZdGLiqaf7WLnEX/iv4Jw= -github.com/jgautheron/goconst v1.10.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc= +github.com/jgautheron/goconst v1.11.0 h1:KgN90z5qXt5f0Uzf3cWXev3hfMMFUyNeKdpkSBRvLDk= +github.com/jgautheron/goconst v1.11.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc= github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -468,8 +472,8 @@ github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRk github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.10.0 h1:Lvs/YAHP24YKg08LA8oDw2z9fJVme090RAXd90S+rrw= -github.com/kisielk/errcheck v1.10.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= +github.com/kisielk/errcheck v1.20.0 h1:9rwHBNKzd4wkDWcROy3DvFGNqEPlkxBg305rvk7HabI= +github.com/kisielk/errcheck v1.20.0/go.mod h1:O+f80MKNwX8Oor2jwgpeQ9An7uJm+hRSgT+h22knRJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= @@ -496,8 +500,8 @@ github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0 github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= -github.com/ldez/gomoddirectives v0.8.0 h1:JqIuTtgvFC2RdH1s357vrE23WJF2cpDCPFgA/TWDGpk= -github.com/ldez/gomoddirectives v0.8.0/go.mod h1:jutzamvZR4XYJLr0d5Honycp4Gy6GEg2mS9+2YX3F1Q= +github.com/ldez/gomoddirectives v0.9.0 h1:2YV/EX7nVlWL4jySusYTzBKHuE3D2fgcRsQuMa3yIoo= +github.com/ldez/gomoddirectives v0.9.0/go.mod h1:DdZzfm9MdXCjn2/UGYXCFfo+tzrp2Ib4iD2Q0kIJkwE= github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= github.com/ldez/structtags v0.6.1 h1:bUooFLbXx41tW8SvkfwfFkkjPYvFFs59AAMgVg6DUBk= @@ -508,8 +512,8 @@ github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= -github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss= +github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= @@ -538,8 +542,8 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= -github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= -github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/maxatome/go-testdeep v1.14.0 h1:rRlLv1+kI8eOI3OaBXZwb3O7xY3exRzdW5QyX48g9wI= github.com/maxatome/go-testdeep v1.14.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= @@ -593,8 +597,8 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= -github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= +github.com/nunnatsa/ginkgolinter v0.24.0 h1:Mp0EagluLFP98JatP6nqp/gGEoljNG97uf9AcxcBVy8= +github.com/nunnatsa/ginkgolinter v0.24.0/go.mod h1:2ZMRuzX6+3XXyY6UZOwb6n+MCocVGbkIsDBC4vuWz5c= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.32.0 h1:Hw7s2pVrQo/8Yz5N77qdnpHaoc+c6cC9WIV1Jce+J6E= github.com/onsi/ginkgo/v2 v2.32.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= @@ -618,8 +622,8 @@ github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= -github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY= +github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pjbgf/sha1cd v0.6.0 h1:3WJ8Wz8gvDz29quX1OcEmkAlUg9diU4GxJHqs0/XiwU= github.com/pjbgf/sha1cd v0.6.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -629,8 +633,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -661,15 +663,15 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= -github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= +github.com/raeperd/recvcheck v0.3.0 h1:PM+XYvyxIj3bo+kobJfFTdTuU3Lmfu96mKDbyHDbRt8= +github.com/raeperd/recvcheck v0.3.0/go.mod h1:PZNwG+HztFYMH2ZPq0Hu3QgkV2yiA6VrtNz9c1fXWJo= github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= +github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= @@ -685,24 +687,24 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= -github.com/securego/gosec/v2 v2.26.1 h1:gdkttGhQFVehqRJ8grKH4DrpqM/QlPKNHBnl8QgcEC4= -github.com/securego/gosec/v2 v2.26.1/go.mod h1:57UW4p0uoP3kxoTkhoo3axLdVAi+OWrLg/Ax/kdqtPE= +github.com/securego/gosec/v2 v2.28.0 h1:ZsSdiDb0AtTpLFVol5z91gbMei9ZiLEPG/pZjZujp7c= +github.com/securego/gosec/v2 v2.28.0/go.mod h1:lb4/9AHe+lJy/kjWmWRWWsEipvbwGKuxf+tY1Pmjdnk= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM= -github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/shirou/gopsutil/v4 v4.26.7 h1:IXzpHz/dkMRYAhKkOXr1HB6SuzWU3eoyyeWe7g3bNZc= +github.com/shirou/gopsutil/v4 v4.26.7/go.mod h1:5O9FjBiXoTDFatIWjZZosqj4pV0DRtLx598xGbBehzM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/sirupsen/logrus v1.10.1 h1:xi4336Zh11WpU14fXR6I67V3yaTPQYwRx2WEtHbRg4Q= +github.com/sirupsen/logrus v1.10.1/go.mod h1:vsQHnG7xzNsxk3NrwboUiWPnIC3dmbjcGPykD7+tiHk= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= @@ -745,8 +747,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= @@ -757,10 +759,10 @@ github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0 github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo= github.com/tetafro/godot v1.5.6 h1:IEkrFCwXaYHlOn4mGzGS3F3dkP6m9t0jpwqBFPIkKiA= github.com/tetafro/godot v1.5.6/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= -github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= -github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= +github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= @@ -792,8 +794,8 @@ github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSW github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.1 h1:CSJynt5txTnORn/DkhiB4mZjwPuifyASC8/6Q0I/QS4= github.com/uudashr/gocognit v1.2.1/go.mod h1:acaubQc6xYlXFEMb9nWX2dYBzJ/bIjEkc1zzvyIZg5Q= -github.com/uudashr/iface v1.4.2 h1:06Vq5RKVYThBsj0Bnw4oasMjD1r+7CE/bcKOA8dVSvg= -github.com/uudashr/iface v1.4.2/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= +github.com/uudashr/iface v1.5.0 h1:PgdMt4uAettGG8K/Kbamc4B9FABgUgnS3TLbl6fnjEk= +github.com/uudashr/iface v1.5.0/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= @@ -830,20 +832,20 @@ go-simpler.org/sloglint v0.12.0 h1:UzWDlLWNE5FLqsvyq3tWYHuQMbqrervOhT8qPl4Mmw4= go-simpler.org/sloglint v0.12.0/go.mod h1:jBjjC2bm8rYrs88oTRlFX497kWjJsyZWYoNaXkGRI6I= go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= -go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= -go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= +go.augendre.info/fatcontext v0.10.0 h1:HhFopmivh8U1+AU7f0kuwUeg2eiIns7YsGQOMHwSJ90= +go.augendre.info/fatcontext v0.10.0/go.mod h1:pqpGvA9GlrXy+aXkp8L2dKz12Zp4g2FhzcAtwToU+2w= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -865,22 +867,22 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 h1:qWFG1Dj7TBjOjOvhEOkmyGPVoquqUKnIU0lEVLp8xyk= -golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= +golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f h1:+lI8cDJ4uceLipg2f1ODay7fEuLkk0BIHXd6PB8icxo= +golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f/go.mod h1:PqrXSW65cXDZH0k4IeUbhmg/bcAZDbzNz3byBpKCsXo= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= +golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -895,8 +897,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -949,8 +951,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= 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.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= @@ -962,8 +964,8 @@ golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0t golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -993,11 +995,11 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= -honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= -mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= -mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= -mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= -mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= +honnef.co/go/tools v0.8.0 h1:UacpzPr7D6i5BAjTkA7sNVcx4kIbhAZcQ4zYtKiXx68= +honnef.co/go/tools v0.8.0/go.mod h1:XA+OnlRA9EDh/ukGvXMNSZNKGwFQJ+5dER0ioUkOxks= +mvdan.cc/gofumpt v0.11.0 h1:0H01XB95PnN2QgCSR9ELdZyTlJqNZ7181B0BTMh5VZc= +mvdan.cc/gofumpt v0.11.0/go.mod h1:BeT5wCsOJt6J9zT2MZIOGszjUHzFkn1/l9g6xAzqsXo= +mvdan.cc/unparam v0.0.0-20260818115549-3f964bcb5673 h1:dEE6li4OPIE54oojY2qaayFS1fSp17G14si0gXRxl0U= +mvdan.cc/unparam v0.0.0-20260818115549-3f964bcb5673/go.mod h1:62roFV3D3nYOWIXv3PfGO4UYEKAotz2WgLywT87ONd8= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= diff --git a/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go b/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go index e719155d..5a0e3574 100644 --- a/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go +++ b/vendor/4d63.com/gocheckcompilerdirectives/checkcompilerdirectives/checkcompilerdirectives.go @@ -86,6 +86,7 @@ var known = []string{ "cgo_unsafe_args", "debug", "embed", + "fix", "generate", "linkname", "nocheckptr", diff --git a/vendor/charm.land/lipgloss/v2/.golangci.yml b/vendor/charm.land/lipgloss/v2/.golangci.yml index c90f0316..f2e6be06 100644 --- a/vendor/charm.land/lipgloss/v2/.golangci.yml +++ b/vendor/charm.land/lipgloss/v2/.golangci.yml @@ -30,6 +30,9 @@ linters: - text: '(slog|log)\.\w+' linters: - noctx + - text: "naming" + linters: + - revive generated: lax presets: - common-false-positives diff --git a/vendor/charm.land/lipgloss/v2/canvas.go b/vendor/charm.land/lipgloss/v2/canvas.go index 396defb8..e6cc3b45 100644 --- a/vendor/charm.land/lipgloss/v2/canvas.go +++ b/vendor/charm.land/lipgloss/v2/canvas.go @@ -82,7 +82,8 @@ func (c *Canvas) Draw(scr uv.Screen, area uv.Rectangle) { c.scr.Draw(scr, area) } -// Render renders the canvas into a styled string. +// Render renders the canvas into a styled string. Any trailing spaces are +// trimmed. func (c *Canvas) Render() string { - return c.scr.Render() + return uv.TrimSpace(c.scr.Render()) } diff --git a/vendor/charm.land/lipgloss/v2/position.go b/vendor/charm.land/lipgloss/v2/position.go index cea67763..ce91442d 100644 --- a/vendor/charm.land/lipgloss/v2/position.go +++ b/vendor/charm.land/lipgloss/v2/position.go @@ -39,7 +39,7 @@ func Place(width, height int, hPos, vPos Position, str string, opts ...Whitespac // PlaceHorizontal places a string or text block horizontally in an unstyled // block of a given width. If the given width is shorter than the max width of -// the string (measured by its longest line) this will be a noop. +// the string (measured by its longest line) this will be a noöp. func PlaceHorizontal(width int, pos Position, str string, opts ...WhitespaceOption) string { lines, contentWidth := getLines(str) gap := width - contentWidth @@ -86,7 +86,7 @@ func PlaceHorizontal(width int, pos Position, str string, opts ...WhitespaceOpti // PlaceVertical places a string or text block vertically in an unstyled block // of a given height. If the given height is shorter than the height of the -// string (measured by its newlines) then this will be a noop. +// string (measured by its newlines) then this will be a noöp. func PlaceVertical(height int, pos Position, str string, opts ...WhitespaceOption) string { contentHeight := strings.Count(str, "\n") + 1 gap := height - contentHeight diff --git a/vendor/charm.land/lipgloss/v2/wrap.go b/vendor/charm.land/lipgloss/v2/wrap.go index ca0a1e23..ccffe89b 100644 --- a/vendor/charm.land/lipgloss/v2/wrap.go +++ b/vendor/charm.land/lipgloss/v2/wrap.go @@ -63,6 +63,12 @@ func (w *WrapWriter) Link() uv.Link { // Write writes to the buffer. func (w *WrapWriter) Write(p []byte) (int, error) { + if w.p == nil { + // The writer has been closed and its parser returned to the pool. + // Writing after close can happen during out-of-order teardown of + // nested writer chains; treat it as a no-op rather than panicking. + return len(p), nil + } for i := range p { b := p[i] w.p.Advance(b) diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/LICENSE b/vendor/dev.gaijin.team/go/exhaustruct/v5/LICENSE new file mode 100644 index 00000000..6698196c --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Gaijin Entertainment + +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/dev.gaijin.team/go/exhaustruct/v5/analyzer/analyzer.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/analyzer.go new file mode 100644 index 00000000..ef1bc9c5 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/analyzer.go @@ -0,0 +1,112 @@ +package analyzer + +import ( + "flag" + "sync" + + "dev.gaijin.team/go/golib/e" + "dev.gaijin.team/go/golib/fields" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + + "dev.gaijin.team/go/exhaustruct/v5/internal/astutil" + "dev.gaijin.team/go/exhaustruct/v5/internal/directive" + "dev.gaijin.team/go/exhaustruct/v5/internal/pattern" + "dev.gaijin.team/go/exhaustruct/v5/internal/structure" +) + +// NewAnalyzer returns an analyzer configured exclusively through command-line +// flags, intended for CLI drivers (singlechecker, go vet -vettool). The +// processor is built lazily on the first run, after the driver has parsed the +// flags. +func NewAnalyzer() *analysis.Analyzer { + config := &Config{} + + lazyProcessor := sync.OnceValues(func() (*structure.Processor, error) { + return newProcessor(config) + }) + + a := newBaseAnalyzer(func(pass *analysis.Pass) (any, error) { + processor, err := lazyProcessor() + if err != nil { + return nil, err + } + + run(pass, config, processor) + + return nil, nil //nolint:nilnil + }) + + a.Flags.Init("", flag.PanicOnError) + config.bindToFlagSet(&a.Flags) + + return a +} + +// NewAnalyzerWithConfig returns an analyzer configured programmatically, +// intended for library consumers such as golangci-lint. The configuration is +// copied and validated immediately; it exposes no flags, and later mutations +// of the passed Config have no effect. +func NewAnalyzerWithConfig(config Config) (*analysis.Analyzer, error) { + processor, err := newProcessor(&config) + if err != nil { + return nil, err + } + + return newBaseAnalyzer(func(pass *analysis.Pass) (any, error) { + run(pass, &config, processor) + + return nil, nil //nolint:nilnil + }), nil +} + +func newBaseAnalyzer(run func(*analysis.Pass) (any, error)) *analysis.Analyzer { + return &analysis.Analyzer{ //nolint:exhaustruct + Name: "exhaustruct", + Doc: "Checks if all structure fields are initialized", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + } +} + +func newProcessor(config *Config) (*structure.Processor, error) { + enforce, err := pattern.NewList(config.EnforcePatterns...) + if err != nil { + return nil, e.NewFrom("compile enforce patterns", err, fields.F("flag", "enforce-rx")) + } + + ignore, err := pattern.NewList(config.IgnorePatterns...) + if err != nil { + return nil, e.NewFrom("compile ignore patterns", err, fields.F("flag", "ignore-rx")) + } + + optional, err := pattern.NewList(config.OptionalPatterns...) + if err != nil { + return nil, e.NewFrom("compile optional patterns", err, fields.F("flag", "optional-rx")) + } + + allowEmpty, err := pattern.NewList(config.AllowEmptyPatterns...) + if err != nil { + return nil, e.NewFrom("compile allow-empty patterns", err, fields.F("flag", "allow-empty-rx")) + } + + fp := astutil.NewFileParser() + + return structure.NewProcessor( + directive.NewScanner(fp), + structure.NewOriginScanner(fp), + structure.WithEnforce(enforce), + structure.WithIgnore(ignore), + structure.WithOptional(optional), + structure.WithAllowEmpty(allowEmpty), + ), nil +} + +func run(pass *analysis.Pass, config *Config, processor *structure.Processor) { + for _, diag := range processor.Directives().ProcessFiles(pass.Fset, pass.Files...) { + pass.Report(diag) + } + + newMissingFieldsVisitor(pass, config, processor).run() + runTagMigration(pass) +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/config.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/config.go new file mode 100644 index 00000000..82101bc3 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/config.go @@ -0,0 +1,134 @@ +package analyzer + +import ( + "flag" + "strings" + + "dev.gaijin.team/go/exhaustruct/v5/internal/pattern" +) + +type Config struct { + // EnforcePatterns is a list of regular expressions to match type names that + // should be checked. Anonymous structs can be matched by '' alias. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + EnforcePatterns Patterns `exhaustruct:"optional"` + + // IgnorePatterns is a list of regular expressions to match type names that + // should be skipped from checking. Anonymous structs can be matched by + // '' alias. + // + // Has precedence over EnforcePatterns. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + IgnorePatterns Patterns `exhaustruct:"optional"` + + // OptionalPatterns is a list of regular expressions to match type names where + // all fields are treated as optional. Anonymous structs can be matched by + // '' alias. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + OptionalPatterns Patterns `exhaustruct:"optional"` + + // AllowEmpty allows empty structures, effectively excluding them from the check. + AllowEmpty bool `exhaustruct:"optional"` + + // AllowEmptyPatterns is a list of regular expressions to match type names that + // should be allowed to be empty. Anonymous structs can be matched by + // '' alias. + // + // Each regular expression must match the full type name, including package path. + // For example, to match type `net/http.Cookie` regular expression should be + // `.*/http\.Cookie`, but not `http\.Cookie`. + AllowEmptyPatterns Patterns `exhaustruct:"optional"` + + // AllowEmptyReturns allows empty structures in return statements. + AllowEmptyReturns bool `exhaustruct:"optional"` + + // AllowEmptyDeclarations allows empty structures in variable declarations. + AllowEmptyDeclarations bool `exhaustruct:"optional"` + + // ReportFullTypePath enables full package path in error messages instead of + // short package name. This helps when configuring include/exclude patterns, + // as import aliases can make short names ambiguous. + ReportFullTypePath bool `exhaustruct:"optional"` + + // ExplicitMode enables opt-in checking. When true, only types marked with + // //exhaustruct:enforce directive or matching enforce-rx patterns are checked. + ExplicitMode bool `exhaustruct:"optional"` +} + +// bindToFlagSet binds the config fields to the provided flag set. +func (c *Config) bindToFlagSet(fs *flag.FlagSet) { + fs.BoolVar(&c.ExplicitMode, "explicit", c.ExplicitMode, + "Enable explicit mode: only check types marked with //exhaustruct:enforce "+ + "directive or matching -enforce-rx patterns") + + fs.Var(&c.EnforcePatterns, "enforce-rx", + "Regular expression to match type names that should be checked. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + + fs.Var(&c.IgnorePatterns, "ignore-rx", + "Regular expression to skip type names from checking, has precedence over -enforce-rx. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + + fs.Var(&c.OptionalPatterns, "optional-rx", + "Regular expression to match type names where all fields are optional. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + + fs.BoolVar(&c.AllowEmpty, "allow-empty", c.AllowEmpty, + "Allow empty structures, effectively excluding them from the check") + + fs.Var(&c.AllowEmptyPatterns, "allow-empty-rx", + "Regular expression to match type names that should be allowed to be empty. "+ + "Anonymous structs can be matched by '' alias. "+ + "Each regex must match the full type name including package path. "+ + "Example: `.*/http\\.Cookie`. Can be used multiple times.") + + fs.BoolVar(&c.AllowEmptyReturns, "allow-empty-returns", c.AllowEmptyReturns, + "Allow empty structures in return statements") + + fs.BoolVar(&c.AllowEmptyDeclarations, "allow-empty-declarations", c.AllowEmptyDeclarations, + "Allow empty structures in variable declarations") + + fs.BoolVar(&c.ReportFullTypePath, "report-full-type-path", c.ReportFullTypePath, + "Report full package path in error messages (e.g., 'net/http.Cookie' instead of 'http.Cookie'). "+ + "Useful for identifying types when configuring enforce/ignore patterns.") +} + +// Patterns is a list of regular expression patterns. It implements +// flag.Value, validating each value as a regular expression at +// flag-parse time so invalid patterns fail early. +type Patterns []string + +// String returns the patterns joined with commas (flag.Value interface). +func (p *Patterns) String() string { + if p == nil { + return "" + } + + return strings.Join(*p, ",") +} + +// Set validates and appends a pattern (flag.Value interface). +func (p *Patterns) Set(value string) error { + if _, err := pattern.NewList(value); err != nil { + return err //nolint:wrapcheck + } + + *p = append(*p, value) + + return nil +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/missing-fields-visitor.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/missing-fields-visitor.go new file mode 100644 index 00000000..558d8092 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/missing-fields-visitor.go @@ -0,0 +1,381 @@ +package analyzer + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "slices" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + + "dev.gaijin.team/go/exhaustruct/v5/internal/directive" + "dev.gaijin.team/go/exhaustruct/v5/internal/structure" +) + +// missingFieldsVisitor checks struct literals for missing field initializations. +type missingFieldsVisitor struct { + pass *analysis.Pass + config *Config + processor *structure.Processor +} + +func newMissingFieldsVisitor( + pass *analysis.Pass, + config *Config, + processor *structure.Processor, +) *missingFieldsVisitor { + return &missingFieldsVisitor{ + pass: pass, + config: config, + processor: processor, + } +} + +func (v *missingFieldsVisitor) run() { + insp := v.pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert + + insp.WithStack([]ast.Node{(*ast.CompositeLit)(nil)}, v.visit) +} + +func (v *missingFieldsVisitor) visit(n ast.Node, push bool, stack []ast.Node) bool { + if !push { + return true + } + + lit, ok := n.(*ast.CompositeLit) + if !ok { + return true + } + + lv := literalVisitor{missingFieldsVisitor: v, lit: lit, stack: stack} + lv.process() + + return true +} + +// literalVisitor carries context for processing a single composite literal. +type literalVisitor struct { + *missingFieldsVisitor + + lit *ast.CompositeLit + stack []ast.Node +} + +// literal holds resolved info for a struct literal being checked. +type literal struct { + strct *structure.Struct + ignored bool + enforced bool +} + +// shouldCheck implements checking decision priority. +func (l literal) shouldCheck(explicitMode bool) bool { + if l.ignored { + return false + } + + if l.enforced { + return true + } + + if l.strct.IsIgnored() { + return false + } + + if l.strct.IsEnforced() { + return true + } + + return !explicitMode +} + +func (lv literalVisitor) process() { + lit, ok := lv.resolveLiteral() + if !ok { + return + } + + if len(lv.lit.Elts) == 0 && lv.checkEmptyAllowed(lit.strct) { + return + } + + if pos, msg := lv.checkLiteral(lit); pos != nil { + lv.pass.Reportf(*pos, "%s", msg) + } +} + +// resolveLiteral extracts struct type information from the composite literal, +// retrieves cached metadata, and looks up directives. +func (lv literalVisitor) resolveLiteral() (lit literal, ok bool) { + typeName, strct, pos := lv.resolveLiteralType() + if strct == nil { + return literal{}, false //nolint:exhaustruct + } + + s, diags := lv.processor.ResolveStruct( + lv.pass.Fset, typeName, strct, pos, lv.pass.Pkg, + ) + + for _, diag := range diags { + lv.pass.Report(diag) + } + + if s == nil { + return literal{}, false //nolint:exhaustruct + } + + litPos := lv.pass.Fset.Position(lv.lit.Pos()) + dirs, dirDiags := lv.processor.Directives().Lookup(lv.pass.Fset, litPos) + + for _, d := range dirDiags { + lv.pass.Report(d) + } + + return literal{ + strct: s, + ignored: dirs.Contains(directive.Ignore), + enforced: dirs.Contains(directive.Enforce), + }, true +} + +// resolveLiteralType resolves the composite literal's type and definition position. +func (lv literalVisitor) resolveLiteralType() (name *types.TypeName, strct *types.Struct, pos token.Pos) { + typ := lv.pass.TypesInfo.TypeOf(lv.lit) + + if ptr, ok := typ.(*types.Pointer); ok { + typ = ptr.Elem() + } + + switch t := typ.(type) { + case *types.Alias: + name = t.Obj() + case *types.Named: + name = t.Obj() + } + + typ = types.Unalias(typ) + + switch t := typ.(type) { + case *types.Named: + var ok bool + + if strct, ok = t.Underlying().(*types.Struct); !ok { + return nil, nil, token.NoPos + } + + pos = name.Pos() + + return name, strct, pos + + case *types.Struct: + pos = lv.findAnonymousStructPos() + + return name, t, pos + + default: + return nil, nil, token.NoPos + } +} + +// findAnonymousStructPos finds the position of the struct keyword for anonymous structs. +func (lv literalVisitor) findAnonymousStructPos() token.Pos { + if lv.lit.Type != nil { + if st, ok := lv.lit.Type.(*ast.StructType); ok { + return st.Struct + } + + return token.NoPos + } + + for i := len(lv.stack) - 2; i >= 0; i-- { //nolint:mnd + switch parent := lv.stack[i].(type) { + case *ast.KeyValueExpr: + continue + + case *ast.CompositeLit: + return structPosFromType(parent.Type) + + default: + return token.NoPos + } + } + + return token.NoPos +} + +func structPosFromType(typ ast.Expr) token.Pos { + if typ == nil { + return token.NoPos + } + + switch t := typ.(type) { + case *ast.ArrayType: + return structPosFromExpr(t.Elt) + + case *ast.MapType: + return structPosFromExpr(t.Value) + } + + return token.NoPos +} + +func structPosFromExpr(expr ast.Expr) token.Pos { + if star, ok := expr.(*ast.StarExpr); ok { + expr = star.X + } + + if st, ok := expr.(*ast.StructType); ok { + return st.Struct + } + + return token.NoPos +} + +func (lv literalVisitor) checkEmptyAllowed(s *structure.Struct) bool { + if lv.config.AllowEmpty { + return true + } + + if s.AllowEmptyDecl { + return true + } + + if ret, ok := lv.getParentReturnStmt(); ok { + if lv.config.AllowEmptyReturns { + return true + } + + if lv.isErrorReturnStatement(ret) { + return true + } + } + + if lv.isChildOfVariableDeclaration() && lv.config.AllowEmptyDeclarations { + return true + } + + return false +} + +func (lv literalVisitor) checkLiteral(lit literal) (*token.Pos, string) { + if !lit.shouldCheck(lv.config.ExplicitMode) { + return nil, "" + } + + strct := lit.strct + + missingFields := strct.SkippedFields(lv.lit, lv.pass.Pkg.Path()) + + if len(missingFields) == 0 { + return nil, "" + } + + pos := lv.lit.Pos() + + displayName := strct.PackageName + "." + strct.Name + if lv.config.ReportFullTypePath { + displayName = strct.FullPath + } + + if len(missingFields) == 1 { + return &pos, fmt.Sprintf("%s is missing field %s", displayName, structure.FormatFieldNames(missingFields)) + } + + return &pos, fmt.Sprintf("%s is missing fields %s", displayName, structure.FormatFieldNames(missingFields)) +} + +func (lv literalVisitor) isChildOfVariableDeclaration() bool { + if len(lv.stack) < 2 { //nolint:mnd + return false + } + + for i := len(lv.stack) - 1; i > 0; i-- { + parent := lv.stack[i-1] + + switch p := parent.(type) { + case *ast.AssignStmt: + if p.Tok == token.DEFINE { + return true + } + + case *ast.ValueSpec: + return true + + case *ast.UnaryExpr: + if p.Op == token.AND { + continue + } + + return false + + default: + return false + } + } + + return false +} + +func (lv literalVisitor) getParentReturnStmt() (*ast.ReturnStmt, bool) { + if len(lv.stack) < 2 { //nolint:mnd + return nil, false + } + + for i := len(lv.stack) - 1; i > 0; i-- { + parent := lv.stack[i-1] + + switch p := parent.(type) { + case *ast.ReturnStmt: + return p, true + + case *ast.UnaryExpr: + if p.Op == token.AND { + continue + } + + return nil, false + + default: + return nil, false + } + } + + return nil, false +} + +//nolint:forcetypeassert,gochecknoglobals +var builtinErrorInterface = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + +func (lv literalVisitor) isErrorReturnStatement(n *ast.ReturnStmt) bool { + if len(n.Results) == 0 { + return false + } + + for _, ri := range slices.Backward(n.Results) { + if ri == lv.lit { + continue + } + + switch ri := ri.(type) { + case *ast.Ident: + if ri.Name == "nil" { + continue + } + + case *ast.UnaryExpr: + if ri.X == lv.lit { + continue + } + } + + resultType := lv.pass.TypesInfo.TypeOf(ri) + if resultType != nil && types.Implements(resultType, builtinErrorInterface) { + return true + } + } + + return false +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/tag-migration-visitor.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/tag-migration-visitor.go new file mode 100644 index 00000000..7e75b668 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/analyzer/tag-migration-visitor.go @@ -0,0 +1,111 @@ +package analyzer + +import ( + "go/ast" + "reflect" + "regexp" + "strings" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" +) + +// runTagMigration scans struct definitions for deprecated exhaustruct tags +// and emits migration diagnostics with suggested fixes, using inspector to +// traverse StructType nodes efficiently. +func runTagMigration(pass *analysis.Pass) { + insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert + + insp.Preorder([]ast.Node{new(ast.StructType)}, func(n ast.Node) { + visitStructType(pass, n) + }) +} + +func visitStructType(pass *analysis.Pass, n ast.Node) { + st, ok := n.(*ast.StructType) + if !ok { + return + } + + if st.Fields == nil { + return + } + + for _, field := range st.Fields.List { + if field.Tag == nil { + continue + } + + value, ok := parseExhaustructTag(field.Tag.Value) + if !ok { + continue + } + + pass.Report(buildTagDiagnostic(field, value)) + } +} + +const exhaustructTagKey = "exhaustruct" + +// parseExhaustructTag extracts value from `exhaustruct:"value"` tag. +// Returns ("", false) if tag not present. +func parseExhaustructTag(tagLiteral string) (string, bool) { + if len(tagLiteral) < 2 { //nolint:mnd + return "", false + } + + // Strip backticks + inner := tagLiteral[1 : len(tagLiteral)-1] + + return reflect.StructTag(inner).Lookup(exhaustructTagKey) +} + +func buildTagDiagnostic(field *ast.Field, tagValue string) analysis.Diagnostic { + return analysis.Diagnostic{ + Pos: field.Tag.Pos(), + Message: `struct tag "exhaustruct" is not supported anymore, use comment directives`, + SuggestedFixes: []analysis.SuggestedFix{buildTagFix(field, tagValue)}, + } +} + +func buildTagFix(field *ast.Field, tagValue string) analysis.SuggestedFix { + tag := field.Tag + newTag := removeExhaustructFromTag(tag.Value) + + if tagValue == "optional" { + if newTag != "" { + newTag += " " + } + + newTag += "//exhaustruct:optional" + } + + // Calculate start position (include leading space if removing entirely) + startPos := tag.Pos() + if newTag == "" { + startPos = field.Type.End() + } + + return analysis.SuggestedFix{ + Message: "fix", + TextEdits: []analysis.TextEdit{{ + Pos: startPos, + End: tag.End(), + NewText: []byte(newTag), + }}, + } +} + +var exhaustructTagPattern = regexp.MustCompile(`\s*exhaustruct:"[^"]*"`) + +func removeExhaustructFromTag(tagLiteral string) string { + tagLiteral = tagLiteral[1 : len(tagLiteral)-1] + tagLiteral = strings.TrimSpace(exhaustructTagPattern.ReplaceAllString(tagLiteral, "")) + + if tagLiteral == "" { + return "" + } + + return "`" + tagLiteral + "`" +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/astutil/file-parser.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/astutil/file-parser.go new file mode 100644 index 00000000..dc437fb2 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/astutil/file-parser.go @@ -0,0 +1,213 @@ +// Package astutil provides AST file parsing utilities for the analyzer. +package astutil + +import ( + "go/ast" + "go/build" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" + "sync" + "sync/atomic" + + "dev.gaijin.team/go/golib/e" + "dev.gaijin.team/go/golib/fields" + "golang.org/x/tools/go/analysis" +) + +type ParseCallback func(fset *token.FileSet, file *ast.File) []analysis.Diagnostic + +// FileParser orchestrates AST parsing by triggering registered callbacks. +// Each file is processed only once. +// +// Safe for concurrent use. +type FileParser struct { + mu sync.RWMutex `exhaustruct:"optional"` + parsed map[string]bool + callbacks []ParseCallback `exhaustruct:"optional"` + parseFlags parser.Mode `exhaustruct:"optional"` + hits atomic.Uint64 `exhaustruct:"optional"` + misses atomic.Uint64 `exhaustruct:"optional"` +} + +type Option func(*FileParser) + +// WithParseFlags sets parser flags for file parsing. +// Default: parser.ParseComments | parser.SkipObjectResolution. +func WithParseFlags(flags parser.Mode) Option { + return func(p *FileParser) { p.parseFlags = flags } +} + +const parsedCachePrealloc = 64 + +func NewFileParser(opts ...Option) *FileParser { + p := &FileParser{ + parsed: make(map[string]bool, parsedCachePrealloc), + parseFlags: parser.ParseComments | parser.SkipObjectResolution, + } + + for _, opt := range opts { + opt(p) + } + + return p +} + +func (p *FileParser) OnFileParsed(cb ParseCallback) { + p.callbacks = append(p.callbacks, cb) +} + +// ProcessFiles triggers all callbacks for each provided AST file. +// Already-parsed files are skipped. +func (p *FileParser) ProcessFiles(fset *token.FileSet, files ...*ast.File) []analysis.Diagnostic { + var allDiags []analysis.Diagnostic + + for _, file := range files { + filename := fset.Position(file.Pos()).Filename + + p.mu.RLock() + + alreadyParsed := p.parsed[filename] + p.mu.RUnlock() + + if alreadyParsed { + p.hits.Add(1) + + continue + } + + p.mu.Lock() + + if p.parsed[filename] { + p.mu.Unlock() + p.hits.Add(1) + + continue + } + + p.misses.Add(1) + + for _, cb := range p.callbacks { + allDiags = append(allDiags, cb(fset, file)...) + } + + p.parsed[filename] = true + p.mu.Unlock() + } + + return allDiags +} + +// ProcessFilename parses a file from disk and triggers all callbacks. +// Returns nil if already processed or if the file belongs to the Go +// distribution. +func (p *FileParser) ProcessFilename(fset *token.FileSet, filename string) []analysis.Diagnostic { + if isGoRootFile(filename) { + return nil + } + + p.mu.RLock() + + alreadyParsed := p.parsed[filename] + p.mu.RUnlock() + + if alreadyParsed { + p.hits.Add(1) + + return nil + } + + p.mu.Lock() + defer p.mu.Unlock() + + if p.parsed[filename] { + p.hits.Add(1) + + return nil + } + + p.misses.Add(1) + + file, err := p.parse(fset, filename) + if err != nil { + p.parsed[filename] = true + + return []analysis.Diagnostic{{ + Pos: token.NoPos, + Message: err.Error(), + }} + } + + var allDiags []analysis.Diagnostic + + for _, cb := range p.callbacks { + allDiags = append(allDiags, cb(fset, file)...) + } + + p.parsed[filename] = true + + return allDiags +} + +func (p *FileParser) Stats() (hits, misses, size uint64) { + p.mu.RLock() + + size = uint64(len(p.parsed)) + + p.mu.RUnlock() + + return p.hits.Load(), p.misses.Load(), size +} + +// goRootPlaceholder is the literal prefix the compiler records instead of the +// real GOROOT for files of the Go distribution, see cmd/internal/objabi.AbsFile. +// Positions loaded from export data carry it as-is, so such paths can never be +// opened. +const goRootPlaceholder = "$GOROOT" + +// isGoRootFile reports whether filename belongs to the Go distribution. Its +// sources carry no exhaustruct directives, so parsing them yields nothing and +// their definitions are treated as directive-free. +func isGoRootFile(filename string) bool { + return hasPathPrefix(filename, goRootPlaceholder) || + hasPathPrefix(filename, build.Default.GOROOT) +} + +// hasPathPrefix reports whether path starts with prefix at a path element +// boundary. Separators are normalized, since the compiler records slashes on +// every platform while GOROOT uses the native separator. An empty prefix, as +// an unset or root GOROOT normalizes to, matches nothing rather than +// everything. +func hasPathPrefix(path, prefix string) bool { + prefix = strings.TrimSuffix(filepath.ToSlash(prefix), "/") + if prefix == "" { + return false + } + + path = filepath.ToSlash(path) + + if !strings.HasPrefix(path, prefix) { + return false + } + + rest := path[len(prefix):] + + return rest == "" || rest[0] == '/' +} + +func (p *FileParser) parse(fset *token.FileSet, filename string) (*ast.File, error) { + //nolint:gosec // filename is derived from source code, not user input + content, err := os.ReadFile(filename) + if err != nil { + return nil, e.NewFrom("read file", err, fields.F("filename", filename)) + } + + file, err := parser.ParseFile(fset, filename, content, p.parseFlags) + if err != nil { + return nil, e.NewFrom("parse file", err, fields.F("filename", filename)) + } + + return file, nil +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/cache/cache.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/cache/cache.go new file mode 100644 index 00000000..c480c6b3 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/cache/cache.go @@ -0,0 +1,100 @@ +// Package cache provides a generic thread-safe cache with hit/miss tracking. +package cache + +import ( + "sync" + "sync/atomic" +) + +type Cache[K comparable, V any] struct { + entries map[K]V + mu sync.RWMutex `exhaustruct:"optional"` + hits atomic.Uint64 `exhaustruct:"optional"` + misses atomic.Uint64 `exhaustruct:"optional"` +} + +func New[K comparable, V any](initialCapacity int) *Cache[K, V] { + return &Cache[K, V]{ + entries: make(map[K]V, initialCapacity), + } +} + +func (c *Cache[K, V]) Get(key K) (v V, ok bool) { + c.mu.RLock() + + v, ok = c.entries[key] + + c.mu.RUnlock() + + if ok { + c.hits.Add(1) + } + + return v, ok +} + +// Peek returns the value without updating hit/miss counters. Use it when the +// caller has already recorded the miss that triggered the fill and a follow-up +// read for the just-written entry must not inflate the hit rate. +func (c *Cache[K, V]) Peek(key K) (v V, ok bool) { + c.mu.RLock() + + v, ok = c.entries[key] + + c.mu.RUnlock() + + return v, ok +} + +// Set stores value and increments miss counter (caller computed the value). +func (c *Cache[K, V]) Set(key K, value V) { + c.mu.Lock() + + c.entries[key] = value + c.misses.Add(1) + + c.mu.Unlock() +} + +// GetOrSet uses double-check locking to avoid computing values that are +// cached between the initial read check and acquiring the write lock. +func (c *Cache[K, V]) GetOrSet(key K, compute func() V) V { + c.mu.RLock() + + if v, ok := c.entries[key]; ok { + c.mu.RUnlock() + c.hits.Add(1) + + return v + } + + c.mu.RUnlock() + + c.mu.Lock() + defer c.mu.Unlock() + + // Double-check after acquiring write lock. + if v, ok := c.entries[key]; ok { + c.hits.Add(1) + + return v + } + + c.misses.Add(1) + + v := compute() + + c.entries[key] = v + + return v +} + +func (c *Cache[K, V]) Stats() (hits, misses, size uint64) { + c.mu.RLock() + + size = uint64(len(c.entries)) + + c.mu.RUnlock() + + return c.hits.Load(), c.misses.Load(), size +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/directive.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/directive.go new file mode 100644 index 00000000..aa7f8d90 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/directive.go @@ -0,0 +1,95 @@ +package directive + +import ( + "slices" + "strings" + + "dev.gaijin.team/go/golib/e" +) + +var ( + ErrEmptyDirective = e.New("empty directive") + ErrUnknownDirective = e.New("unknown directive") + ErrDuplicateDirectives = e.New("duplicate directives") +) + +type Directive string + +const ( + // Ignore skips checking for a specific struct literal. + Ignore Directive = "ignore" + // Enforce forces check even if type is excluded. + Enforce Directive = "enforce" + // Optional marks a field as optional. + Optional Directive = "optional" +) + +func (d Directive) IsValid() bool { + switch d { + case Ignore, Enforce, Optional: + return true + + default: + return false + } +} + +// Directives represents a collection of directives for a single line. +// Multiple directives can be specified comma-separated: //exhaustruct:enforce,optional. +type Directives []Directive + +func (ds Directives) Contains(d Directive) bool { + return slices.Contains(ds, d) +} + +// directivePrefix is the exact prefix for exhaustruct directives. +// Format: //exhaustruct: [optional comment]. +const directivePrefix = "//exhaustruct:" + +func Parse(text string) (found bool, result Directives, errs []error) { + text, found = strings.CutPrefix(text, directivePrefix) + if !found { + return false, nil, nil + } + + if idx := strings.IndexAny(text, " \t\n"); idx > 0 { + text = text[:idx] + } + + if text == "" { + return true, nil, []error{ErrEmptyDirective} + } + + parts := strings.Split(text, ",") + + result = make(Directives, 0, len(parts)) + + var hasDups bool + + for _, part := range parts { + d := Directive(part) + + if !d.IsValid() { + errs = append(errs, ErrUnknownDirective.WithField("directive", d)) + continue + } + + // giving the resulting size, linear search would be most efficient + if slices.Contains(result, d) { + hasDups = true + continue + } + + result = append(result, d) + } + + if hasDups { + errs = append(errs, ErrDuplicateDirectives) + } + + if len(result) == 0 { + result = nil + } + + return true, result, errs +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/scanner.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/scanner.go new file mode 100644 index 00000000..0de61ad5 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/directive/scanner.go @@ -0,0 +1,189 @@ +package directive + +import ( + "go/ast" + "go/token" + + "golang.org/x/tools/go/analysis" + + "dev.gaijin.team/go/exhaustruct/v5/internal/astutil" + "dev.gaijin.team/go/exhaustruct/v5/internal/cache" +) + +// Scanner provides thread-safe caching and lookup of file directives. +type Scanner struct { + parser *astutil.FileParser + cache *cache.Cache[string, fileDirectives] +} + +const cachePreallocSize = 64 + +// NewScanner creates a new directive scanner that registers a callback +// with the file parser to extract directives from parsed files. +func NewScanner(parser *astutil.FileParser) *Scanner { + s := &Scanner{ + parser: parser, + cache: cache.New[string, fileDirectives](cachePreallocSize), + } + + parser.OnFileParsed(s.onFileParsed) + + return s +} + +func (s *Scanner) onFileParsed(fset *token.FileSet, file *ast.File) []analysis.Diagnostic { + filename := fset.Position(file.Pos()).Filename + + fd, diags := s.parseFileDirectives(fset, file) + + s.cache.Set(filename, fd) + + return diags +} + +// ProcessFiles pre-populates the cache by delegating to FileParser.ProcessFiles. +// Returns diagnostics from directive parsing. +func (s *Scanner) ProcessFiles(fset *token.FileSet, files ...*ast.File) []analysis.Diagnostic { + return s.parser.ProcessFiles(fset, files...) +} + +// Lookup returns the directives at the given source position. +// If the file is not in cache, triggers FileParser.ProcessFilename to parse it. +func (s *Scanner) Lookup(fset *token.FileSet, pos token.Position) (Directives, []analysis.Diagnostic) { + if pos.Filename == "" { + return nil, nil + } + + if fd, ok := s.cache.Get(pos.Filename); ok { + return fd[pos.Line], nil + } + + // Cache miss - parse file (triggers onFileParsed callback, which stores + // the result via cache.Set and increments the miss counter). + diags := s.parser.ProcessFilename(fset, pos.Filename) + + // Peek avoids counting this self-induced read as a hit — the miss was + // already recorded by Set above. + if fd, ok := s.cache.Peek(pos.Filename); ok { + return fd[pos.Line], diags + } + + // Still not in cache means parsing failed. + return nil, diags +} + +func (s *Scanner) Stats() (hits, misses, size uint64) { + return s.cache.Stats() +} + +// fileDirectives holds directives found in a single file, indexed by line number. +type fileDirectives map[int]Directives + +// parseFileDirectives parses an AST file and extracts all exhaustruct directives. +// Returns diagnostics in case file parsing errors, directive parsing errors, or +// conflicting directives for the same target line. +func (*Scanner) parseFileDirectives(fset *token.FileSet, file *ast.File) (fileDirectives, []analysis.Diagnostic) { + directives, diagnostics := parseCommentDirectives(fset, file.Comments) + + if len(directives) == 0 { + return nil, diagnostics + } + + ast.Inspect(file, func(n ast.Node) bool { + switch n.(type) { + case nil, *ast.Comment, *ast.CommentGroup: + return false + } + + line := fset.Position(n.Pos()).Line + if d, ok := directives[line]; ok { + d.targetLine = line + directives[line] = d + } + + return true + }) + + result := make(fileDirectives, len(directives)) + + for line, d := range directives { + _, exists := result[d.targetLine] + if !exists { + result[d.targetLine] = d.directives + continue + } + + pos := d.pos + + // directives from block comments win over inline comments + if line != d.targetLine { + result[d.targetLine] = d.directives + pos = directives[d.targetLine].pos + } + + diagnostics = append(diagnostics, analysis.Diagnostic{ + Pos: pos, + Message: "directive ignored, conflicting directive already exists for the same target line", + }) + } + + return result, diagnostics +} + +type parsedDirective struct { + pos token.Pos + targetLine int + directives Directives +} + +func parseCommentDirectives( + fset *token.FileSet, + comments []*ast.CommentGroup, +) (map[int]parsedDirective, []analysis.Diagnostic) { + var ( + directives = make(map[int]parsedDirective) + diagnostics []analysis.Diagnostic + ) + + for _, cg := range comments { + hasDirective := false + + for _, comment := range cg.List { + found, parsed, errs := Parse(comment.Text) + if !found { + continue + } + + pos := comment.Pos() + + for _, err := range errs { + diagnostics = append(diagnostics, analysis.Diagnostic{ + Pos: pos, + Message: err.Error(), + }) + } + + if len(parsed) == 0 { + continue + } + + if hasDirective { + diagnostics = append(diagnostics, analysis.Diagnostic{ + Pos: pos, + Message: "multiple exhaustruct directives in a single comment group, ignoring", + }) + + continue + } + + hasDirective = true + directives[fset.Position(pos).Line] = parsedDirective{ + pos: pos, + targetLine: fset.Position(cg.End()).Line + 1, + directives: parsed, + } + } + } + + return directives, diagnostics +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/pattern/list.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/pattern/list.go new file mode 100644 index 00000000..c715839f --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/pattern/list.go @@ -0,0 +1,63 @@ +package pattern + +import ( + "regexp" + + "dev.gaijin.team/go/golib/e" + "dev.gaijin.team/go/golib/fields" +) + +// List is a collection of compiled regular expressions. +type List []*regexp.Regexp + +// NewList compiles patterns into a List. +// Returns error if any pattern is empty or invalid. +func NewList(patterns ...string) (List, error) { + if len(patterns) == 0 { + return nil, nil + } + + list := make(List, 0, len(patterns)) + + for _, pattern := range patterns { + re, err := compilePattern(pattern) + if err != nil { + return nil, err + } + + list = append(list, re) + } + + return list, nil +} + +// MatchFullString returns true if any regex matches the entire string. +// Pattern "test" matches "test" but not "testing" or "contest". +func (l List) MatchFullString(target string) bool { + if len(l) == 0 { + return false + } + + for i := range len(l) { + // A match spanning [0, len(target)) covers every byte of target, so the + // matched substring is target itself — no need to allocate it for comparison. + if loc := l[i].FindStringIndex(target); loc != nil && loc[0] == 0 && loc[1] == len(target) { + return true + } + } + + return false +} + +func compilePattern(pattern string) (*regexp.Regexp, error) { + if pattern == "" { + return nil, e.New("empty regular expression is not allowed") + } + + re, err := regexp.Compile(pattern) + if err != nil { + return nil, e.NewFrom("compile regular expression", err, fields.F("pattern", pattern)) + } + + return re, nil +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/origin-scanner.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/origin-scanner.go new file mode 100644 index 00000000..4f8c774d --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/origin-scanner.go @@ -0,0 +1,121 @@ +package structure + +import ( + "go/ast" + "go/token" + + "golang.org/x/tools/go/analysis" + + "dev.gaijin.team/go/exhaustruct/v5/internal/astutil" + "dev.gaijin.team/go/exhaustruct/v5/internal/cache" +) + +type TypeOrigin uint8 + +const ( + OriginUnknown TypeOrigin = iota + OriginStruct + OriginAlias + OriginDerived +) + +type fileOrigins map[string]TypeOrigin + +// OriginScanner extracts type origin information from AST files. +// Registers with FileParser to process files as they are parsed. +// Thread-safe. +type OriginScanner struct { + parser *astutil.FileParser + cache *cache.Cache[string, fileOrigins] +} + +const originCachePrealloc = 64 + +func NewOriginScanner(parser *astutil.FileParser) *OriginScanner { + o := &OriginScanner{ + parser: parser, + cache: cache.New[string, fileOrigins](originCachePrealloc), + } + + parser.OnFileParsed(o.onFileParsed) + + return o +} + +func (o *OriginScanner) onFileParsed( + fset *token.FileSet, + file *ast.File, +) []analysis.Diagnostic { + filename := fset.Position(file.Pos()).Filename + + origins := extractTypeOrigins(file) + + o.cache.Set(filename, origins) + + return nil +} + +// Lookup returns the type origin for a named type in the given file. +// Triggers on-demand parsing if file is not cached. +func (o *OriginScanner) Lookup( + fset *token.FileSet, + filename string, + typeName string, +) TypeOrigin { + if filename == "" || typeName == "" { + return OriginUnknown + } + + if origins, ok := o.cache.Get(filename); ok { + return origins[typeName] + } + + // Cache miss - parse file (onFileParsed stores the result via cache.Set + // and records the miss). Peek avoids inflating the hit rate by re-reading + // the entry we just wrote. + o.parser.ProcessFilename(fset, filename) + + if origins, ok := o.cache.Peek(filename); ok { + return origins[typeName] + } + + return OriginUnknown +} + +func (o *OriginScanner) Stats() (hits, misses, size uint64) { + return o.cache.Stats() +} + +func extractTypeOrigins(file *ast.File) fileOrigins { + origins := make(fileOrigins) + + for _, decl := range file.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok || gd.Tok != token.TYPE { + continue + } + + for _, spec := range gd.Specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + + origins[ts.Name.Name] = classifyTypeSpec(ts) + } + } + + return origins +} + +func classifyTypeSpec(ts *ast.TypeSpec) TypeOrigin { + if ts.Assign != token.NoPos { + return OriginAlias + } + + if _, isStruct := ts.Type.(*ast.StructType); isStruct { + return OriginStruct + } + + return OriginDerived +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/processor.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/processor.go new file mode 100644 index 00000000..1c63030e --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/processor.go @@ -0,0 +1,254 @@ +package structure + +import ( + "go/token" + "go/types" + + "golang.org/x/tools/go/analysis" + + "dev.gaijin.team/go/exhaustruct/v5/internal/cache" + "dev.gaijin.team/go/exhaustruct/v5/internal/directive" + "dev.gaijin.team/go/exhaustruct/v5/internal/pattern" +) + +type Processor struct { + directives *directive.Scanner + origins *OriginScanner + fieldsCache *cache.Cache[*types.Struct, structFields] + structCache *cache.Cache[token.Position, *Struct] + + enforce pattern.List `exhaustruct:"optional"` + ignore pattern.List `exhaustruct:"optional"` + optional pattern.List `exhaustruct:"optional"` + allowEmpty pattern.List `exhaustruct:"optional"` +} + +type Option func(*Processor) + +func WithEnforce(patterns pattern.List) Option { + return func(p *Processor) { p.enforce = patterns } +} + +func WithIgnore(patterns pattern.List) Option { + return func(p *Processor) { p.ignore = patterns } +} + +func WithOptional(patterns pattern.List) Option { + return func(p *Processor) { p.optional = patterns } +} + +func WithAllowEmpty(patterns pattern.List) Option { + return func(p *Processor) { p.allowEmpty = patterns } +} + +const cachePreallocSize = 64 + +func NewProcessor(directives *directive.Scanner, origins *OriginScanner, opts ...Option) *Processor { + p := &Processor{ + directives: directives, + origins: origins, + fieldsCache: cache.New[*types.Struct, structFields](cachePreallocSize), + structCache: cache.New[token.Position, *Struct](cachePreallocSize), + } + + for _, opt := range opts { + opt(p) + } + + return p +} + +// Directives returns the directive scanner the processor was constructed +// with, shared so callers can resolve use-site directives against the same +// cache. +func (p *Processor) Directives() *directive.Scanner { + return p.directives +} + +// ResolveStruct returns Struct metadata for the given type. +// Type resolution (pointers, aliases) is done by the caller. +// +// Parameters: +// - typeName: the type's TypeName, or nil for anonymous structs +// - strct: the underlying struct type (required) +// - pos: position of type definition (from analyzer's AST inspection) +// - callerPkg: package context, used for anonymous struct path +func (p *Processor) ResolveStruct( + fset *token.FileSet, + typeName *types.TypeName, + strct *types.Struct, + pos token.Pos, + callerPkg *types.Package, +) (*Struct, []analysis.Diagnostic) { + if strct == nil { + return nil, nil + } + + position := fset.Position(pos) + + // Check cache before allocating + if position.IsValid() { + if cached, ok := p.structCache.Get(position); ok { + return cached, nil + } + } + + s := p.buildStruct(typeName, position, callerPkg) + + diags := p.populateFields(fset, s, strct) + p.resolveStructOrigin(fset, s) + + diags = append(diags, p.resolveStructDirectives(fset, s)...) + p.matchStructPatterns(s) + + if s.Position.IsValid() { + p.structCache.Set(s.Position, s) + } + + return s, diags +} + +// buildStruct creates Struct metadata from type info. +func (*Processor) buildStruct(typeName *types.TypeName, pos token.Position, callerPkg *types.Package) *Struct { + if typeName != nil { + pkg := typeName.Pkg() + + return &Struct{ + Name: typeName.Name(), + FullPath: pkg.Path() + "." + typeName.Name(), + PackageName: pkg.Name(), + Position: pos, + } + } + + // Anonymous struct + return &Struct{ + Name: AnonymousName, + FullPath: callerPkg.Path() + "." + AnonymousName, + PackageName: callerPkg.Name(), + Position: pos, + } +} + +func (p *Processor) getStructFields(fset *token.FileSet, strct *types.Struct) (structFields, []analysis.Diagnostic) { + if fields, ok := p.fieldsCache.Get(strct); ok { + return fields, nil + } + + fields, diags := p.resolveStructFields(fset, strct) + + p.fieldsCache.Set(strct, fields) + + return fields, diags +} + +func (p *Processor) resolveStructFields( + fset *token.FileSet, + strct *types.Struct, +) (structFields, []analysis.Diagnostic) { + result := structFields{ + packagePath: "", + fields: make([]fieldInfo, 0, strct.NumFields()), + } + + var diags []analysis.Diagnostic + + for f := range strct.Fields() { + if result.packagePath == "" && f.Pkg() != nil { + result.packagePath = f.Pkg().Path() + } + + field := fieldInfo{ + name: f.Name(), + exported: f.Exported(), + } + + if p.directives != nil { + fieldPos := fset.Position(f.Pos()) + dirs, d := p.directives.Lookup(fset, fieldPos) + + diags = append(diags, d...) + + field.enforced = dirs.Contains(directive.Enforce) + field.optional = dirs.Contains(directive.Optional) + } + + result.fields = append(result.fields, field) + } + + return result, diags +} + +func (p *Processor) populateFields(fset *token.FileSet, s *Struct, strct *types.Struct) []analysis.Diagnostic { + resolved, diags := p.getStructFields(fset, strct) + + // Fields are external when declared in a different package than the struct type. + // This happens for derived types and aliases from external packages. + // + // Rationale behind that filtering is that noone except package that has declared + // the struct can access unexported fields, therefore we can simply filter them + // out to save up on storage. Usage of derived type from the package of structure + // definition is simply impossible since it will cause import cycle - thus, such + // filtering is safe. + fieldsExternal := resolved.packagePath != s.PackagePath() + + s.Fields = Fields{ + PackagePath: resolved.packagePath, + Items: make([]Field, 0, len(resolved.fields)), + } + + for _, sf := range resolved.fields { + if fieldsExternal && !sf.exported { + continue + } + + fieldPath := s.FullPath + "#" + sf.name + + s.Fields.Items = append(s.Fields.Items, Field{ + Name: sf.name, + Exported: sf.exported, + Enforced: sf.enforced, + Optional: sf.optional, + PatternEnforced: p.enforce.MatchFullString(fieldPath), + PatternOptional: p.optional.MatchFullString(fieldPath), + }) + } + + return diags +} + +func (p *Processor) resolveStructOrigin(fset *token.FileSet, s *Struct) { + if !s.Position.IsValid() || s.Name == AnonymousName { + return + } + + origin := p.origins.Lookup(fset, s.Position.Filename, s.Name) + + s.IsAlias = origin == OriginAlias + s.IsDerived = origin == OriginDerived +} + +func (p *Processor) resolveStructDirectives(fset *token.FileSet, s *Struct) []analysis.Diagnostic { + if p.directives == nil || !s.Position.IsValid() { + return nil + } + + dirs, diags := p.directives.Lookup(fset, s.Position) + + s.Enforced = dirs.Contains(directive.Enforce) + s.Ignored = dirs.Contains(directive.Ignore) + s.Optional = dirs.Contains(directive.Optional) + + return diags +} + +func (p *Processor) matchStructPatterns(s *Struct) { + s.PatternEnforced = p.enforce.MatchFullString(s.FullPath) + s.PatternIgnored = p.ignore.MatchFullString(s.FullPath) + s.PatternOptional = p.optional.MatchFullString(s.FullPath) + s.AllowEmptyDecl = p.allowEmpty.MatchFullString(s.FullPath) +} + +func (p *Processor) Stats() (hits, misses, size uint64) { + return p.structCache.Stats() +} diff --git a/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/struct.go b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/struct.go new file mode 100644 index 00000000..c6cd49f2 --- /dev/null +++ b/vendor/dev.gaijin.team/go/exhaustruct/v5/internal/structure/struct.go @@ -0,0 +1,224 @@ +package structure + +import ( + "go/ast" + "go/token" + "strings" +) + +const AnonymousName = "" + +// fieldInfo contains raw field data independent of type name. +type fieldInfo struct { + // name is the name of the field. + name string + // exported indicates if the field is exported. + exported bool `exhaustruct:"optional"` + // enforced indicates if the field is enforced via directive. + enforced bool `exhaustruct:"optional"` + // optional indicates if the field is optional via directive. + optional bool `exhaustruct:"optional"` +} + +// structFields contains field information for a struct, independent of type name. +type structFields struct { + // packagePath is the package path where fields are declared. + packagePath string + // fields is the list of fields in declaration order. + fields []fieldInfo +} + +type Struct struct { + Name string + FullPath string + PackageName string + + Position token.Position `exhaustruct:"optional"` + Fields Fields `exhaustruct:"optional"` + + Enforced bool `exhaustruct:"optional"` + Ignored bool `exhaustruct:"optional"` + Optional bool `exhaustruct:"optional"` + + PatternEnforced bool `exhaustruct:"optional"` + PatternIgnored bool `exhaustruct:"optional"` + PatternOptional bool `exhaustruct:"optional"` + + AllowEmptyDecl bool `exhaustruct:"optional"` + + // Detected via OriginScanner AST inspection before types.Unalias. + IsAlias bool `exhaustruct:"optional"` + IsDerived bool `exhaustruct:"optional"` +} + +// PackagePath returns the package path of the struct type. +func (s *Struct) PackagePath() string { + if idx := strings.LastIndex(s.FullPath, "."); idx >= 0 { + return s.FullPath[:idx] + } + + return s.FullPath +} + +// IsEnforced returns true if struct is enforced via directive or pattern. +func (s *Struct) IsEnforced() bool { + return s.Enforced || s.PatternEnforced +} + +// IsIgnored returns true if struct is ignored via directive or pattern. +func (s *Struct) IsIgnored() bool { + return s.Ignored || s.PatternIgnored +} + +// IsOptional returns true if struct is optional via directive or pattern. +func (s *Struct) IsOptional() bool { + return s.Optional || s.PatternOptional +} + +// SkippedFields returns missing required fields for a composite literal. +// callerPkgPath is used to determine if unexported fields are accessible. +// For positional literals: returns fields after the last provided element. +// For named literals: returns fields not present in the literal. +func (s *Struct) SkippedFields(lit *ast.CompositeLit, callerPkgPath string) []Field { + externalPkg := s.Fields.PackagePath != callerPkgPath + + if isNamedLiteral(lit) { + return s.skippedNamed(lit, externalPkg) + } + + return s.skippedPositional(len(lit.Elts), externalPkg) +} + +// isNamedLiteral checks if a composite literal uses named fields. It treats +// empty literals as not named, since positional literals checks are simpler. +func isNamedLiteral(lit *ast.CompositeLit) bool { + if len(lit.Elts) == 0 { + return false + } + + _, ok := lit.Elts[0].(*ast.KeyValueExpr) + + return ok +} + +func (s *Struct) skippedPositional(count int, externalPkg bool) []Field { + items := s.Fields.Items + + if count >= len(items) { + return nil + } + + remaining := items[count:] + missing := make([]Field, 0, len(remaining)) + + for _, f := range remaining { + if s.isFieldRequired(f, externalPkg) { + missing = append(missing, f) + } + } + + if len(missing) == 0 { + return nil + } + + return missing +} + +func (s *Struct) skippedNamed(lit *ast.CompositeLit, externalPkg bool) []Field { + present := make(map[string]bool, len(lit.Elts)) + + for _, elt := range lit.Elts { + if kv, ok := elt.(*ast.KeyValueExpr); ok { + if k, ok := kv.Key.(*ast.Ident); ok { + present[k.Name] = true + } + } + } + + missing := make([]Field, 0, len(s.Fields.Items)-len(present)) + + for _, f := range s.Fields.Items { + if !present[f.Name] && s.isFieldRequired(f, externalPkg) { + missing = append(missing, f) + } + } + + if len(missing) == 0 { + return nil + } + + return missing +} + +func (s *Struct) isFieldRequired(f Field, externalPkg bool) bool { + // explicit field directives win over everything + if f.Enforced { + return true + } + + if f.Optional { + return false + } + + // field-level patterns apply only when they specifically target the field — + // i.e., the pattern matches the field path but not the struct path. A broad + // pattern that also matches the struct is handled via s.IsEnforced/IsOptional + // and must not silently promote unrelated fields to required/optional. + if f.PatternEnforced && !s.PatternEnforced { + return true + } + + if f.PatternOptional && !s.PatternOptional { + return false + } + + // optionality can be inherited from the structure settings + if s.IsOptional() { + return false + } + + // unexported fields are only required for same-package usage + if externalPkg && !f.Exported { + return false + } + + return true +} + +type Field struct { + Name string + Exported bool `exhaustruct:"optional"` + Enforced bool `exhaustruct:"optional"` + Optional bool `exhaustruct:"optional"` + + PatternEnforced bool `exhaustruct:"optional"` + PatternOptional bool `exhaustruct:"optional"` +} + +// Fields is a collection of struct fields with shared package metadata. +// Items are in declaration order (required for positional literals). +type Fields struct { + PackagePath string + Items []Field +} + +func FormatFieldNames(fields []Field) string { + switch len(fields) { + case 0: + return "" + case 1: + return fields[0].Name + } + + var b strings.Builder + + b.Grow(len(fields)) + b.WriteString(fields[0].Name) + + for _, s := range fields[1:] { + b.WriteString(", ") + b.WriteString(s.Name) + } + + return b.String() +} diff --git a/vendor/dev.gaijin.team/go/golib/fields/field.go b/vendor/dev.gaijin.team/go/golib/fields/field.go index 324b2970..716586ba 100644 --- a/vendor/dev.gaijin.team/go/golib/fields/field.go +++ b/vendor/dev.gaijin.team/go/golib/fields/field.go @@ -1,4 +1,3 @@ -// Package fields provides types and functions for working with key-value fields. package fields import ( diff --git a/vendor/dev.gaijin.team/go/golib/fields/list.go b/vendor/dev.gaijin.team/go/golib/fields/list.go index 5a881f77..7da83b20 100644 --- a/vendor/dev.gaijin.team/go/golib/fields/list.go +++ b/vendor/dev.gaijin.team/go/golib/fields/list.go @@ -44,7 +44,7 @@ func (l List) ToDict() Dict { // } func (l List) All() iter.Seq2[string, any] { return func(yield func(string, any) bool) { - for i := 0; i < len(l); i++ { + for i := range len(l) { if !yield(l[i].K, l[i].V) { return } diff --git a/vendor/github.com/Abirdcfly/dupword/dupword.go b/vendor/github.com/Abirdcfly/dupword/dupword.go index a3eaced8..5b482006 100644 --- a/vendor/github.com/Abirdcfly/dupword/dupword.go +++ b/vendor/github.com/Abirdcfly/dupword/dupword.go @@ -99,15 +99,17 @@ func NewAnalyzer() *analysis.Analyzer { a.Flags.Var(&analyzer.keywords, "keyword", "keywords for detecting duplicate words") a.Flags.Var(&analyzer.ignoreWords, "ignore", "ignore words") a.Flags.BoolVar(&analyzer.commentsOnly, "comments-only", false, "check only comments, skip strings") + a.Flags.BoolVar(&analyzer.skipRawStrings, "skip-raw-strings", false, "skip raw string literals (backtick-delimited)") a.Flags.Var(version{}, "V", "print version and exit") return a } type analyzer struct { - keywords keywords - ignoreWords ignore - commentsOnly bool + keywords keywords + ignoreWords ignore + commentsOnly bool + skipRawStrings bool } func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) { @@ -186,6 +188,9 @@ func (a *analyzer) fixDuplicateWordInString(pass *analysis.Pass, lit *ast.BasicL if lit.Kind != token.STRING { return } + if a.skipRawStrings && len(lit.Value) > 0 && lit.Value[0] == '`' { + return + } value, err := strconv.Unquote(lit.Value) if err != nil { fmt.Printf("lit.Value:%v, err: %v\n", lit.Value, err) @@ -193,9 +198,14 @@ func (a *analyzer) fixDuplicateWordInString(pass *analysis.Pass, lit *ast.BasicL value = lit.Value } quote := value != lit.Value + isRawString := quote && len(lit.Value) > 0 && lit.Value[0] == '`' update, keyword, find := a.Check(value) if quote { - update = strconv.Quote(update) + if isRawString { + update = "`" + update + "`" + } else { + update = strconv.Quote(update) + } } if find { pass.Report(analysis.Diagnostic{Pos: lit.Pos(), End: lit.End(), Message: fmt.Sprintf(Message, keyword), SuggestedFixes: []analysis.SuggestedFix{{ @@ -268,8 +278,8 @@ func (a *analyzer) checkOneKey(raw, key string) (new string, findWord string, fi // space start position spaceStart = i curWord = raw[wordStart:i] - } else if i == len(raw)-1 { - // last position + } else if i == len(raw)-1 && !unicode.IsSpace(r) { + // last position (non-space): write the final word word := raw[wordStart:] if ((key != "" && word == key) || key == "") && word == preWord { if !a.excludeWords(cutTrailingCommas(word)) { @@ -283,6 +293,25 @@ func (a *analyzer) checkOneKey(raw, key string) (new string, findWord string, fi } lastRune = r } + // Flush remaining content when the string ends with whitespace: + // the last word (curWord) and trailing whitespace haven't been written yet. + if len(raw) > 0 && unicode.IsSpace(rune(raw[len(raw)-1])) { + if curWord != "" { + if ((key != "" && curWord == key) || key == "") && curWord == preWord && curWord != "" { + if !a.excludeWords(cutTrailingCommas(curWord)) { + find = true + findWordMap[curWord] = true + } else { + newLine.WriteString(lastSpace) + newLine.WriteString(curWord) + } + } else { + newLine.WriteString(lastSpace) + newLine.WriteString(curWord) + } + } + newLine.WriteString(raw[spaceStart:]) + } if find { new = newLine.String() findWordSlice := make([]string, len(findWordMap)) diff --git a/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go b/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go index 9bf56232..91d3c6bd 100644 --- a/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go +++ b/vendor/github.com/AlwxSin/noinlineerr/noinlineerr.go @@ -4,6 +4,7 @@ import ( "bytes" "go/ast" "go/printer" + "go/token" "go/types" "golang.org/x/tools/go/analysis" @@ -11,7 +12,13 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -const errMessage = "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" +func errMessage(tok token.Token) string { + if tok == token.ASSIGN { + return "avoid inline error handling using `if err = ...; err != nil`; use plain assignment `err = ...`" + } + + return "avoid inline error handling using `if err := ...; err != nil`; use plain assignment `err := ...`" +} func NewAnalyzer() *analysis.Analyzer { return &analysis.Analyzer{ @@ -67,8 +74,8 @@ func inlineErrorInspector(pass *analysis.Pass) func(n ast.Node) { // or there are any variables with same name // then we can make a shadow conflict with other variables // so don't do anything beside simple error message - if len(assignStmt.Lhs) != 1 || shadowVarsExists(ident.Name, pass.TypesInfo.Scopes[ifStmt]) { - pass.Reportf(ident.Pos(), errMessage) + if len(assignStmt.Lhs) != 1 || (assignStmt.Tok == token.DEFINE && shadowVarsExists(ident.Name, pass.TypesInfo.Scopes[ifStmt])) { + pass.Reportf(ident.Pos(), errMessage(assignStmt.Tok)) return } @@ -85,13 +92,13 @@ func inlineErrorInspector(pass *analysis.Pass) func(n ast.Node) { pass.Report(analysis.Diagnostic{ Pos: ident.Pos(), End: ident.End(), - Message: errMessage, + Message: errMessage(assignStmt.Tok), SuggestedFixes: []analysis.SuggestedFix{ { Message: "move err assignment outside if", TextEdits: []analysis.TextEdit{ { - // insert err := ... before if + // insert err := ... or err = ... before if Pos: ifStmt.Pos(), End: ifStmt.Pos(), NewText: []byte(assignText + "\n"), diff --git a/vendor/github.com/ClickHouse/clickhouse-go-linter/passes/chbatchclose/chbatchclose.go b/vendor/github.com/ClickHouse/clickhouse-go-linter/passes/chbatchclose/chbatchclose.go index 3da2c55d..cc0f6894 100644 --- a/vendor/github.com/ClickHouse/clickhouse-go-linter/passes/chbatchclose/chbatchclose.go +++ b/vendor/github.com/ClickHouse/clickhouse-go-linter/passes/chbatchclose/chbatchclose.go @@ -146,28 +146,73 @@ func (a *analyzer) handleAssign(pass *analysis.Pass, assign *ast.AssignStmt, usa } } -// handleDefer checks if a defer statement calls Close() or Abort() on a tracked Batch variable. +// handleDefer checks if a defer statement calls Close() on a tracked Batch variable. +// Two shapes are supported: +// - direct selector call: defer batch.Close() +// - immediately-invoked closure: defer func() { ... batch.Close() ... }() +// (no params; nested FuncLits inside the closure body are not descended into) func handleDefer(deferStmt *ast.DeferStmt, usages map[string]*batchUsage) { call := deferStmt.Call - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return - } - varName := util.IdentName(sel.X) - if varName == "" { - return - } - u, exists := usages[varName] - if !exists { - return - } - switch sel.Sel.Name { - case "Close": - u.deferredClose = true + switch fun := call.Fun.(type) { + case *ast.SelectorExpr: + varName := util.IdentName(fun.X) + if varName == "" { + return + } + u, exists := usages[varName] + if !exists { + return + } + if fun.Sel.Name == "Close" { + u.deferredClose = true + } + case *ast.FuncLit: + // only no-arg closures are supported for the moment + if fun.Type.Params != nil && len(fun.Type.Params.List) > 0 { + return + } + handleDeferredClosure(fun.Body, usages) } } +// handleDeferredClosure walks the body of a deferred closure looking for +// `.Close()` calls. It does not descend into nested FuncLits, so +// `defer func() { go func() { batch.Close() }() }()` and similar are not +// treated as a valid defensive close. +func handleDeferredClosure(body *ast.BlockStmt, usages map[string]*batchUsage) { + ast.Inspect(body, func(n ast.Node) bool { + if n == nil { + return false + } + // don't descend into nested closures (goroutines, callbacks, etc.) + if n != body { + if _, ok := n.(*ast.FuncLit); ok { + return false + } + } + call, ok := n.(*ast.CallExpr) + if !ok { + return true + } + sel, ok := call.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + if sel.Sel.Name != "Close" { + return true + } + varName := util.IdentName(sel.X) + if varName == "" { + return true + } + if u, exists := usages[varName]; exists { + u.deferredClose = true + } + return true + }) +} + // handleReturn checks if any return value is a tracked Batch variable. func handleReturn(ret *ast.ReturnStmt, usages map[string]*batchUsage) { for _, result := range ret.Results { diff --git a/vendor/github.com/alecthomas/chroma/v2/.golangci.yml b/vendor/github.com/alecthomas/chroma/v2/.golangci.yml index 91f313b1..a345ac65 100644 --- a/vendor/github.com/alecthomas/chroma/v2/.golangci.yml +++ b/vendor/github.com/alecthomas/chroma/v2/.golangci.yml @@ -1,89 +1,122 @@ +version: "2" run: tests: true - output: - print-issued-lines: false - + show-stats: false + formats: + text: + print-issued-lines: false + colors: true linters: - enable-all: true + default: all disable: - - lll - - gocyclo + - exhaustive + - prealloc - dupl - - gochecknoglobals - - funlen - - godox - - wsl - - gocognit - - nolintlint - - testpackage - - godot - - nestif - - paralleltest - - nlreturn + - godoclint - cyclop - - gci - - gofumpt - - errorlint - - exhaustive - - wrapcheck - - stylecheck - - thelper - - nonamedreturns - - revive + - depguard - dupword + - err113 + - errname + - errorlint - exhaustruct - - varnamelen + - forbidigo - forcetypeassert + - funlen + - gochecknoglobals + - gocognit + - gocritic + - gocyclo + - godot + - godox + - gomoddirectives - ireturn + - lll - maintidx - - govet - - testableexamples - - musttag - - depguard - - goconst - - perfsprint - mnd + - nakedret + - nestif + - nilnil + - nlreturn + - nolintlint + - nonamedreturns + - paralleltest + - perfsprint - predeclared - recvcheck - - tenv - - err113 - -linters-settings: - gocyclo: - min-complexity: 10 - dupl: - threshold: 100 - goconst: - min-len: 8 - min-occurrences: 3 - forbidigo: - #forbid: - # - (Must)?NewLexer$ - exclude_godoc_examples: false - - + - revive + - testpackage + - varnamelen + - wastedassign + - whitespace + - wsl + - wsl_v5 + - funcorder + - noinlineerr + - tagalign + - goconst + - gochecknoinits + - durationcheck + - embeddedstructfieldcheck + - wrapcheck + - gomodguard + settings: + dupl: + threshold: 100 + exhaustive: + default-signifies-exhaustive: true + goconst: + min-len: 8 + min-occurrences: 3 + gocyclo: + min-complexity: 10 + wrapcheck: + report-internal-errors: false + ignore-package-globs: + - github.com/alecthomas/errors + exclusions: + generated: lax + rules: + - path: (.+)\.go$ + text: "^(G104|G204|G307|G304):" + - path: (.+)\.go$ + text: Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked + - path: (.+)\.go$ + text: exported method `(.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos)` should have comment or be unexported + - path: (.+)\.go$ + text: uses unkeyed fields + - path: (.+)\.go$ + text: declaration of "err" shadows declaration + - path: (.+)\.go$ + text: bad syntax for struct tag key + - path: (.+)\.go$ + text: bad syntax for struct tag pair + - path: (.+)\.go$ + text: ^ST1012 + - path: (.+)\.go$ + text: log/slog.Logger.*must not be called + - path: (.+)_test\.go$ + text: error returned from external package is unwrapped + - linters: [staticcheck] + text: QF1008 + - text: "Error return value of `.*.Write` is not checked" + linters: [errcheck] + path: (.+)_test\.go$ + paths: + - third_party$ + - builtin$ + - examples$ issues: - exclude-dirs: - - _examples - max-per-linter: 0 - max-same: 0 - exclude-use-default: false - exclude: - # Captured by errcheck. - - '^(G104|G204):' - # Very commonly not checked. - - 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked' - - 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON|.*\.EntityURN|.*\.GoString|.*\.Pos) should have comment or be unexported' - - 'composite literal uses unkeyed fields' - - 'declaration of "err" shadows declaration' - - 'should not use dot imports' - - 'Potential file inclusion via variable' - - 'should have comment or be unexported' - - 'comment on exported var .* should be of the form' - - 'at least one file in a package should have a package comment' - - 'string literal contains the Unicode' - - 'methods on the same type should have the same receiver name' - - '_TokenType_name should be _TokenTypeName' - - '`_TokenType_map` should be `_TokenTypeMap`' - - 'rewrite if-else to switch statement' + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/alecthomas/chroma/v2/AGENTS.md b/vendor/github.com/alecthomas/chroma/v2/AGENTS.md index 0d3b6ee4..d15d770a 100644 --- a/vendor/github.com/alecthomas/chroma/v2/AGENTS.md +++ b/vendor/github.com/alecthomas/chroma/v2/AGENTS.md @@ -1,6 +1,6 @@ Chroma is a syntax highlighting library, tool and web playground for Go. It is based on Pygments and includes importers for it, so most of the same concepts from Pygments apply to Chroma. -This project is written in Go, uses Hermit to manage tooling, and Just for helper commands. Helper scripts are in ./scripts. +This project is written in Go, uses Hermit to manage tooling, and Just for helper commands. Helper tooling is primarily in ./_tools. Language definitions are XML files defined in ./lexers/embedded/*.xml. diff --git a/vendor/github.com/alecthomas/chroma/v2/BUILD.bit b/vendor/github.com/alecthomas/chroma/v2/BUILD.bit new file mode 100644 index 00000000..f8ee1aee --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/BUILD.bit @@ -0,0 +1,93 @@ +let version = exec("git describe --tags --dirty --always") | trim +# TinyGo's installation root; used to source `wasm_exec.js`. +let tinygoroot = exec("tinygo env TINYGOROOT") | trim + + +# Generate tokentype_enumer.go from types.go via `//go:generate`. +tokentype = go.generate { + package = "." + inputs = ["types.go"] + outputs = ["tokentype_enumer.go"] +} + +# Regenerate the lexer table in README.md by invoking the host `chroma` binary. +# GOOS/GOARCH are cleared so cross-compile env vars don't break the local run. +protected readme = exec { + command = "./table.py" + inputs = ["table.py", "lexers/**/*.go", "lexers/**/*.xml"] + output = "README.md" +} + +# Format frontend JS sources in place. Runs as a sub-step of `index-min-js`, +# so bundling always sees formatted sources. +format-js = exec { + command = "biome format --write cmd/chromad/static/index.js cmd/chromad/static/chroma.js" + inputs = ["biome.js", "cmd/chromad/static/index.js", "cmd/chromad/static/chroma.js"] +} + +# Copy TinyGo's wasm_exec.js into the chromad static assets. +wasm-exec = exec { + command = "install -m644 '#{tinygoroot}/targets/wasm_exec.js' cmd/chromad/static/wasm_exec.js" + resolve = "sha256 '#{tinygoroot}/targets/wasm_exec.js'" + output = "cmd/chromad/static/wasm_exec.js" +} + +# Build the chroma WASM module via tinygo (installed via hermit) for the +# smaller output binary. +chroma-wasm = exec { + command = "tinygo build -no-debug -target wasm -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go" + inputs = ["cmd/libchromawasm/**/*.go", "*.go", "lexers/**/*.go", "lexers/**/*.xml", "formatters/**/*.go", "styles/**/*.go"] + output = "cmd/chromad/static/chroma.wasm" +} + +# Bundle and minify the frontend JS. Depends on `format-js` so the bundle +# always reflects formatted sources. +index-min-js = exec { + command = "esbuild --platform=browser --format=esm --bundle cmd/chromad/static/index.js --minify --external:./wasm_exec.js --outfile=cmd/chromad/static/index.min.js" + inputs = ["cmd/chromad/static/index.js", "cmd/chromad/static/chroma.js"] + output = "cmd/chromad/static/index.min.js" + depends_on = [format-js] +} + +# Bundle and minify the frontend CSS. +index-min-css = exec { + command = "esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css" + inputs = ["cmd/chromad/static/index.css", "cmd/chromad/static/bulma.css"] + output = "cmd/chromad/static/index.min.css" +} + +# Build the chromad server binary. cmd/chromad is a separate Go module, so +# `dir` puts the build in there and `package = "."` resolves against that +# module. `output` stays project-root-relative; bit absolutises it before +# passing to `go build -o`. Defaults to linux/amd64 to match the deploy +# target; override with GOOS/GOARCH env vars for local builds. +chromad = go.exe { + dir = "cmd/chromad" + package = "." + output = "build/chromad" + flags = ["-ldflags", "-X 'main.version=#{version}'"] + goos = env("GOOS", "linux") + goarch = env("GOARCH", "amd64") + cgo = false + depends_on = [wasm-exec, chroma-wasm, index-min-js, index-min-css, test] +} + +pre format-go = go.fmt { + package = "./..." +} + +# Run Go tests. +test = go.test { + package = "./..." +} + +# Deploy chromad to swapoff.org. Must be explicitly selected. +explicit upload = exec { + command = <<-EOF + scp #{chromad.path} root@swapoff.org: + ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart' + EOF + depends_on = [chromad] +} + +target default = [test, chromad, readme, tokentype] diff --git a/vendor/github.com/alecthomas/chroma/v2/Bitfile b/vendor/github.com/alecthomas/chroma/v2/Bitfile deleted file mode 100644 index bf158633..00000000 --- a/vendor/github.com/alecthomas/chroma/v2/Bitfile +++ /dev/null @@ -1,24 +0,0 @@ -VERSION = %(git describe --tags --dirty --always)% -export CGOENABLED = 0 - -tokentype_enumer.go: types.go - build: go generate - -# Regenerate the list of lexers in the README -README.md: lexers/*.go lexers/*/*.xml table.py - build: ./table.py - -clean - -implicit %{1}%{2}.min.%{3}: **/*.{css,js} - build: esbuild --bundle %{IN} --minify --outfile=%{OUT} - -implicit build/%{1}: cmd/* - cd cmd/%{1} - inputs: cmd/%{1}/**/* **/*.go - build: go build -ldflags="-X 'main.version=%{VERSION}'" -o ../../build/%{1} . - -#upload: chromad -# build: -# scp chromad root@swapoff.org: -# ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart' -# touch upload diff --git a/vendor/github.com/alecthomas/chroma/v2/Dockerfile b/vendor/github.com/alecthomas/chroma/v2/Dockerfile index 8a706766..dc10ec75 100644 --- a/vendor/github.com/alecthomas/chroma/v2/Dockerfile +++ b/vendor/github.com/alecthomas/chroma/v2/Dockerfile @@ -28,7 +28,7 @@ ENV GOARCH=amd64 RUN just chromad # Runtime stage -FROM alpine:3.23 AS runtime +FROM alpine:3.24 AS runtime # Install ca-certificates for HTTPS requests RUN apk --no-cache add ca-certificates curl diff --git a/vendor/github.com/alecthomas/chroma/v2/Justfile b/vendor/github.com/alecthomas/chroma/v2/Justfile index 24e3816f..4db3dc31 100644 --- a/vendor/github.com/alecthomas/chroma/v2/Justfile +++ b/vendor/github.com/alecthomas/chroma/v2/Justfile @@ -1,4 +1,4 @@ -set positional-arguments := true +set positional-arguments set shell := ["bash", "-c"] version := `git describe --tags --dirty --always` @@ -21,6 +21,10 @@ tokentype-string: format-js: biome format --write cmd/chromad/static/index.js cmd/chromad/static/chroma.js +# Tidy Go modules +tidy: + find . -name 'go.mod' -execdir go mod tidy \; + # Build chromad binary chromad: wasm-exec chroma-wasm #!/usr/bin/env bash diff --git a/vendor/github.com/alecthomas/chroma/v2/README.md b/vendor/github.com/alecthomas/chroma/v2/README.md index d6747695..df962da7 100644 --- a/vendor/github.com/alecthomas/chroma/v2/README.md +++ b/vendor/github.com/alecthomas/chroma/v2/README.md @@ -36,25 +36,25 @@ translators for Pygments lexers and styles. | Prefix | Language | :----: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, AMPL, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, ATL, AutoHotkey, AutoIt, Awk +| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, AMPL, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, Arturo, ATL, AutoHotkey, AutoIt, Awk | B | Ballerina, Bash, Bash Session, Batchfile, Beef, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck | C | C, C#, C++, C3, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Core, Crystal, CSS, CSV, CUE, Cython -| D | D, Dart, Dax, Desktop file, Diff, Django/Jinja, dns, Docker, DTD, Dylan -| E | EBNF, Elixir, Elm, EmacsLisp, Erlang +| D | D, Dart, Dax, Desktop file, Devicetree, Diff, Django/Jinja, dns, Docker, DTD, Dylan +| E | EBNF, Elixir, Elm, EmacsLisp, ERB, Erlang | F | Factor, Fennel, Fish, Forth, Fortran, FortranFixed, FSharp | G | GAS, GDScript, GDScript3, Gemtext, Genshi, Genshi HTML, Genshi Text, Gettext, Gherkin, Gleam, GLSL, Gnuplot, Go, Go HTML Template, Go Template, Go Text Template, GraphQL, Groff, Groovy | H | Handlebars, Hare, Haskell, Haxe, HCL, Hexdump, HLB, HLSL, HolyC, HTML, HTTP, Hy | I | Idris, Igor, INI, Io, ISCdhcpd | J | J, Janet, Java, JavaScript, JSON, JSONata, Jsonnet, Julia, Jungle -| K | Kakoune, Kotlin -| L | Lean4, Lighttpd configuration file, LLVM, lox, Lua, Luau -| M | Makefile, Mako, markdown, Markless, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL +| K | Kakoune, KDL, Kotlin +| L | Lateralus, Lean4, Lighttpd configuration file, LilyPond, LLVM, lox, Lua, Luau +| M | Makefile, Mako, markdown, Markless, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, microcad, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonBit, MoonScript, MorrowindScript, Myghty, MySQL | N | NASM, Natural, NDISASM, Newspeak, Nginx configuration file, Nim, Nix, NSIS, Nu | O | Objective-C, ObjectPascal, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode | P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, Promela, PromQL, properties, Protocol Buffer, Protocol Buffer Text Format, PRQL, PSL, Puppet, Python, Python 2 | Q | QBasic, QML | R | R, Racket, Ragel, Raku, react, ReasonML, reg, Rego, reStructuredText, Rexx, RGBDS Assembly, Ring, RPGLE, RPMSpec, Ruby, Rust -| S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, Spade, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog +| S | SAS, Sass, Scala, scdoc, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, Spade, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog | T | TableGen, Tal, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, Typst | U | ucode | V | V, V shell, Vala, VB.net, verilog, VHDL, VHS, VimL, vue @@ -276,6 +276,8 @@ for that setup the `chroma` executable can be just symlinked to `~/.lessfilter`. its input using Chroma * [Hugo](https://gohugo.io/) is a static site generator that [uses Chroma for syntax highlighting code examples](https://gohugo.io/content-management/syntax-highlighting/) +* [f4](https://github.com/unxed/f4) is asynchronious cross platform Far Manager clone in Go + that uses Chroma for syntax highlighting in built-in editor ## Testing lexers diff --git a/vendor/github.com/alecthomas/chroma/v2/colour.go b/vendor/github.com/alecthomas/chroma/v2/colour.go index e33d0106..8add068d 100644 --- a/vendor/github.com/alecthomas/chroma/v2/colour.go +++ b/vendor/github.com/alecthomas/chroma/v2/colour.go @@ -52,7 +52,7 @@ type Colour int32 // NewColour creates a Colour directly from RGB values. func NewColour(r, g, b uint8) Colour { - return ParseColour(fmt.Sprintf("%02x%02x%02x", r, g, b)) + return Colour(int32(r)<<16|int32(g)<<8|int32(b)) + 1 } // Distance between this colour and another. diff --git a/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go b/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go index 1aaafd0f..e876aab7 100644 --- a/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go +++ b/vendor/github.com/alecthomas/chroma/v2/formatters/html/html.go @@ -4,6 +4,7 @@ import ( "fmt" "html" "io" + "slices" "sort" "strconv" "strings" @@ -83,6 +84,11 @@ func WithPreWrapper(wrapper PreWrapper) Option { } } +// WithModeClasses adds the style's mode (eg. "light" or "dark") as a CSS +// class on wrapper elements and scopes WriteCSS rules by mode. This enables +// combining light and dark stylesheets and switching themes at runtime. +func WithModeClasses(b bool) Option { return func(f *Formatter) { f.modeClasses = b } } + // WrapLongLines wraps long lines. func WrapLongLines(b bool) Option { return func(f *Formatter) { @@ -206,6 +212,7 @@ type Formatter struct { inlineCode bool preventSurroundingPre bool tabWidth int + modeClasses bool wrapLongLines bool lineNumbers bool lineNumbersInTable bool @@ -241,7 +248,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. fmt.Fprintf(w, "body { %s; }\n", css[chroma.Background]) fmt.Fprint(w, "") } - fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.Background)) + fmt.Fprintf(w, "\n", f.styleAttrWithMode(css, chroma.Background, style)) } wrapInTable := f.lineNumbers && f.lineNumbersInTable @@ -252,10 +259,10 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. if wrapInTable { // List line numbers in its own - fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.PreWrapper)) + fmt.Fprintf(w, "\n", f.styleAttrWithMode(css, chroma.PreWrapper, style)) fmt.Fprintf(w, "", f.styleAttr(css, chroma.LineTable)) fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.LineTableTD)) - fmt.Fprintf(w, "%s", f.preWrapper.Start(false, f.styleAttr(css, chroma.PreWrapper))) + fmt.Fprintf(w, "%s", f.preWrapper.Start(false, f.styleAttrWithMode(css, chroma.PreWrapper, style))) for index := range lines { line := f.baseLineNumber + index highlight, next := f.shouldHighlight(highlightIndex, line) @@ -277,7 +284,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. fmt.Fprintf(w, "\n", f.styleAttr(css, chroma.LineTableTD, "width:100%")) } - fmt.Fprintf(w, "%s", f.preWrapper.Start(true, f.styleAttr(css, chroma.PreWrapper))) + fmt.Fprintf(w, "%s", f.preWrapper.Start(true, f.styleAttrWithMode(css, chroma.PreWrapper, style))) highlightIndex = 0 for index, tokens := range lines { @@ -288,7 +295,7 @@ func (f *Formatter) writeHTML(w io.Writer, style *chroma.Style, tokens []chroma. highlightIndex++ } - if !(f.preventSurroundingPre || f.inlineCode) { + if !f.preventSurroundingPre && !f.inlineCode { // Start of Line fmt.Fprint(w, ``) // End of CodeLine fmt.Fprint(w, ``) // End of Line @@ -414,6 +421,26 @@ func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.Toke return fmt.Sprintf(` style="%s"`, strings.Join(css, ";")) } +// modeClass returns the CSS class corresponding to the style's mode (eg. +// "light" or "dark"), with the formatter's class prefix applied. +func (f *Formatter) modeClass(style *chroma.Style) string { + return f.prefix + style.Mode().String() +} + +// styleAttrWithMode is like styleAttr but, in classes mode, appends the +// style's mode class alongside the existing class. Used for the outer +// wrapper and standalone so external CSS can target the mode. +func (f *Formatter) styleAttrWithMode(styles map[chroma.TokenType]string, tt chroma.TokenType, style *chroma.Style) string { + if !f.Classes || !f.modeClasses { + return f.styleAttr(styles, tt) + } + cls := f.class(tt) + if cls == "" { + return "" + } + return fmt.Sprintf(` class="%s %s"`, cls, f.modeClass(style)) +} + func (f *Formatter) tabWidthStyle() string { if f.tabWidth != 0 && f.tabWidth != 8 { return fmt.Sprintf("-moz-tab-size: %[1]d; -o-tab-size: %[1]d; tab-size: %[1]d;", f.tabWidth) @@ -437,20 +464,38 @@ func (f *Formatter) writeCSSRule(w io.Writer, comment string, selector string, s } // WriteCSS writes CSS style definitions (without any surrounding HTML). +// +// Rules are scoped by the style's mode (eg. ".chroma.dark") so that CSS +// generated from a light and dark style can be combined without conflict. +// To support dynamic theme switching, call WriteCSS with both styles, +// concatenate the output, and toggle the wrapper's mode class (added +// automatically by Format) at runtime. Tokens that one theme leaves +// unstyled fall back to that theme's ".chroma." text/background +// via the CSS cascade; pass WithAllClasses(true) if you need every +// token's rule materialised explicitly for both themes. func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error { css := f.styleCache.get(style, false) + var chromaSel, bgSel string + if f.modeClasses { + modeCls := f.modeClass(style) + chromaSel = fmt.Sprintf(".%schroma.%s", f.prefix, modeCls) + bgSel = fmt.Sprintf(".%sbg.%s", f.prefix, modeCls) + } else { + chromaSel = fmt.Sprintf(".%schroma", f.prefix) + bgSel = fmt.Sprintf(".%sbg", f.prefix) + } // Special-case background as it is mapped to the outer ".chroma" class. - if err := f.writeCSSRule(w, chroma.Background.String(), fmt.Sprintf(".%sbg", f.prefix), css[chroma.Background]); err != nil { + if err := f.writeCSSRule(w, chroma.Background.String(), bgSel, css[chroma.Background]); err != nil { return err } // Special-case PreWrapper as it is the ".chroma" class. - if err := f.writeCSSRule(w, chroma.PreWrapper.String(), fmt.Sprintf(".%schroma", f.prefix), css[chroma.PreWrapper]); err != nil { + if err := f.writeCSSRule(w, chroma.PreWrapper.String(), chromaSel, css[chroma.PreWrapper]); err != nil { return err } // Special-case code column of table to expand width. if f.lineNumbers && f.lineNumbersInTable { - selector := fmt.Sprintf(".%schroma .%s:last-child", f.prefix, f.class(chroma.LineTableTD)) + selector := fmt.Sprintf("%s .%s:last-child", chromaSel, f.class(chroma.LineTableTD)) if err := f.writeCSSRule(w, chroma.LineTableTD.String(), selector, "width: 100%;"); err != nil { return err } @@ -460,7 +505,7 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error { targetedLineCSS := StyleEntryToCSS(style.Get(chroma.LineHighlight)) for _, tt := range []chroma.TokenType{chroma.LineNumbers, chroma.LineNumbersTable} { comment := fmt.Sprintf("%s targeted by URL anchor", tt) - selector := fmt.Sprintf(".%schroma .%s:target", f.prefix, f.class(tt)) + selector := fmt.Sprintf("%s .%s:target", chromaSel, f.class(tt)) if err := f.writeCSSRule(w, comment, selector, targetedLineCSS); err != nil { return err } @@ -481,7 +526,7 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error { if class == "" { continue } - if err := f.writeCSSRule(w, tt.String(), fmt.Sprintf(".%schroma .%s", f.prefix, class), css[tt]); err != nil { + if err := f.writeCSSRule(w, tt.String(), fmt.Sprintf("%s .%s", chromaSel, class), css[tt]); err != nil { return err } } @@ -613,8 +658,7 @@ func (l *styleCache) get(style *chroma.Style, compress bool) map[chroma.TokenTyp defer l.mu.Unlock() // Look for an existing entry. - for i := len(l.cache) - 1; i >= 0; i-- { - entry := l.cache[i] + for i, entry := range slices.Backward(l.cache) { if entry.style == style && entry.compressed == compress { // Top of the cache, no need to adjust the order. if i == len(l.cache)-1 { diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arturo.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arturo.xml new file mode 100644 index 00000000..541dc46e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/arturo.xml @@ -0,0 +1,119 @@ + + + + Arturo + arturo + art + *.art + + + + + + + + + + + + + + + + + + + + + + + + + 3 + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml index f1b454fa..4044f491 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/dart.xml @@ -81,7 +81,7 @@ - + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gemfile_lock.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gemfile_lock.xml new file mode 100644 index 00000000..83fc47b7 --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/gemfile_lock.xml @@ -0,0 +1,81 @@ + + + Gemfile.lock + gemfile-lock + gemfilelock + Gemfile.lock + *.gemfile.lock + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml index 3ce33ff6..4ef5fd26 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/java.xml @@ -32,7 +32,7 @@ pattern="(assert|break|case|catch|continue|default|do|else|finally|for|if|goto|instanceof|new|return|switch|this|throw|try|while)\b"> - + @@ -44,7 +44,7 @@ + pattern="(abstract|const|enum|exports|extends|final|implements|native|non-sealed|open|opens|permits|private|protected|provides|public|requires|sealed|static|strictfp|super|synchronized|throws|to|transient|transitive|uses|volatile|with|yield)\b"> @@ -64,6 +64,10 @@ + + + + @@ -71,7 +75,7 @@ - + @@ -147,6 +151,15 @@ + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml index 0057aa1b..f65d7103 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/json.xml @@ -2,12 +2,15 @@ JSON json + jsonl *.json + *.jsonl *.jsonc *.json5 *.avsc .luaurc application/json + application/jsonl true true diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lilypond.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lilypond.xml new file mode 100644 index 00000000..fe4ac8ed --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/lilypond.xml @@ -0,0 +1,133 @@ + + + + LilyPond + lilypond + *.ly + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml index 32655808..82d4b375 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/nu.xml @@ -3,7 +3,12 @@ Nu nu *.nu + application/x-shellscript text/plain + text/x-shellscript + + + @@ -118,4 +123,4 @@ - + \ No newline at end of file diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml index 15a3422d..32d1bb08 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/postscript.xml @@ -5,6 +5,10 @@ postscr *.ps *.eps + *.epsf + *.epsi + *.pfa + *.t42 application/postscript @@ -86,4 +90,4 @@ - \ No newline at end of file + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml index 157d321f..f8f0c8d7 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/protocol_buffer.xml @@ -7,7 +7,7 @@ - + @@ -16,7 +16,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,9 +46,12 @@ - + + + + @@ -62,6 +65,9 @@ + + + @@ -69,7 +75,7 @@ - + @@ -115,4 +121,4 @@ - \ No newline at end of file + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml index baa7e435..15e96ba8 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/ruby.xml @@ -12,7 +12,11 @@ *.rbx *.duby Gemfile + *.gemfile Vagrantfile + Appraisals + .pryrc + *.json.jbuilder text/x-ruby application/x-ruby true diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/templ.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/templ.xml new file mode 100644 index 00000000..14c26d6b --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/templ.xml @@ -0,0 +1,315 @@ + + + Templ + templ + *.templ + text/x-templ + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml index 07075541..ede15d33 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/embedded/yaml.xml @@ -23,6 +23,9 @@ + + + @@ -78,15 +81,22 @@ + + + + + + + - + - + @@ -95,14 +105,14 @@ - + - + diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/go.go b/vendor/github.com/alecthomas/chroma/v2/lexers/go.go index c6123b90..e6e04cca 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/go.go +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/go.go @@ -30,8 +30,8 @@ func goRules() Rules { "root": { {`\n`, TextWhitespace, nil}, {`\s+`, TextWhitespace, nil}, - {`//[^\s][^\n\r]*`, CommentPreproc, nil}, - {`//\s+[^\n\r]*`, CommentSingle, nil}, + {`//[^\s\n\r][^\n\r]*`, CommentPreproc, nil}, + {`//[^\n\r]*`, CommentSingle, nil}, {`/(\\\n)?[*](.|\n)*?[*](\\\n)?/`, CommentMultiline, nil}, {`(import|package)\b`, KeywordNamespace, nil}, {`(var|func|struct|map|chan|type|interface|const)\b`, KeywordDeclaration, nil}, diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/http.go b/vendor/github.com/alecthomas/chroma/v2/lexers/http.go index b57cb1b8..fee74d3b 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/http.go +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/http.go @@ -122,7 +122,7 @@ func (d *httpBodyContentTyper) Tokenise(options *TokeniseOptions, text string) ( if err != nil { panic(err) } - return EOF + return subIterator() } } } diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go b/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go index bcd5b178..eed2cb7e 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/markdown.go @@ -1,11 +1,13 @@ package lexers import ( + "strings" + . "github.com/alecthomas/chroma/v2" // nolint ) -// Markdown lexer. -var Markdown = Register(MustNewLexer( +// Markdown lexer with YAML frontmatter and HTML comment support. +var Markdown = Register(&markdownLexer{Lexer: MustNewLexer( &Config{ Name: "markdown", Aliases: []string{"md", "mkd"}, @@ -13,11 +15,69 @@ var Markdown = Register(MustNewLexer( MimeTypes: []string{"text/x-markdown"}, }, markdownRules, -)) +)}) + +// markdownLexer wraps the base Markdown lexer to highlight top-of-file YAML frontmatter. +type markdownLexer struct { + Lexer +} + +// Lexes Markdown, highlighting a leading YAML frontmatter block before delegating to Markdown rules. +func (m *markdownLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { + frontmatter, rest, ok := splitFrontmatter(text) + if !ok { + return m.Lexer.Tokenise(options, text) + } + + yamlLexer := Get("YAML") + if yamlLexer == nil { + return m.Lexer.Tokenise(options, text) + } + + yamlTokens, err := yamlLexer.Tokenise(options, frontmatter) + if err != nil { + return nil, err + } + markdownTokens, err := m.Lexer.Tokenise(options, rest) + if err != nil { + return nil, err + } + return Concaterator(yamlTokens, markdownTokens), nil +} + +// Extracts a leading YAML frontmatter block if the document starts with one. +func splitFrontmatter(text string) (frontmatter string, rest string, ok bool) { + if !strings.HasPrefix(text, "---\n") && !strings.HasPrefix(text, "---\r\n") { + return "", text, false + } + + lineEnd := strings.IndexByte(text, '\n') + if lineEnd < 0 { + return "", text, false + } + if strings.TrimSuffix(text[:lineEnd], "\r") != "---" { + return "", text, false + } + + for pos := lineEnd + 1; pos < len(text); { + next := strings.IndexByte(text[pos:], '\n') + if next < 0 { + break + } + lineEnd = pos + next + line := strings.TrimSuffix(text[pos:lineEnd], "\r") + if line == "---" { + return text[:lineEnd+1], text[lineEnd+1:], true + } + pos = lineEnd + 1 + } + return "", text, false +} func markdownRules() Rules { return Rules{ "root": { + {``, CommentMultiline, nil}, {`^(#[^#].+\n)`, ByGroups(GenericHeading), nil}, {`^(#{2,6}.+\n)`, ByGroups(GenericSubheading), nil}, {`^(\s*)([*-] )(\[[ xX]\])( .+\n)`, ByGroups(Text, Keyword, Keyword, UsingSelf("inline")), nil}, @@ -33,6 +93,7 @@ func markdownRules() Rules { Include("inline"), }, "inline": { + {``, CommentMultiline, nil}, {`\\.`, Text, nil}, {`(\s)(\*|_)((?:(?!\2).)*)(\2)((?=\W|\n))`, ByGroups(Text, GenericEmph, GenericEmph, GenericEmph, Text), nil}, {`(\s)((\*\*|__).*?)\3((?=\W|\n))`, ByGroups(Text, GenericStrong, GenericStrong, Text), nil}, diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go b/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go index 508513d7..437590e9 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/markless.go @@ -70,14 +70,14 @@ func marklessRules() Rules { {`(! )([^ ]+)(.+?)$`, ByGroups(Keyword, NameFunction, NameVariable), nil}, }, "embed": { - {`(\[ )([^ ]+)( )([^,]+)`, ByGroups(Keyword, NameFunction, TextWhitespace, String), Push("embed-options")}, + {`(\[ )([^ ]+)( )([^,\]\n]+)`, ByGroups(Keyword, NameFunction, TextWhitespace, String), Push("embed-options")}, }, "embed-options": { {`\\.`, Text, nil}, {`,`, Punctuation, nil}, {`\]?$`, Keyword, Pop(1)}, // Generic key or key/value pair - {`( *)([^, \]]+)([^,\]]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil}, + {`( *)([^, \]\n]+)([^,\]\n]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil}, {`.`, Text, nil}, }, "footnote": { diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/raku.go b/vendor/github.com/alecthomas/chroma/v2/lexers/raku.go index da354dce..38d8fe8a 100644 --- a/vendor/github.com/alecthomas/chroma/v2/lexers/raku.go +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/raku.go @@ -6,7 +6,7 @@ import ( "strings" "unicode/utf8" - "github.com/dlclark/regexp2" + "github.com/dlclark/regexp2/v2" . "github.com/alecthomas/chroma/v2" // nolint ) @@ -458,8 +458,7 @@ func rakuRules() Rules { var podRegex *regexp2.Regexp if tokenClass == rakuPod { podRegex = regexp2.MustCompile( - state.NamedGroups[`ws`]+`=end`+`\s+`+regexp2.Escape(state.NamedGroups[`name`]), - 0, + state.NamedGroups[`ws`] + `=end` + `\s+` + regexp2.Escape(state.NamedGroups[`name`]), ) } else { closingChars = []rune(strings.Repeat(string(closingChar), nChars)) @@ -478,7 +477,7 @@ func rakuRules() Rules { match, err := podRegex.FindRunesMatchStartingAt(text, searchPos+nChars) if err == nil { closingChars = match.Runes() - nextClosePos = match.Index + nextClosePos = match.RuneIndex } else { nextClosePos = -1 } @@ -1599,8 +1598,7 @@ func quote(groups []string, state *LexerState) Iterator { var tokenStates []string // Set tokenStates based on adverbs - adverbs := strings.Split(adverbsStr, ":") - for _, adverb := range adverbs { + for adverb := range strings.SplitSeq(adverbsStr, ":") { switch adverb { case "c", "closure": tokenStates = append(tokenStates, "Q-closure") diff --git a/vendor/github.com/alecthomas/chroma/v2/lexers/yaml_jinja.go b/vendor/github.com/alecthomas/chroma/v2/lexers/yaml_jinja.go new file mode 100644 index 00000000..6df1911e --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/lexers/yaml_jinja.go @@ -0,0 +1,20 @@ +package lexers + +import ( + . "github.com/alecthomas/chroma/v2" // nolint +) + +// YAML+Jinja is YAML with Jinja templating embedded. Used by Ansible playbooks +// and Salt SLS files. +var YAMLJinja = Register(DelegatingLexer( + MustNewXMLLexer(embedded, "embedded/yaml.xml"), + MustNewXMLLexer(embedded, "embedded/django_jinja.xml").SetConfig( + &Config{ + Name: "YAML+Jinja", + Aliases: []string{"yaml+jinja", "salt", "sls", "ansible"}, + Filenames: []string{"*.sls"}, + MimeTypes: []string{"text/x-yaml+jinja", "text/x-sls"}, + DotAll: true, + }, + ), +)) diff --git a/vendor/github.com/alecthomas/chroma/v2/regexp.go b/vendor/github.com/alecthomas/chroma/v2/regexp.go index d183fa5d..2c494061 100644 --- a/vendor/github.com/alecthomas/chroma/v2/regexp.go +++ b/vendor/github.com/alecthomas/chroma/v2/regexp.go @@ -3,6 +3,7 @@ package chroma import ( "encoding/json" "fmt" + "maps" "os" "path/filepath" "regexp" @@ -12,7 +13,7 @@ import ( "time" "unicode/utf8" - "github.com/dlclark/regexp2" + "github.com/dlclark/regexp2/v2" ) // A Rule is the fundamental matching unit of the Regex lexer state machine. @@ -70,9 +71,7 @@ func (r Rules) Clone() Rules { // Merge creates a clone of "r" then merges "rules" into the clone. func (r Rules) Merge(rules Rules) Rules { out := r.Clone() - for k, v := range rules.Clone() { - out[k] = v - } + maps.Copy(out, rules.Clone()) return out } @@ -177,19 +176,19 @@ type LexerState struct { // Named Group matches. NamedGroups map[string]string // Custum context for mutators. - MutatorContext map[interface{}]interface{} + MutatorContext map[any]any iteratorStack []Iterator options *TokeniseOptions newlineAdded bool } // Set mutator context. -func (l *LexerState) Set(key interface{}, value interface{}) { +func (l *LexerState) Set(key any, value any) { l.MutatorContext[key] = value } // Get mutator context. -func (l *LexerState) Get(key interface{}) interface{} { +func (l *LexerState) Get(key any) any { return l.MutatorContext[key] } @@ -369,7 +368,7 @@ func (r *RegexLexer) maybeCompile() (err error) { pattern = "(?" + rule.flags + ")" + pattern } pattern = `\G` + pattern - rule.Regexp, err = regexp2.Compile(pattern, 0) + rule.Regexp, err = regexp2.Compile(pattern) if err != nil { return fmt.Errorf("failed to compile rule %s.%d: %s", state, i, err) } @@ -484,7 +483,7 @@ func (r *RegexLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, Text: []rune(text), Stack: []string{options.State}, Rules: r.rules, - MutatorContext: map[interface{}]interface{}{}, + MutatorContext: map[any]any{}, } return state.Iterator, nil } @@ -501,7 +500,7 @@ func (r *RegexLexer) MustRules() Rules { func matchRules(text []rune, pos int, rules []*CompiledRule) (int, *CompiledRule, []string, map[string]string) { for i, rule := range rules { match, err := rule.Regexp.FindRunesMatchStartingAt(text, pos) - if match != nil && err == nil && match.Index == pos { + if match != nil && err == nil && match.RuneIndex == pos { groups := []string{} namedGroups := make(map[string]string) for _, g := range match.Groups() { diff --git a/vendor/github.com/alecthomas/chroma/v2/renovate.json5 b/vendor/github.com/alecthomas/chroma/v2/renovate.json5 index 9ade4812..050483e8 100644 --- a/vendor/github.com/alecthomas/chroma/v2/renovate.json5 +++ b/vendor/github.com/alecthomas/chroma/v2/renovate.json5 @@ -9,6 +9,7 @@ "schedule:earlyMondays", // Run once a week. 'helpers:pinGitHubActionDigests', ], + "postUpdateOptions": ["gomodTidy"], "packageRules": [ { "matchPackageNames": ["golangci-lint"], diff --git a/vendor/github.com/alecthomas/chroma/v2/serialise.go b/vendor/github.com/alecthomas/chroma/v2/serialise.go index 3d7f6c5d..dacf69c5 100644 --- a/vendor/github.com/alecthomas/chroma/v2/serialise.go +++ b/vendor/github.com/alecthomas/chroma/v2/serialise.go @@ -13,7 +13,7 @@ import ( "regexp" "strings" - "github.com/dlclark/regexp2" + "github.com/dlclark/regexp2/v2" ) // Serialisation of Chroma rules to XML. The format is: @@ -440,14 +440,14 @@ func (t TokenType) MarshalXML(e *xml.Encoder, start xml.StartElement) error { } // This hijinks is a bit unfortunate but without it we can't deserialise into TokenType. -func newFromTemplate(template interface{}) (value func() interface{}, target interface{}) { +func newFromTemplate(template any) (value func() any, target any) { t := reflect.TypeOf(template) - if t.Kind() == reflect.Ptr { + if t.Kind() == reflect.Pointer { v := reflect.New(t.Elem()) return v.Interface, v.Interface() } v := reflect.New(t) - return func() interface{} { return v.Elem().Interface() }, v.Interface() + return func() any { return v.Elem().Interface() }, v.Interface() } func (b *Emitters) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { diff --git a/vendor/github.com/alecthomas/chroma/v2/style.go b/vendor/github.com/alecthomas/chroma/v2/style.go index cc8d9a60..36989ad3 100644 --- a/vendor/github.com/alecthomas/chroma/v2/style.go +++ b/vendor/github.com/alecthomas/chroma/v2/style.go @@ -4,7 +4,8 @@ import ( "encoding/xml" "fmt" "io" - "sort" + "maps" + "slices" "strings" ) @@ -18,6 +19,24 @@ const ( No ) +// Mode indicates whether a style is intended for a light or dark background. +type Mode uint8 + +// Mode values. +const ( + Light Mode = iota + Dark +) + +func (m Mode) String() string { + switch m { + case Dark: + return "dark" + default: + return "light" + } +} + func (t Trilean) String() string { switch t { case Yes: @@ -31,12 +50,14 @@ func (t Trilean) String() string { // Prefix returns s with "no" as a prefix if Trilean is no. func (t Trilean) Prefix(s string) string { - if t == Yes { + switch t { + case Yes: return s - } else if t == No { + case No: return "no" + s + default: + return "" } - return "" } // A StyleEntry in the Style map. @@ -111,11 +132,10 @@ func (s StyleEntry) Sub(e StyleEntry) StyleEntry { // Ancestors should be provided from oldest to newest. func (s StyleEntry) Inherit(ancestors ...StyleEntry) StyleEntry { out := s - for i := len(ancestors) - 1; i >= 0; i-- { + for _, ancestor := range slices.Backward(ancestors) { if out.NoInherit { return out } - ancestor := ancestors[i] if !out.Colour.IsSet() { out.Colour = ancestor.Colour } @@ -147,19 +167,24 @@ func (s StyleEntry) IsZero() bool { // // Once built, a Style is immutable. type StyleBuilder struct { - entries map[TokenType]string - name string - parent *Style + entries map[TokenType]string + name string + counterpart string + parent *Style } func NewStyleBuilder(name string) *StyleBuilder { return &StyleBuilder{name: name, entries: map[TokenType]string{}} } +// Counterpart sets the lowercase name of the opposite-mode style. +func (s *StyleBuilder) Counterpart(name string) *StyleBuilder { + s.counterpart = strings.ToLower(name) + return s +} + func (s *StyleBuilder) AddAll(entries StyleEntries) *StyleBuilder { - for ttype, entry := range entries { - s.entries[ttype] = entry - } + maps.Copy(s.entries, entries) return s } @@ -205,10 +230,15 @@ func (s *StyleBuilder) Transform(transform func(StyleEntry) StyleEntry) *StyleBu } func (s *StyleBuilder) Build() (*Style, error) { + counterpart := s.counterpart + if counterpart == "" && s.parent != nil { + counterpart = s.parent.Counterpart + } style := &Style{ - Name: s.name, - entries: map[TokenType]StyleEntry{}, - parent: s.parent, + Name: s.name, + Counterpart: counterpart, + entries: map[TokenType]StyleEntry{}, + parent: s.parent, } for ttype, descriptor := range s.entries { entry, err := ParseStyleEntry(descriptor) @@ -257,9 +287,23 @@ func MustNewStyle(name string, entries StyleEntries) *Style { // // See http://pygments.org/docs/styles/ for details. Semantics are intended to be identical. type Style struct { - Name string - entries map[TokenType]StyleEntry - parent *Style + Name string + // Counterpart is the lowercase name of the style intended as this style's + // opposite-mode pair (eg. "github-dark" for "github"). Resolved via + // styles.GetForMode. May be empty. + Counterpart string + entries map[TokenType]StyleEntry + parent *Style +} + +// Mode returns Light or Dark based on the brightness of the Background entry's +// background colour. Styles with an unset Background default to Light. +func (s *Style) Mode() Mode { + bg := s.get(Background).Background + if bg.IsSet() && bg.Brightness() < 0.5 { + return Dark + } + return Light } func (s *Style) MarshalXML(e *xml.Encoder, start xml.StartElement) error { @@ -268,6 +312,9 @@ func (s *Style) MarshalXML(e *xml.Encoder, start xml.StartElement) error { } start.Name = xml.Name{Local: "style"} start.Attr = []xml.Attr{{Name: xml.Name{Local: "name"}, Value: s.Name}} + if s.Counterpart != "" { + start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "counterpart"}, Value: s.Counterpart}) + } if err := e.EncodeToken(start); err != nil { return err } @@ -275,7 +322,7 @@ func (s *Style) MarshalXML(e *xml.Encoder, start xml.StartElement) error { for ttype := range s.entries { sorted = append(sorted, ttype) } - sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) + slices.Sort(sorted) for _, ttype := range sorted { entry := s.entries[ttype] el := xml.StartElement{Name: xml.Name{Local: "entry"}} @@ -295,9 +342,12 @@ func (s *Style) MarshalXML(e *xml.Encoder, start xml.StartElement) error { func (s *Style) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { for _, attr := range start.Attr { - if attr.Name.Local == "name" { + switch attr.Name.Local { + case "name": s.Name = attr.Value - } else { + case "counterpart": + s.Counterpart = strings.ToLower(attr.Value) + default: return fmt.Errorf("unexpected attribute %s", attr.Name.Local) } } @@ -437,8 +487,7 @@ func MustParseStyleEntry(entry string) StyleEntry { // ParseStyleEntry parses a Pygments style entry. func ParseStyleEntry(entry string) (StyleEntry, error) { // nolint: gocyclo out := StyleEntry{} - parts := strings.Fields(entry) - for _, part := range parts { + for part := range strings.FieldsSeq(entry) { switch { case part == "italic": out.Italic = Yes diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/api.go b/vendor/github.com/alecthomas/chroma/v2/styles/api.go index 9e21c884..43fa26dd 100644 --- a/vendor/github.com/alecthomas/chroma/v2/styles/api.go +++ b/vendor/github.com/alecthomas/chroma/v2/styles/api.go @@ -64,3 +64,32 @@ func Get(name string) *chroma.Style { } return Fallback } + +// GetForMode returns the named style if it already matches mode, otherwise its +// registered counterpart if one exists and matches mode. If neither matches, +// the originally-requested style is returned (or Fallback if the name is +// unknown), so callers always get something usable. +func GetForMode(name string, mode chroma.Mode) *chroma.Style { + style := Get(name) + if style.Mode() == mode { + return style + } + if style.Counterpart == "" { + return style + } + counterpart, ok := Registry[style.Counterpart] + if !ok || counterpart.Mode() != mode { + return style + } + return counterpart +} + +// RegisterPair links two styles as light/dark counterparts of each other. +// +// Both styles are also registered if they are not already present. +func RegisterPair(a, b *chroma.Style) { + Register(a) + Register(b) + a.Counterpart = strings.ToLower(b.Name) + b.Counterpart = strings.ToLower(a.Name) +} diff --git a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml index c87c8765..a6e41ab8 100644 --- a/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml +++ b/vendor/github.com/alecthomas/chroma/v2/styles/catppuccin-latte.xml @@ -1,4 +1,4 @@ - - - - -`) - w.WriteString("") - w.WriteString("

") - w.WriteString(html.EscapeString(name)) - w.WriteString("

") - w.WriteString(` -help -
- -

-Click on a value or block to toggle highlighting of that value/block -and its uses. (Values and blocks are highlighted by ID, and IDs of -dead items may be reused, so not all highlights necessarily correspond -to the clicked item.) -

- -

-Faded out values and blocks are dead code that has not been eliminated. -

- -

-Values printed in italics have a dependency cycle. -

- -

-CFG: Dashed edge is for unlikely branches. Blue color is for backward edges. -Edge with a dot means that this edge follows the order in which blocks were laid out. -

- -
-`) - w.WriteString("") - w.WriteString("") -} - -func (w *HTMLWriter) Close() { - if w == nil { - return - } - io.WriteString(w.w, "") - io.WriteString(w.w, "
") - io.WriteString(w.w, "") - io.WriteString(w.w, "") - w.w.Close() - fmt.Printf("dumped IR to %v\n", w.path) -} - -// WriteFunc writes f in a column headed by title. -// phase is used for collapsing columns and should be unique across the table. -func (w *HTMLWriter) WriteFunc(phase, title string, f *Function) { - if w == nil { - return - } - w.WriteColumn(phase, title, "", funcHTML(f, phase, w.dot)) -} - -// WriteColumn writes raw HTML in a column headed by title. -// It is intended for pre- and post-compilation log output. -func (w *HTMLWriter) WriteColumn(phase, title, class, html string) { - if w == nil { - return - } - id := strings.Replace(phase, " ", "-", -1) - // collapsed column - w.Printf("
%v
", id, phase) - - if class == "" { - w.Printf("", id) - } else { - w.Printf("", id, class) - } - w.WriteString("

" + title + "

") - w.WriteString(html) - w.WriteString("") -} - -func (w *HTMLWriter) Printf(msg string, v ...any) { - if _, err := fmt.Fprintf(w.w, msg, v...); err != nil { - log.Fatalf("%v", err) - } -} - -func (w *HTMLWriter) WriteString(s string) { - if _, err := io.WriteString(w.w, s); err != nil { - log.Fatalf("%v", err) - } -} - -func valueHTML(v Node) string { - if v == nil { - return "<nil>" - } - // TODO: Using the value ID as the class ignores the fact - // that value IDs get recycled and that some values - // are transmuted into other values. - class := fmt.Sprintf("t%d", v.ID()) - var label string - switch v := v.(type) { - case *Function: - label = v.RelString(nil) - case *Builtin: - label = v.Name() - default: - label = class - } - return fmt.Sprintf("%s", class, label) -} - -func valueLongHTML(v Node) string { - // TODO: Any intra-value formatting? - // I'm wary of adding too much visual noise, - // but a little bit might be valuable. - // We already have visual noise in the form of punctuation - // maybe we could replace some of that with formatting. - var s strings.Builder - s.WriteString(fmt.Sprintf("", v.ID())) - - linenumber := "(?)" - if v.Pos().IsValid() { - line := v.Parent().Prog.Fset.Position(v.Pos()).Line - linenumber = fmt.Sprintf("(%d)", line, line) - } - - s.WriteString(fmt.Sprintf("%s %s = %s", valueHTML(v), linenumber, opName(v))) - - if v, ok := v.(Value); ok { - s.WriteString(" <" + html.EscapeString(v.Type().String()) + ">") - } - - switch v := v.(type) { - case *Parameter: - s.WriteString(fmt.Sprintf(" {%s}", html.EscapeString(v.name))) - case *BinOp: - s.WriteString(fmt.Sprintf(" {%s}", html.EscapeString(v.Op.String()))) - case *UnOp: - s.WriteString(fmt.Sprintf(" {%s}", html.EscapeString(v.Op.String()))) - case *Extract: - name := v.Tuple.Type().(*types.Tuple).At(v.Index).Name() - s.WriteString(fmt.Sprintf(" [%d] (%s)", v.Index, name)) - case *Field: - st := v.X.Type().Underlying().(*types.Struct) - // Be robust against a bad index. - name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() - } - s.WriteString(fmt.Sprintf(" [%d] (%s)", v.Field, name)) - case *FieldAddr: - st := deref(v.X.Type()).Underlying().(*types.Struct) - // Be robust against a bad index. - name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() - } - - s.WriteString(fmt.Sprintf(" [%d] (%s)", v.Field, name)) - case *Recv: - s.WriteString(fmt.Sprintf(" {%t}", v.CommaOk)) - case *Call: - if v.Common().IsInvoke() { - s.WriteString(fmt.Sprintf(" {%s}", html.EscapeString(v.Common().Method.FullName()))) - } - case *Const: - if v.Value == nil { - s.WriteString(" {<nil>}") - } else { - s.WriteString(fmt.Sprintf(" {%s}", html.EscapeString(v.Value.String()))) - } - case *Sigma: - s.WriteString(fmt.Sprintf(" [#%s]", v.From)) - } - for _, a := range v.Operands(nil) { - s.WriteString(fmt.Sprintf(" %s", valueHTML(*a))) - } - if v, ok := v.(Instruction); ok { - s.WriteString(fmt.Sprintf(" (%s)", v.Comment())) - } - - // OPT(dh): we're calling namedValues many times on the same function. - allNames := namedValues(v.Parent()) - var names []string - for name, values := range allNames { - for _, value := range values { - if v == value { - names = append(names, name.Name()) - break - } - } - } - if len(names) != 0 { - s.WriteString(" (" + strings.Join(names, ", ") + ")") - } - - s.WriteString("") - return s.String() -} - -func blockHTML(b *BasicBlock) string { - // TODO: Using the value ID as the class ignores the fact - // that value IDs get recycled and that some values - // are transmuted into other values. - s := html.EscapeString(b.String()) - return fmt.Sprintf("%s", s, s) -} - -func blockLongHTML(b *BasicBlock) string { - var kind string - var term Instruction - if len(b.Instrs) > 0 { - term = b.Control() - kind = opName(term) - } - // TODO: improve this for HTML? - var s strings.Builder - s.WriteString(fmt.Sprintf("%s", b.Index, kind)) - - if term != nil { - ops := term.Operands(nil) - if len(ops) > 0 { - var ss []string - for _, op := range ops { - ss = append(ss, valueHTML(*op)) - } - s.WriteString(" " + strings.Join(ss, ", ")) - } - } - if len(b.Succs) > 0 { - s.WriteString(" →") // right arrow - for _, c := range b.Succs { - s.WriteString(" " + blockHTML(c)) - } - } - return s.String() -} - -func funcHTML(f *Function, phase string, dot *dotWriter) string { - buf := new(bytes.Buffer) - if dot != nil { - dot.writeFuncSVG(buf, phase, f) - } - fmt.Fprint(buf, "") - p := htmlFuncPrinter{w: buf} - fprintFunc(p, f) - - // fprintFunc(&buf, f) // TODO: HTML, not text,
for line breaks, etc. - fmt.Fprint(buf, "
") - return buf.String() -} - -type htmlFuncPrinter struct { - w io.Writer -} - -func (p htmlFuncPrinter) startBlock(b *BasicBlock, reachable bool) { - var dead string - if !reachable { - dead = "dead-block" - } - fmt.Fprintf(p.w, "
    ", b, dead) - fmt.Fprintf(p.w, "
  • %s:", blockHTML(b)) - if len(b.Preds) > 0 { - io.WriteString(p.w, " ←") // left arrow - for _, pred := range b.Preds { - fmt.Fprintf(p.w, " %s", blockHTML(pred)) - } - } - if len(b.Instrs) > 0 { - io.WriteString(p.w, ``) - } - io.WriteString(p.w, "
  • ") - if len(b.Instrs) > 0 { // start list of values - io.WriteString(p.w, "
  • ") - io.WriteString(p.w, "
      ") - } -} - -func (p htmlFuncPrinter) endBlock(b *BasicBlock) { - if len(b.Instrs) > 0 { // end list of values - io.WriteString(p.w, "
    ") - io.WriteString(p.w, "
  • ") - } - io.WriteString(p.w, "
  • ") - fmt.Fprint(p.w, blockLongHTML(b)) - io.WriteString(p.w, "
  • ") - io.WriteString(p.w, "
") -} - -func (p htmlFuncPrinter) value(v Node, live bool) { - var dead string - if !live { - dead = "dead-value" - } - fmt.Fprintf(p.w, "
  • ", dead) - fmt.Fprint(p.w, valueLongHTML(v)) - io.WriteString(p.w, "
  • ") -} - -func (p htmlFuncPrinter) startDepCycle() { - fmt.Fprintln(p.w, "") -} - -func (p htmlFuncPrinter) endDepCycle() { - fmt.Fprintln(p.w, "") -} - -func (p htmlFuncPrinter) named(n string, vals []Value) { - fmt.Fprintf(p.w, "
  • name %s: ", n) - for _, val := range vals { - fmt.Fprintf(p.w, "%s ", valueHTML(val)) - } - fmt.Fprintf(p.w, "
  • ") -} - -type dotWriter struct { - path string - broken bool -} - -// newDotWriter returns non-nil value when mask is valid. -// dotWriter will generate SVGs only for the phases specified in the mask. -// mask can contain following patterns and combinations of them: -// * - all of them; -// x-y - x through y, inclusive; -// x,y - x and y, but not the passes between. -func newDotWriter() *dotWriter { - path, err := exec.LookPath("dot") - if err != nil { - fmt.Println(err) - return nil - } - return &dotWriter{path: path} -} - -func (d *dotWriter) writeFuncSVG(w io.Writer, phase string, f *Function) { - if d.broken { - return - } - cmd := exec.Command(d.path, "-Tsvg") - pipe, err := cmd.StdinPipe() - if err != nil { - d.broken = true - fmt.Println(err) - return - } - buf := new(bytes.Buffer) - cmd.Stdout = buf - bufErr := new(bytes.Buffer) - cmd.Stderr = bufErr - err = cmd.Start() - if err != nil { - d.broken = true - fmt.Println(err) - return - } - fmt.Fprint(pipe, `digraph "" { margin=0; size="4,40"; ranksep=.2; `) - id := strings.Replace(phase, " ", "-", -1) - fmt.Fprintf(pipe, `id="g_graph_%s";`, id) - fmt.Fprintf(pipe, `node [style=filled,fillcolor=white,fontsize=16,fontname="Menlo,Times,serif",margin="0.01,0.03"];`) - fmt.Fprintf(pipe, `edge [fontsize=16,fontname="Menlo,Times,serif"];`) - for _, b := range f.Blocks { - layout := "" - fmt.Fprintf(pipe, `%v [label="%v%s\n%v",id="graph_node_%v_%v"];`, b, b, layout, b.Control().String(), id, b) - } - indexOf := make([]int, len(f.Blocks)) - for i, b := range f.Blocks { - indexOf[b.Index] = i - } - - // XXX - /* - ponums := make([]int32, len(f.Blocks)) - _ = postorderWithNumbering(f, ponums) - isBackEdge := func(from, to int) bool { - return ponums[from] <= ponums[to] - } - */ - isBackEdge := func(from, to int) bool { return false } - - for _, b := range f.Blocks { - for i, s := range b.Succs { - style := "solid" - color := "black" - arrow := "vee" - if isBackEdge(b.Index, s.Index) { - color = "blue" - } - fmt.Fprintf(pipe, `%v -> %v [label=" %d ",style="%s",color="%s",arrowhead="%s"];`, b, s, i, style, color, arrow) - } - } - fmt.Fprint(pipe, "}") - pipe.Close() - err = cmd.Wait() - if err != nil { - d.broken = true - fmt.Printf("dot: %v\n%v\n", err, bufErr.String()) - return - } - - svgID := "svg_graph_" + id - fmt.Fprintf(w, `
    `, svgID, svgID) - // For now, an awful hack: edit the html as it passes through - // our fingers, finding ' 0 || len(targs) > 0 + if len(rtargs) > 0 { + // possibly generic method on generic type + obj = prog.canon.instantiateMethod(fn.object, rtargs, prog.ctxt) + } else { + // generic method on non-generic type + obj = fn.object // instantiation does not exist yet + } + if len(targs) > 0 { + // generic method + instSig, err := types.Instantiate(prog.ctxt, obj.Signature(), targs, false) + if err != nil { + panic(err) + } + instance, ok := instSig.(*types.Signature) + if !ok { + panic("Instantiate of a Signature returned a non-signature") + } + // Do not canonicalize generic methods, because the receiver is not + // part of a Signature's type identity. For example, + // (*G[int]).m[int] and (G[int]).n[int] may be identical types even + // though their receiver types differ. + sig = instance + } else { + // non-generic method on generic type + sig = obj.Signature() + } + } else { + // function, len(rtargs) == 0 && len(targs) > 0 + instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false) + if err != nil { + panic(err) + } + instance, ok := instSig.(*types.Signature) + if !ok { + panic("Instantiate of a Signature returned a non-signature") + } + obj = fn.object // instantiation does not exist yet + sig = prog.canon.Type(instance).(*types.Signature) + } + + // Choose strategy (instance or wrapper). + var ( + synthetic string + subst *subster + build buildFunc + ) + if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(slices.Concat(rtargs, targs)...) { + synthetic = fmt.Sprintf("instance of %s", fn.Name()) + if fn.syntax != nil { + subst = makeSubster(prog.ctxt, obj, fn.recvtypeparams, rtargs, fn.typeparams, targs) + build = (*builder).buildFromSyntax + } else { + build = (*builder).buildParamsOnly + } + } else { + synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name()) + build = (*builder).buildInstantiationWrapper + } + + name := fn.Name() + if len(targs) > 0 { + name = fmt.Sprintf("%s%s", name, targstr(targs)) // may not be unique + } + + /* generic instance or instantiation wrapper */ + ret := &Function{ + name: name, + object: obj, + Signature: sig, + Synthetic: synthetic, + syntax: fn.syntax, // \ + info: fn.info, // } empty for non-created packages + goversion: fn.goversion, // / + build: build, + topLevelOrigin: fn, + pos: obj.Pos(), + Pkg: nil, + Prog: fn.Prog, + recvtypeparams: fn.recvtypeparams, // share with origin + recvtypeargs: rtargs, + typeparams: fn.typeparams, // share with origin + typeargs: targs, + subst: subst, + } + return ret +} + +// isParameterized reports whether any of the specified types contains +// a free type parameter. It is safe to call concurrently. +func (prog *Program) isParameterized(ts ...types.Type) bool { + prog.hasParamsMu.Lock() + defer prog.hasParamsMu.Unlock() + + // TODO(adonovan): profile. If this operation is expensive, + // handle the most common but shallow cases such as T, pkg.T, + // *T without consulting the cache under the lock. + + return slices.ContainsFunc(ts, prog.hasParams.Has) +} diff --git a/vendor/honnef.co/go/tools/go/ir/irutil/load.go b/vendor/honnef.co/go/tools/go/ir/irutil/load.go index bbf0e271..49eaa722 100644 --- a/vendor/honnef.co/go/tools/go/ir/irutil/load.go +++ b/vendor/honnef.co/go/tools/go/ir/irutil/load.go @@ -13,16 +13,9 @@ import ( "honnef.co/go/tools/go/ir" - //lint:ignore SA1019 go/loader is deprecated, but works fine for our tests - "golang.org/x/tools/go/loader" "golang.org/x/tools/go/packages" ) -type Options struct { - // Which function, if any, to print in HTML form - PrintFunc string -} - // Packages creates an IR program for a set of packages. // // The packages must have been loaded from source syntax using the @@ -40,8 +33,26 @@ type Options struct { // packages with well-typed syntax trees. // // The mode parameter controls diagnostics and checking during IR construction. -func Packages(initial []*packages.Package, mode ir.BuilderMode, opts *Options) (*ir.Program, []*ir.Package) { - return doPackages(initial, mode, false, opts) +func Packages(initial []*packages.Package, mode ir.BuilderMode) (*ir.Program, []*ir.Package) { + // TODO(adonovan): opt: this calls CreatePackage far more than + // necessary: for all dependencies, not just the (non-initial) + // direct dependencies of the initial packages. + // + // But can it reasonably be changed without breaking the + // spirit and/or letter of the law above? Clients may notice + // if we call CreatePackage less, as methods like + // Program.FuncValue will return nil. Or must we provide a new + // function (and perhaps deprecate this one)? Is it worth it? + // + // Tim King makes the interesting point that it would be + // possible to entirely alleviate the client from the burden + // of calling CreatePackage for non-syntax packages, if we + // were to treat vars and funcs lazily in the same way we now + // treat methods. (In essence, try to move away from the + // notion of ir.Packages, and make the Program answer + // all reasonable questions about any types.Object.) + + return doPackages(initial, mode, false) } // AllPackages creates an IR program for a set of packages plus all @@ -61,21 +72,17 @@ func Packages(initial []*packages.Package, mode ir.BuilderMode, opts *Options) ( // well-typed syntax trees. // // The mode parameter controls diagnostics and checking during IR construction. -func AllPackages(initial []*packages.Package, mode ir.BuilderMode, opts *Options) (*ir.Program, []*ir.Package) { - return doPackages(initial, mode, true, opts) +func AllPackages(initial []*packages.Package, mode ir.BuilderMode) (*ir.Program, []*ir.Package) { + return doPackages(initial, mode, true) } -func doPackages(initial []*packages.Package, mode ir.BuilderMode, deps bool, opts *Options) (*ir.Program, []*ir.Package) { - +func doPackages(initial []*packages.Package, mode ir.BuilderMode, deps bool) (*ir.Program, []*ir.Package) { var fset *token.FileSet if len(initial) > 0 { fset = initial[0].Fset } prog := ir.NewProgram(fset, mode) - if opts != nil { - prog.PrintFunc = opts.PrintFunc - } isInitial := make(map[*packages.Package]bool, len(initial)) for _, p := range initial { @@ -86,10 +93,12 @@ func doPackages(initial []*packages.Package, mode ir.BuilderMode, deps bool, opt packages.Visit(initial, nil, func(p *packages.Package) { if p.Types != nil && !p.IllTyped { var files []*ast.File + var info *types.Info if deps || isInitial[p] { files = p.Syntax + info = p.TypesInfo } - irmap[p] = prog.CreatePackage(p.Types, files, p.TypesInfo, true) + irmap[p] = prog.CreatePackage(p.Types, files, info, true) } }) @@ -100,30 +109,8 @@ func doPackages(initial []*packages.Package, mode ir.BuilderMode, deps bool, opt return prog, irpkgs } -// CreateProgram returns a new program in IR form, given a program -// loaded from source. An IR package is created for each transitively -// error-free package of lprog. -// -// Code for bodies of functions is not built until Build is called -// on the result. -// -// The mode parameter controls diagnostics and checking during IR construction. -// -// Deprecated: use golang.org/x/tools/go/packages and the Packages -// function instead; see ir.ExampleLoadPackages. -func CreateProgram(lprog *loader.Program, mode ir.BuilderMode) *ir.Program { - prog := ir.NewProgram(lprog.Fset, mode) - - for _, info := range lprog.AllPackages { - if info.TransitivelyErrorFree { - prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable) - } - } - - return prog -} - -// BuildPackage builds an IR program with IR for a single package. +// BuildPackage builds an IR program with IR intermediate +// representation (IR) for all functions of a single package. // // It populates pkg by type-checking the specified file ASTs. All // dependencies are loaded using the importer specified by tc, which @@ -176,6 +163,25 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil } createAll(pkg.Imports()) + // TODO(adonovan): we could replace createAll with just: + // + // // Create IR packages for all imports. + // for _, p := range pkg.Imports() { + // prog.CreatePackage(p, nil, nil, true) + // } + // + // (with minor changes to changes to ../builder_test.go as + // shown in CL 511715 PS 10.) But this would strictly violate + // the letter of the doc comment above, which says "all + // dependencies created". + // + // Tim makes the good point with some extra work we could + // remove the need for any CreatePackage calls except the + // ones with syntax (i.e. primary packages). Of course + // You wouldn't have ir.Packages and Members for as + // many things but no-one really uses that anyway. + // I wish I had done this from the outset. + // Create and build the primary package. irpkg := prog.CreatePackage(pkg, files, info, false) irpkg.Build() diff --git a/vendor/honnef.co/go/tools/go/ir/irutil/stub.go b/vendor/honnef.co/go/tools/go/ir/irutil/stub.go index 4311c7db..a686ede6 100644 --- a/vendor/honnef.co/go/tools/go/ir/irutil/stub.go +++ b/vendor/honnef.co/go/tools/go/ir/irutil/stub.go @@ -6,22 +6,87 @@ import ( // IsStub reports whether a function is a stub. A function is // considered a stub if it has no instructions or if all it does is -// return a constant value. +// return a fixed value (either an actual constant or a new allocation). func IsStub(fn *ir.Function) bool { + if fn.Source() == nil { + // External functions have to be assumed to not be stubs. + return false + } + for _, b := range fn.Blocks { for _, instr := range b.Instrs { switch instr.(type) { - case *ir.Const: - // const naturally has no side-effects case *ir.Panic: // panic is a stub if it only uses constants case *ir.Return: // return is a stub if it only uses constants - case *ir.DebugRef: case *ir.Jump: // if there are no disallowed instructions, then we're // only jumping to the exit block (or possibly // somewhere else that's stubby?) + case *ir.MakeInterface: + // this can only be wrapping Const and HeapAlloc, which is fine. + case *ir.Alloc: + // allocating is fine as long as all we do with the allocation + // is return it (possibly in an interface value) + default: + // all other instructions are assumed to do actual work + return false + } + } + } + return true +} + +// IsTrivial reports whether a function is trivial. A function is +// considered trivial if it is a stub, only returns a global variable, or calls +// another trivial function. +func IsTrivial(fn *ir.Function) bool { + return isTrivial(fn, nil) +} + +func isTrivial(fn *ir.Function, seen map[*ir.Function]struct{}) bool { + if fn.Source() == nil { + // External functions have to be assumed to be nontrivial. + return false + } + + if _, ok := seen[fn]; ok { + // Mutual recursion is not trivial + return false + } + + // We delay adding to seen until a call, to avoid creating garbage in the + // common case. + for _, b := range fn.Blocks { + for _, instr := range b.Instrs { + switch instr := instr.(type) { + case *ir.Panic: + // panic is a stub if it only uses constants + case *ir.Return: + // return is a stub if it only uses constants + case *ir.Jump: + // if there are no disallowed instructions, then we're + // only jumping to the exit block (or possibly + // somewhere else that's stubby?) + case *ir.MakeInterface: + // this can only be wrapping allowed instructions + case *ir.Alloc: + // allocating is fine as long as all we do with the allocation + // is return it (possibly in an interface value) + case *ir.Load: + if _, ok := instr.X.(*ir.Global); !ok { + return false + } + case *ir.Call: + if seen == nil { + seen = make(map[*ir.Function]struct{}) + } + seen[fn] = struct{}{} + callee := instr.Call.StaticCallee() + if callee == nil || !isTrivial(callee, seen) { + return false + } default: // all other instructions are assumed to do actual work return false diff --git a/vendor/honnef.co/go/tools/go/ir/irutil/switch.go b/vendor/honnef.co/go/tools/go/ir/irutil/switch.go index afe899d8..cf7c54e4 100644 --- a/vendor/honnef.co/go/tools/go/ir/irutil/switch.go +++ b/vendor/honnef.co/go/tools/go/ir/irutil/switch.go @@ -129,20 +129,10 @@ func Switches(fn *ir.Function) []Switch { return switches } -func isSameX(x1 ir.Value, x2 ir.Value) bool { - if x1 == x2 { - return true - } - if x2, ok := x2.(*ir.Sigma); ok { - return isSameX(x1, x2.X) - } - return false -} - func valueSwitch(sw *Switch, k *ir.Const, seen map[*ir.BasicBlock]bool) { b := sw.Start x := sw.X - for isSameX(sw.X, x) { + for sw.X == x { if seen[b] { break } @@ -159,13 +149,13 @@ func valueSwitch(sw *Switch, k *ir.Const, seen map[*ir.BasicBlock]bool) { switch instr.(type) { case *ir.If, *ir.BinOp: n++ - case *ir.Sigma, *ir.Phi, *ir.DebugRef: + case *ir.Phi: default: n += 1000 } } if n != 2 { - // Block b contains not just 'if x == k' and σ/ϕ nodes, + // Block b contains not just 'if x == k' and ϕ nodes, // so it may have side effects that // make it unsafe to elide. break @@ -183,7 +173,7 @@ func valueSwitch(sw *Switch, k *ir.Const, seen map[*ir.BasicBlock]bool) { func typeSwitch(sw *Switch, y ir.Value, T types.Type, seen map[*ir.BasicBlock]bool) { b := sw.Start x := sw.X - for isSameX(sw.X, x) { + for sw.X == x { if seen[b] { break } @@ -201,7 +191,7 @@ func typeSwitch(sw *Switch, y ir.Value, T types.Type, seen map[*ir.BasicBlock]bo switch instr.(type) { case *ir.TypeAssert, *ir.Extract, *ir.If: n++ - case *ir.Sigma, *ir.Phi: + case *ir.Phi: default: n += 1000 } diff --git a/vendor/honnef.co/go/tools/go/ir/irutil/util.go b/vendor/honnef.co/go/tools/go/ir/irutil/util.go index 9fed28bb..c8b980b3 100644 --- a/vendor/honnef.co/go/tools/go/ir/irutil/util.go +++ b/vendor/honnef.co/go/tools/go/ir/irutil/util.go @@ -47,42 +47,31 @@ func Walk(b *ir.BasicBlock, fn func(*ir.BasicBlock) bool) { func Vararg(x *ir.Slice) ([]ir.Value, bool) { var out []ir.Value - alloc, ok := ir.Unwrap(x.X).(*ir.Alloc) + alloc, ok := x.X.(*ir.Alloc) if !ok { return nil, false } - var checkAlloc func(alloc ir.Value) bool - checkAlloc = func(alloc ir.Value) bool { - for _, ref := range *alloc.Referrers() { - if ref == x { - continue - } - if ref.Block() != x.Block() { - return false + for _, ref := range *alloc.Referrers() { + if ref == x { + continue + } + if ref.Block() != x.Block() { + return nil, false + } + switch ref := ref.(type) { + case *ir.IndexAddr: + idx := ref + if len(*idx.Referrers()) != 1 { + return nil, false } - switch ref := ref.(type) { - case *ir.IndexAddr: - idx := ref - if len(*idx.Referrers()) != 1 { - return false - } - store, ok := (*idx.Referrers())[0].(*ir.Store) - if !ok { - return false - } - out = append(out, store.Val) - case *ir.Copy: - if !checkAlloc(ref) { - return false - } - default: - return false + store, ok := (*idx.Referrers())[0].(*ir.Store) + if !ok { + return nil, false } + out = append(out, store.Val) + default: + return nil, false } - return true - } - if !checkAlloc(alloc) { - return nil, false } return out, true } @@ -111,16 +100,6 @@ func IsCallToAny(call *ir.CallCommon, names ...string) bool { return slices.Contains(names, q) } -func FilterDebug(instr []ir.Instruction) []ir.Instruction { - var out []ir.Instruction - for _, ins := range instr { - if _, ok := ins.(*ir.DebugRef); !ok { - out = append(out, ins) - } - } - return out -} - func IsExample(fn *ir.Function) bool { if !strings.HasPrefix(fn.Name(), "Example") { return false @@ -132,7 +111,7 @@ func IsExample(fn *ir.Function) bool { return strings.HasSuffix(f.Name(), "_test.go") } -// Flatten recursively returns the underlying value of an ir.Sigma or +// Flatten recursively returns the underlying value of an // ir.Phi node. If all edges in an ir.Phi node are the same (after // flattening), the flattened edge will get returned. If flattening is // not possible, nil is returned. @@ -151,8 +130,6 @@ func Flatten(v ir.Value) ir.Value { seen[v] = struct{}{} switch v := v.(type) { - case *ir.Sigma: - dfs(v.X) case *ir.Phi: for _, e := range v.Edges { dfs(e) diff --git a/vendor/honnef.co/go/tools/go/ir/irutil/visit.go b/vendor/honnef.co/go/tools/go/ir/irutil/visit.go index f2135dca..ef438a9a 100644 --- a/vendor/honnef.co/go/tools/go/ir/irutil/visit.go +++ b/vendor/honnef.co/go/tools/go/ir/irutil/visit.go @@ -2,9 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package irutil +package irutil // import "honnef.co/go/tools/go/ir/irutil" -import "honnef.co/go/tools/go/ir" +import ( + "go/ast" + "go/types" + + _ "unsafe" // for linkname hack + + "honnef.co/go/tools/go/ir" +) // This file defines utilities for visiting the IR of // a Program. @@ -18,50 +25,122 @@ import "honnef.co/go/tools/go/ir" // synthetic wrappers. // // Precondition: all packages are built. +// +// TODO(adonovan): this function is underspecified. It doesn't +// actually work like a linker, which computes reachability from main +// using something like go/callgraph/cha (without materializing the +// call graph). In fact, it treats all public functions and all +// methods of public non-parameterized types as roots, even though +// they may be unreachable--but only in packages created from syntax. +// +// I think we should deprecate AllFunctions function in favor of two +// clearly defined ones: +// +// 1. The first would efficiently compute CHA reachability from a set +// of main packages, making it suitable for a whole-program +// analysis context with InstantiateGenerics, in conjunction with +// Program.Build. +// +// 2. The second would return only the set of functions corresponding +// to source Func{Decl,Lit} syntax, like SrcFunctions in +// go/analysis/passes/buildssa; this is suitable for +// package-at-a-time (or handful of packages) context. +// ir.Package could easily expose it as a field. +// +// We could add them unexported for now and use them via the linkname hack. func AllFunctions(prog *ir.Program) map[*ir.Function]bool { - visit := visitor{ - prog: prog, - seen: make(map[*ir.Function]bool), + seen := make(map[*ir.Function]bool) + + var function func(fn *ir.Function) + function = func(fn *ir.Function) { + if !seen[fn] { + seen[fn] = true + var buf [10]*ir.Value // avoid alloc in common case + for _, b := range fn.Blocks { + for _, instr := range b.Instrs { + for _, op := range instr.Operands(buf[:0]) { + if fn, ok := (*op).(*ir.Function); ok { + function(fn) + } + } + } + } + } } - visit.program() - return visit.seen -} -type visitor struct { - prog *ir.Program - seen map[*ir.Function]bool -} + // TODO(adonovan): opt: provide a way to share a builder + // across a sequence of MethodValue calls. -func (visit *visitor) program() { - for _, pkg := range visit.prog.AllPackages() { - for _, mem := range pkg.Members { - if fn, ok := mem.(*ir.Function); ok { - visit.function(fn) + methodsOf := func(T types.Type) { + if !types.IsInterface(T) { + mset := prog.MethodSets.MethodSet(T) + for sel := range mset.Methods() { + // Skip generic methods. + if sel.Obj().(*types.Func).Signature().TypeParams() == nil { + function(prog.MethodValue(sel)) + } } } } - for _, T := range visit.prog.RuntimeTypes() { - mset := visit.prog.MethodSets.MethodSet(T) - for i, n := 0, mset.Len(); i < n; i++ { - visit.function(visit.prog.MethodValue(mset.At(i))) + + // Historically, Program.RuntimeTypes used to include the type + // of any exported member of a package loaded from syntax that + // has a non-parameterized type, plus all types + // reachable from that type using reflection, even though + // these runtime types may not be required for them. + // + // Rather than break existing programs that rely on + // AllFunctions visiting extra methods that are unreferenced + // by IR and unreachable via reflection, we moved the logic + // here, unprincipled though it is. + // (See doc comment for better ideas.) + // + // Nonetheless, after the move, we no longer visit every + // method of any type recursively reachable from T, only the + // methods of T and *T themselves, and we only apply this to + // named types T, and not to the type of every exported + // package member. + exportedTypeHack := func(t *ir.Type) { + if isSyntactic(t.Package()) && + ast.IsExported(t.Name()) && + !types.IsInterface(t.Type()) { + // Consider only named types. + // (Ignore aliases and unsafe.Pointer.) + if named, ok := t.Type().(*types.Named); ok { + // Skip generic types. + if named.TypeParams() == nil { + methodsOf(named) // T + methodsOf(types.NewPointer(named)) // *T + } + } } } -} -func (visit *visitor) function(fn *ir.Function) { - if !visit.seen[fn] { - visit.seen[fn] = true - var buf [10]*ir.Value // avoid alloc in common case - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - for _, op := range instr.Operands(buf[:0]) { - if fn, ok := (*op).(*ir.Function); ok { - visit.function(fn) - } - } + for _, pkg := range prog.AllPackages() { + for _, mem := range pkg.Members { + switch mem := mem.(type) { + case *ir.Function: + // Visit all package-level declared functions. + // + // (This may include generic functions, which is + // inconsistent with the treatment of methods: + // we skip both generic methods, + // and methods of generic types.) + function(mem) + + case *ir.Type: + exportedTypeHack(mem) } } } + + // Visit all methods of types for which runtime types were + // materialized, as they are reachable through reflection. + for _, T := range prog.RuntimeTypes() { + methodsOf(T) + } + + return seen } // MainPackages returns the subset of the specified packages @@ -76,3 +155,12 @@ func MainPackages(pkgs []*ir.Package) []*ir.Package { } return mains } + +// TODO(adonovan): propose a principled API for this. One possibility +// is a new field, Package.SrcFunctions []*Function, which would +// contain the list of SrcFunctions described in point 2 of the +// AllFunctions doc comment, or nil if the package is not from syntax. +// But perhaps overloading nil vs empty slice is too subtle. +// +//go:linkname isSyntactic honnef.co/go/tools/go/ir.isSyntactic +func isSyntactic(pkg *ir.Package) bool diff --git a/vendor/honnef.co/go/tools/go/ir/lift.go b/vendor/honnef.co/go/tools/go/ir/lift.go index c2da8774..61324b0c 100644 --- a/vendor/honnef.co/go/tools/go/ir/lift.go +++ b/vendor/honnef.co/go/tools/go/ir/lift.go @@ -7,7 +7,7 @@ package ir // This file defines the lifting pass which tries to "lift" Alloc // cells (new/local variables) into SSA registers, replacing loads // with the dominating stored value, eliminating loads and stores, and -// inserting φ- and σ-nodes as needed. +// inserting φ-nodes as needed. // Cited papers and resources: // @@ -43,7 +43,6 @@ package ir // Also see many other "TODO: opt" suggestions in the code. import ( - "encoding/binary" "fmt" "os" "slices" @@ -79,16 +78,8 @@ func (df domFrontier) add(u, v *BasicBlock) { // the DF -> IDF step. func (df domFrontier) build(fn *Function) { for _, b := range fn.Blocks { - preds := b.Preds[0:len(b.Preds):len(b.Preds)] - if b == fn.Exit { - for i, v := range fn.fakeExits.values { - if v { - preds = append(preds, fn.Blocks[i]) - } - } - } - if len(preds) >= 2 { - for _, p := range preds { + if len(b.Preds) >= 2 { + for _, p := range b.Preds { runner := p for runner != b.dom.idom { df.add(runner, b) @@ -105,42 +96,27 @@ func buildDomFrontier(fn *Function) domFrontier { return df } -type postDomFrontier BlockMap[[]*BasicBlock] - -func (rdf postDomFrontier) add(u, v *BasicBlock) { - rdf[u.Index] = append(rdf[u.Index], v) -} - -func (rdf postDomFrontier) build(fn *Function) { - for _, b := range fn.Blocks { - succs := b.Succs[0:len(b.Succs):len(b.Succs)] - if fn.fakeExits.Has(b) { - succs = append(succs, fn.Exit) +func removeInstr(refs []Instruction, instr Instruction) []Instruction { + s := refs + i := -1 + for j := range s { + if instr == s[j] { + i = j + break } - if len(succs) >= 2 { - for _, s := range succs { - runner := s - for runner != b.pdom.idom { - rdf.add(runner, b) - runner = runner.pdom.idom - } - } + } + if i == -1 { + return s + } + // Don't start copying elements until we find one to delete. + for j := i + 1; j < len(s); j++ { + if v := s[j]; v != instr { + s[i] = v + i++ } } -} - -func buildPostDomFrontier(fn *Function) postDomFrontier { - rdf := make(postDomFrontier, len(fn.Blocks)) - rdf.build(fn) - return rdf -} - -func removeInstr(refs []Instruction, instr Instruction) []Instruction { - return removeInstrsIf(refs, func(i Instruction) bool { return i == instr }) -} - -func removeInstrsIf(refs []Instruction, p func(Instruction) bool) []Instruction { - return slices.DeleteFunc(refs, p) + clear(s[i:]) // zero/nil out the obsolete elements, for GC + return s[:i] } func clearInstrs(instrs []Instruction) { @@ -163,8 +139,8 @@ func numberNodesPerBlock(f *Function) { } // lift replaces local and new Allocs accessed only with -// load/store by IR registers, inserting φ- and σ-nodes where necessary. -// The result is a program in pruned SSI form. +// load/store by IR registers, inserting φ-nodes where necessary. +// The result is a program in pruned SSA form. // // Preconditions: // - fn has no dead blocks (blockopt has run). @@ -190,10 +166,7 @@ func lift(fn *Function) bool { // // But we will start with the simplest correct code. var df domFrontier - var rdf postDomFrontier - var closure *closure var newPhis BlockMap[[]newPhi] - var newSigmas BlockMap[[]newSigma] // During this pass we will replace some BasicBlock.Instrs // (allocs, loads and stores) with nil, keeping a count in @@ -221,6 +194,19 @@ func lift(fn *Function) bool { // Number nodes, for liftable numberNodesPerBlock(fn) + heads := make(BlockMap[int], len(fn.Blocks)) + for i := range heads { + heads[i] = -1 + } + for _, b := range fn.Blocks { + for i, instr := range b.Instrs { + if _, ok := instr.(*Phi); !ok { + heads[b.Index] = i + break + } + } + } + for _, b := range fn.Blocks { b.gaps = 0 b.rundefers = 0 @@ -228,19 +214,14 @@ func lift(fn *Function) bool { for _, instr := range b.Instrs { switch instr := instr.(type) { case *Alloc: - if !liftable(instr, instructions) { + if !liftable(instr, instructions, heads) { instr.index = -1 continue } if numAllocs == 0 { df = buildDomFrontier(fn) - rdf = buildPostDomFrontier(fn) - if len(fn.Blocks) > 2 { - closure = transitiveClosure(fn) - } newPhis = make(BlockMap[[]newPhi], len(fn.Blocks)) - newSigmas = make(BlockMap[[]newSigma], len(fn.Blocks)) if debugLifting { title := false @@ -261,11 +242,11 @@ func lift(fn *Function) bool { usesDefer = true if eliminateDeferStack { // Clear _DeferStack and remove references to loads - if instr._DeferStack != nil { - if refs := instr._DeferStack.Referrers(); refs != nil { + if instr.DeferStack != nil { + if refs := instr.DeferStack.Referrers(); refs != nil { *refs = removeInstr(*refs, instr) } - instr._DeferStack = nil + instr.DeferStack = nil } } case *RunDefers: @@ -303,7 +284,7 @@ func lift(fn *Function) bool { for _, b := range fn.Blocks { for _, instr := range b.Instrs { if instr, ok := instr.(*Alloc); ok && instr.index >= 0 { - liftAlloc(closure, df, rdf, instr, newPhis, newSigmas) + liftAlloc(df, instr, newPhis) } } } @@ -316,12 +297,12 @@ func lift(fn *Function) bool { renaming := make([]Value, numAllocs) // Renaming. - rename(fn.Blocks[0], renaming, newPhis, newSigmas) + rename(fn.Blocks[0], renaming, newPhis) - simplifyPhisAndSigmas(newPhis, newSigmas) + simplifyPhis(newPhis) - // Eliminate dead φ- and σ-nodes. - markLiveNodes(fn.Blocks, newPhis, newSigmas) + // Eliminate dead φ-nodes. + markLiveNodes(fn.Blocks, newPhis) // Eliminate ssa:deferstack() call. if eliminateDeferStack { @@ -342,23 +323,6 @@ func lift(fn *Function) bool { if numAllocs > 0 { nps := newPhis[b.Index] head = make([]Instruction, 0, len(nps)) - for _, pred := range b.Preds { - nss := newSigmas[pred.Index] - idx := pred.succIndex(b) - for _, newSigma := range nss { - if sigma := newSigma.sigmas[idx]; sigma != nil && sigma.live { - head = append(head, sigma) - - // we didn't populate referrers before, as most - // sigma nodes will be killed - if refs := sigma.X.Referrers(); refs != nil { - *refs = append(*refs, sigma) - } - } else if sigma != nil { - sigma.block = nil - } - } - } for _, np := range nps { if np.phi.live { head = append(head, np.phi) @@ -388,7 +352,7 @@ func lift(fn *Function) bool { // that seems to only be the case ~1% of the time, which // doesn't seem worth the extra branch. - // Remove dead instructions, add phis and sigmas + // Remove dead instructions, add phis ns := len(b.Instrs) + j - b.gaps - rundefersToKill if ns <= cap(b.Instrs) { // b.Instrs has enough capacity to store all instructions @@ -458,21 +422,17 @@ func lift(fn *Function) bool { func hasDirectReferrer(instr Instruction) bool { for _, instr := range *instr.Referrers() { - switch instr.(type) { - case *Phi, *Sigma: - // ignore - default: + if _, ok := instr.(*Phi); !ok { return true } } return false } -func markLiveNodes(blocks []*BasicBlock, newPhis BlockMap[[]newPhi], newSigmas BlockMap[[]newSigma]) { - // Phis and sigmas may become dead due to optimization passes. We may also insert more nodes than strictly - // necessary, e.g. sigma nodes for constants, which will never be used. +func markLiveNodes(blocks []*BasicBlock, newPhis BlockMap[[]newPhi]) { + // Phis may become dead due to optimization passes. - // Phi and sigma nodes are considered live if a non-phi, non-sigma + // Phi nodes are considered live if a non-phi // node uses them. Once we find a node that is live, we mark all // of its operands as used, too. for _, npList := range newPhis { @@ -483,15 +443,6 @@ func markLiveNodes(blocks []*BasicBlock, newPhis BlockMap[[]newPhi], newSigmas B } } } - for _, npList := range newSigmas { - for _, np := range npList { - for _, sigma := range np.sigmas { - if sigma != nil && !sigma.live && hasDirectReferrer(sigma) { - markLiveSigma(sigma) - } - } - } - } // Existing φ-nodes due to && and || operators // are all considered live (see Go issue 19622). for _, b := range blocks { @@ -504,48 +455,18 @@ func markLiveNodes(blocks []*BasicBlock, newPhis BlockMap[[]newPhi], newSigmas B func markLivePhi(phi *Phi) { phi.live = true for _, rand := range phi.Edges { - switch rand := rand.(type) { - case *Phi: + if rand, ok := rand.(*Phi); ok { if !rand.live { markLivePhi(rand) } - case *Sigma: - if !rand.live { - markLiveSigma(rand) - } } } } -func markLiveSigma(sigma *Sigma) { - sigma.live = true - switch rand := sigma.X.(type) { - case *Phi: - if !rand.live { - markLivePhi(rand) - } - case *Sigma: - if !rand.live { - markLiveSigma(rand) - } - } -} - -// simplifyPhisAndSigmas removes duplicate phi and sigma nodes, -// and replaces trivial phis with non-phi alternatives. Phi +// simplifyPhis replaces trivial phis with non-phi alternatives. Phi // nodes where all edges are identical, or consist of only the phi // itself and one other value, may be replaced with the value. -func simplifyPhisAndSigmas(newPhis BlockMap[[]newPhi], newSigmas BlockMap[[]newSigma]) { - // temporary numbering of values used in phis so that we can build map keys - var id ID - for _, npList := range newPhis { - for _, np := range npList { - for _, edge := range np.phi.Edges { - edge.setID(id) - id++ - } - } - } +func simplifyPhis(newPhis BlockMap[[]newPhi]) { // find all phis that are trivial and can be replaced with a // non-phi value. run until we reach a fixpoint, because replacing // a phi may make other phis trivial. @@ -554,7 +475,7 @@ func simplifyPhisAndSigmas(newPhis BlockMap[[]newPhi], newSigmas BlockMap[[]newS for _, npList := range newPhis { for _, np := range npList { if np.phi.live { - // we're reusing 'live' to mean 'dead' in the context of simplifyPhisAndSigmas + // we're reusing 'live' to mean 'dead' in the context of simplifyPhis continue } if r, ok := isUselessPhi(np.phi); ok { @@ -567,84 +488,6 @@ func simplifyPhisAndSigmas(newPhis BlockMap[[]newPhi], newSigmas BlockMap[[]newS } } } - - // Replace duplicate sigma nodes with a single node. These nodes exist when multiple allocs get replaced with the - // same dominating store. - for _, sigmaList := range newSigmas { - primarySigmas := map[struct { - succ int - v Value - }]*Sigma{} - for _, sigmas := range sigmaList { - for succ, sigma := range sigmas.sigmas { - if sigma == nil { - continue - } - if sigma.live { - // we're reusing 'live' to mean 'dead' in the context of simplifyPhisAndSigmas - continue - } - key := struct { - succ int - v Value - }{succ, sigma.X} - if alt, ok := primarySigmas[key]; ok { - replaceAll(sigma, alt) - sigma.live = true - changed = true - } else { - primarySigmas[key] = sigma - } - } - } - } - - // Replace duplicate phi nodes with a single node. As far as we know, these duplicate nodes only ever exist - // because of the previous sigma deduplication. - keyb := make([]byte, 0, 4*8) - for _, npList := range newPhis { - primaryPhis := map[string]*Phi{} - for _, np := range npList { - if np.phi.live { - continue - } - if n := len(np.phi.Edges) * 8; cap(keyb) >= n { - keyb = keyb[:n] - } else { - keyb = make([]byte, n, n*2) - } - for i, e := range np.phi.Edges { - binary.LittleEndian.PutUint64(keyb[i*8:i*8+8], uint64(e.ID())) - } - if alt, ok := primaryPhis[string(keyb)]; ok { - replaceAll(np.phi, alt) - np.phi.live = true - changed = true - } else { - primaryPhis[string(keyb)] = np.phi - } - } - } - - } - - for _, npList := range newPhis { - for _, np := range npList { - np.phi.live = false - for _, edge := range np.phi.Edges { - edge.setID(0) - } - } - } - - for _, sigmaList := range newSigmas { - for _, sigmas := range sigmaList { - for _, sigma := range sigmas.sigmas { - if sigma != nil { - sigma.live = false - } - } - } } } @@ -724,109 +567,6 @@ func (s *BlockSet) Take() int { return -1 } -type closure struct { - span []uint32 - reachables BlockMap[interval] -} - -type interval uint32 - -const ( - flagMask = 1 << 31 - numBits = 20 - lengthBits = 32 - numBits - 1 - lengthMask = (1<>numBits - } else { - // large interval - i++ - start = uint32(inv & numMask) - end = uint32(r[i]) - } - if idx >= start && idx <= end { - return true - } - } - return false -} - -func (c closure) reachable(id int) []interval { - return c.reachables[c.span[id]:c.span[id+1]] -} - -func (c closure) walk(current *BasicBlock, b *BasicBlock, visited []bool) { - // TODO(dh): the 'current' argument seems to be unused - // TODO(dh): there's no reason for this to be a method - visited[b.Index] = true - for _, succ := range b.Succs { - if visited[succ.Index] { - continue - } - visited[succ.Index] = true - c.walk(current, succ, visited) - } -} - -func transitiveClosure(fn *Function) *closure { - reachable := make(BlockMap[bool], len(fn.Blocks)) - c := &closure{} - c.span = make([]uint32, len(fn.Blocks)+1) - - addInterval := func(start, end uint32) { - if l := end - start; l <= 1<= 0 { // store of zero to Alloc cell - // Replace dominated loads by the zero value. - renaming[instr.index] = nil - if debugLifting { - fmt.Fprintf(os.Stderr, "\tkill alloc %s\n", instr) - } - // Delete the Alloc. - u.Instrs[i] = nil - u.gaps++ - } + worklist := []worklistEntry{{u_, renaming_}} + var freelist [][]Value - case *Store: - if alloc, ok := instr.Addr.(*Alloc); ok && alloc.index >= 0 { // store to Alloc cell - // Replace dominated loads by the stored value. - renaming[alloc.index] = instr.Val - if debugLifting { - fmt.Fprintf(os.Stderr, "\tkill store %s; new value: %s\n", - instr, instr.Val.Name()) - } - if refs := instr.Addr.Referrers(); refs != nil { - *refs = removeInstr(*refs, instr) - } - if refs := instr.Val.Referrers(); refs != nil { - *refs = removeInstr(*refs, instr) - } - // Delete the Store. - u.Instrs[i] = nil - u.gaps++ - } + for len(worklist) > 0 { + entry := worklist[len(worklist)-1] + worklist = worklist[:len(worklist)-1] + u, renaming := entry.u, entry.renaming - case *Load: - if alloc, ok := instr.X.(*Alloc); ok && alloc.index >= 0 { // load of Alloc cell - // In theory, we wouldn't be able to replace loads directly, because a loaded value could be used in - // different branches, in which case it should be replaced with different sigma nodes. But we can't - // simply defer replacement, either, because then later stores might incorrectly affect this load. - // - // To avoid doing renaming on _all_ values (instead of just loads and stores like we're doing), we make - // sure during code generation that each load is only used in one block. For example, in constant switch - // statements, where the tag is only evaluated once, we store it in a temporary and load it for each - // comparison, so that we have individual loads to replace. - // - // Because we only rename stores and loads, the end result will not contain sigma nodes for all - // constants. Some constants may be used directly, e.g. in comparisons such as 'x == 5'. We may still - // end up inserting dead sigma nodes in branches, but these will never get used in renaming and will be - // cleaned up when we remove dead phis and sigmas. - newval := renamed(u.Parent(), renaming, alloc) - if debugLifting { - fmt.Fprintf(os.Stderr, "\tupdate load %s = %s with %s\n", - instr.Name(), instr, newval) - } - replaceAll(instr, newval) - u.Instrs[i] = nil - u.gaps++ - } + // Each φ-node becomes the new name for its associated Alloc. + for _, np := range newPhis[u.Index] { + phi := np.phi + alloc := np.alloc + renaming[alloc.index] = phi + } - case *DebugRef: - if x, ok := instr.X.(*Alloc); ok && x.index >= 0 { - if instr.IsAddr { - instr.X = renamed(u.Parent(), renaming, x) - instr.IsAddr = false + // Rename loads and stores of allocs. + for i, instr := range u.Instrs { + switch instr := instr.(type) { + case *Alloc: + if instr.index >= 0 { // store of zero to Alloc cell + // Replace dominated loads by the zero value. + renaming[instr.index] = nil + if debugLifting { + fmt.Fprintf(os.Stderr, "\tkill alloc %s\n", instr) + } + // Delete the Alloc. + u.Instrs[i] = nil + u.gaps++ + } - // Add DebugRef to instr.X's referrers. - if refs := instr.X.Referrers(); refs != nil { - *refs = append(*refs, instr) + case *Store: + if alloc, ok := instr.Addr.(*Alloc); ok && alloc.index >= 0 { // store to Alloc cell + // Replace dominated loads by the stored value. + renaming[alloc.index] = instr.Val + if debugLifting { + fmt.Fprintf(os.Stderr, "\tkill store %s; new value: %s\n", + instr, instr.Val.Name()) } - } else { - // A source expression denotes the address - // of an Alloc that was optimized away. - instr.X = nil + if refs := instr.Addr.Referrers(); refs != nil { + *refs = removeInstr(*refs, instr) + } + if refs := instr.Val.Referrers(); refs != nil { + *refs = removeInstr(*refs, instr) + } + // Delete the Store. + u.Instrs[i] = nil + u.gaps++ + } - // Delete the DebugRef. + case *Load: + if alloc, ok := instr.X.(*Alloc); ok && alloc.index >= 0 { // load of Alloc cell + newval := renamed(u.Parent(), renaming, alloc) + if debugLifting { + fmt.Fprintf(os.Stderr, "\tupdate load %s = %s with %s\n", + instr.Name(), instr, newval) + } + // Replace all references to the loaded value by the dominating + // stored value. + replaceAll(instr, newval) u.Instrs[i] = nil u.gaps++ } + + case *debugRef: + if x, ok := instr.X.(*Alloc); ok && x.index >= 0 { + if instr.IsAddr { + instr.X = renamed(u.Parent(), renaming, x) + instr.IsAddr = false + + // Add DebugRef to instr.X's referrers. + if refs := instr.X.Referrers(); refs != nil { + *refs = append(*refs, instr) + } + } else { + // A source expression denotes the address + // of an Alloc that was optimized away. + instr.X = nil + + // Delete the DebugRef. + u.Instrs[i] = nil + u.gaps++ + } + } } } - } - // update all outgoing sigma nodes with the dominating store - for _, sigmas := range newSigmas[u.Index] { - for _, sigma := range sigmas.sigmas { - if sigma == nil { + // For each φ-node in a CFG successor, rename the edge. + for _, v := range u.Succs { + phis := newPhis[v.Index] + if len(phis) == 0 { continue } - sigma.X = renamed(u.Parent(), renaming, sigmas.alloc) - } - } - - // For each φ-node in a CFG successor, rename the edge. - for succi, v := range u.Succs { - phis := newPhis[v.Index] - if len(phis) == 0 { - continue - } - i := v.predIndex(u) - for _, np := range phis { - phi := np.phi - alloc := np.alloc - // if there's a sigma node, use it, else use the dominating value - var newval Value - for _, sigmas := range newSigmas[u.Index] { - if sigmas.alloc == alloc && sigmas.sigmas[succi] != nil { - newval = sigmas.sigmas[succi] - break + i := v.predIndex(u) + for _, np := range phis { + phi := np.phi + alloc := np.alloc + newval := renamed(u.Parent(), renaming, alloc) + if debugLifting { + fmt.Fprintf(os.Stderr, "\tsetphi %s edge %s -> %s (#%d) (alloc=%s) := %s\n", + phi.Name(), u, v, i, alloc.Name(), newval.Name()) + } + phi.Edges[i] = newval + if prefs := newval.Referrers(); prefs != nil { + *prefs = append(*prefs, phi) } - } - if newval == nil { - newval = renamed(u.Parent(), renaming, alloc) - } - if debugLifting { - fmt.Fprintf(os.Stderr, "\tsetphi %s edge %s -> %s (#%d) (alloc=%s) := %s\n", - phi.Name(), u, v, i, alloc.Name(), newval.Name()) - } - phi.Edges[i] = newval - if prefs := newval.Referrers(); prefs != nil { - *prefs = append(*prefs, phi) } } - } - // Continue depth-first recursion over domtree, pushing a - // fresh copy of the renaming map for each subtree. - r := make([]Value, len(renaming)) - for _, v := range u.dom.children { - copy(r, renaming) - - // on entry to a block, the incoming sigma nodes become the new values for their alloc - if idx := u.succIndex(v); idx != -1 { - for _, sigma := range newSigmas[u.Index] { - if sigma.sigmas[idx] != nil { - r[sigma.alloc.index] = sigma.sigmas[idx] - } + // Continue depth-first recursion over domtree, pushing a + // fresh copy of the renaming map for each subtree. + for _, v := range slices.Backward(u.dom.children) { + var r []Value + if len(freelist) == 0 { + r = make([]Value, len(renaming)) + } else { + r = freelist[len(freelist)-1] + freelist = freelist[:len(freelist)-1] } + copy(r, renaming) + worklist = append(worklist, worklistEntry{v, r}) } - rename(v, r, newPhis, newSigmas) + freelist = append(freelist, renaming) } - } func simplifyConstantCompositeValues(fn *Function) bool { @@ -1772,7 +1216,7 @@ func simplifyConstantCompositeValues(fn *Function) bool { } } if replaced { - replaceAll(cv, emitConst(fn, ac)) + replaceAll(cv, ac) killInstruction(cv) } diff --git a/vendor/honnef.co/go/tools/go/ir/lvalue.go b/vendor/honnef.co/go/tools/go/ir/lvalue.go index 86eb4a5d..502293c8 100644 --- a/vendor/honnef.co/go/tools/go/ir/lvalue.go +++ b/vendor/honnef.co/go/tools/go/ir/lvalue.go @@ -24,7 +24,7 @@ type lvalue interface { // An address is an lvalue represented by a true pointer. type address struct { - addr Value + addr Value // must have a pointer core type. expr ast.Expr // source syntax of the value (not address) [debug mode] } diff --git a/vendor/honnef.co/go/tools/go/ir/methods.go b/vendor/honnef.co/go/tools/go/ir/methods.go index 082029da..9ad8e410 100644 --- a/vendor/honnef.co/go/tools/go/ir/methods.go +++ b/vendor/honnef.co/go/tools/go/ir/methods.go @@ -10,235 +10,168 @@ import ( "fmt" "go/types" - "honnef.co/go/tools/analysis/lint" + "golang.org/x/tools/go/types/typeutil" + "honnef.co/go/tools/internal/xtools-internal/typesinternal" ) // MethodValue returns the Function implementing method sel, building -// wrapper methods on demand. It returns nil if sel denotes an -// abstract (interface) method. +// wrapper methods on demand. It returns nil if sel denotes an +// interface or generic method. // // Precondition: sel.Kind() == MethodVal. // // Thread-safe. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) +// Acquires prog.methodsMu. func (prog *Program) MethodValue(sel *types.Selection) *Function { if sel.Kind() != types.MethodVal { panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel)) } T := sel.Recv() if types.IsInterface(T) { - return nil // abstract method + return nil // interface method or type parameter } + + if prog.isParameterized(T, sel.Type()) { + return nil // method on generic type or generic method + } + if prog.mode&LogSource != 0 { defer logStack("MethodValue %s %v", T, sel)() } - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - return prog.addMethod(prog.createMethodSet(T), sel) -} - -// LookupMethod returns the implementation of the method of type T -// identified by (pkg, name). It returns nil if the method exists but -// is abstract, and panics if T has no such method. -func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function { - sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name) - if sel == nil { - panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name))) - } - return prog.MethodValue(sel) -} + var b builder -// methodSet contains the (concrete) methods of a non-interface type. -type methodSet struct { - mapping map[string]*Function // populated lazily - complete bool // mapping contains all methods -} + m := func() *Function { + prog.methodsMu.Lock() + defer prog.methodsMu.Unlock() -// Precondition: !isInterface(T). -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) createMethodSet(T types.Type) *methodSet { - mset, ok := prog.methodSets.At(T) - if !ok { - mset = &methodSet{mapping: make(map[string]*Function)} - prog.methodSets.Set(T, mset) - } - return mset -} + // Get or create SSA method set. + mset, ok := prog.methodSets.At(T) + if !ok { + mset = &methodSet{mapping: make(map[string]*Function)} + prog.methodSets.Set(T, mset) + } -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function { - if sel.Kind() == types.MethodExpr { - panic(sel) - } - id := sel.Obj().Id() - fn := mset.mapping[id] - if fn == nil { - obj := sel.Obj().(*types.Func) - - needsPromotion := len(sel.Index()) > 1 - needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv()) - if needsPromotion || needsIndirection { - fn = makeWrapper(prog, sel) + // Get or create SSA method. + id := sel.Obj().Id() + fn, ok := mset.mapping[id] + if !ok { + obj := sel.Obj().(*types.Func) + needsPromotion := len(sel.Index()) > 1 + needsIndirection := !isPointer(recvType(obj)) && isPointer(T) + if needsPromotion || needsIndirection { + fn = createWrapper(prog, toSelection(sel), nil) + fn.buildshared = b.shared() + b.enqueue(fn) + } else { + fn = prog.objectMethod(obj, nil, &b) + } + if fn.Signature.Recv() == nil { + panic(fn) + } + mset.mapping[id] = fn } else { - fn = prog.declaredFunc(obj) - } - if fn.Signature.Recv() == nil { - panic(fn) // missing receiver + b.waitForSharedFunction(fn) } - mset.mapping[id] = fn - } - return fn -} -// RuntimeTypes returns a new unordered slice containing all -// concrete types in the program for which a complete (non-empty) -// method set is required at run-time. -// -// Thread-safe. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (prog *Program) RuntimeTypes() []types.Type { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() + return fn + }() - var res []types.Type - prog.methodSets.Iterate(func(T types.Type, v *methodSet) { - if v.complete { - res = append(res, T) - } - }) - return res -} + b.iterate() -// declaredFunc returns the concrete function/method denoted by obj. -// Panic ensues if there is none. -func (prog *Program) declaredFunc(obj *types.Func) *Function { - if origin := obj.Origin(); origin != obj { - // Calling method on instantiated type, create a wrapper that calls the generic type's method - base := prog.packageLevelValue(origin) - return makeInstance(prog, base.(*Function), obj.Type().(*types.Signature), nil) - } else { - if v := prog.packageLevelValue(obj); v != nil { - return v.(*Function) - } - } - panic("no concrete method: " + obj.String()) + return m } -// needMethodsOf ensures that runtime type information (including the -// complete method set) is available for the specified type T and all -// its subcomponents. -// -// needMethodsOf must be called for at least every type that is an -// operand of some MakeInterface instruction, and for the type of -// every exported package member. -// -// Precondition: T is not a method signature (*Signature with Recv()!=nil). +// objectMethod returns the Function for a given method symbol. +// The symbol may be an instance of a generic function. It need not +// belong to an existing SSA package created by a call to +// prog.CreatePackage. // -// Thread-safe. (Called via emitConv from multiple builder goroutines.) +// objectMethod panics if the function is not a method. // -// TODO(adonovan): make this faster. It accounts for 20% of SSA build time. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (prog *Program) needMethodsOf(T types.Type) { - prog.methodsMu.Lock() - prog.needMethods(T, false) - prog.methodsMu.Unlock() -} - -// Precondition: T is not a method signature (*Signature with Recv()!=nil). -// Recursive case: skip => don't create methods for T. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) needMethods(T types.Type, skip bool) { - // Each package maintains its own set of types it has visited. - if prevSkip, ok := prog.runtimeTypes.At(T); ok { - // needMethods(T) was previously called - if !prevSkip || skip { - return // already seen, with same or false 'skip' value - } - } - prog.runtimeTypes.Set(T, skip) - - tmset := prog.MethodSets.MethodSet(T) - - if !skip && !types.IsInterface(T) && tmset.Len() > 0 { - // Create methods of T. - mset := prog.createMethodSet(T) - if !mset.complete { - mset.complete = true - n := tmset.Len() - for i := range n { - prog.addMethod(mset, tmset.At(i)) - } - } +// Acquires prog.objectMethodsMu. +func (prog *Program) objectMethod(obj *types.Func, targs []types.Type, b *builder) *Function { + sig := obj.Type().(*types.Signature) + if sig.Recv() == nil { + panic("not a method: " + obj.String()) } - // Recursion over signatures of each method. - for method := range tmset.Methods() { - sig := method.Type().(*types.Signature) - prog.needMethods(sig.Params(), false) - prog.needMethods(sig.Results(), false) + // Instantiation of generic? + if orig := obj.Origin(); orig != obj || len(targs) > 0 { + return prog.objectMethod(orig, nil, b).instance(receiverTypeArgs(obj), targs, b) } - switch t := T.(type) { - case *types.Basic: - // nop - - case *types.Interface, *types.TypeParam: - // nop---handled by recursion over method set. - - case *types.Pointer: - prog.needMethods(t.Elem(), false) - - case *types.Slice: - prog.needMethods(t.Elem(), false) - - case *types.Chan: - prog.needMethods(t.Elem(), false) + // Belongs to a created package? + if fn := prog.FuncValue(obj); fn != nil { + return fn + } - case *types.Map: - prog.needMethods(t.Key(), false) - prog.needMethods(t.Elem(), false) + // Consult/update cache of methods created from types.Func. + prog.objectMethodsMu.Lock() + defer prog.objectMethodsMu.Unlock() + fn, ok := prog.objectMethods[obj] + if !ok { + fn = createFunction(prog, obj, obj.Name(), nil, nil, "") + fn.Synthetic = "from type information (on demand)" + fn.buildshared = b.shared() + b.enqueue(fn) - case *types.Signature: - if t.Recv() != nil { - panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv())) - } - prog.needMethods(t.Params(), false) - prog.needMethods(t.Results(), false) - - case *types.Named: - // A pointer-to-named type can be derived from a named - // type via reflection. It may have methods too. - prog.needMethods(types.NewPointer(t), false) - - // Consider 'type T struct{S}' where S has methods. - // Reflection provides no way to get from T to struct{S}, - // only to S, so the method set of struct{S} is unwanted, - // so set 'skip' flag during recursion. - prog.needMethods(t.Underlying(), true) - - case *types.Array: - prog.needMethods(t.Elem(), false) - - case *types.Struct: - for i, n := 0, t.NumFields(); i < n; i++ { - prog.needMethods(t.Field(i).Type(), false) + if prog.objectMethods == nil { + prog.objectMethods = make(map[*types.Func]*Function) } + prog.objectMethods[obj] = fn + } else { + b.waitForSharedFunction(fn) + } + return fn +} - case *types.Tuple: - for i, n := 0, t.Len(); i < n; i++ { - prog.needMethods(t.At(i).Type(), false) - } +// LookupMethod returns the implementation of the method of type T +// identified by (pkg, name). It returns nil if the method exists but +// is an interface method or generic method, and panics if T has no such method. +func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function { + sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name) + if sel == nil { + panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name))) + } + return prog.MethodValue(sel) +} - case *types.Alias: - prog.needMethods(types.Unalias(t), false) +// methodSet contains the (concrete) methods of a concrete type (non-interface, non-parameterized). +type methodSet struct { + mapping map[string]*Function // populated lazily +} - default: - lint.ExhaustiveTypeSwitch(T) +// RuntimeTypes returns a new unordered slice containing all types in +// the program for which a runtime type is required. +// +// A runtime type is required for any non-parameterized, non-interface +// type that is converted to an interface, or for any type (including +// interface types) derivable from one through reflection. +// +// The methods of such types may be reachable through reflection or +// interface calls even if they are never called directly. +// +// Thread-safe. +// +// Acquires prog.makeInterfaceTypesMu. +func (prog *Program) RuntimeTypes() []types.Type { + prog.makeInterfaceTypesMu.Lock() + defer prog.makeInterfaceTypesMu.Unlock() + + // Compute the derived types on demand, since many SSA clients + // never call RuntimeTypes, and those that do typically call + // it once (often within irutil.AllFunctions, which will + // eventually not use it; see Go issue #69291.) This + // eliminates the need to eagerly compute all the element + // types during SSA building. + var runtimeTypes []types.Type + add := func(t types.Type) { runtimeTypes = append(runtimeTypes, t) } + var set typeutil.Map // for de-duping identical types + for t := range prog.makeInterfaceTypes { + typesinternal.ForEachElement(&set, &prog.MethodSets, t, add) } + + return runtimeTypes } diff --git a/vendor/honnef.co/go/tools/go/ir/mode.go b/vendor/honnef.co/go/tools/go/ir/mode.go index 8a87a605..8f55bce0 100644 --- a/vendor/honnef.co/go/tools/go/ir/mode.go +++ b/vendor/honnef.co/go/tools/go/ir/mode.go @@ -20,26 +20,30 @@ import ( type BuilderMode uint const ( - PrintPackages BuilderMode = 1 << iota // Print package inventory to stdout - PrintFunctions // Print function IR code to stdout - PrintSource // Print source code when printing function IR - LogSource // Log source locations as IR builder progresses - SanityCheckFunctions // Perform sanity checking of function bodies - NaiveForm // Build naïve IR form: don't replace local loads/stores with registers - GlobalDebug // Enable debug info for all packages - SplitAfterNewInformation // Split live range after we learn something new about a value + PrintPackages BuilderMode = 1 << iota // Print package inventory to stdout + PrintFunctions // Print function IR code to stdout + PrintSource // Print source code when printing function IR + LogSource // Log source locations as IR builder progresses + SanityCheckFunctions // Perform sanity checking of function bodies + NaiveForm // Build naïve IR form: don't replace local loads/stores with registers + BuildSerially // Build packages serially, not in parallel. + GlobalDebug // Enable debug info for all packages + BareInits // Build init functions without guards or calls to dependent inits + InstantiateGenerics // Instantiate generics functions (monomorphize) while building ) const BuilderModeDoc = `Options controlling the IR builder. -The value is a sequence of zero or more of these symbols: +The value is a sequence of zero or more of these letters: C perform sanity [C]hecking of the IR form. D include [D]ebug info for every function. P print [P]ackage inventory. F print [F]unction IR code. A print [A]ST nodes responsible for IR instructions S log [S]ource locations as IR builder progresses. +L build distinct packages seria[L]ly instead of in parallel. N build [N]aive IR form: don't replace local loads/stores with registers. -I Split live range after a value is used as slice or array index +I build bare [I]nit functions: no init guards or calls to dependent inits. +G instantiate [G]eneric function bodies via monomorphization ` func (m BuilderMode) String() string { @@ -65,9 +69,15 @@ func (m BuilderMode) String() string { if m&NaiveForm != 0 { buf.WriteByte('N') } - if m&SplitAfterNewInformation != 0 { + if m&BuildSerially != 0 { + buf.WriteByte('L') + } + if m&BareInits != 0 { buf.WriteByte('I') } + if m&InstantiateGenerics != 0 { + buf.WriteByte('G') + } return buf.String() } @@ -85,13 +95,17 @@ func (m *BuilderMode) Set(s string) error { case 'A': mode |= PrintSource case 'S': - mode |= LogSource + mode |= LogSource | BuildSerially case 'C': mode |= SanityCheckFunctions case 'N': mode |= NaiveForm + case 'L': + mode |= BuildSerially case 'I': - mode |= SplitAfterNewInformation + mode |= BareInits + case 'G': + mode |= InstantiateGenerics default: return fmt.Errorf("unknown BuilderMode option: %q", c) } diff --git a/vendor/honnef.co/go/tools/go/ir/print.go b/vendor/honnef.co/go/tools/go/ir/print.go index f2468763..c71518ad 100644 --- a/vendor/honnef.co/go/tools/go/ir/print.go +++ b/vendor/honnef.co/go/tools/go/ir/print.go @@ -24,17 +24,19 @@ import ( // Functions (including methods) and Globals use RelString and // all types are displayed with relType, so that only cross-package // references are package-qualified. -func relName(v Value, i Instruction) string { +func relName(v Value, i Node) string { if v == nil { return "" } var from *types.Package if i != nil { - from = i.Parent().pkg() + from = i.Parent().relPkg() } switch v := v.(type) { case Member: // *Function or *Global return v.RelString(from) + case *Const: + return v.RelString(from) } return v.Name() } @@ -66,41 +68,37 @@ func relString(m Member, from *types.Package) string { // It never appears in disassembly, which uses Value.Name(). func (v *Parameter) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("Parameter <%s> {%s}", relType(v.Type(), from), v.name) + from := v.Parent().relPkg() + return fmt.Sprintf("parameter %s : %s", v.Object().Name(), relType(v.Type(), from)) } func (v *FreeVar) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("FreeVar <%s> %s", relType(v.Type(), from), v.Name()) + from := v.Parent().relPkg() + return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from)) } func (v *Builtin) String() string { - return fmt.Sprintf("Builtin %s", v.Name()) + return fmt.Sprintf("builtin %s", v.Name()) } // Instruction.String() func (v *Alloc) String() string { - from := v.Parent().pkg() - storage := "Stack" + op := "local" if v.Heap { - storage = "Heap" + op = "new" } - return fmt.Sprintf("%sAlloc <%s>", storage, relType(v.Type(), from)) -} - -func (v *Sigma) String() string { - from := v.Parent().pkg() - s := fmt.Sprintf("Sigma <%s> [b%d] %s", relType(v.Type(), from), v.From.Index, v.X.Name()) - return s + from := v.Parent().relPkg() + return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment()) } func (v *Phi) String() string { var b bytes.Buffer - fmt.Fprintf(&b, "Phi <%s>", v.Type()) + b.WriteString("phi [") for i, edge := range v.Edges { - b.WriteString(" ") + if i > 0 { + b.WriteString(", ") + } // Be robust against malformed CFG. if v.block == nil { b.WriteString("??") @@ -110,39 +108,40 @@ func (v *Phi) String() string { if i < len(v.block.Preds) { block = v.block.Preds[i].Index } - fmt.Fprintf(&b, "%d:", block) + fmt.Fprintf(&b, "%d: ", block) edgeVal := "" // be robust if edge != nil { edgeVal = relName(edge, v) } b.WriteString(edgeVal) } + b.WriteString("]") + if v.Comment() != "" { + b.WriteString(" #") + b.WriteString(v.Comment()) + } return b.String() } func printCall(v *CallCommon, prefix string, instr Instruction) string { var b bytes.Buffer + b.WriteString(prefix) if !v.IsInvoke() { - if value, ok := instr.(Value); ok { - fmt.Fprintf(&b, "%s <%s> %s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr)) - } else { - fmt.Fprintf(&b, "%s %s", prefix, relName(v.Value, instr)) - } + b.WriteString(relName(v.Value, instr)) } else { - if value, ok := instr.(Value); ok { - fmt.Fprintf(&b, "%sInvoke <%s> %s.%s", prefix, relType(value.Type(), instr.Parent().pkg()), relName(v.Value, instr), v.Method.Name()) - } else { - fmt.Fprintf(&b, "%sInvoke %s.%s", prefix, relName(v.Value, instr), v.Method.Name()) - } + fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name()) } - for _, arg := range v.TypeArgs { - b.WriteString(" ") - b.WriteString(relType(arg, instr.Parent().pkg())) - } - for _, arg := range v.Args { - b.WriteString(" ") + b.WriteString("(") + for i, arg := range v.Args { + if i > 0 { + b.WriteString(", ") + } b.WriteString(relName(arg, instr)) } + if v.Signature().Variadic() { + b.WriteString("...") + } + b.WriteString(")") return b.String() } @@ -151,65 +150,97 @@ func (c *CallCommon) String() string { } func (v *Call) String() string { - return printCall(&v.Call, "Call", v) + return printCall(&v.Call, "", v) } func (v *BinOp) String() string { - return fmt.Sprintf("BinOp <%s> {%s} %s %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v), relName(v.Y, v)) + return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v)) } func (v *UnOp) String() string { - return fmt.Sprintf("UnOp <%s> {%s} %s", relType(v.Type(), v.Parent().pkg()), v.Op.String(), relName(v.X, v)) + return fmt.Sprintf("%s%s", v.Op, relName(v.X, v)) } func (v *Load) String() string { - return fmt.Sprintf("Load <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v)) -} - -func (v *Copy) String() string { - return fmt.Sprintf("Copy <%s> %s", relType(v.Type(), v.Parent().pkg()), relName(v.X, v)) + return fmt.Sprintf("*%s", relName(v.X, v)) } func printConv(prefix string, v, x Value) string { - from := v.Parent().pkg() - return fmt.Sprintf("%s <%s> %s", + from := v.Parent().relPkg() + return fmt.Sprintf("%s %s <- %s (%s)", prefix, relType(v.Type(), from), + relType(x.Type(), from), relName(x, v.(Instruction))) } -func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) } -func (v *Convert) String() string { return printConv("Convert", v, v.X) } -func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) } -func (v *SliceToArrayPointer) String() string { return printConv("SliceToArrayPointer", v, v.X) } +func (v *ChangeType) String() string { return printConv("changetype", v, v.X) } +func (v *Convert) String() string { return printConv("convert", v, v.X) } +func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) } +func (v *SliceToArrayPointer) String() string { return printConv("slice to array pointer", v, v.X) } func (v *SliceToArray) String() string { return printConv("SliceToArray", v, v.X) } -func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) } +func (v *MakeInterface) String() string { return printConv("make", v, v.X) } + +func (v *MultiConvert) String() string { + from := v.Parent().relPkg() + + var b strings.Builder + b.WriteString(printConv("multiconvert", v, v.X)) + b.WriteString(" [") + for i, s := range termListOf(v.from) { + for j, d := range termListOf(v.to) { + if i != 0 || j != 0 { + b.WriteString(" | ") + } + fmt.Fprintf(&b, "%s <- %s", relTerm(d, from), relTerm(s, from)) + } + } + b.WriteString("]") + return b.String() +} func (v *MakeClosure) String() string { - from := v.Parent().pkg() var b bytes.Buffer - fmt.Fprintf(&b, "MakeClosure <%s> %s", relType(v.Type(), from), relName(v.Fn, v)) + fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v)) if v.Bindings != nil { - for _, c := range v.Bindings { - b.WriteString(" ") + b.WriteString(" [") + for i, c := range v.Bindings { + if i > 0 { + b.WriteString(", ") + } b.WriteString(relName(c, v)) } + b.WriteString("]") } return b.String() } func (v *MakeSlice) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("MakeSlice <%s> %s %s", + from := v.Parent().relPkg() + return fmt.Sprintf("make %s %s %s", relType(v.Type(), from), relName(v.Len, v), relName(v.Cap, v)) } func (v *Slice) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("Slice <%s> %s %s %s %s", - relType(v.Type(), from), relName(v.X, v), relName(v.Low, v), relName(v.High, v), relName(v.Max, v)) + var b bytes.Buffer + b.WriteString("slice ") + b.WriteString(relName(v.X, v)) + b.WriteString("[") + if v.Low != nil { + b.WriteString(relName(v.Low, v)) + } + b.WriteString(":") + if v.High != nil { + b.WriteString(relName(v.High, v)) + } + if v.Max != nil { + b.WriteString(":") + b.WriteString(relName(v.Max, v)) + } + b.WriteString("]") + return b.String() } func (v *MakeMap) String() string { @@ -217,77 +248,69 @@ func (v *MakeMap) String() string { if v.Reserve != nil { res = relName(v.Reserve, v) } - from := v.Parent().pkg() - return fmt.Sprintf("MakeMap <%s> %s", relType(v.Type(), from), res) + from := v.Parent().relPkg() + return fmt.Sprintf("make %s %s", relType(v.Type(), from), res) } func (v *MakeChan) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("MakeChan <%s> %s", relType(v.Type(), from), relName(v.Size, v)) + from := v.Parent().relPkg() + return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v)) } func (v *FieldAddr) String() string { - from := v.Parent().pkg() - // v.X.Type() might be a pointer to a type parameter whose core type is a pointer to a struct - st := deref(typeutil.CoreType(deref(v.X.Type()))).Underlying().(*types.Struct) // Be robust against a bad index. name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() + if fld := fieldOf(deref(v.X.Type()), v.Field); fld != nil { + name = fld.Name() } - return fmt.Sprintf("FieldAddr <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v)) + return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) } func (v *Field) String() string { - st := typeutil.CoreType(v.X.Type()).Underlying().(*types.Struct) // Be robust against a bad index. name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() + if fld := fieldOf(v.X.Type(), v.Field); fld != nil { + name = fld.Name() } - from := v.Parent().pkg() - return fmt.Sprintf("Field <%s> [%d] (%s) %s", relType(v.Type(), from), v.Field, name, relName(v.X, v)) + return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) } func (v *IndexAddr) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("IndexAddr <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) + return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v)) } func (v *Index) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("Index <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) + return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) } func (v *MapLookup) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("MapLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) + return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk)) } func (v *StringLookup) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("StringLookup <%s> %s %s", relType(v.Type(), from), relName(v.X, v), relName(v.Index, v)) + return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v)) } func (v *Range) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("Range <%s> %s", relType(v.Type(), from), relName(v.X, v)) + return "range " + relName(v.X, v) } func (v *Next) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("Next <%s> %s", relType(v.Type(), from), relName(v.Iter, v)) + return "next " + relName(v.Iter, v) } func (v *TypeAssert) String() string { - from := v.Parent().pkg() - return fmt.Sprintf("TypeAssert <%s> %s", relType(v.Type(), from), relName(v.X, v)) + from := v.Parent().relPkg() + return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from)) } func (v *Extract) String() string { - from := v.Parent().pkg() name := v.Tuple.Type().(*types.Tuple).At(v.Index).Name() - return fmt.Sprintf("Extract <%s> [%d] (%s) %s", relType(v.Type(), from), v.Index, name, relName(v.Tuple, v)) + if name == "" { + return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index) + } else { + return fmt.Sprintf("extract %s #%d (%s)", relName(v.Tuple, v), v.Index, name) + } } func (s *Jump) String() string { @@ -296,7 +319,7 @@ func (s *Jump) String() string { if s.block != nil && len(s.block.Succs) == 1 { block = s.block.Succs[0].Index } - str := fmt.Sprintf("Jump → b%d", block) + str := fmt.Sprintf("jump %d", block) if s.Comment() != "" { str = fmt.Sprintf("%s # %s", str, s.Comment()) } @@ -304,12 +327,7 @@ func (s *Jump) String() string { } func (s *Unreachable) String() string { - // Be robust against malformed CFG. - block := -1 - if s.block != nil && len(s.block.Succs) == 1 { - block = s.block.Succs[0].Index - } - return fmt.Sprintf("Unreachable → b%d", block) + return "Unreachable" } func (s *If) String() string { @@ -319,7 +337,7 @@ func (s *If) String() string { tblock = s.block.Succs[0].Index fblock = s.block.Succs[1].Index } - return fmt.Sprintf("If %s → b%d b%d", relName(s.Cond, s), tblock, fblock) + return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock) } func (s *ConstantSwitch) String() string { @@ -337,79 +355,89 @@ func (s *ConstantSwitch) String() string { func (v *CompositeValue) String() string { var b bytes.Buffer - from := v.Parent().pkg() - fmt.Fprintf(&b, "CompositeValue <%s>", relType(v.Type(), from)) - if v.NumSet >= len(v.Values) { - // All values provided - fmt.Fprint(&b, " [all]") - } else if v.Bitmap.BitLen() == 0 { - // No values provided - fmt.Fprint(&b, " [none]") - } else { - // Some values provided - bits := fmt.Appendf(nil, "%0*b", len(v.Values), &v.Bitmap) - for i := 0; i < len(bits)/2; i++ { - o := len(bits) - 1 - i - bits[i], bits[o] = bits[o], bits[i] + fmt.Fprint(&b, "{") + first := true + + var printValue func(idx int, vv Value) + switch typ := typeutil.CoreType(v.typ).(type) { + case *types.Struct: + printValue = func(idx int, vv Value) { + fieldName := typ.Field(idx).Name() + fmt.Fprintf(&b, "%s: %s", fieldName, relName(vv, v)) } - fmt.Fprintf(&b, " [%s]", bits) + case *types.Array: + if v.NumSet >= len(v.Values) { + printValue = func(idx int, vv Value) { + fmt.Fprint(&b, relName(vv, v)) + } + } else { + // This is currently unreachable as we don't use CompositeValue for + // incomplete arrays. + printValue = func(idx int, vv Value) { + fmt.Fprintf(&b, "%d: %s", idx, relName(vv, v)) + } + } + default: + panic(fmt.Sprintf("internal error: unexpected type %T (%v)", typ, typ)) } - for _, vv := range v.Values { - fmt.Fprintf(&b, " %s", relName(vv, v)) + for i, vv := range v.Values { + if !first { + fmt.Fprint(&b, ", ") + } + first = false + printValue(i, vv) } + fmt.Fprint(&b, "}") return b.String() } func (s *TypeSwitch) String() string { - from := s.Parent().pkg() var b bytes.Buffer - fmt.Fprintf(&b, "TypeSwitch <%s> %s", relType(s.typ, from), relName(s.Tag, s)) + fmt.Fprintf(&b, "switch %s.(type)", relName(s.Tag, s)) for _, cond := range s.Conds { - fmt.Fprintf(&b, " %q", relType(cond, s.block.parent.pkg())) + fmt.Fprintf(&b, " %s", relType(cond, s.block.parent.relPkg())) } return b.String() } func (s *Go) String() string { - return printCall(&s.Call, "Go", s) + return printCall(&s.Call, "go ", s) } func (s *Panic) String() string { - // Be robust against malformed CFG. - block := -1 - if s.block != nil && len(s.block.Succs) == 1 { - block = s.block.Succs[0].Index - } - return fmt.Sprintf("Panic %s → b%d", relName(s.X, s), block) + return "panic " + relName(s.X, s) } func (s *Return) String() string { var b bytes.Buffer - b.WriteString("Return") - for _, r := range s.Results { - b.WriteString(" ") + b.WriteString("return") + for i, r := range s.Results { + if i == 0 { + b.WriteString(" ") + } else { + b.WriteString(", ") + } b.WriteString(relName(r, s)) } return b.String() } func (*RunDefers) String() string { - return "RunDefers" + return "rundefers" } func (s *Send) String() string { - return fmt.Sprintf("Send %s %s", relName(s.Chan, s), relName(s.X, s)) + return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s)) } func (recv *Recv) String() string { - from := recv.Parent().pkg() - return fmt.Sprintf("Recv <%s> %s", relType(recv.Type(), from), relName(recv.Chan, recv)) + return fmt.Sprintf("<-%s", relName(recv.Chan, recv)) } func (s *Defer) String() string { - prefix := "Defer " - if s._DeferStack != nil { - prefix += "[" + relName(s._DeferStack, s) + "] " + prefix := "defer " + if s.DeferStack != nil { + prefix += "[" + relName(s.DeferStack, s) + "] " } c := printCall(&s.Call, prefix, s) return c @@ -432,26 +460,24 @@ func (s *Select) String() string { } non := "" if !s.Blocking { - non = "Non" + non = "non" } - from := s.Parent().pkg() - return fmt.Sprintf("Select%sBlocking <%s> [%s]", non, relType(s.Type(), from), b.String()) + return fmt.Sprintf("select %sblocking [%s]", non, b.String()) } func (s *Store) String() string { - return fmt.Sprintf("Store {%s} %s %s", - s.Val.Type(), relName(s.Addr, s), relName(s.Val, s)) + return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s)) } func (s *BlankStore) String() string { - return fmt.Sprintf("BlankStore %s", relName(s.Val, s)) + return fmt.Sprintf("_ = %s", relName(s.Val, s)) } func (s *MapUpdate) String() string { - return fmt.Sprintf("MapUpdate %s %s %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) + return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s)) } -func (s *DebugRef) String() string { +func (s *debugRef) String() string { p := s.Parent().Prog.Fset.Position(s.Pos()) var descr any if s.object != nil { @@ -513,27 +539,16 @@ func WritePackage(buf *bytes.Buffer, p *Package) { case *Global: fmt.Fprintf(buf, " var %-*s %s\n", - maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) + maxname, name, relType(deref(mem.Type()), from)) } } fmt.Fprintf(buf, "\n") } -func (v *MultiConvert) String() string { - from := v.Parent().Pkg.Pkg - - var b strings.Builder - b.WriteString(printConv("MultiConvert", v, v.X)) - b.WriteString(" [") - for i, s := range v.from.Terms { - for j, d := range v.to.Terms { - if i != 0 || j != 0 { - b.WriteString(" | ") - } - fmt.Fprintf(&b, "%s -> %s", relTerm(s, from), relTerm(d, from)) - } +func commaOk(x bool) string { + if x { + return ",ok" } - b.WriteString("]") - return b.String() + return "" } diff --git a/vendor/honnef.co/go/tools/go/ir/sanity.go b/vendor/honnef.co/go/tools/go/ir/sanity.go index 5663b4cf..ab379ed8 100644 --- a/vendor/honnef.co/go/tools/go/ir/sanity.go +++ b/vendor/honnef.co/go/tools/go/ir/sanity.go @@ -94,13 +94,6 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { switch instr := instr.(type) { case *If, *Jump, *Return, *Panic, *Unreachable, *ConstantSwitch: s.errorf("control flow instruction not at end of block") - case *Sigma: - if idx > 0 { - prev := s.block.Instrs[idx-1] - if _, ok := prev.(*Sigma); !ok { - s.errorf("Sigma instruction follows a non-Sigma: %T", prev) - } - } case *Phi: if idx == 0 { // It suffices to apply this check to just the first phi node. @@ -110,18 +103,20 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { } else { prev := s.block.Instrs[idx-1] switch prev.(type) { - case *Phi, *Sigma: + case *Phi: default: - s.errorf("Phi instruction follows a non-Phi, non-Sigma: %T", prev) + s.errorf("Phi instruction follows a non-Phi: %T", prev) } } if ne, np := len(instr.Edges), len(s.block.Preds); ne != np { s.errorf("phi node has %d edges but %d predecessors", ne, np) - } else { for i, e := range instr.Edges { if e == nil { s.errorf("phi node '%s' has no value for edge #%d from %s", instr.Comment(), i, s.block.Preds[i]) + } else if !types.Identical(instr.typ, e.Type()) { + s.errorf("phi node '%s' has a different type (%s) for edge #%d from %s (%s)", + instr.Comment(), instr.Type(), i, s.block.Preds[i], e.Type()) } } } @@ -133,19 +128,21 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { case *BinOp: case *Call: + if common := instr.Call; common.IsInvoke() { + if !types.IsInterface(common.Value.Type()) { + s.errorf("invoke on %s (%s) which is not an interface type (or type param)", common.Value, common.Value.Type()) + } + } case *ChangeInterface: case *ChangeType: case *SliceToArrayPointer: case *SliceToArray: case *Convert: - tsetInstrX := typeutil.NewTypeSet(instr.X.Type().Underlying()) - tsetInstr := typeutil.NewTypeSet(instr.Type().Underlying()) - ok1 := tsetInstr.Any(func(term *types.Term) bool { _, ok := term.Type().Underlying().(*types.Basic); return ok }) - ok2 := tsetInstrX.Any(func(term *types.Term) bool { _, ok := term.Type().Underlying().(*types.Basic); return ok }) - if !ok1 && !ok2 { - s.errorf("convert %s -> %s: at least one type set must contain basic type", instr.X.Type(), instr.Type()) + if from := instr.X.Type(); !isBasicConvTypes(from) { + if to := instr.Type(); !isBasicConvTypes(to) { + s.errorf("convert %s -> %s: at least one type must be basic (or all basic, []byte, or []rune)", from, to) + } } - case *MultiConvert: case *Defer: case *Extract: @@ -163,7 +160,13 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { if numFree != numBind { s.errorf("MakeClosure has %d Bindings for function %s with %d free vars", numBind, instr.Fn, numFree) - + } else { + for i, fv := range instr.Fn.(*Function).FreeVars { + if !types.Identical(instr.Bindings[i].Type(), fv.Type()) { + s.errorf("MakeClosure binding %d for %s has type %s, expected %s", + i, fv.Name(), instr.Bindings[i].Type(), fv.Type()) + } + } } if recv := instr.Type().(*types.Signature).Recv(); recv != nil { s.errorf("MakeClosure's type includes receiver %s", recv.Type()) @@ -174,22 +177,44 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { case *MakeSlice: case *MapUpdate: case *Next: + rng, ok := instr.Iter.(*Range) + if !ok { + s.errorf("Next: Iter is %T, not *Range", instr.Iter) + } + var ek, ev types.Type + switch xt := typeutil.CoreType(rng.X.Type()).(type) { + case *types.Basic: + if types.Default(xt) != tString { + s.errorf("Next: basic operand of Next.Iter (Range) is %s, want string or untyped string", xt) + } + ek, ev = tInt, tRune + case *types.Map: + ek, ev = xt.Key(), xt.Elem() + } + + res := instr.Type().(*types.Tuple) // (ok bool, k K, v V), but K or V may be invalid if unused + if !types.Identical(res.At(1).Type(), ek) && res.At(1).Type() != tInvalid { + s.errorf("Next: key type %s does not match map key type %s", res.At(1).Type(), ek) + } + if !types.Identical(res.At(2).Type(), ev) && res.At(2).Type() != tInvalid { + s.errorf("Next: value type %s does not match map value type %s", res.At(2).Type(), ev) + } + case *Range: case *RunDefers: case *Select: case *Send: case *Slice: case *Store: + if !types.Identical(instr.Val.Type(), typeutil.CoreType(instr.Addr.Type()).(*types.Pointer).Elem()) { + s.errorf("Store: value type %s does not match address type %s", + instr.Val.Type(), instr.Addr.Type()) + } case *TypeAssert: case *UnOp: - case *DebugRef: + case *debugRef: case *BlankStore: case *Load: - case *Parameter: - case *Const: - case *AggregateConst: - case *ArrayConst: - case *GenericConst: case *Recv: case *TypeSwitch: case *CompositeValue: @@ -209,6 +234,8 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { t := v.Type() if t == nil { s.errorf("no type: %s = %s", v.Name(), v) + } else if t == tDeferStack { + // not a proper type; ignore. } else if b, ok := t.Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 { if _, ok := v.(*Const); !ok { s.errorf("instruction has 'untyped' result: %s = %s : %s", v.Name(), v, t) @@ -255,18 +282,23 @@ func (s *sanity) checkFinalInstr(instr Instruction) { } case *Panic: - if nsuccs := len(s.block.Succs); nsuccs != 1 { - s.errorf("Panic-terminated block has %d successors; expected one", nsuccs) + if nsuccs := len(s.block.Succs); nsuccs != 0 { + s.errorf("Panic-terminated block has %d successors; expected none", nsuccs) return } case *Unreachable: - if nsuccs := len(s.block.Succs); nsuccs != 1 { - s.errorf("Unreachable-terminated block has %d successors; expected one", nsuccs) + if nsuccs := len(s.block.Succs); nsuccs != 0 { + s.errorf("Unreachable-terminated block has %d successors; expected none", nsuccs) return } case *ConstantSwitch: + if nsuccs := len(s.block.Succs); nsuccs != len(instr.Conds) { + s.errorf("ConstantSwitch-terminated block has %d successors for %d constants", + nsuccs, len(instr.Conds)) + return + } default: s.errorf("non-control flow instruction at end of block") @@ -284,8 +316,9 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) { } // Check all blocks are reachable. - // (The entry block is always implicitly reachable, the exit block may be unreachable.) - if index > 1 && len(b.Preds) == 0 { + // (The entry block is always implicitly reachable, + // as is the Recover block, if any.) + if (index > 0 && b != b.parent.Recover) && len(b.Preds) == 0 { s.warnf("unreachable block") if b.Instrs == nil { // Since this block is about to be pruned, @@ -352,7 +385,7 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) { // Check that "untyped" types only appear on constant operands. if _, ok := (*op).(*Const); !ok { - if basic, ok := types.Unalias((*op).Type()).(*types.Basic); ok { + if basic, ok := (*op).Type().Underlying().(*types.Basic); ok { if basic.Info()&types.IsUntyped != 0 { s.errorf("operand #%d of %s is untyped: %s", i, instr, basic) } @@ -413,40 +446,139 @@ func (s *sanity) checkReferrerList(v Value) { } } +func (s *sanity) checkFunctionParams() { + signature := s.fn.Signature + params := s.fn.Params + + // startSigParams is the start of signature.Params() within params. + startSigParams := 0 + if signature.Recv() != nil { + startSigParams = 1 + } + + if startSigParams+signature.Params().Len() != len(params) { + s.errorf("function has %d parameters in signature but has %d after building", + startSigParams+signature.Params().Len(), len(params)) + return + } + + for i, param := range params { + var sigType types.Type + si := i - startSigParams + if si < 0 { + sigType = signature.Recv().Type() + } else { + sigType = signature.Params().At(si).Type() + } + + if !types.Identical(sigType, param.Type()) { + s.errorf("expect type %s in signature but got type %s in param %d", sigType, param.Type(), i) + } + } +} + +// checkTransientFields checks whether all transient fields of Function are cleared. +func (s *sanity) checkTransientFields() { + fn := s.fn + if fn.build != nil { + s.errorf("function transient field 'build' is not nil") + } + if fn.currentBlock != nil { + s.errorf("function transient field 'currentBlock' is not nil") + } + if fn.vars != nil { + s.errorf("function transient field 'vars' is not nil") + } + if fn.results != nil { + s.errorf("function transient field 'results' is not nil") + } + if fn.returnVars != nil { + s.errorf("function transient field 'returnVars' is not nil") + } + if fn.targets != nil { + s.errorf("function transient field 'targets' is not nil") + } + if fn.lblocks != nil { + s.errorf("function transient field 'lblocks' is not nil") + } + if fn.subst != nil { + s.errorf("function transient field 'subst' is not nil") + } + if fn.jump != nil { + s.errorf("function transient field 'jump' is not nil") + } + if fn.deferstack != nil { + s.errorf("function transient field 'deferstack' is not nil") + } + if fn.source != nil { + s.errorf("function transient field 'source' is not nil") + } + if fn.exits != nil { + s.errorf("function transient field 'exits' is not nil") + } + if fn.uniq != 0 { + s.errorf("function transient field 'uniq' is not zero") + } +} + func (s *sanity) checkFunction(fn *Function) bool { - // TODO(adonovan): check Function invariants: - // - check params match signature - // - check transient fields are nil - // - warn if any fn.Locals do not appear among block instructions. s.fn = fn + s.checkFunctionParams() + s.checkTransientFields() + + // TODO(taking): Sanity check origin, typeparams, and typeargs. if fn.Prog == nil { s.errorf("nil Prog") } var buf bytes.Buffer - _ = fn.String() // must not crash - _ = fn.RelString(fn.pkg()) // must not crash - WriteFunction(&buf, fn) // must not crash + _ = fn.String() // must not crash + _ = fn.RelString(fn.relPkg()) // must not crash + WriteFunction(&buf, fn) // must not crash // All functions have a package, except delegates (which are // shared across packages, or duplicated as weak symbols in a // separate-compilation model), and error.Error. if fn.Pkg == nil { - switch fn.Synthetic { - case SyntheticWrapper, SyntheticBound, SyntheticThunk, SyntheticGeneric: - default: - if !strings.HasSuffix(fn.name, "Error") { - s.errorf("nil Pkg") - } + if strings.HasPrefix(fn.Synthetic, "from type information (on demand)") || + strings.HasPrefix(fn.Synthetic, "wrapper ") || + strings.HasPrefix(fn.Synthetic, "bound ") || + strings.HasPrefix(fn.Synthetic, "thunk ") || + strings.HasSuffix(fn.name, "Error") || + strings.HasPrefix(fn.Synthetic, "instance ") || + strings.HasPrefix(fn.Synthetic, "instantiation ") || + fn.parent != nil && fn.parent.hasTypeArgs() /* anon fun in instance */ { + // ok + } else { + s.errorf("nil Pkg") } } - if syn, src := fn.Synthetic == 0, fn.source != nil; src != syn { - if _, ok := fn.source.(*ast.RangeStmt); !ok || fn.Synthetic != SyntheticRangeOverFuncYield { - // Only range-over-func yield functions are synthetic and have syntax + if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn { + if fn.hasTypeArgs() && fn.Prog.mode&InstantiateGenerics != 0 { + // ok (instantiation with InstantiateGenerics on) + } else if fn.hasTypeArgs() && fn.topLevelOrigin != nil { + // ok (we always have the syntax set for instantiation) + } else if _, rng := fn.syntax.(*ast.RangeStmt); rng && fn.Synthetic == "range-over-func yield" { + // ok (range-func-yields are both synthetic and keep syntax) + } else { s.errorf("got fromSource=%t, hasSyntax=%t; want same values", src, syn) } } + + // Build the set of valid referrers. + s.instrs = make(map[Instruction]struct{}) + + // instrs are the instructions that are present in the function. + for instr := range fn.instrs() { + s.instrs[instr] = unit{} + } + + // Check all Locals allocations appear in the function instruction. for i, l := range fn.Locals { + if _, present := s.instrs[l]; !present { + s.warnf("function doesn't contain Local alloc %s", l.Name()) + } + if l.Parent() != fn { s.errorf("Local %s at index %d has wrong parent", l.Name(), i) } @@ -454,13 +586,6 @@ func (s *sanity) checkFunction(fn *Function) bool { s.errorf("Local %s at index %d has Heap flag set", l.Name(), i) } } - // Build the set of valid referrers. - s.instrs = make(map[Instruction]struct{}) - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - s.instrs[instr] = struct{}{} - } - } for i, p := range fn.Params { if p.Parent() != fn { s.errorf("Param %s at index %d has wrong parent", p.Name(), i) @@ -473,7 +598,6 @@ func (s *sanity) checkFunction(fn *Function) bool { } if !types.Identical(p.Type(), sig.Params().At(j).Type()) { s.errorf("Param %s at index %d has wrong type (%s, versus %s in Signature)", p.Name(), i, p.Type(), sig.Params().At(j).Type()) - } } @@ -498,12 +622,18 @@ func (s *sanity) checkFunction(fn *Function) bool { } s.checkBlock(b, i) } + if fn.Recover != nil && fn.Blocks[fn.Recover.Index] != fn.Recover { + s.errorf("Recover block is not in Blocks slice") + } s.block = nil for i, anon := range fn.AnonFuncs { if anon.Parent() != fn { s.errorf("AnonFuncs[%d]=%s but %s.Parent()=%s", i, anon, anon, anon.Parent()) } + if i != int(anon.anonIdx) { + s.errorf("AnonFuncs[%d]=%s but %s.anonIdx=%d", i, anon, anon, anon.anonIdx) + } } s.fn = nil return !s.insane @@ -516,6 +646,19 @@ func sanityCheckPackage(pkg *Package) { if pkg.Pkg == nil { panic(fmt.Sprintf("Package %s has no Object", pkg)) } + if pkg.info != nil { + panic(fmt.Sprintf("package %s field 'info' is not cleared", pkg)) + } + if pkg.files != nil { + panic(fmt.Sprintf("package %s field 'files' is not cleared", pkg)) + } + if pkg.created != nil { + panic(fmt.Sprintf("package %s field 'created' is not cleared", pkg)) + } + if pkg.initVersion != nil { + panic(fmt.Sprintf("package %s field 'initVersion' is not cleared", pkg)) + } + _ = pkg.String() // must not crash for name, mem := range pkg.Members { diff --git a/vendor/honnef.co/go/tools/go/ir/scc.go b/vendor/honnef.co/go/tools/go/ir/scc.go new file mode 100644 index 00000000..d7f74085 --- /dev/null +++ b/vendor/honnef.co/go/tools/go/ir/scc.go @@ -0,0 +1,106 @@ +package ir + +import ( + "math" +) + +type sccState struct { + fn *Function + index int + lows BlockMap[int] + F []int + sccs []*SCC +} + +func (s *sccState) scc(v *BasicBlock) { + // This is Tarjan's algorithm, with some optimizations from [1] applied. + // + // [1] R. E. Tarjan and U. Zwick, “Finding strong components using depth-first search,” Apr. 11, 2022, arXiv: arXiv:2201.07197. doi: 10.48550/arXiv.2201.07197. + vi := v.Index + lows := s.lows + + s.index += 2 + lows[vi] = s.index + + for _, w := range v.Succs { + wi := w.Index + + if lows[wi] == 0 { + s.scc(w) + } + + if lows[wi] < lows[vi] { + lows[vi] = lows[wi] | 1 + } + } + + if lows[vi]&1 == 0 { + leaderLow := lows[vi] + + scc := &SCC{ + Index: len(s.sccs), + } + F := s.F + for lows[F[len(F)-1]] >= leaderLow { + x := F[len(F)-1] + F = F[:len(F)-1] + + lows[x] = math.MaxInt + scc.Blocks = append(scc.Blocks, s.fn.Blocks[x]) + s.fn.Blocks[x].SCC = scc + } + s.F = F + + lows[vi] = math.MaxInt + scc.Blocks = append(scc.Blocks, v) + v.SCC = scc + s.sccs = append(s.sccs, scc) + } else { + s.F = append(s.F, vi) + } +} + +// buildSCCs computes the strongly connected components of fn's control flow graph. +func buildSCCs(fn *Function) { + n := len(fn.Blocks) + + if n == 0 { + return + } + + state := sccState{ + fn: fn, + index: 0, + // The +1 makes space for the sentinel value stored in F. + lows: make(BlockMap[int], n+1), + F: []int{n}, + } + + // All blocks are reachable from the entry block. + state.scc(fn.Blocks[0]) + + seen := make([]bool, len(state.sccs)) + for _, scc := range state.sccs { + clear(seen) + for _, b := range scc.Blocks { + for _, succ := range b.Succs { + if succ.SCC != b.SCC && !seen[succ.SCC.Index] { + b.SCC.Succs = append(b.SCC.Succs, succ.SCC) + succ.SCC.Preds = append(succ.SCC.Preds, b.SCC) + seen[succ.SCC.Index] = true + } + } + } + } + + fn.SCCs = state.sccs + + // This iterates over the SCCs in reverse topological order, i.e., "bottom + // up". This allows us to build up reachability sets. + for _, scc := range fn.SCCs { + scc.reachable.SetBit(&scc.reachable, scc.Index, 1) + for _, succ := range scc.Succs { + scc.reachable.Or(&scc.reachable, &succ.reachable) + } + } +} diff --git a/vendor/honnef.co/go/tools/go/ir/source.go b/vendor/honnef.co/go/tools/go/ir/source.go index 5e3ac28b..bd05db73 100644 --- a/vendor/honnef.co/go/tools/go/ir/source.go +++ b/vendor/honnef.co/go/tools/go/ir/source.go @@ -80,14 +80,23 @@ func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function } case *ast.FuncDecl: - // Declared function/method. - fn := findNamedFunc(pkg, decl.Pos()) - if fn == nil && decl.Recv == nil && decl.Name.Name == "init" { + if decl.Recv == nil && decl.Name.Name == "init" { + // Explicit init() function. + for _, b := range pkg.init.Blocks { + for _, instr := range b.Instrs { + if instr, ok := instr.(*Call); ok { + if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos { + return callee + } + } + } + } // Hack: return non-nil when IR is not yet // built so that HasEnclosingFunction works. return pkg.init } - return fn + // Declared function/method. + return findNamedFunc(pkg, decl.Name.NamePos) } } return nil // not in any function @@ -96,9 +105,25 @@ func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function // findNamedFunc returns the named function whose FuncDecl.Ident is at // position pos. func findNamedFunc(pkg *Package, pos token.Pos) *Function { - for _, fn := range pkg.Functions { - if fn.Pos() == pos { - return fn + // Look at all package members and method sets of named types. + // Not very efficient. + for _, mem := range pkg.Members { + switch mem := mem.(type) { + case *Function: + if mem.Pos() == pos { + return mem + } + case *Type: + mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type())) + for i, n := 0, mset.Len(); i < n; i++ { + // Don't call Program.Method: avoid creating wrappers. + obj := mset.At(i).Obj().(*types.Func) + if obj.Pos() == pos { + // obj from MethodSet may not be the origin type. + m := obj.Origin() + return pkg.values[m].(*Function) + } + } } } return nil @@ -127,19 +152,9 @@ func findNamedFunc(pkg *Package, pos token.Pos) *Function { // EnclosingFunction to locate the Function, then ValueForExpr to find // the ir.Value.) func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) { - if f.debugInfo() { // (opt) - e = unparen(e) - for _, b := range f.Blocks { - for _, instr := range b.Instrs { - if ref, ok := instr.(*DebugRef); ok { - if ref.Expr == e { - return ref.X, ref.IsAddr - } - } - } - } - } - return + e = ast.Unparen(e) + entry := f.exprToValue[e] + return entry.v, entry.isAddr } // --- Lookup functions for source-level named entities (types.Objects) --- @@ -151,25 +166,26 @@ func (prog *Program) Package(obj *types.Package) *Package { return prog.packages[obj] } -// packageLevelValue returns the package-level value corresponding to -// the specified named object, which may be a package-level const -// (*Const), var (*Global) or func (*Function) of some package in -// prog. It returns nil if the object is not found. -func (prog *Program) packageLevelValue(obj types.Object) Value { +// packageLevelMember returns the package-level member corresponding +// to the specified symbol, which may be a package-level const +// (*NamedConst), var (*Global) or func/method (*Function) of some +// package in prog. +// +// It returns nil if the object belongs to a package that has not been +// created by prog.CreatePackage. +func (prog *Program) packageLevelMember(obj types.Object) Member { if pkg, ok := prog.packages[obj.Pkg()]; ok { return pkg.values[obj] } return nil } -// FuncValue returns the concrete Function denoted by the source-level -// named function obj, or nil if obj denotes an interface method. -// -// TODO(adonovan): check the invariant that obj.Type() matches the -// result's Signature, both in the params/results and in the receiver. +// FuncValue returns the SSA function or (non-interface) method +// denoted by the specified func symbol. It returns nil if the symbol +// denotes an interface method, or belongs to a package that was not +// created by prog.CreatePackage. func (prog *Program) FuncValue(obj *types.Func) *Function { - obj = obj.Origin() - fn, _ := prog.packageLevelValue(obj).(*Function) + fn, _ := prog.packageLevelMember(obj).(*Function) return fn } @@ -184,8 +200,8 @@ func (prog *Program) ConstValue(obj *types.Const) *Const { return NewConst(obj.Val(), obj.Type(), nil) } // Package-level named constant? - if v := prog.packageLevelValue(obj); v != nil { - return v.(*Const) + if v := prog.packageLevelMember(obj); v != nil { + return v.(*NamedConst).Value } return NewConst(obj.Val(), obj.Type(), nil) } @@ -244,18 +260,12 @@ func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (val } // Other ident? - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - if dr, ok := instr.(*DebugRef); ok { - if dr.Pos() == id.Pos() { - return dr.X, dr.IsAddr - } - } - } + if v, ok := fn.exprToValue[id]; ok { + return v.v, v.isAddr } // Defining ident of package-level var? - if v := prog.packageLevelValue(obj); v != nil { + if v := prog.packageLevelMember(obj); v != nil { return v.(*Global), true } diff --git a/vendor/honnef.co/go/tools/go/ir/ssa.go b/vendor/honnef.co/go/tools/go/ir/ssa.go index cd8ae012..e9277360 100644 --- a/vendor/honnef.co/go/tools/go/ir/ssa.go +++ b/vendor/honnef.co/go/tools/go/ir/ssa.go @@ -5,7 +5,7 @@ package ir // This package defines a high-level intermediate representation for -// Go programs using static single-information (SSI) form. +// Go programs using static single-assignment (SSA) form. import ( "fmt" @@ -13,10 +13,16 @@ import ( "go/constant" "go/token" "go/types" + "iter" "math/big" + "reflect" + "slices" + "strings" "sync" + "unsafe" "honnef.co/go/tools/go/types/typeutil" + "honnef.co/go/tools/internal/xtools-internal/typeparams" ) const ( @@ -30,18 +36,31 @@ type ID int // A Program is a partial or complete Go program converted to IR form. type Program struct { Fset *token.FileSet // position information for the files of this Program - PrintFunc string // create ir.html for function specified in PrintFunc imported map[string]*Package // all importable Packages, keyed by import path - packages map[*types.Package]*Package // all loaded Packages, keyed by object + packages map[*types.Package]*Package // all created Packages mode BuilderMode // set of mode bits for IR construction MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets - methodsMu sync.Mutex // guards the following maps: - methodSets typeutil.Map[*methodSet] // maps type to its concrete methodSet - runtimeTypes typeutil.Map[bool] // types for which rtypes are needed - canon typeutil.Map[types.Type] // type canonicalization map + canon *canonizer // type canonicalization map + ctxt *types.Context // cache for type checking instantiations - noReturn func(*types.Func) bool + methodsMu sync.Mutex + methodSets typeutil.Map[*methodSet] // maps type to its concrete *methodSet + + // memoization of whether a type refers to type parameters + hasParamsMu sync.Mutex + hasParams typeparams.Free + + // set of concrete types used as MakeInterface operands + makeInterfaceTypesMu sync.Mutex + makeInterfaceTypes map[types.Type]unit // (may contain redundant identical types) + + // objectMethods is a memoization of objectMethod + // to avoid creation of duplicate methods from type information. + objectMethodsMu sync.Mutex + objectMethods map[*types.Func]*Function + + noReturn func(*types.Func) bool // (optional) predicate that decides whether a given call cannot return } // A Package is a single analyzed Go package containing Members for @@ -53,14 +72,14 @@ type Program struct { // initializer) and "init#%d", the nth declared init function, // and unspecified other things too. type Package struct { - Prog *Program // the owning program - Pkg *types.Package // the corresponding go/types.Package - Members map[string]Member // all package members keyed by name (incl. init and init#%d) - Functions []*Function // all functions, excluding anonymous ones - values map[types.Object]Value // package members (incl. types and methods), keyed by object - init *Function // Func("init"); the package's init function - debug bool // include full debug info in this package - printFunc string // which function to print in HTML form + Prog *Program // the owning program + Pkg *types.Package // the corresponding go/types.Package + Members map[string]Member // all package members keyed by name (incl. init and init#%d) + Functions []*Function // all functions, excluding anonymous ones + values map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function (values but not types) + init *Function // Func("init"); the package's init function + debug bool // include full debug info in this package + syntax bool // package was loaded from syntax // The following fields are set transiently, then cleared // after building. @@ -68,6 +87,7 @@ type Package struct { ninit int32 // number of init functions info *types.Info // package type information files []*ast.File // package ASTs + created []*Function // members created as a result of building this package (includes declared functions, wrappers) initVersion map[ast.Expr]string // goversion to use for each global var init expr } @@ -106,8 +126,6 @@ type NamedConst struct { // A Value is an IR value that can be referenced by an instruction. type Value interface { - setID(ID) - // Name returns the name of this value, and determines how // this Value appears when used as an operand of an // Instruction. @@ -122,17 +140,6 @@ type Value interface { // and may not even be unique within a function. Name() string - // ID returns the ID of this value. IDs are unique within a single - // function and are densely numbered, but may contain gaps. - // Values and other Instructions share the same ID space. - // Globally, values are identified by their addresses. However, - // IDs exist to facilitate efficient storage of mappings between - // values and data when analysing functions. - // - // NB: IDs are allocated late in the IR construction process and - // are not available to early stages of said process. - ID() ID - // If this value is an Instruction, String returns its // disassembled form; otherwise it returns unspecified // human-readable information about the Value, such as its @@ -193,15 +200,15 @@ type Instruction interface { // String returns the disassembled form of this value. // // Examples of Instructions that are Values: - // "BinOp {+} t1 t2" (BinOp) - // "Call len t1" (Call) + // "x + y" (BinOp) + // "len([])" (Call) // Note that the name of the Value is not printed. // // Examples of Instructions that are not Values: - // "Return t1" (Return) - // "Store {int} t2 t1" (Store) + // "return x" (Return) + // "*y = x" (Store) // - // (The separation of Value.Name() from Value.String() is useful + // (The separation Value.Name() from Value.String() is useful // for some analyses which distinguish the operation from the // value it defines, e.g., 'y = local int' is both an allocation // of memory 'local int' and a definition of a pointer y.) @@ -270,10 +277,7 @@ type Instruction interface { // use the more specific and informative Value or Instruction // interfaces where appropriate. type Node interface { - setID(ID) - // Common methods: - ID() ID String() string Source() ast.Node Pos() token.Pos @@ -284,39 +288,6 @@ type Node interface { Referrers() *[]Instruction // nil for non-Values } -type Synthetic int - -const ( - SyntheticLoadedFromExportData Synthetic = iota + 1 - SyntheticPackageInitializer - SyntheticThunk - SyntheticWrapper - SyntheticBound - SyntheticGeneric - SyntheticRangeOverFuncYield -) - -func (syn Synthetic) String() string { - switch syn { - case SyntheticLoadedFromExportData: - return "loaded from export data" - case SyntheticPackageInitializer: - return "package initializer" - case SyntheticThunk: - return "thunk" - case SyntheticWrapper: - return "wrapper" - case SyntheticBound: - return "bound" - case SyntheticGeneric: - return "generic" - case SyntheticRangeOverFuncYield: - return "range-over-func yield" - default: - return fmt.Sprintf("Synthetic(%d)", syn) - } -} - // Function represents the parameters, results, and code of a function // or method. // @@ -331,6 +302,11 @@ func (syn Synthetic) String() string { // the disassembly. // To iterate over the blocks in dominance order, use DomPreorder(). // +// Recover is an optional second entry point to which control resumes +// after a recovered panic. The Recover block may contain only a return +// statement, preceded by a load of the function's named return +// parameters, if any. +// // A nested function (Parent()!=nil) that refers to one or more // lexically enclosing local variables ("free variables") has FreeVars. // Such functions cannot be called directly but require a @@ -346,7 +322,7 @@ func (syn Synthetic) String() string { // // Pos() returns the declaring ast.FuncLit.Type.Func or the position // of the ast.FuncDecl.Name, if the function was explicit in the -// source. Synthetic wrappers, for which Synthetic != "", may share +// source. Synthetic wrappers, for which Synthetic != "", may share // the same position as the function they wrap. // Syntax.Pos() always returns the position of the declaring "func" token. // @@ -354,6 +330,7 @@ func (syn Synthetic) String() string { // the loop body is transformed into a synthetic anonymous function // that is passed as the yield argument in a call to the iterator. // In that case, Function.Source() is the ast.RangeStmt. +// and Function.Syntax is the ast.RangeStmt. // // Synthetic functions, for which Synthetic != "", are functions // that do not appear in the source AST. These include: @@ -361,23 +338,47 @@ func (syn Synthetic) String() string { // - thunks, // - bound functions, // - empty functions built from loaded type information, -// - yield functions created from range-over-func loops, and -// - package init functions. +// - yield functions created from range-over-func loops, +// - package init functions, and +// - instantiations of generic functions. +// +// Synthetic wrapper functions may share the same position +// as the function they wrap. // // Type() returns the function's Signature. +// +// A generic function is a function or method that has uninstantiated type +// parameters (TypeParams() != nil). Consider a hypothetical generic +// method, (*Map[K,V]).Get. It may be instantiated with all +// non-parameterized types as (*Map[string,int]).Get or with +// parameterized types as (*Map[string,U]).Get, where U is a type parameter. +// In both instantiations, Origin() refers to the instantiated generic +// method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of +// the generic method. TypeArgs() refers to [string,U] or [string,int], +// respectively, and is nil in the generic method. type Function struct { - node - name string - object *types.Func // symbol for declared function (nil for FuncLit or synthetic init) - method *types.Selection // info about provenance of synthetic methods + object *types.Func // symbol for declared function (nil for FuncLit or synthetic init) + method *selection // info about provenance of synthetic methods; thunk => non-nil Signature *types.Signature - generics instanceWrapperMap + pos token.Pos + syntax ast.Node + + // source information + Synthetic string // provenance of synthetic function; "" for true source functions + info *types.Info // type annotations (if syntax != nil) + goversion string // Go version of syntax (NB: init is special) + + parent *Function // enclosing function if anon; nil if global + Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) + Prog *Program // enclosing program + + exprToValue map[ast.Expr]struct { + v Value + isAddr bool + } - Synthetic Synthetic // provenance of synthetic function; 0 for true source functions - parent *Function // enclosing function if anon; nil if global - Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) - Prog *Program // enclosing program + buildshared *task // wait for a shared function to be done building (may be nil if <=1 builder ever needs to wait) // These fields are populated only when the function body is built: @@ -385,123 +386,37 @@ type Function struct { FreeVars []*FreeVar // free variables whose values must be supplied by closure Locals []*Alloc // frame-allocated variables of this function Blocks []*BasicBlock // basic blocks of the function; nil => external - Exit *BasicBlock // The function's exit block + Recover *BasicBlock // optional; control transfers here after recovered panic AnonFuncs []*Function // anonymous functions (from FuncLit, RangeStmt) directly beneath this one referrers []Instruction // referring instructions (iff Parent() != nil) - - goversion string // Go version of syntax (NB: init is special) - - // uniq is not stored in functionBody because we need it after function building finishes - uniq int64 // source of unique ints within the source tree while building - - *functionBody -} - -type instanceWrapperMap struct { - h typeutil.Hasher - entries map[uint32][]struct { - key *types.TypeList - val *Function - } - len int -} - -func typeListIdentical(l1, l2 *types.TypeList) bool { - if l1.Len() != l2.Len() { - return false - } - for i := 0; i < l1.Len(); i++ { - t1 := l1.At(i) - t2 := l2.At(i) - if !types.Identical(t1, t2) { - return false - } - } - return true -} - -func (m *instanceWrapperMap) At(key *types.TypeList) *Function { - if m.entries == nil { - m.entries = make(map[uint32][]struct { - key *types.TypeList - val *Function - }) - m.h = typeutil.MakeHasher() - } - - var hash uint32 - for t := range key.Types() { - hash += m.h.Hash(t) - } - - for _, e := range m.entries[hash] { - if typeListIdentical(e.key, key) { - return e.val - } - } - return nil -} - -func (m *instanceWrapperMap) Set(key *types.TypeList, val *Function) { - if m.entries == nil { - m.entries = make(map[uint32][]struct { - key *types.TypeList - val *Function - }) - m.h = typeutil.MakeHasher() - } - - var hash uint32 - for t := range key.Types() { - hash += m.h.Hash(t) - } - for i, e := range m.entries[hash] { - if typeListIdentical(e.key, key) { - m.entries[hash][i].val = val - return - } - } - m.entries[hash] = append(m.entries[hash], struct { - key *types.TypeList - val *Function - }{key, val}) - m.len++ -} - -func (m *instanceWrapperMap) Len() int { - return m.len -} - -type constValue struct { - c Constant - idx int -} - -type functionBody struct { - // The following fields are set transiently during building, - // then cleared. - currentBlock *BasicBlock // where to emit code - vars map[*types.Var]Value // addresses of local variables - results []*Alloc // result allocations of the current function - returnVars []*types.Var // variables for a return statement. Either results or for range-over-func a parent's results - targets *targets // linked stack of branch targets - lblocks map[*types.Label]*lblock // labelled blocks - jump *types.Var // synthetic variable for the yield state (non-nil => range-over-func) - deferstack *types.Var // synthetic variable holding enclosing ssa:deferstack() - sourceFn *Function // nearest enclosing source function - exits []*exit // exits of the function that need to be resolved - - consts map[constKey]constValue - aggregateConsts typeutil.Map[[]*AggregateConst] - - wr *HTMLWriter - fakeExits BlockSet - blocksets [5]BlockSet - hasDefer bool - - // a contiguous block of instructions that will be used by blocks, - // to avoid making multiple allocations. - scratchInstructions []Instruction + anonIdx int32 // position of a nested function in parent's AnonFuncs. fn.Parent()!=nil => fn.Parent().AnonFunc[fn.anonIdx] == fn. + + SCCs []*SCC // SCC DAG in reverse topological order + + recvtypeparams *types.TypeParamList // receiver type parameters of this function. recvtypeparams.Len() > 0 => method on generic or instance of generic type + recvtypeargs []types.Type // type arguments that instantiated recvtypeparams. len(recvtypeargs) > 0 => method on instance of generic type + typeparams *types.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function or method + typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function or method + topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil. + generic *generic // instances of this function, if generic + + // The following fields are cleared after building. + build buildFunc // algorithm to build function body (nil => built) + currentBlock *BasicBlock // where to emit code + vars map[*types.Var]Value // addresses of local variables + results []*Alloc // result allocations of the current function + returnVars []*types.Var // variables for a return statement. Either results or for range-over-func a parent's results + targets *targets // linked stack of branch targets + lblocks map[*types.Label]*lblock // labelled blocks + subst *subster // type parameter substitutions (if non-nil) + jump *types.Var // synthetic variable for the yield state (non-nil => range-over-func) + deferstack *types.Var // synthetic variable holding enclosing ssa:deferstack() + source *Function // nearest enclosing source function + exits []*exit // exits of the function that need to be resolved + uniq int64 // source of unique ints within the source tree while building + liftableBlockMap BlockMap[liftableBlockDesc] + + blocksets [4]BlockSet } // BasicBlock represents an IR basic block. @@ -529,12 +444,18 @@ type BasicBlock struct { parent *Function // parent function Instrs []Instruction // instructions in order Preds, Succs []*BasicBlock // predecessors and successors + SCC *SCC // strongly connected component succs2 [2]*BasicBlock // initial space for Succs dom domInfo // dominator tree info - pdom domInfo // post-dominator tree info - post int - gaps int // number of nil Instrs (transient) - rundefers int // number of rundefers (transient) + gaps int // number of nil Instrs (transient) + rundefers int // number of rundefers (transient) +} + +type SCC struct { + Index int + Blocks []*BasicBlock + Preds, Succs []*SCC + reachable big.Int } // Pure values ---------------------------------------- @@ -568,42 +489,46 @@ type FreeVar struct { // A Parameter represents an input parameter of a function. type Parameter struct { - register + node - name string - object *types.Var // non-nil + name string + object *types.Var // non-nil + typ types.Type + parent *Function + referrers []Instruction } -// A Const represents the value of a constant expression. -// -// The underlying type of a constant may be any boolean, numeric, or -// string type. In addition, a Const may represent the nil value of -// any reference type---interface, map, channel, pointer, slice, or -// function---but not "untyped nil". -// -// All source-level constant expressions are represented by a Const -// of the same type and value. +// A Const represents a value known at build time. // -// Value holds the exact value of the constant, independent of its -// Type(), using the same representation as package go/constant uses for -// constants, or nil for a typed nil value. +// Consts include true constants of boolean, numeric, and string types, as +// defined by the Go spec; these are represented by a non-nil Value field. // -// Pos() returns token.NoPos. +// Consts also include the "zero" value of any type, of which the nil values +// of various pointer-like types are a special case; these are represented +// by a nil Value field. // // Example printed form: // -// Const {42} -// Const {"test"} -// Const {(3 + 4i)} +// 42:int +// "hello":untyped string +// 3+4i:MyComplex +// nil:*int +// nil:[]string +// [3]int{}:[3]int +// struct{x string}{}:struct{x string} +// 0:interface{int|int64} +// nil:interface{bool|int} // no go/constant representation type Const struct { - register + node + typ types.Type Value constant.Value } type AggregateConst struct { - register + node + typ types.Type Values []Value } @@ -613,33 +538,20 @@ type CompositeValue struct { // Bitmap records which elements were explicitly provided. For example, [4]byte{2: x} would have a bitmap of 0010. Bitmap big.Int // The number of bits set in Bitmap + // TODO(dh): remove NumSet. we can just query the bitmap. NumSet int // Dense list of values in the composite literal. Omitted elements are filled in with zero values. Values []Value } -// TODO add the element's zero constant to ArrayConst -type ArrayConst struct { - register -} - -type GenericConst struct { - register -} - type Constant interface { - Instruction Value aConstant() RelString(*types.Package) string - equal(Constant) bool - setType(types.Type) } func (*Const) aConstant() {} func (*AggregateConst) aConstant() {} -func (*ArrayConst) aConstant() {} -func (*GenericConst) aConstant() {} // A Global is a named Value holding the address of a package-level // variable. @@ -712,60 +624,17 @@ type Builtin struct { // // Example printed form: // -// t1 = StackAlloc <*int> -// t2 = HeapAlloc <*int> (new) +// t0 = local int +// t1 = new int type Alloc struct { register Heap bool index int // dense numbering; for lifting } -var _ Instruction = (*Sigma)(nil) -var _ Value = (*Sigma)(nil) - -// The Sigma instruction represents an SSI σ-node, which splits values -// at branches in the control flow. -// -// Conceptually, σ-nodes exist at the end of blocks that branch and -// constitute parallel assignments to one value per destination block. -// However, such a representation would be awkward to work with, so -// instead we place σ-nodes at the beginning of branch targets. The -// From field denotes to which incoming edge the node applies. -// -// Within a block, all σ-nodes must appear before all non-σ nodes. -// -// Example printed form: -// -// t2 = Sigma [#0] t1 (x) -type Sigma struct { - register - From *BasicBlock - X Value - - live bool // used during lifting -} - -type CopyInfo uint64 - -const ( - CopyInfoUnspecified CopyInfo = 0 - CopyInfoNotNil CopyInfo = 1 << iota - CopyInfoNotZeroLength - CopyInfoNotNegative - CopyInfoSingleConcreteType - CopyInfoClosed -) - -type Copy struct { - register - X Value - Why Instruction - Info CopyInfo -} - // The Phi instruction represents an SSA φ-node, which combines values // that differ across incoming control-flow edges and yields a new -// value. Within a block, all φ-nodes must appear before all non-φ, non-σ +// value. Within a block, all φ-nodes must appear before all non-φ // nodes. // // Pos() returns the position of the && or || for short-circuit @@ -774,7 +643,7 @@ type Copy struct { // // Example printed form: // -// t3 = Phi 2:t1 4:t2 (x) +// t2 = phi [0: t0, 1: t1] type Phi struct { register Edges []Value // Edges[i] is value for Block().Preds[i] @@ -794,9 +663,9 @@ type Phi struct { // // Example printed form: // -// t3 = Call <()> println t1 t2 -// t4 = Call <()> foo$1 -// t6 = Invoke t5.String +// t2 = println(t0, t1) +// t4 = t3() +// t7 = invoke t5.Println(...t6) type Call struct { register Call CallCommon @@ -808,7 +677,7 @@ type Call struct { // // Example printed form: // -// t3 = BinOp {+} t2 t1 +// t1 = t0 + 1:int type BinOp struct { register // One of: @@ -826,7 +695,7 @@ type BinOp struct { // // Example printed form: // -// t2 = UnOp {^} t1 +// t0 = ^x type UnOp struct { register Op token.Token // One of: NOT SUB XOR ! - ^ @@ -856,15 +725,23 @@ type Load struct { // - between (possibly named) pointers to identical base types. // - from a bidirectional channel to a read- or write-channel, // optionally adding/removing a name. +// - between a type (t) and an instance of the type (tσ), i.e. +// Type() == σ(X.Type()) (or X.Type()== σ(Type())) where +// σ is the type substitution of Parent().TypeParams by +// Parent().TypeArgs. // // This operation cannot fail dynamically. // +// Type changes may to be to or from a type parameter (or both). All +// types in the type set of X.Type() have a value-preserving type +// change to all types in the type set of Type(). +// // Pos() returns the ast.CallExpr.Lparen, if the instruction arose // from an explicit conversion in the source. // // Example printed form: // -// t2 = ChangeType <*T> t1 +// t1 = changetype *int <- IntPtr (t0) type ChangeType struct { register X Value @@ -884,6 +761,10 @@ type ChangeType struct { // // A conversion may imply a type name change also. // +// Conversions may to be to or from a type parameter. All types in +// the type set of X.Type() can be converted to all types in the type +// set of Type(). +// // This operation cannot fail dynamically. // // Conversions of untyped string/number/bool constants to a specific @@ -894,7 +775,7 @@ type ChangeType struct { // // Example printed form: // -// t2 = Convert <[]byte> t1 +// t1 = convert []byte <- string (t0) type Convert struct { register X Value @@ -915,9 +796,8 @@ type Convert struct { // t1 = multiconvert D <- S (t0) [*[2]rune <- []rune | string <- []rune] type MultiConvert struct { register - X Value - from typeutil.TypeSet - to typeutil.TypeSet + X Value + from, to types.Type } // ChangeInterface constructs a value of one interface type from a @@ -931,7 +811,7 @@ type MultiConvert struct { // // Example printed form: // -// t2 = ChangeInterface t1 +// t1 = change interface interface{} <- I (t0) type ChangeInterface struct { register X Value @@ -943,9 +823,17 @@ type ChangeInterface struct { // Pos() returns the ast.CallExpr.Lparen, if the instruction arose // from an explicit conversion in the source. // +// Conversion may to be to or from a type parameter. All types in +// the type set of X.Type() must be a slice types that can be converted to +// all types in the type set of Type() which must all be pointer to array +// types. +// +// This operation can fail dynamically if the length of the slice is less +// than the length of the array. +// // Example printed form: // -// t2 = SliceToArrayPointer <*[4]byte> t1 +// t1 = slice to array pointer *[4]byte <- []byte (t0) type SliceToArrayPointer struct { register X Value @@ -980,7 +868,8 @@ type SliceToArray struct { // // Example printed form: // -// t2 = MakeInterface t1 +// t1 = make interface{} <- int (42:int) +// t1 = make Stringer <- t0 type MakeInterface struct { register X Value @@ -996,8 +885,8 @@ type MakeInterface struct { // // Example printed form: // -// t1 = MakeClosure foo$1 t1 t2 -// t5 = MakeClosure (T).foo$bound t4 +// t0 = make closure anon@1.2 [x y z] +// t1 = make closure bound$(main.I).add [i] type MakeClosure struct { register Fn Value // always a *Function @@ -1014,8 +903,8 @@ type MakeClosure struct { // // Example printed form: // -// t1 = MakeMap -// t2 = MakeMap t1 +// t1 = make map[string]int t0 +// t1 = make StringIntMap t0 type MakeMap struct { register Reserve Value // initial space reservation; nil => default @@ -1031,8 +920,8 @@ type MakeMap struct { // // Example printed form: // -// t3 = MakeChan t1 -// t4 = MakeChan t2 +// t1 = make chan int t0 +// t1 = make IntChan t0 type MakeChan struct { register Size Value // int; size of buffer; zero => synchronous. @@ -1053,8 +942,8 @@ type MakeChan struct { // // Example printed form: // -// t3 = MakeSlice <[]string> t1 t2 -// t4 = MakeSlice t1 t2 +// t2 = make []string t1 t0 +// t2 = make StringSlice t1 t0 type MakeSlice struct { register Len Value @@ -1076,7 +965,7 @@ type MakeSlice struct { // // Example printed form: // -// t4 = Slice <[]int> t3 t2 t1 +// t2 = slice t0[t1:] type Slice struct { register X Value // slice, string, or *array @@ -1094,15 +983,18 @@ type Slice struct { // Type() returns a (possibly named) *types.Pointer. // // Pos() returns the position of the ast.SelectorExpr.Sel for the -// field, if explicit in the source. +// field, if explicit in the source. For implicit selections, returns +// the position of the inducing explicit selection. If produced for a +// struct literal S{f: e}, it returns the position of the colon; for +// S{e} it returns the start of expression e. // // Example printed form: // -// t2 = FieldAddr <*int> [0] (X) t1 +// t1 = &t0.name [#1] type FieldAddr struct { register X Value // *struct - Field int // field is X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct).Field(Field) + Field int // index into CoreType(CoreType(X.Type()).(*types.Pointer).Elem()).(*types.Struct).Fields } // The Field instruction yields the Field of struct X. @@ -1112,22 +1004,23 @@ type FieldAddr struct { // package-local identifiers and permit compact representations. // // Pos() returns the position of the ast.SelectorExpr.Sel for the -// field, if explicit in the source. +// field, if explicit in the source. For implicit selections, returns +// the position of the inducing explicit selection. // // Example printed form: // -// t2 = FieldAddr [0] (X) t1 +// t1 = t0.name [#1] type Field struct { register X Value // struct - Field int // index into X.Type().(*types.Struct).Fields + Field int // index into CoreType(X.Type()).(*types.Struct).Fields } // The IndexAddr instruction yields the address of the element at // index Index of collection X. Index is an integer expression. // -// The elements of maps and strings are not addressable; use StringLookup, MapLookup or -// MapUpdate instead. +// The elements of maps and strings are not addressable; use Lookup (map), +// Index (string), or MapUpdate instead. // // Dynamically, this instruction panics if X evaluates to a nil *array // pointer. @@ -1139,28 +1032,31 @@ type Field struct { // // Example printed form: // -// t3 = IndexAddr <*int> t2 t1 +// t2 = &t0[t1] type IndexAddr struct { register - X Value // slice or *array, + X Value // *array, slice or type parameter with types array, *array, or slice. Index Value // numeric index } -// The Index instruction yields element Index of array X. +// The Index instruction yields element Index of collection X, an array, +// string or type parameter containing an array, a string, a pointer to an, +// array or a slice. // // Pos() returns the ast.IndexExpr.Lbrack for the index operation, if // explicit in the source. // // Example printed form: // -// t3 = Index t2 t1 +// t2 = t0[t1] type Index struct { register - X Value // array + X Value // array, string or type parameter with types array, *array, slice, or string. Index Value // integer index } // The MapLookup instruction yields element Index of collection X, a map. +// Index is the appropriate key type. // // If CommaOk, the result is a 2-tuple of the value above and a // boolean indicating the result of a map membership test for the key. @@ -1170,8 +1066,8 @@ type Index struct { // // Example printed form: // -// t4 = MapLookup t3 t1 -// t6 = MapLookup <(string, bool)> t3 t2 +// t2 = t0[t1] +// t5 = t3[t4],ok type MapLookup struct { register X Value // map @@ -1238,8 +1134,8 @@ type SelectState struct { // // Example printed form: // -// t6 = SelectNonBlocking <(index int, ok bool, int)> [<-t4, t5<-t1] -// t11 = SelectBlocking <(index int, ok bool)> [] +// t3 = select nonblocking [<-t0, t1<-t2] +// t4 = select blocking [] type Select struct { register States []*SelectState @@ -1257,7 +1153,7 @@ type Select struct { // // Example printed form: // -// t2 = Range t1 +// t0 = range "hello":string type Range struct { register X Value // string or map @@ -1280,8 +1176,7 @@ type Range struct { // // Example printed form: // -// t5 = Next <(ok bool, k int, v rune)> t2 -// t5 = Next <(ok bool, k invalid type, v invalid type)> t2 +// t1 = next t0 type Next struct { register Iter Value @@ -1299,6 +1194,9 @@ type Next struct { // is AssertedType's zero value. The components of the pair must be // accessed using the Extract instruction. // +// If Underlying: tests whether interface value X has the underlying +// type AssertedType. +// // If AssertedType is a concrete type, TypeAssert checks whether the // dynamic type in interface X is equal to it, and if so, the result // of the conversion is a copy of the value in the interface. @@ -1313,16 +1211,17 @@ type Next struct { // Type() reflects the actual type of the result, possibly a // 2-types.Tuple; AssertedType is the asserted type. // -// Pos() returns the ast.CallExpr.Lparen if the instruction arose from -// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the -// instruction arose from an explicit e.(T) operation; or the -// ast.CaseClause.Case if the instruction arose from a case of a -// type-switch statement. +// Depending on the TypeAssert's purpose, Pos may return: +// - the ast.CallExpr.Lparen of an explicit T(e) conversion; +// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation; +// - the ast.CaseClause.Case of a case of a type-switch statement; +// - the Ident(m).NamePos of an interface method value i.m +// (for which TypeAssert may be used to effect the nil check). // // Example printed form: // -// t2 = TypeAssert t1 -// t4 = TypeAssert <(value fmt.Stringer, ok bool)> t1 +// t1 = typeassert t0.(int) +// t3 = typeassert,ok t2.(T) type TypeAssert struct { register X Value @@ -1338,7 +1237,7 @@ type TypeAssert struct { // // Example printed form: // -// t7 = Extract [1] (ok) t4 +// t1 = extract t0 #1 type Extract struct { register Tuple Value @@ -1356,7 +1255,7 @@ type Extract struct { // // Example printed form: // -// Jump → b1 +// jump done type Jump struct { anInstruction } @@ -1365,15 +1264,12 @@ type Jump struct { // continue after the preceding function call because it terminates // the process. // -// The instruction acts as a control instruction, jumping to the exit -// block. However, this jump will never execute. -// // An Unreachable instruction must be the last instruction of its -// containing BasicBlock. +// containing BasicBlock, which must have no successors. // // Example printed form: // -// Unreachable → b1 +// Unreachable type Unreachable struct { anInstruction } @@ -1389,7 +1285,7 @@ type Unreachable struct { // // Example printed form: // -// If t2 → b1 b2 +// if t0 goto done else body type If struct { anInstruction Cond Value @@ -1429,8 +1325,8 @@ type TypeSwitch struct { // // Example printed form: // -// Return -// Return t1 t2 +// return +// return t0, t1 type Return struct { anInstruction Results []Value @@ -1447,7 +1343,7 @@ type Return struct { // // Example printed form: // -// RunDefers +// rundefers type RunDefers struct { anInstruction } @@ -1455,7 +1351,7 @@ type RunDefers struct { // The Panic instruction initiates a panic with value X. // // A Panic instruction must be the last instruction of its containing -// BasicBlock, which must have one successor, the exit block. +// BasicBlock, which must have no successors. // // NB: 'go panic(x)' and 'defer panic(x)' do not use this instruction; // they are treated as calls to a built-in function. @@ -1465,7 +1361,7 @@ type RunDefers struct { // // Example printed form: // -// Panic t1 +// panic t0 type Panic struct { anInstruction X Value // an interface{} @@ -1480,9 +1376,9 @@ type Panic struct { // // Example printed form: // -// Go println t1 -// Go t3 -// GoInvoke t4.Bar t2 +// go println(t0, t1) +// go t3() +// go invoke t5.Println(...t6) type Go struct { anInstruction Call CallCommon @@ -1491,10 +1387,10 @@ type Go struct { // The Defer instruction pushes the specified call onto a stack of // functions to be called by a RunDefers instruction or by a panic. // -// If _DeferStack != nil, it indicates the defer list that the defer is +// If DeferStack != nil, it indicates the defer list that the defer is // added to. Defer list values come from the Builtin function // ssa:deferstack. Calls to ssa:deferstack() produces the defer stack -// of the current function frame. _DeferStack allows for deferring into an +// of the current function frame. DeferStack allows for deferring into an // alternative function stack than the current function. // // See CallCommon for generic function call documentation. @@ -1503,15 +1399,13 @@ type Go struct { // // Example printed form: // -// Defer println t1 -// Defer t3 -// DeferInvoke t4.Bar t2 +// defer println(t0, t1) +// defer t3() +// defer invoke t5.Println(...t6) type Defer struct { anInstruction - Call CallCommon - _DeferStack Value // stack (from ssa:deferstack() intrinsic) onto which this function is pushed - - // TODO: Exporting _DeferStack and possibly making _DeferStack != nil awaits proposal https://github.com/golang/go/issues/66601. + Call CallCommon + DeferStack Value // stack of deferred functions (from ssa:deferstack() intrinsic) onto which this function is pushed } // The Send instruction sends X on channel Chan. @@ -1520,7 +1414,7 @@ type Defer struct { // // Example printed form: // -// Send t2 t1 +// send t0 <- t1 type Send struct { anInstruction Chan, X Value @@ -1556,7 +1450,7 @@ type Recv struct { // // Example printed form: // -// Store {int} t2 t1 +// *x = y type Store struct { anInstruction Addr Value @@ -1586,7 +1480,7 @@ type BlankStore struct { // // Example printed form: // -// MapUpdate t3 t1 t2 +// t0[t1] = t2 type MapUpdate struct { anInstruction Map Value @@ -1594,17 +1488,22 @@ type MapUpdate struct { Value Value } -// A DebugRef instruction maps a source-level expression Expr to the +// A debugRef instruction maps a source-level expression Expr to the // IR value X that represents the value (!IsAddr) or address (IsAddr) // of that expression. // -// DebugRef is a pseudo-instruction: it has no dynamic effect. +// debugRef is a pseudo-instruction: it has no dynamic effect. // // Pos() returns Expr.Pos(), the start position of the source-level // expression. This is not the same as the "designated" token as // documented at Value.Pos(). e.g. CallExpr.Pos() does not return the // position of the ("designated") Lparen token. // +// If Expr is an *ast.Ident denoting a var or func, Object() returns +// the object; though this information can be obtained from the type +// checker, including it here greatly facilitates debugging. +// For non-Ident expressions, Object() returns nil. +// // DebugRefs are generated only for functions built with debugging // enabled; see Package.SetDebugMode() and the GlobalDebug builder // mode flag. @@ -1622,7 +1521,7 @@ type MapUpdate struct { // ; *ast.CallExpr @ 102:9 is t5 // ; var x float64 @ 109:72 is x // ; address of *ast.CompositeLit @ 216:10 is t0 -type DebugRef struct { +type debugRef struct { anInstruction Expr ast.Expr // the referring expression (never *ast.ParenExpr) object types.Object // the identity of the source var/func @@ -1647,12 +1546,8 @@ type register struct { type node struct { source ast.Node - id ID } -func (n *node) setID(id ID) { n.id = id } -func (n node) ID() ID { return n.id } - func (n *node) setSource(source ast.Node) { n.source = source } func (n *node) Source() ast.Node { return n.source } @@ -1667,10 +1562,19 @@ func (n *node) Pos() token.Pos { // It provides the implementations of the Block and setBlock methods. type anInstruction struct { node + id ID block *BasicBlock // the basic block of this instruction comment string } +func (instr *anInstruction) setID(id ID) { + instr.id = id +} + +func (instr anInstruction) ID() ID { + return instr.id +} + func (instr anInstruction) Comment() string { return instr.comment } @@ -1706,16 +1610,17 @@ func (instr anInstruction) Comment() string { // // Example printed form: // -// t3 = Call <()> println t1 t2 -// Go t3 -// Defer t3 +// t2 = println(t0, t1) +// go t3() +// defer t5(...t6) // // 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon // represents a dynamically dispatched call to an interface method. // In this mode, Value is the interface value and Method is the -// interface's abstract method. Note: an abstract method may be -// shared by multiple interfaces due to embedding; Value.Type() -// provides the specific interface used for this call. +// interface's abstract method. The interface value may be a type +// parameter. Note: an interface method may be shared by multiple +// interfaces due to embedding; Value.Type() provides the specific +// interface used for this call. // // Value is implicitly supplied to the concrete method implementation // as the receiver parameter; in other words, Args[0] holds not the @@ -1723,18 +1628,18 @@ func (instr anInstruction) Comment() string { // // Example printed form: // -// t6 = Invoke t5.String -// GoInvoke t4.Bar t2 -// DeferInvoke t4.Bar t2 +// t1 = invoke t0.String() +// go invoke t3.Run(t2) +// defer invoke t4.Handle(...t5) // // For all calls to variadic functions (Signature().Variadic()), // the last element of Args is a slice. type CallCommon struct { - Value Value // receiver (invoke mode) or func value (call mode) - Method *types.Func // abstract method (invoke mode) - Args []Value // actual parameters (in static method call, includes receiver) - TypeArgs []types.Type - Results Value + Value Value // receiver (invoke mode) or func value (call mode) + Method *types.Func // interface method (invoke mode) + Args []Value // actual parameters (in static method call, includes receiver) + + source ast.Node } // IsInvoke returns true if this call has "invoke" (not "call") mode. @@ -1742,6 +1647,13 @@ func (c *CallCommon) IsInvoke() bool { return c.Method != nil } +func (c *CallCommon) Pos() token.Pos { + if c.source != nil { + return c.source.Pos() + } + return token.NoPos +} + // Signature returns the signature of the called function. // // For an "invoke"-mode call, the signature of the interface method is @@ -1801,6 +1713,10 @@ func (s *Call) Common() *CallCommon { return &s.Call } func (s *Defer) Common() *CallCommon { return &s.Call } func (s *Go) Common() *CallCommon { return &s.Call } +func (s *Call) setSource(source ast.Node) { s.source = source; s.Call.source = source } +func (s *Defer) setSource(source ast.Node) { s.source = source; s.Call.source = source } +func (s *Go) setSource(source ast.Node) { s.source = source; s.Call.source = source } + func (s *Call) Value() *Call { return s } func (s *Defer) Value() *Call { return nil } func (s *Go) Value() *Call { return nil } @@ -1846,7 +1762,187 @@ func (v *Function) Referrers() *[]Instruction { return nil } -func (v *Parameter) Object() types.Object { return v.object } +// Returns returns an iterator over all blocks containing return statements. +func (v *Function) Returns() iter.Seq[*BasicBlock] { + return func(yield func(*BasicBlock) bool) { + for _, b := range v.Blocks { + if _, ok := b.Control().(*Return); ok { + if !yield(b) { + return + } + } + } + } +} + +// Exits returns an iterator over all blocks that have no successors. +func (v *Function) Exits() iter.Seq[*BasicBlock] { + return func(yield func(*BasicBlock) bool) { + for _, b := range v.Blocks { + if len(b.Succs) == 0 { + if !yield(b) { + return + } + } + } + } +} + +// Nodes returns an iterator over the basic block indices. +func (v *Function) Nodes() iter.Seq[int] { + return func(yield func(int) bool) { + for i := range v.Blocks { + if !yield(i) { + return + } + } + } +} + +// NumNodes returns the number of basic blocks in the graph. +func (v *Function) NumNodes() int { return len(v.Blocks) } + +// Out returns an iterator over the successor block indices of a given node. +func (v *Function) Out(node int) iter.Seq[int] { + return func(yield func(int) bool) { + for _, succ := range v.Blocks[node].Succs { + if !yield(succ.Index) { + return + } + } + } +} + +func (v *Parameter) Type() types.Type { return v.typ } +func (v *Parameter) Name() string { return v.name } +func (v *Parameter) Object() types.Object { return v.object } +func (v *Parameter) Referrers() *[]Instruction { return &v.referrers } +func (v *Parameter) Pos() token.Pos { return v.object.Pos() } +func (v *Parameter) Parent() *Function { return v.parent } + +// TypeParams are the function's type parameters if generic or the +// type parameters that were instantiated if fn is an instantiation. +// +// Specifically, the resulting list behaves like: +// +// func f // [] +// func f[P] // [P] +// func (T) m // [] +// func (T) m[P] // [P] +// func (T[P]) m // [P] +// func (T[P]) m[Q] // [P (index=0), Q (index=0)] +// +// Note that receiver type parameters precede other type parameters. +// Also, type parameters may have the same index if they come from +// different source type parameter lists. +func (fn *Function) TypeParams() *types.TypeParamList { + return consTypeParamLists(fn.recvtypeparams, fn.typeparams) +} + +func consTypeParamLists(l, r *types.TypeParamList) *types.TypeParamList { + if l.Len() == 0 { + return r + } + if r.Len() == 0 { + return l + } + + tpars := make([]*types.TypeParam, l.Len()+r.Len()) + for i := range l.Len() { + tpars[i] = l.At(i) + } + for i := range r.Len() { + tpars[i+l.Len()] = r.At(i) + } + // This logic unsafely assumes (and asserts) that the layout of the + // TypeParamList is identical to that of a slice of TypeParams. This + // is a hack while we work on getting a constructor for TypeParamList + // approved (see go.dev/issue/79603). + t := reflect.TypeFor[types.TypeParamList]() + if t.NumField() != 1 { + panic("TypeParamList has unexpected fields") + } + if f := t.Field(0); f.Offset != 0 || f.Type != reflect.TypeFor[[]*types.TypeParam]() { + panic("TypeParamList field is not []*TypeParam") + } + return (*types.TypeParamList)(unsafe.Pointer(&tpars)) +} + +// TypeArgs are the types that TypeParams() were instantiated by to create fn +// from fn.Origin(). +// +// Specifically, the resulting slice behaves like: +// +// f // [] +// f[int] // [int] +// T.m // [] +// T.m[int] // [int] +// T[int].m // [int] +// T[int].m[uint] // [int, uint] +// +// Note that receiver type arguments precede other type arguments. +func (fn *Function) TypeArgs() []types.Type { + return slices.Concat(fn.recvtypeargs, fn.typeargs) +} + +// Origin returns the generic function from which fn was instantiated, +// or nil if fn is not an instantiation. +func (fn *Function) Origin() *Function { + if fn.parent != nil && fn.parent.hasTypeArgs() { + // Nested functions are BUILT at a different time than their instances. + // Build declared package if not yet BUILT. This is not an expected use + // case, but is simple and robust. + fn.declaredPackage().Build() + } + return origin(fn) +} + +// hasTypeParams returns whether fn has any type parameters +func (fn *Function) hasTypeParams() bool { + return fn.recvtypeparams.Len()+fn.typeparams.Len() > 0 +} + +// hasTypeArgs returns whether fn has any type arguments +func (fn *Function) hasTypeArgs() bool { + return len(fn.recvtypeargs)+len(fn.typeargs) > 0 +} + +// subrtargs returns fn's receiver type parameters substituted with receiver type arguments +func (fn *Function) subrtargs(m *types.Func) []types.Type { + return fn.subst.types(receiverTypeArgs(m)) +} + +// subtargs returns fn's type parameters substituted with (possibly implied) type arguments +func (fn *Function) subtargs(id *ast.Ident) []types.Type { + return fn.subst.types(instanceArgs(fn.info, id)) +} + +// targstr returns a comma-separated string of the types in targs +func targstr(targs []types.Type) string { + var sb strings.Builder + if len(targs) > 0 { + sb.WriteString("[") + for i := range targs { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(targs[i].String()) + } + sb.WriteString("]") + } + return sb.String() +} + +// origin is the function that fn is an instantiation of. Returns nil if fn is +// not an instantiation. +// +// Precondition: fn and the origin function are done building. +func origin(fn *Function) *Function { + if fn.parent != nil && fn.parent.hasTypeArgs() { + return origin(fn.parent).AnonFuncs[fn.anonIdx] + } + return fn.topLevelOrigin +} func (v *Alloc) Type() types.Type { return v.typ } func (v *Alloc) Referrers() *[]Instruction { return &v.referrers } @@ -1879,6 +1975,11 @@ func (c *NamedConst) Object() types.Object { return c.object } func (c *NamedConst) Package() *Package { return c.pkg } func (c *NamedConst) RelString(from *types.Package) string { return relString(c, from) } +func (v *Function) Pos() token.Pos { return v.pos } +func (v *Function) Source() ast.Node { return v.syntax } + +func (d *debugRef) Object() types.Object { return d.object } + // Func returns the package-level function of the specified name, // or nil if not found. func (p *Package) Func(name string) (f *Function) { @@ -1907,7 +2008,7 @@ func (p *Package) Type(name string) (t *Type) { return } -func (s *DebugRef) Pos() token.Pos { return s.Expr.Pos() } +func (s *debugRef) Pos() token.Pos { return s.Expr.Pos() } // Operands. @@ -1936,7 +2037,7 @@ func (s *Call) Operands(rands []*Value) []*Value { } func (s *Defer) Operands(rands []*Value) []*Value { - return append(s.Call.Operands(rands), &s._DeferStack) + return append(s.Call.Operands(rands), &s.DeferStack) } func (v *ChangeInterface) Operands(rands []*Value) []*Value { @@ -1963,11 +2064,7 @@ func (v *SliceToArray) Operands(rands []*Value) []*Value { return append(rands, &v.X) } -func (s *DebugRef) Operands(rands []*Value) []*Value { - return append(rands, &s.X) -} - -func (s *Copy) Operands(rands []*Value) []*Value { +func (s *debugRef) Operands(rands []*Value) []*Value { return append(rands, &s.X) } @@ -2060,10 +2157,6 @@ func (s *Panic) Operands(rands []*Value) []*Value { return append(rands, &s.X) } -func (v *Sigma) Operands(rands []*Value) []*Value { - return append(rands, &v.X) -} - func (v *Phi) Operands(rands []*Value) []*Value { for i := range v.Edges { rands = append(rands, &v.Edges[i]) @@ -2140,11 +2233,9 @@ func (v *CompositeValue) Operands(rands []*Value) []*Value { } // Non-Instruction Values: -func (v *Builtin) Operands(rands []*Value) []*Value { return rands } -func (v *FreeVar) Operands(rands []*Value) []*Value { return rands } -func (v *Const) Operands(rands []*Value) []*Value { return rands } -func (v *ArrayConst) Operands(rands []*Value) []*Value { return rands } -func (v *GenericConst) Operands(rands []*Value) []*Value { return rands } -func (v *Function) Operands(rands []*Value) []*Value { return rands } -func (v *Global) Operands(rands []*Value) []*Value { return rands } -func (v *Parameter) Operands(rands []*Value) []*Value { return rands } +func (v *Builtin) Operands(rands []*Value) []*Value { return rands } +func (v *FreeVar) Operands(rands []*Value) []*Value { return rands } +func (v *Const) Operands(rands []*Value) []*Value { return rands } +func (v *Function) Operands(rands []*Value) []*Value { return rands } +func (v *Global) Operands(rands []*Value) []*Value { return rands } +func (v *Parameter) Operands(rands []*Value) []*Value { return rands } diff --git a/vendor/honnef.co/go/tools/go/ir/subst.go b/vendor/honnef.co/go/tools/go/ir/subst.go new file mode 100644 index 00000000..07b636a4 --- /dev/null +++ b/vendor/honnef.co/go/tools/go/ir/subst.go @@ -0,0 +1,577 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ir + +import ( + "fmt" + "go/types" + + "honnef.co/go/tools/go/types/typeutil" + "honnef.co/go/tools/internal/xtools-internal/aliases" +) + +// subster defines a type substitution operation of a set of type parameters +// to type parameter free replacement types. Substitution is done within +// the context of a package-level function instantiation. *Named types +// declared in the function are unique to the instantiation. +// +// For example, given a parameterized function F +// +// func F[S, T any]() any { +// type X struct{ s S; next *X } +// var p *X +// return p +// } +// +// calling the instantiation F[string, int]() returns an interface +// value (*X[string,int], nil) where the underlying value of +// X[string,int] is a struct{s string; next *X[string,int]}. +// +// A nil *subster is a valid, empty substitution map. It always acts as +// the identity function. This allows for treating parameterized and +// non-parameterized functions identically while compiling to ssa. +// +// Not concurrency-safe. +// +// Note: Some may find it helpful to think through some of the most +// complex substitution cases using lambda calculus inspired notation. +// subst.typ() solves evaluating a type expression E +// within the body of a function Fn[m] with the type parameters m +// once we have applied the type arguments N. +// We can succinctly write this as a function application: +// +// ((λm. E) N) +// +// go/types does not provide this interface directly. +// So what subster provides is a type substitution operation +// +// E[m:=N] +type subster struct { + replacements map[*types.TypeParam]types.Type // values should contain no type params + cache map[types.Type]types.Type // cache of subst results + origin *types.Func // types.Objects declared within this origin function are unique within this context + ctxt *types.Context // speeds up repeated instantiations + uniqueness typeutil.Map[types.Type] // determines the uniqueness of the instantiations within the function + // TODO(taking): consider adding Pos +} + +// Returns a subster that replaces rtparams[i] with rtargs[i] and tparams[i] with targs[i]. +// Uses ctxt as a cache. rtargs and targs should not contain any types in rtparams or tparams. +// fn is the generic function for which we are substituting. +func makeSubster(ctxt *types.Context, fn *types.Func, rtparams *types.TypeParamList, rtargs []types.Type, tparams *types.TypeParamList, targs []types.Type) *subster { + got := len(rtargs) + len(targs) + want := rtparams.Len() + tparams.Len() + if got != want { + panic(fmt.Sprintf("makeSubster argument count must match: got %d; want %d", got, want)) + } + + subst := &subster{ + replacements: make(map[*types.TypeParam]types.Type, want), + cache: make(map[types.Type]types.Type), + origin: fn.Origin(), + ctxt: ctxt, + } + for i := 0; i < rtparams.Len(); i++ { + subst.replacements[rtparams.At(i)] = rtargs[i] + } + for i := 0; i < tparams.Len(); i++ { + subst.replacements[tparams.At(i)] = targs[i] + } + return subst +} + +// typ returns the type of t with the type parameter tparams[i] substituted +// for the type targs[i] where subst was created using tparams and targs. +func (subst *subster) typ(t types.Type) (res types.Type) { + if subst == nil { + return t // A nil subst is type preserving. + } + if r, ok := subst.cache[t]; ok { + return r + } + defer func() { + subst.cache[t] = res + }() + + switch t := t.(type) { + case *types.TypeParam: + if r := subst.replacements[t]; r != nil { + return r + } + return t + + case *types.Basic: + return t + + case *types.Array: + if r := subst.typ(t.Elem()); r != t.Elem() { + return types.NewArray(r, t.Len()) + } + return t + + case *types.Slice: + if r := subst.typ(t.Elem()); r != t.Elem() { + return types.NewSlice(r) + } + return t + + case *types.Pointer: + if r := subst.typ(t.Elem()); r != t.Elem() { + return types.NewPointer(r) + } + return t + + case *types.Tuple: + return subst.tuple(t) + + case *types.Struct: + return subst.struct_(t) + + case *types.Map: + key := subst.typ(t.Key()) + elem := subst.typ(t.Elem()) + if key != t.Key() || elem != t.Elem() { + return types.NewMap(key, elem) + } + return t + + case *types.Chan: + if elem := subst.typ(t.Elem()); elem != t.Elem() { + return types.NewChan(t.Dir(), elem) + } + return t + + case *types.Signature: + return subst.signature(t) + + case *types.Union: + return subst.union(t) + + case *types.Interface: + return subst.interface_(t) + + case *types.Alias: + return subst.alias(t) + + case *types.Named: + return subst.named(t) + + case *typeutil.Iterator: + elem := subst.typ(t.Elem()) + if elem != t.Elem() { + return typeutil.NewIterator(elem) + } + return t + + case *typeutil.DeferStack: + return t + + default: + panic(fmt.Sprintf("internal error: unhandled type %T", t)) + } +} + +// types returns the result of {subst.typ(ts[i])}. +func (subst *subster) types(ts []types.Type) []types.Type { + res := make([]types.Type, len(ts)) + for i := range ts { + res[i] = subst.typ(ts[i]) + } + return res +} + +func (subst *subster) tuple(t *types.Tuple) *types.Tuple { + if t != nil { + if vars := subst.varlist(t); vars != nil { + return types.NewTuple(vars...) + } + } + return t +} + +type varlist interface { + At(i int) *types.Var + Len() int +} + +// fieldlist is an adapter for structs for the varlist interface. +type fieldlist struct { + str *types.Struct +} + +func (fl fieldlist) At(i int) *types.Var { return fl.str.Field(i) } +func (fl fieldlist) Len() int { return fl.str.NumFields() } + +func (subst *subster) struct_(t *types.Struct) *types.Struct { + if t != nil { + if fields := subst.varlist(fieldlist{t}); fields != nil { + tags := make([]string, t.NumFields()) + for i, n := 0, t.NumFields(); i < n; i++ { + tags[i] = t.Tag(i) + } + return types.NewStruct(fields, tags) + } + } + return t +} + +// varlist returns subst(in[i]) or return nils if subst(v[i]) == v[i] for all i. +func (subst *subster) varlist(in varlist) []*types.Var { + var out []*types.Var // nil => no updates + for i, n := 0, in.Len(); i < n; i++ { + v := in.At(i) + w := subst.var_(v) + if v != w && out == nil { + out = make([]*types.Var, n) + for j := 0; j < i; j++ { + out[j] = in.At(j) + } + } + if out != nil { + out[i] = w + } + } + return out +} + +func (subst *subster) var_(v *types.Var) *types.Var { + if v != nil { + if typ := subst.typ(v.Type()); typ != v.Type() { + if v.IsField() { + return types.NewField(v.Pos(), v.Pkg(), v.Name(), typ, v.Embedded()) + } + return types.NewParam(v.Pos(), v.Pkg(), v.Name(), typ) + } + } + return v +} + +func (subst *subster) union(u *types.Union) *types.Union { + var out []*types.Term // nil => no updates + + for i, n := 0, u.Len(); i < n; i++ { + t := u.Term(i) + r := subst.typ(t.Type()) + if r != t.Type() && out == nil { + out = make([]*types.Term, n) + for j := 0; j < i; j++ { + out[j] = u.Term(j) + } + } + if out != nil { + out[i] = types.NewTerm(t.Tilde(), r) + } + } + + if out != nil { + return types.NewUnion(out) + } + return u +} + +func (subst *subster) interface_(iface *types.Interface) *types.Interface { + if iface == nil { + return nil + } + + // methods for the interface. Initially nil if there is no known change needed. + // Signatures for the method where recv is nil. NewInterfaceType fills in the receivers. + var methods []*types.Func + initMethods := func(n int) { // copy first n explicit methods + methods = make([]*types.Func, iface.NumExplicitMethods()) + for i := range n { + f := iface.ExplicitMethod(i) + norecv := changeRecv(f.Type().(*types.Signature), nil) + methods[i] = types.NewFunc(f.Pos(), f.Pkg(), f.Name(), norecv) + } + } + for i := 0; i < iface.NumExplicitMethods(); i++ { + f := iface.ExplicitMethod(i) + // On interfaces, we need to cycle break on anonymous interface types + // being in a cycle with their signatures being in cycles with their receivers + // that do not go through a Named. + norecv := changeRecv(f.Type().(*types.Signature), nil) + sig := subst.typ(norecv) + if sig != norecv && methods == nil { + initMethods(i) + } + if methods != nil { + methods[i] = types.NewFunc(f.Pos(), f.Pkg(), f.Name(), sig.(*types.Signature)) + } + } + + var embeds []types.Type + initEmbeds := func(n int) { // copy first n embedded types + embeds = make([]types.Type, iface.NumEmbeddeds()) + for i := range n { + embeds[i] = iface.EmbeddedType(i) + } + } + for i := 0; i < iface.NumEmbeddeds(); i++ { + e := iface.EmbeddedType(i) + r := subst.typ(e) + if e != r && embeds == nil { + initEmbeds(i) + } + if embeds != nil { + embeds[i] = r + } + } + + if methods == nil && embeds == nil { + return iface + } + if methods == nil { + initMethods(iface.NumExplicitMethods()) + } + if embeds == nil { + initEmbeds(iface.NumEmbeddeds()) + } + return types.NewInterfaceType(methods, embeds).Complete() +} + +func (subst *subster) alias(t *types.Alias) types.Type { + // See subster.named. This follows the same strategy. + tparams := t.TypeParams() + targs := t.TypeArgs() + tname := t.Obj() + torigin := t.Origin() + + if !declaredWithin(tname, subst.origin) { + // t is declared outside of the function origin. So t is a package level type alias. + if targs.Len() == 0 { + // No type arguments so no instantiation needed. + return t + } + + // Instantiate with the substituted type arguments. + newTArgs := subst.typelist(targs) + return subst.instantiate(torigin, newTArgs) + } + + if targs.Len() == 0 { + // t is declared within the function origin and has no type arguments. + // + // Example: This corresponds to A or B in F, but not A[int]: + // + // func F[T any]() { + // type A[S any] = struct{t T, s S} + // type B = T + // var x A[int] + // ... + // } + // + // This is somewhat different than *Named as *Alias cannot be created recursively. + + // Copy and substitute type params. + var newTParams []*types.TypeParam + for cur := range tparams.TypeParams() { + cobj := cur.Obj() + cname := types.NewTypeName(cobj.Pos(), cobj.Pkg(), cobj.Name(), nil) + ntp := types.NewTypeParam(cname, nil) + subst.cache[cur] = ntp // See the comment "Note: Subtle" in subster.named. + newTParams = append(newTParams, ntp) + } + + // Substitute rhs. + rhs := subst.typ(t.Rhs()) + + // Create the fresh alias. + obj := aliases.New(tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams) + + // Substitute into all of the constraints after they are created. + for i, ntp := range newTParams { + bound := tparams.At(i).Constraint() + ntp.SetConstraint(subst.typ(bound)) + } + return obj.Type() + } + + // t is declared within the function origin and has type arguments. + // + // Example: This corresponds to A[int] in F. Cases A and B are handled above. + // func F[T any]() { + // type A[S any] = struct{t T, s S} + // type B = T + // var x A[int] + // ... + // } + subOrigin := subst.typ(torigin) + subTArgs := subst.typelist(targs) + return subst.instantiate(subOrigin, subTArgs) +} + +func (subst *subster) named(t *types.Named) types.Type { + // A Named type is a user defined type. + // Ignoring generics, Named types are canonical: they are identical if + // and only if they have the same defining symbol. + // Generics complicate things, both if the type definition itself is + // parameterized, and if the type is defined within the scope of a + // parameterized function. In this case, two named types are identical if + // and only if their identifying symbols are identical, and all type + // arguments bindings in scope of the named type definition (including the + // type parameters of the definition itself) are equivalent. + // + // Notably: + // 1. For type definition type T[P1 any] struct{}, T[A] and T[B] are identical + // only if A and B are identical. + // 2. Inside the generic func Fn[m any]() any { type T struct{}; return T{} }, + // the result of Fn[A] and Fn[B] have identical type if and only if A and + // B are identical. + // 3. Both 1 and 2 could apply, such as in + // func F[m any]() any { type T[x any] struct{}; return T{} } + // + // A subster replaces type parameters within a function scope, and therefore must + // also replace free type parameters in the definitions of local types. + // + // Note: There are some detailed notes sprinkled throughout that borrow from + // lambda calculus notation. These contain some over simplifying math. + // + // LC: One way to think about subster is that it is a way of evaluating + // ((λm. E) N) as E[m:=N]. + // Each Named type t has an object *TypeName within a scope S that binds an + // underlying type expression U. U can refer to symbols within S (+ S's ancestors). + // Let x = t.TypeParams() and A = t.TypeArgs(). + // Each Named type t is then either: + // U where len(x) == 0 && len(A) == 0 + // λx. U where len(x) != 0 && len(A) == 0 + // ((λx. U) A) where len(x) == len(A) + // In each case, we will evaluate t[m:=N]. + tparams := t.TypeParams() // x + targs := t.TypeArgs() // A + + if !declaredWithin(t.Obj(), subst.origin) { + // t is declared outside of Fn[m]. + // + // In this case, we can skip substituting t.Underlying(). + // The underlying type cannot refer to the type parameters. + // + // LC: Let free(E) be the set of free type parameters in an expression E. + // Then whenever m ∉ free(E), then E = E[m:=N]. + // t ∉ Scope(fn) so therefore m ∉ free(U) and m ∩ x = ∅. + if targs.Len() == 0 { + // t has no type arguments. So it does not need to be instantiated. + // + // This is the normal case in real Go code, where t is not parameterized, + // declared at some package scope, and m is a TypeParam from a parameterized + // function F[m] or method. + // + // LC: m ∉ free(A) lets us conclude m ∉ free(t). So t=t[m:=N]. + return t + } + + // t is declared outside of Fn[m] and has type arguments. + // The type arguments may contain type parameters m so + // substitute the type arguments, and instantiate the substituted + // type arguments. + // + // LC: Evaluate this as ((λx. U) A') where A' = A[m := N]. + newTArgs := subst.typelist(targs) + return subst.instantiate(t.Origin(), newTArgs) + } + + // t is declared within Fn[m]. + + if targs.Len() == 0 { // no type arguments? + assert(t == t.Origin(), "local parameterized type abstraction must be an origin type") + + // t has no type arguments. + // The underlying type of t may contain the function's type parameters, + // replace these, and create a new type. + // + // Subtle: We short circuit substitution and use a newly created type in + // subst, i.e. cache[t]=fresh, to preemptively replace t with fresh + // in recursive types during traversal. This both breaks infinite cycles + // and allows for constructing types with the replacement applied in + // subst.typ(U). + // + // A new copy of the Named and Typename (and constraints) per function + // instantiation matches the semantics of Go, which treats all function + // instantiations F[N] as having distinct local types. + // + // LC: x.Len()=0 can be thought of as a special case of λx. U. + // LC: Evaluate (λx. U)[m:=N] as (λx'. U') where U'=U[x:=x',m:=N]. + tname := t.Obj() + obj := types.NewTypeName(tname.Pos(), tname.Pkg(), tname.Name(), nil) + fresh := types.NewNamed(obj, nil, nil) + var newTParams []*types.TypeParam + for cur := range tparams.TypeParams() { + cobj := cur.Obj() + cname := types.NewTypeName(cobj.Pos(), cobj.Pkg(), cobj.Name(), nil) + ntp := types.NewTypeParam(cname, nil) + subst.cache[cur] = ntp + newTParams = append(newTParams, ntp) + } + fresh.SetTypeParams(newTParams) + subst.cache[t] = fresh + subst.cache[fresh] = fresh + fresh.SetUnderlying(subst.typ(t.Underlying())) + // Substitute into all of the constraints after they are created. + for i, ntp := range newTParams { + bound := tparams.At(i).Constraint() + ntp.SetConstraint(subst.typ(bound)) + } + return fresh + } + + // t is defined within Fn[m] and t has type arguments (an instantiation). + // We reduce this to the two cases above: + // (1) substitute the function's type parameters into t.Origin(). + // (2) substitute t's type arguments A and instantiate the updated t.Origin() with these. + // + // LC: Evaluate ((λx. U) A)[m:=N] as (t' A') where t' = (λx. U)[m:=N] and A'=A [m:=N] + subOrigin := subst.typ(t.Origin()) + subTArgs := subst.typelist(targs) + return subst.instantiate(subOrigin, subTArgs) +} + +func (subst *subster) instantiate(orig types.Type, targs []types.Type) types.Type { + i, err := types.Instantiate(subst.ctxt, orig, targs, false) + assert(err == nil, "failed to Instantiate named (Named or Alias) type") + if c, _ := subst.uniqueness.At(i); c != nil { + return c + } + subst.uniqueness.Set(i, i) + return i +} + +func (subst *subster) typelist(l *types.TypeList) []types.Type { + res := make([]types.Type, l.Len()) + for i := 0; i < l.Len(); i++ { + res[i] = subst.typ(l.At(i)) + } + return res +} + +func (subst *subster) signature(t *types.Signature) types.Type { + tparams := t.TypeParams() + + // We are choosing not to support tparams.Len() > 0 until a need has been observed in practice. + // + // There are some known usages for types.Types coming from types.{Eval,CheckExpr}. + // To support tparams.Len() > 0, we just need to do the following [pseudocode]: + // targs := {subst.replacements[tparams[i]]]}; Instantiate(ctxt, t, targs, false) + + assert(tparams.Len() == 0, "Substituting types.Signatures with generic functions are currently unsupported.") + + // Either: + // (1)non-generic function. + // no type params to substitute + // (2)generic method and recv needs to be substituted. + + // Receivers can be either: + // named + // pointer to named + // interface + // nil + // interface is the problematic case. We need to cycle break there! + recv := subst.var_(t.Recv()) + params := subst.tuple(t.Params()) + results := subst.tuple(t.Results()) + if recv != t.Recv() || params != t.Params() || results != t.Results() { + return types.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) + } + return t +} diff --git a/vendor/honnef.co/go/tools/go/ir/task.go b/vendor/honnef.co/go/tools/go/ir/task.go new file mode 100644 index 00000000..7a44404b --- /dev/null +++ b/vendor/honnef.co/go/tools/go/ir/task.go @@ -0,0 +1,103 @@ +// Copyright 2024 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 ir + +import ( + "sync/atomic" +) + +// Each task has two states: it is initially "active", +// and transitions to "done". +// +// tasks form a directed graph. An edge from x to y (with y in x.edges) +// indicates that the task x waits on the task y to be done. +// Cycles are permitted. +// +// Calling x.wait() blocks the calling goroutine until task x, +// and all the tasks transitively reachable from x are done. +// +// The nil *task is always considered done. +type task struct { + done chan unit // close when the task is done. + edges map[*task]unit // set of predecessors of this task. + transitive atomic.Bool // true once it is known all predecessors are done. +} + +func (x *task) isTransitivelyDone() bool { return x == nil || x.transitive.Load() } + +// addEdge creates an edge from x to y, indicating that +// x.wait() will not return before y is done. +// All calls to x.addEdge(...) should happen before x.markDone(). +func (x *task) addEdge(y *task) { + if x == y || y.isTransitivelyDone() { + return // no work remaining + } + + // heuristic done check + select { + case <-x.done: + panic("cannot add an edge to a done task") + default: + } + + if x.edges == nil { + x.edges = make(map[*task]unit) + } + x.edges[y] = unit{} +} + +// markDone changes the task's state to markDone. +func (x *task) markDone() { + if x != nil { + close(x.done) + } +} + +// wait blocks until x and all the tasks it can reach through edges are done. +func (x *task) wait() { + if x.isTransitivelyDone() { + return // already known to be done. Skip allocations. + } + + // Use BFS to wait on u.done to be closed, for all u transitively + // reachable from x via edges. + // + // This work can be repeated by multiple workers doing wait(). + // + // Note: Tarjan's SCC algorithm is able to mark SCCs as transitively done + // as soon as the SCC has been visited. This is theoretically faster, but is + // a more complex algorithm. Until we have evidence, we need the more complex + // algorithm, the simpler algorithm BFS is implemented. + // + // In Go 1.23, ssa/TestStdlib reaches <=3 *tasks per wait() in most schedules + // On some schedules, there is a cycle building net/http and internal/trace/testtrace + // due to slices functions. + work := []*task{x} + enqueued := map[*task]unit{x: {}} + for i := 0; i < len(work); i++ { + u := work[i] + if u.isTransitivelyDone() { // already transitively done + work[i] = nil + continue + } + <-u.done // wait for u to be marked done. + + for v := range u.edges { + if _, ok := enqueued[v]; !ok { + enqueued[v] = unit{} + work = append(work, v) + } + } + } + + // work is transitively closed over dependencies. + // u in work is done (or transitively done and skipped). + // u is transitively done. + for _, u := range work { + if u != nil { + x.transitive.Store(true) + } + } +} diff --git a/vendor/honnef.co/go/tools/go/ir/typeset.go b/vendor/honnef.co/go/tools/go/ir/typeset.go new file mode 100644 index 00000000..6154e4f1 --- /dev/null +++ b/vendor/honnef.co/go/tools/go/ir/typeset.go @@ -0,0 +1,175 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ir + +import ( + "go/types" + + "honnef.co/go/tools/go/types/typeutil" +) + +// Utilities for dealing with type sets. + +const debug = false + +// typeset is an iterator over the (type/underlying type) pairs of the +// specific type terms of the type set implied by t. +// If t is a type parameter, the implied type set is the type set of t's constraint. +// In that case, if there are no specific terms, typeset calls yield with (nil, nil). +// If t is not a type parameter, the implied type set consists of just t. +// In any case, typeset is guaranteed to call yield at least once. +func typeset(typ types.Type, yield func(t, u types.Type) bool) { + switch typ := types.Unalias(typ).(type) { + case *types.TypeParam, *types.Interface: + terms := termListOf(typ) + if len(terms) == 0 { + yield(nil, nil) + return + } + for _, term := range terms { + u := types.Unalias(term.Type()) + if !term.Tilde() { + u = u.Underlying() + } + if debug { + assert(types.Identical(u, u.Underlying()), "Unalias(x) == under(x) for ~x terms") + } + if !yield(term.Type(), u) { + break + } + } + return + default: + yield(typ, typ.Underlying()) + } +} + +// termListOf returns the type set of typ as a normalized term set. Returns an empty set on an error. +func termListOf(typ types.Type) []*types.Term { + return typeutil.NewTypeSet(typ).Terms +} + +// typeSetIsEmpty returns true if a typeset is empty. +func typeSetIsEmpty(typ types.Type) bool { + var empty bool + typeset(typ, func(t, _ types.Type) bool { + empty = t == nil + return false + }) + return empty +} + +// isBytestring returns true if T has the same terms as interface{[]byte | string}. +// These act like a core type for some operations: slice expressions, append and copy. +// +// See https://go.dev/ref/spec#Core_types for the details on bytestring. +func isBytestring(T types.Type) bool { + U := T.Underlying() + if _, ok := U.(*types.Interface); !ok { + return false + } + + hasBytes, hasString := false, false + ok := underIs(U, func(t types.Type) bool { + switch { + case isString(t): + hasString = true + return true + case isByteSlice(t): + hasBytes = true + return true + default: + return false + } + }) + return ok && hasBytes && hasString +} + +// underIs calls f with the underlying types of the type terms +// of the type set of typ and reports whether all calls to f returned true. +// If there are no specific terms, underIs returns the result of f(nil). +func underIs(typ types.Type, f func(types.Type) bool) bool { + var ok bool + typeset(typ, func(t, u types.Type) bool { + ok = f(u) + return ok + }) + return ok +} + +// indexType returns the element type and index mode of a IndexExpr over a type. +// It returns an invalid mode if the type is not indexable; this should never occur in a well-typed program. +func indexType(typ types.Type) (types.Type, indexMode) { + switch U := typ.Underlying().(type) { + case *types.Array: + return U.Elem(), ixArrVar + case *types.Pointer: + if arr, ok := U.Elem().Underlying().(*types.Array); ok { + return arr.Elem(), ixVar + } + case *types.Slice: + return U.Elem(), ixVar + case *types.Map: + return U.Elem(), ixMap + case *types.Basic: + return tByte, ixValue // must be a string + case *types.Interface: + var elem types.Type + mode := ixInvalid + typeset(typ, func(t, _ types.Type) bool { + if t == nil { + return false // empty set + } + e, m := indexType(t) + if elem == nil { + elem, mode = e, m + } + if debug && !types.Identical(elem, e) { // if type checked, just a sanity check + mode = ixInvalid + return false + } + // Update the mode to the most constrained address type. + mode = mode.meet(m) + return mode != ixInvalid + }) + return elem, mode + } + return nil, ixInvalid +} + +// An indexMode specifies the (addressing) mode of an index operand. +// +// Addressing mode of an index operation is based on the set of +// underlying types. +// Hasse diagram of the indexMode meet semi-lattice: +// +// ixVar ixMap +// | | +// ixArrVar | +// | | +// ixValue | +// \ / +// ixInvalid +type indexMode byte + +const ( + ixInvalid indexMode = iota // index is invalid + ixValue // index is a computed value (not addressable) + ixArrVar // like ixVar, but index operand contains an array + ixVar // index is an addressable variable + ixMap // index is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment) +) + +// meet is the address type that is constrained by both x and y. +func (x indexMode) meet(y indexMode) indexMode { + if (x == ixMap || y == ixMap) && x != y { + return ixInvalid + } + // Use int representation and return min. + if x < y { + return y + } + return x +} diff --git a/vendor/honnef.co/go/tools/go/ir/util.go b/vendor/honnef.co/go/tools/go/ir/util.go index 97fe9c5f..d845c9a1 100644 --- a/vendor/honnef.co/go/tools/go/ir/util.go +++ b/vendor/honnef.co/go/tools/go/ir/util.go @@ -13,16 +13,17 @@ import ( "go/types" "io" "os" + "sync" + _ "unsafe" // for go:linkname hack - "honnef.co/go/tools/go/ast/astutil" "honnef.co/go/tools/go/types/typeutil" "golang.org/x/exp/typeparams" ) -//// AST utilities +type unit struct{} -func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } +//// AST utilities // isBlankIdent returns true iff e is an Ident with name "_". // They have no associated types.Object, and thus no type. @@ -33,14 +34,66 @@ func isBlankIdent(e ast.Expr) bool { //// Type utilities. Some of these belong in go/types. -// isPointer returns true for types whose underlying type is a pointer, -// and for type parameters whose core type is a pointer. -func isPointer(typ types.Type) bool { - if ctyp := typeutil.CoreType(typ); ctyp != nil { - _, ok := ctyp.(*types.Pointer) - return ok +// isString reports whether t is exactly a string type. +// t is assumed to be an Underlying type (not Named or Alias). +func isString(t types.Type) bool { + basic, ok := t.(*types.Basic) + return ok && basic.Info()&types.IsString != 0 +} + +// isByteSlice reports whether t is of the form []~bytes. +// t is assumed to be an Underlying type (not Named or Alias). +func isByteSlice(t types.Type) bool { + if b, ok := t.(*types.Slice); ok { + e, _ := b.Elem().Underlying().(*types.Basic) + return e != nil && e.Kind() == types.Byte + } + return false +} + +// isRuneSlice reports whether t is of the form []~runes. +// t is assumed to be an Underlying type (not Named or Alias). +func isRuneSlice(t types.Type) bool { + if b, ok := t.(*types.Slice); ok { + e, _ := b.Elem().Underlying().(*types.Basic) + return e != nil && e.Kind() == types.Rune } - _, ok := typ.Underlying().(*types.Pointer) + return false +} + +// isBasicConvTypes returns true when the type set of a type +// can be one side of a Convert operation. This is when: +// - All are basic, []byte, or []rune. +// - At least 1 is basic. +// - At most 1 is []byte or []rune. +func isBasicConvTypes(typ types.Type) bool { + basics, cnt := 0, 0 + ok := underIs(typ, func(t types.Type) bool { + cnt++ + if isBasic(t) { + basics++ + return true + } + return isByteSlice(t) || isRuneSlice(t) + }) + return ok && basics >= 1 && cnt-basics <= 1 +} + +// isPointer reports whether t's underlying type is a pointer. +func isPointer(t types.Type) bool { + return is[*types.Pointer](t.Underlying()) +} + +// isPointerCore reports whether t's core type is a pointer. +// +// (Most pointer manipulation is related to receivers, in which case +// isPointer is appropriate. tecallers can use isPointer(t). +func isPointerCore(t types.Type) bool { + return is[*types.Pointer](typeutil.CoreType(t)) +} + +func is[T any](x any) bool { + _, ok := x.(T) return ok } @@ -67,6 +120,44 @@ func recvType(obj *types.Func) types.Type { return obj.Type().(*types.Signature).Recv().Type() } +// fieldOf returns the index'th field of the (core type of) a struct type; +// otherwise returns nil. +func fieldOf(typ types.Type, index int) *types.Var { + if st, ok := typeutil.CoreType(typ).(*types.Struct); ok { + if 0 <= index && index < st.NumFields() { + return st.Field(index) + } + } + return nil +} + +// isUntyped reports whether typ is the type of an untyped constant. +func isUntyped(typ types.Type) bool { + // No Underlying/Unalias: untyped constant types cannot be Named or Alias. + b, ok := typ.(*types.Basic) + return ok && b.Info()&types.IsUntyped != 0 +} + +// declaredWithin reports whether an object is declared within a function. +// +// obj must not be a method or a field. +func declaredWithin(obj types.Object, fn *types.Func) bool { + if obj.Pos() != token.NoPos { + return fn.Scope().Contains(obj.Pos()) // trust the positions if they exist. + } + if fn.Pkg() != obj.Pkg() { + return false // fast path for different packages + } + + // Traverse Parent() scopes for fn.Scope(). + for p := obj.Parent(); p != nil; p = p.Parent() { + if p == fn.Scope() { + return true + } + } + return false +} + // logStack prints the formatted "start" message to stderr and // returns a closure that prints the corresponding "end" message. // Call using 'defer logStack(...)()' to show builder stack on panic. @@ -102,61 +193,244 @@ func makeLen(T types.Type) *Builtin { } } -type StackMap struct { - m []map[Value]Value +func assert(x bool, msg string) { + if !x { + panic(msg) + } } -func (m *StackMap) Push() { - m.m = append(m.m, map[Value]Value{}) -} +// BlockMap is a mapping from basic blocks (identified by their indices) to values. +type BlockMap[T any] []T -func (m *StackMap) Pop() { - m.m = m.m[:len(m.m)-1] +// isBasic reports whether t is a basic type. +func isBasic(t types.Type) bool { + _, ok := t.(*types.Basic) + return ok } -func (m *StackMap) Get(key Value) (Value, bool) { - for i := len(m.m) - 1; i >= 0; i-- { - if v, ok := m.m[i][key]; ok { - return v, true +// receiverTypeArgs returns the type arguments to a method's receiver. +// Returns an empty list if the receiver does not have type arguments. +func receiverTypeArgs(method *types.Func) []types.Type { + recv := method.Signature().Recv() + named := func() (named *types.Named) { + t := recv.Type() + if ptr, ok := types.Unalias(t).(*types.Pointer); ok { + t = ptr.Elem() } + named, _ = types.Unalias(t).(*types.Named) + return named + }() + if named == nil { + return nil // recv is anonymous struct/interface + } + ts := named.TypeArgs() + if ts.Len() == 0 { + return nil + } + targs := make([]types.Type, ts.Len()) + for i := 0; i < ts.Len(); i++ { + targs[i] = ts.At(i) + } + return targs +} + +// recvAsFirstArg takes a method signature and returns a function +// signature with receiver as the first parameter. +func recvAsFirstArg(sig *types.Signature) *types.Signature { + params := make([]*types.Var, 0, 1+sig.Params().Len()) + params = append(params, sig.Recv()) + for v := range sig.Params().Variables() { + params = append(params, v) + } + return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) +} + +// instance returns whether an expression is a simple or qualified identifier +// that is a generic instantiation. +func instance(info *types.Info, expr ast.Expr) bool { + // Compare the logic here against go/types.instantiatedIdent, + // which also handles *IndexExpr and *IndexListExpr. + var id *ast.Ident + switch x := expr.(type) { + case *ast.Ident: + id = x + case *ast.SelectorExpr: + id = x.Sel + default: + return false + } + _, ok := info.Instances[id] + return ok +} + +// isNonTypeParamInterface reports whether t is an interface type but not a type parameter. +func isNonTypeParamInterface(t types.Type) bool { + return !typeparams.IsTypeParam(t) && types.IsInterface(t) +} + +// instanceArgs returns the Instance[id].TypeArgs as a slice. +func instanceArgs(info *types.Info, id *ast.Ident) []types.Type { + targList := info.Instances[id].TypeArgs + if targList == nil { + return nil + } + + targs := make([]types.Type, targList.Len()) + for i, n := 0, targList.Len(); i < n; i++ { + targs[i] = targList.At(i) } - return nil, false + return targs } -func (m *StackMap) Set(k Value, v Value) { - m.m[len(m.m)-1][k] = v +// Mapping of a type T to a canonical instance C s.t. types.Identical(T, C). +// Thread-safe. +type canonizer struct { + mu sync.Mutex + types typeutil.Map[types.Type] // map from type to a canonical instance + lists typeListMap // map from a list of types to a canonical instance } -// Unwrap recursively unwraps Sigma and Copy nodes. -func Unwrap(v Value) Value { - for { - switch vv := v.(type) { - case *Sigma: - v = vv.X - case *Copy: - v = vv.X - default: - return v +func newCanonizer() *canonizer { + c := &canonizer{} + h := typeutil.MakeHasher() + c.types.SetHasher(h) + c.lists.hasher = h + return c +} + +// List returns a canonical representative of a list of types. +// Representative of the empty list is nil. +func (c *canonizer) List(ts []types.Type) *typeList { + if len(ts) == 0 { + return nil + } + + unaliasAll := func(ts []types.Type) []types.Type { + // Is there some top level alias? + var found bool + for _, t := range ts { + if _, ok := t.(*types.Alias); ok { + found = true + break + } + } + if !found { + return ts // no top level alias } + + cp := make([]types.Type, len(ts)) // copy with top level aliases removed. + for i, t := range ts { + cp[i] = types.Unalias(t) + } + return cp } + l := unaliasAll(ts) + + c.mu.Lock() + defer c.mu.Unlock() + return c.lists.rep(l) } -func assert(x bool) { - if !x { - panic("failed assertion") +// Type returns a canonical representative of type T. +// Removes top-level aliases. +// +// For performance, reasons the canonical instance is order-dependent, +// and may contain deeply nested aliases. +func (c *canonizer) Type(T types.Type) types.Type { + T = types.Unalias(T) // remove the top level alias. + + c.mu.Lock() + defer c.mu.Unlock() + + if r, _ := c.types.At(T); r != nil { + return r } + c.types.Set(T, T) + return T } -// BlockMap is a mapping from basic blocks (identified by their indices) to values. -type BlockMap[T any] []T +// A type for representing a canonized list of types. +type typeList []types.Type -// isBasic reports whether t is a basic type. -func isBasic(t types.Type) bool { - _, ok := t.(*types.Basic) - return ok +func (l *typeList) identical(ts []types.Type) bool { + if l == nil { + return len(ts) == 0 + } + n := len(*l) + if len(ts) != n { + return false + } + for i, left := range *l { + right := ts[i] + if !types.Identical(left, right) { + return false + } + } + return true } -// isNonTypeParamInterface reports whether t is an interface type but not a type parameter. -func isNonTypeParamInterface(t types.Type) bool { - return !typeparams.IsTypeParam(t) && types.IsInterface(t) +type typeListMap struct { + hasher typeutil.Hasher + buckets map[uint32][]*typeList } + +// rep returns a canonical representative of a slice of types. +func (m *typeListMap) rep(ts []types.Type) *typeList { + if m == nil || len(ts) == 0 { + return nil + } + + if m.buckets == nil { + m.buckets = make(map[uint32][]*typeList) + } + + h := m.hash(ts) + bucket := m.buckets[h] + for _, l := range bucket { + if l.identical(ts) { + return l + } + } + + // not present. create a representative. + cp := make(typeList, len(ts)) + copy(cp, ts) + rep := &cp + + m.buckets[h] = append(bucket, rep) + return rep +} + +func (m *typeListMap) hash(ts []types.Type) uint32 { + if m == nil { + return 0 + } + // Some smallish prime far away from typeutil.Hash. + n := len(ts) + h := uint32(13619) + 2*uint32(n) + for i := range n { + h += 3 * m.hasher.Hash(ts[i]) + } + return h +} + +// instantiateMethod instantiates m with targs and returns a canonical representative for this method. +func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func { + recv := recvType(m) + if p, ok := types.Unalias(recv).(*types.Pointer); ok { + recv = p.Elem() + } + named := types.Unalias(recv).(*types.Named) + inst, err := types.Instantiate(ctxt, named.Origin(), targs, false) + if err != nil { + panic(err) + } + rep := canon.Type(inst) + obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name()) + return obj.(*types.Func) +} + +// Exposed to irutil using the linkname hack. +// +//go:linkname isSyntactic honnef.co/go/tools/go/ir.isSyntactic +func isSyntactic(pkg *Package) bool { return pkg.syntax } diff --git a/vendor/honnef.co/go/tools/go/ir/wrappers.go b/vendor/honnef.co/go/tools/go/ir/wrappers.go index 6b358a7c..1d7b3e48 100644 --- a/vendor/honnef.co/go/tools/go/ir/wrappers.go +++ b/vendor/honnef.co/go/tools/go/ir/wrappers.go @@ -26,7 +26,7 @@ import ( // -- wrappers ----------------------------------------------------------- -// makeWrapper returns a synthetic method that delegates to the +// createWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // @@ -36,65 +36,92 @@ import ( // following axes of variation when making changes: // - optional receiver indirection // - optional implicit field selections +// - optional method type arguments // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func makeWrapper(prog *Program, sel *types.Selection) *Function { - obj := sel.Obj().(*types.Func) // the declared function - sig := sel.Type().(*types.Signature) // type of this wrapper +func createWrapper(prog *Program, sel *selection, targs []types.Type) *Function { + obj := sel.obj.(*types.Func) // the declared function + name, sig := maybeInstance(prog, obj.Name(), sel.typ.(*types.Signature), targs) var recv *types.Var // wrapper's receiver or thunk's params[0] - name := obj.Name() - var description Synthetic - var start int // first regular param - if sel.Kind() == types.MethodExpr { + var description string + if sel.kind == types.MethodExpr { name += "$thunk" - description = SyntheticThunk + description = "thunk" recv = sig.Params().At(0) - start = 1 } else { - description = SyntheticWrapper + description = "wrapper" recv = sig.Recv() } + description = fmt.Sprintf("%s for %s", description, obj) if prog.mode&LogSource != 0 { - defer logStack("make %s to (%s)", description, recv.Type())() + defer logStack("create %s to (%s)", description, recv.Type())() } - fn := &Function{ - name: name, - method: sel, - object: obj, - Signature: sig, - Synthetic: description, - Prog: prog, - functionBody: new(functionBody), + /* method wrapper */ + return &Function{ + name: name, + method: sel, + object: obj, + Signature: sig, + Synthetic: description, + Prog: prog, + pos: obj.Pos(), + typeargs: targs, + // wrappers have no syntax + build: (*builder).buildWrapper, + info: nil, + goversion: "", + } +} + +// maybeInstance returns name and sig instantiated to reflect any type arguments in targs. +func maybeInstance(prog *Program, name string, sig *types.Signature, targs []types.Type) (string, *types.Signature) { + if len(targs) > 0 { + name = fmt.Sprintf("%s%s", name, targstr(targs)) + instSig, err := types.Instantiate(prog.ctxt, sig, targs, false) + if err != nil { + // validate was false, we should never get an error + panic(err) + } + sig = prog.canon.Type(instSig).(*types.Signature) + } + return name, sig +} + +// buildWrapper builds fn.Body for a method wrapper. +func (b *builder) buildWrapper(fn *Function) { + var recv *types.Var // wrapper's receiver or thunk's params[0] + var start int // first regular param + if fn.method.kind == types.MethodExpr { + recv = fn.Signature.Params().At(0) + start = 1 + } else { + recv = fn.Signature.Recv() } - fn.initHTML(prog.PrintFunc) + fn.startBody() fn.addSpilledParam(recv, nil) createParams(fn, start) - indices := sel.Index() + indices := fn.method.index var v Value = fn.Locals[0] // spilled receiver - if isPointer(sel.Recv()) { + if isPointer(fn.method.recv) { v = emitLoad(fn, v, nil) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" - if len(indices) == 1 && !isPointer(recvType(obj)) { + if len(indices) == 1 && !isPointer(recvType(fn.object)) { var c Call c.Call.Value = &Builtin{ - name: "ir:wrapnilchk", - sig: types.NewSignatureType(nil, nil, nil, - types.NewTuple(anonVar(sel.Recv()), anonVar(tString), anonVar(tString)), - types.NewTuple(anonVar(sel.Recv())), false), + name: "ssa:wrapnilchk", + sig: types.NewSignatureType(nil, nil, nil, types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(fn.method.recv)), false), } c.Call.Args = []Value{ v, - emitConst(fn, stringConst(deref(sel.Recv()).String(), nil)), - emitConst(fn, stringConst(sel.Obj().Name(), nil)), + stringConst(deref(fn.method.recv).String(), nil), + stringConst(fn.method.obj.Name(), nil), } c.setType(v.Type()) v = fn.emit(&c, nil) @@ -116,22 +143,21 @@ func makeWrapper(prog *Program, sel *types.Selection) *Function { // address of implicit C field. var c Call - if r := recvType(obj); !types.IsInterface(r) { // concrete method + if r := recvType(fn.object); !types.IsInterface(r) { // concrete method if !isPointer(r) { v = emitLoad(fn, v, nil) } - c.Call.Value = prog.declaredFunc(obj) + c.Call.Value = fn.Prog.objectMethod(fn.object, fn.typeargs, b) c.Call.Args = append(c.Call.Args, v) } else { - c.Call.Method = obj - c.Call.Value = emitLoad(fn, v, nil) + c.Call.Method = fn.object + c.Call.Value = emitLoad(fn, v, nil) // interface (possibly a typeparam) } for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c, nil) fn.finishBody() - return fn } // createParams creates parameters for wrapper method fn based on its @@ -146,7 +172,7 @@ func createParams(fn *Function, start int) { // -- bounds ----------------------------------------------------------- -// makeBound returns a bound method wrapper (or "bound"), a synthetic +// createBound returns a bound method wrapper (or "bound"), a synthetic // function that delegates to a concrete or interface method denoted // by obj. The resulting function has no receiver, but has one free // variable which will be used as the method's receiver in the @@ -165,56 +191,63 @@ func createParams(fn *Function, start int) { // // f := func() { return t.meth() } // -// Unlike makeWrapper, makeBound need perform no indirection or field +// Unlike createWrapper, createBound need perform no indirection or field // selections because that can be done before the closure is // constructed. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeBound(prog *Program, obj *types.Func) *Function { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() +func createBound(prog *Program, obj *types.Func, targs []types.Type) *Function { + description := fmt.Sprintf("bound method wrapper for %s", obj) if prog.mode&LogSource != 0 { - defer logStack("%s", SyntheticBound)() + defer logStack("%s", description)() } + name, sig := maybeInstance(prog, obj.Name(), obj.Type().(*types.Signature), targs) + + /* bound method wrapper */ fn := &Function{ - name: obj.Name() + "$bound", - object: obj, - Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver - Synthetic: SyntheticBound, - Prog: prog, - functionBody: new(functionBody), + name: name + "$bound", + object: obj, + Signature: changeRecv(sig, nil), // drop receiver + Synthetic: description, + Prog: prog, + pos: obj.Pos(), + typeargs: targs, + // wrappers have no syntax + build: (*builder).buildBound, + info: nil, + goversion: "", } - fn.initHTML(prog.PrintFunc) + fn.FreeVars = []*FreeVar{{name: "recv", typ: recvType(obj), parent: fn}} // (cyclic) + return fn +} - fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn} - fn.FreeVars = []*FreeVar{fv} +// buildBound builds fn.Body for a bound method closure. +func (b *builder) buildBound(fn *Function) { fn.startBody() createParams(fn, 0) var c Call - if !types.IsInterface(recvType(obj)) { // concrete - c.Call.Value = prog.declaredFunc(obj) - c.Call.Args = []Value{fv} + recv := fn.FreeVars[0] + if !types.IsInterface(recvType(fn.object)) { // concrete + c.Call.Value = fn.Prog.objectMethod(fn.object, fn.typeargs, b) + c.Call.Args = []Value{recv} } else { - c.Call.Value = fv - c.Call.Method = obj + c.Call.Method = fn.object + c.Call.Value = recv // interface (possibly a typeparam) } for _, arg := range fn.Params { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c, nil) fn.finishBody() - return fn } // -- thunks ----------------------------------------------------------- -// makeThunk returns a thunk, a synthetic function that delegates to a -// concrete or interface method denoted by sel.Obj(). The resulting +// createThunk returns a thunk, a synthetic function that delegates to a +// concrete or interface method denoted by sel.obj. The resulting // function has no receiver, but has an additional (first) regular // parameter. // -// Precondition: sel.Kind() == types.MethodExpr. +// Precondition: sel.kind == types.MethodExpr. // // type T int or: type T interface { meth() } // func (t T) meth() @@ -225,17 +258,12 @@ func makeBound(prog *Program, obj *types.Func) *Function { // f is a synthetic wrapper defined as if by: // // f := func(t T) { return t.meth() } -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeThunk(prog *Program, sel *types.Selection) *Function { - if sel.Kind() != types.MethodExpr { +func createThunk(prog *Program, sel *selection, targs []types.Type) *Function { + if sel.kind != types.MethodExpr { panic(sel) } - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - fn := makeWrapper(prog, sel) + fn := createWrapper(prog, sel, targs) if fn.Signature.Recv() != nil { panic(fn) // unexpected receiver } @@ -246,97 +274,84 @@ func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignatureType(recv, nil, nil, s.Params(), s.Results(), s.Variadic()) } -// makeInstance creates a wrapper function with signature sig that calls the generic function fn. -// If targs is not nil, fn is a function and targs describes the concrete type arguments. -// If targs is nil, fn is a method and the type arguments are derived from the receiver. -func makeInstance(prog *Program, fn *Function, sig *types.Signature, targs *types.TypeList) *Function { - if sig.Recv() != nil { - assert(targs == nil) - // Methods don't have their own type parameters, but the receiver does - targs = types.Unalias(deref(sig.Recv().Type())).(*types.Named).TypeArgs() - } else { - assert(targs != nil) - } +// A local version of *types.Selection. +// Needed for some additional control, such as creating a MethodExpr for an instantiation. +type selection struct { + kind types.SelectionKind + recv types.Type + typ types.Type + obj types.Object + index []int + indirect bool +} - wrapper := fn.generics.At(targs) - if wrapper != nil { - return wrapper +func toSelection(sel *types.Selection) *selection { + return &selection{ + kind: sel.Kind(), + recv: sel.Recv(), + typ: sel.Type(), + obj: sel.Obj(), + index: sel.Index(), + indirect: sel.Indirect(), } +} - var name string - if sig.Recv() != nil { - name = fn.name - } else { - name = fmt.Sprintf("%s$generic#%d", fn.name, fn.generics.Len()) - } - w := &Function{ - name: name, - object: fn.object, - Signature: sig, - Synthetic: SyntheticGeneric, - Prog: prog, - functionBody: new(functionBody), - } - w.initHTML(prog.PrintFunc) - w.startBody() +// -- instantiations -------------------------------------------------- + +// buildInstantiationWrapper builds the body of an instantiation +// wrapper fn. The body calls the original generic function, +// bracketed by ChangeType conversions on its arguments and results. +func (b *builder) buildInstantiationWrapper(fn *Function) { + orig := fn.topLevelOrigin + sig := fn.Signature + + fn.startBody() if sig.Recv() != nil { - w.addParamVar(sig.Recv(), nil) + fn.addParamVar(sig.Recv(), nil) } - createParams(w, 0) + createParams(fn, 0) + + // Create body. Add a call to origin generic function + // and make type changes between argument and parameters, + // as well as return values. var c Call - c.Call.Value = fn - tresults := fn.Signature.Results() - if tresults.Len() == 1 { - c.typ = tresults.At(0).Type() + c.Call.Value = orig + if res := orig.Signature.Results(); res.Len() == 1 { + c.typ = res.At(0).Type() } else { - c.typ = tresults - } - - changeType := func(v Value, typ types.Type) Value { - if types.Identical(v.Type(), typ) { - return v - } - var c ChangeType - c.X = v - c.typ = typ - return w.emit(&c, nil) + c.typ = res } - for i, arg := range w.Params { - if sig.Recv() != nil { - if i == 0 { - c.Call.Args = append(c.Call.Args, changeType(w.Params[0], fn.Signature.Recv().Type())) - } else { - c.Call.Args = append(c.Call.Args, changeType(arg, fn.Signature.Params().At(i-1).Type())) - } + // parameter of instance becomes an argument to the call + // to the original generic function. + argOffset := 0 + for i, arg := range fn.Params { + var typ types.Type + if i == 0 && sig.Recv() != nil { + typ = orig.Signature.Recv().Type() + argOffset = 1 } else { - c.Call.Args = append(c.Call.Args, changeType(arg, fn.Signature.Params().At(i).Type())) + typ = orig.Signature.Params().At(i - argOffset).Type() } + c.Call.Args = append(c.Call.Args, emitTypeCoercion(fn, arg, typ, nil)) } - for arg := range targs.Types() { - c.Call.TypeArgs = append(c.Call.TypeArgs, arg) - } - results := w.emit(&c, nil) + + results := fn.emit(&c, nil) var ret Return - switch tresults.Len() { + switch res := sig.Results(); res.Len() { case 0: + // no results, do nothing. case 1: - ret.Results = []Value{changeType(results, sig.Results().At(0).Type())} + ret.Results = []Value{emitTypeCoercion(fn, results, res.At(0).Type(), nil)} default: - for i := 0; i < tresults.Len(); i++ { - v := emitExtract(w, results, i, nil) - ret.Results = append(ret.Results, changeType(v, sig.Results().At(i).Type())) + for i := 0; i < sig.Results().Len(); i++ { + v := emitExtract(fn, results, i, nil) + ret.Results = append(ret.Results, emitTypeCoercion(fn, v, res.At(i).Type(), nil)) } } - w.Exit = w.newBasicBlock("exit") - emitJump(w, w.Exit, nil) - w.currentBlock = w.Exit - w.emit(&ret, nil) - w.currentBlock = nil + fn.emit(&ret, nil) + fn.currentBlock = nil - w.finishBody() - - fn.generics.Set(targs, w) - return w + fn.finishBody() } diff --git a/vendor/honnef.co/go/tools/go/ir/write.go b/vendor/honnef.co/go/tools/go/ir/write.go deleted file mode 100644 index 139c8cf3..00000000 --- a/vendor/honnef.co/go/tools/go/ir/write.go +++ /dev/null @@ -1,5 +0,0 @@ -package ir - -func NewJump(parent *BasicBlock) *Jump { - return &Jump{anInstruction{block: parent}} -} diff --git a/vendor/honnef.co/go/tools/go/types/typeutil/typeparams.go b/vendor/honnef.co/go/tools/go/types/typeutil/typeparams.go index 15b20a74..a53c0955 100644 --- a/vendor/honnef.co/go/tools/go/types/typeutil/typeparams.go +++ b/vendor/honnef.co/go/tools/go/types/typeutil/typeparams.go @@ -49,6 +49,9 @@ func (ts TypeSet) CoreType() types.Type { if !ok { return nil } + if !types.Identical(ch1.Elem(), ch2.Elem()) { + return nil + } if ch1.Dir() == types.SendRecv { // typ is currently a bidirectional channel. The term's type is either also bidirectional, or // unidirectional. Use the term's type. @@ -100,7 +103,12 @@ func Any(typ types.Type, fn func(*types.Term) bool) bool { return NewTypeSet(typ).Any(fn) } -func IsSlice(term *types.Term) bool { - _, ok := term.Type().Underlying().(*types.Slice) +func IsType[T types.Type](term *types.Term) bool { + _, ok := term.Type().Underlying().(T) return ok } + +//go:fix inline +func IsSlice(term *types.Term) bool { + return IsType[*types.Slice](term) +} diff --git a/vendor/honnef.co/go/tools/go/types/typeutil/unify.go b/vendor/honnef.co/go/tools/go/types/typeutil/unify.go new file mode 100644 index 00000000..ced507ca --- /dev/null +++ b/vendor/honnef.co/go/tools/go/types/typeutil/unify.go @@ -0,0 +1,345 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The code in this file is copied from +// x/tools/gopls/internal/golang/implementation.go + +package typeutil + +import ( + "fmt" + "go/types" + "iter" + "reflect" +) + +// Unify reports whether the types of x and y match. +// +// If unifier is nil, unify reports only whether it succeeded. +// If unifier is non-nil, it is populated with the values +// of type parameters determined during a successful unification. +// If unification succeeds without binding a type parameter, that parameter +// will not be present in the map. +// +// On entry, the unifier's contents are treated as the values of already-bound type +// parameters, constraining the unification. +// +// For example, if unifier is an empty (not nil) map on entry, then the types +// +// func[T any](T, int) +// +// and +// +// func[U any](bool, U) +// +// will unify, with T=bool and U=int. +// That is, the contents of unifier after unify returns will be +// +// {T: bool, U: int} +// +// where "T" is the type parameter T and "bool" is the basic type for bool. +// +// But if unifier is {T: int} is int on entry, then unification will fail, because T +// does not unify with bool. +// +// Unify does not preserve aliases. For example, given the following: +// +// type String = string +// type A[T] = T +// +// unification succeeds with T bound to string, not String. +// +// See also: unify in cache/methodsets/fingerprint, which implements +// unification for type fingerprints, for the global index. +// +// BUG: literal interfaces are not handled properly. But this function is currently +// used only for signatures, where such types are very rare. +func Unify(x, y types.Type, unifier map[*types.TypeParam]types.Type) bool { + // bindings[tp] is the binding for type parameter tp. + // Although type parameters are nominally bound to types, each bindings[tp] + // is a pointer to a type, so unbound variables that unify can share a binding. + bindings := map[*types.TypeParam]*types.Type{} + + // Bindings is initialized with pointers to the provided types. + for tp, t := range unifier { + bindings[tp] = &t + } + + // bindingFor returns the *types.Type in bindings for tp if tp is not nil, + // creating one if needed. + bindingFor := func(tp *types.TypeParam) *types.Type { + if tp == nil { + return nil + } + b := bindings[tp] + if b == nil { + b = new(types.Type) + bindings[tp] = b + } + return b + } + + // bind sets b to t if b does not occur in t. + bind := func(b *types.Type, t types.Type) bool { + for tp := range typeParams(t) { + if b == bindings[tp] { + return false // failed "occurs" check + } + } + *b = t + return true + } + + // uni performs the actual unification. + depth := 0 + var uni func(x, y types.Type) bool + uni = func(x, y types.Type) bool { + // Panic if recursion gets too deep, to detect bugs before + // overflowing the stack. + depth++ + defer func() { depth-- }() + if depth > 100 { + panic("unify: max depth exceeded") + } + + x = types.Unalias(x) + y = types.Unalias(y) + + tpx, _ := x.(*types.TypeParam) + tpy, _ := y.(*types.TypeParam) + if tpx != nil || tpy != nil { + // Identical type params unify. + if tpx == tpy { + return true + } + bx := bindingFor(tpx) + by := bindingFor(tpy) + + // If both args are type params and neither is bound, have them share a binding. + if bx != nil && by != nil && *bx == nil && *by == nil { + // Arbitrarily give y's binding to x. + bindings[tpx] = by + return true + } + // Treat param bindings like original args in what follows. + if bx != nil && *bx != nil { + x = *bx + } + if by != nil && *by != nil { + y = *by + } + // If the x param is unbound, bind it to y. + if bx != nil && *bx == nil { + return bind(bx, y) + } + // If the y param is unbound, bind it to x. + if by != nil && *by == nil { + return bind(by, x) + } + // Unify the binding of a bound parameter. + return uni(x, y) + } + + // Neither arg is a type param. + + if reflect.TypeOf(x) != reflect.TypeOf(y) { + return false // mismatched types + } + + switch x := x.(type) { + case *types.Array: + y := y.(*types.Array) + return x.Len() == y.Len() && + uni(x.Elem(), y.Elem()) + + case *types.Basic: + y := y.(*types.Basic) + return x.Kind() == y.Kind() + + case *types.Chan: + y := y.(*types.Chan) + return x.Dir() == y.Dir() && + uni(x.Elem(), y.Elem()) + + case *types.Interface: + y := y.(*types.Interface) + // TODO(adonovan,jba): fix: for correctness, we must check + // that both interfaces have the same set of methods + // modulo type parameters, while avoiding the risk of + // unbounded interface recursion. + // + // Since non-empty interface literals are vanishingly + // rare in methods signatures, we ignore this for now. + // If more precision is needed we could compare method + // names and arities, still without full recursion. + return x.NumMethods() == y.NumMethods() + + case *types.Map: + y := y.(*types.Map) + return uni(x.Key(), y.Key()) && + uni(x.Elem(), y.Elem()) + + case *types.Named: + y := y.(*types.Named) + if x.Origin() != y.Origin() { + return false // different named types + } + xtargs := x.TypeArgs() + ytargs := y.TypeArgs() + if xtargs.Len() != ytargs.Len() { + return false // arity error (ill-typed) + } + for i := range xtargs.Len() { + if !uni(xtargs.At(i), ytargs.At(i)) { + return false // mismatched type args + } + } + return true + + case *types.Pointer: + y := y.(*types.Pointer) + return uni(x.Elem(), y.Elem()) + + case *types.Signature: + y := y.(*types.Signature) + return x.Variadic() == y.Variadic() && + uni(x.Params(), y.Params()) && + uni(x.Results(), y.Results()) + + case *types.Slice: + y := y.(*types.Slice) + return uni(x.Elem(), y.Elem()) + + case *types.Struct: + y := y.(*types.Struct) + if x.NumFields() != y.NumFields() { + return false + } + for i := range x.NumFields() { + xf := x.Field(i) + yf := y.Field(i) + if xf.Embedded() != yf.Embedded() || + xf.Name() != yf.Name() || + x.Tag(i) != y.Tag(i) || + !xf.Exported() && xf.Pkg() != yf.Pkg() || + !uni(xf.Type(), yf.Type()) { + return false + } + } + return true + + case *types.Tuple: + y := y.(*types.Tuple) + if x.Len() != y.Len() { + return false + } + for i := range x.Len() { + if !uni(x.At(i).Type(), y.At(i).Type()) { + return false + } + } + return true + + default: // incl. *Union, *TypeParam + panic(fmt.Sprintf("unexpected Type %#v", x)) + } + } + + if !uni(x, y) { + clear(unifier) + return false + } + + // Populate the input map with the resulting types. + if unifier != nil { + for tparam, tptr := range bindings { + unifier[tparam] = *tptr + } + } + return true +} + +// typeParams yields all the free type parameters within t that are relevant for +// unification. +// +// Note: this function is tailored for the specific needs of the unification algorithm. +// Don't try to use it for other purposes, see [typeparams.Free] instead. +func typeParams(t types.Type) iter.Seq[*types.TypeParam] { + return func(yield func(*types.TypeParam) bool) { + seen := map[*types.TypeParam]bool{} // yield each type param only once + + // tps(t) yields each TypeParam in t and returns false to stop. + var tps func(types.Type) bool + tps = func(t types.Type) bool { + t = types.Unalias(t) + + switch t := t.(type) { + case *types.TypeParam: + if seen[t] { + return true + } + seen[t] = true + return yield(t) + + case *types.Basic: + return true + + case *types.Array: + return tps(t.Elem()) + + case *types.Chan: + return tps(t.Elem()) + + case *types.Interface: + // TODO(jba): implement. + return true + + case *types.Map: + return tps(t.Key()) && tps(t.Elem()) + + case *types.Named: + if t.Origin() == t { + // generic type: look at type params + return every(t.TypeParams().TypeParams(), + func(tp *types.TypeParam) bool { return tps(tp) }) + } + // instantiated type: look at type args + return every(t.TypeArgs().Types(), tps) + + case *types.Pointer: + return tps(t.Elem()) + + case *types.Signature: + return tps(t.Params()) && tps(t.Results()) + + case *types.Slice: + return tps(t.Elem()) + + case *types.Struct: + return every(t.Fields(), + func(v *types.Var) bool { return tps(v.Type()) }) + + case *types.Tuple: + return every(t.Variables(), + func(v *types.Var) bool { return tps(v.Type()) }) + + default: // incl. *Union + panic(fmt.Sprintf("unexpected Type %#v", t)) + } + } + + tps(t) + } +} + +// every reports whether every pred(t) for t in seq returns true, +// stopping at the first false element. +func every[T any](seq iter.Seq[T], pred func(T) bool) bool { + for t := range seq { + if !pred(t) { + return false + } + } + return true +} diff --git a/vendor/honnef.co/go/tools/internal/iterutil/iterutil.go b/vendor/honnef.co/go/tools/internal/iterutil/iterutil.go new file mode 100644 index 00000000..e2f1f093 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/iterutil/iterutil.go @@ -0,0 +1,21 @@ +package iterutil + +import "iter" + +func All[T any](seq iter.Seq[T], fn func(T) bool) bool { + for v := range seq { + if !fn(v) { + return false + } + } + return true +} + +func Any[T any](seq iter.Seq[T], fn func(T) bool) bool { + for v := range seq { + if fn(v) { + return true + } + } + return false +} diff --git a/vendor/honnef.co/go/tools/internal/passes/buildir/buildir.go b/vendor/honnef.co/go/tools/internal/passes/buildir/buildir.go index 5db18e30..1e2cc493 100644 --- a/vendor/honnef.co/go/tools/internal/passes/buildir/buildir.go +++ b/vendor/honnef.co/go/tools/internal/passes/buildir/buildir.go @@ -11,7 +11,6 @@ package buildir import ( - "go/types" "reflect" "honnef.co/go/tools/go/ir" @@ -63,20 +62,10 @@ func run(pass *analysis.Pass) (any, error) { prog.SetNoReturn(cfgs.NoReturn) - // Create IR packages for all imports. - // Order is not significant. - created := make(map[*types.Package]bool) - var createAll func(pkgs []*types.Package) - createAll = func(pkgs []*types.Package) { - for _, p := range pkgs { - if !created[p] { - created[p] = true - prog.CreatePackage(p, nil, nil, true) - createAll(p.Imports()) - } - } + // Create IR packages for direct imports. + for _, p := range pass.Pkg.Imports() { + prog.CreatePackage(p, nil, nil, true) } - createAll(pass.Pkg.Imports()) // Create and build the primary package. irpkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) diff --git a/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go b/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go index f07496dd..6bae3f78 100644 --- a/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go +++ b/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go @@ -13,7 +13,6 @@ import ( "honnef.co/go/tools/analysis/report" "honnef.co/go/tools/go/ast/astutil" "honnef.co/go/tools/go/ir" - "honnef.co/go/tools/go/ir/irutil" "honnef.co/go/tools/go/types/typeutil" "honnef.co/go/tools/internal/passes/buildir" @@ -58,7 +57,7 @@ func CheckRangeStringRunes(pass *analysis.Pass) (any, error) { // Expect two refs: one for obtaining the length of the slice, // one for accessing the elements - if len(irutil.FilterDebug(*refs)) != 2 { + if len(*refs) != 2 { // TODO(dh): right now, we check that only one place // refers to our slice. This will miss cases such as // ranging over the slice twice. Ideally, we'd ensure that diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/aliases/aliases.go b/vendor/honnef.co/go/tools/internal/xtools-internal/aliases/aliases.go new file mode 100644 index 00000000..a4ae04bc --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/aliases/aliases.go @@ -0,0 +1,18 @@ +// Copyright 2024 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 aliases + +import ( + "go/token" + "go/types" +) + +// New creates a new TypeName in Package pkg that +// is an alias for the type rhs. +func New(pos token.Pos, pkg *types.Package, name string, rhs types.Type, tparams []*types.TypeParam) *types.TypeName { + tname := types.NewTypeName(pos, pkg, name, nil) + types.NewAlias(tname, rhs).SetTypeParams(tparams) + return tname +} diff --git a/vendor/honnef.co/go/tools/internal/analysisinternal/typeindex/typeindex.go b/vendor/honnef.co/go/tools/internal/xtools-internal/analysis/typeindex/typeindex.go similarity index 80% rename from vendor/honnef.co/go/tools/internal/analysisinternal/typeindex/typeindex.go rename to vendor/honnef.co/go/tools/internal/xtools-internal/analysis/typeindex/typeindex.go index 44d207c0..1bd7b78e 100644 --- a/vendor/honnef.co/go/tools/internal/analysisinternal/typeindex/typeindex.go +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/analysis/typeindex/typeindex.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package typeindex defines an analyzer that provides a -// [golang.org/x/tools/internal/typesinternal/typeindex.Index]. +// [honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex.Index]. // // Like [golang.org/x/tools/go/analysis/passes/inspect], it is // intended to be used as a helper by other analyzers; it reports no @@ -16,13 +16,13 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" - "honnef.co/go/tools/internal/typesinternal/typeindex" + "honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex" ) var Analyzer = &analysis.Analyzer{ Name: "typeindex", Doc: "indexes of type information for later passes", - URL: "https://pkg.go.dev/golang.org/x/tools/internal/analysisinternal/typeindex", + URL: "https://pkg.go.dev/honnef.co/go/tools/internal/xtools-internal/analysis/typeindex", Run: func(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) return typeindex.New(inspect, pass.Pkg, pass.TypesInfo), nil diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/clone.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/clone.go new file mode 100644 index 00000000..2c9b6bb4 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/clone.go @@ -0,0 +1,71 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil + +import ( + "go/ast" + "reflect" +) + +// CloneNode returns a deep copy of a Node. +// It omits pointers to ast.{Scope,Object} variables. +func CloneNode[T ast.Node](n T) T { + return cloneNode(n).(T) +} + +func cloneNode(n ast.Node) ast.Node { + var clone func(x reflect.Value) reflect.Value + set := func(dst, src reflect.Value) { + src = clone(src) + if src.IsValid() { + dst.Set(src) + } + } + clone = func(x reflect.Value) reflect.Value { + switch x.Kind() { + case reflect.Pointer: + if x.IsNil() { + return x + } + // Skip fields of types potentially involved in cycles. + switch x.Interface().(type) { + case *ast.Object, *ast.Scope: + return reflect.Zero(x.Type()) + } + y := reflect.New(x.Type().Elem()) + set(y.Elem(), x.Elem()) + return y + + case reflect.Struct: + y := reflect.New(x.Type()).Elem() + for i := 0; i < x.Type().NumField(); i++ { + set(y.Field(i), x.Field(i)) + } + return y + + case reflect.Slice: + if x.IsNil() { + return x + } + y := reflect.MakeSlice(x.Type(), x.Len(), x.Cap()) + for i := 0; i < x.Len(); i++ { + set(y.Index(i), x.Index(i)) + } + return y + + case reflect.Interface: + y := reflect.New(x.Type()).Elem() + set(y, x.Elem()) + return y + + case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.UnsafePointer: + panic(x) // unreachable in AST + + default: + return x // bool, string, number + } + } + return clone(reflect.ValueOf(n)).Interface().(ast.Node) +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/comment.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/comment.go new file mode 100644 index 00000000..40a34721 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/comment.go @@ -0,0 +1,143 @@ +// Copyright 2025 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 astutil + +import ( + "go/ast" + "go/token" + "iter" + "sort" + "strings" +) + +// Deprecation returns the paragraph of the doc comment that starts with the +// conventional "Deprecation: " marker, as defined by +// https://go.dev/wiki/Deprecated, or "" if the documented symbol is not +// deprecated. +func Deprecation(doc *ast.CommentGroup) string { + for p := range strings.SplitSeq(doc.Text(), "\n\n") { + // There is still some ambiguity for deprecation message. This function + // only returns the paragraph introduced by "Deprecated: ". More + // information related to the deprecation may follow in additional + // paragraphs, but the deprecation message should be able to stand on + // its own. See golang/go#38743. + if strings.HasPrefix(p, "Deprecated: ") { + return p + } + } + return "" +} + +// -- plundered from the future (CL 605517, issue #68021) -- + +// TODO(adonovan): replace with ast.Directive in go1.26 (#68021). +// Beware of our local mods to handle analysistest +// "want" comments on the same line. + +// A directive is a comment line with special meaning to the Go +// toolchain or another tool. It has the form: +// +// //tool:name args +// +// The "tool:" portion is missing for the three directives named +// line, extern, and export. +// +// See https://go.dev/doc/comment#Syntax for details of Go comment +// syntax and https://pkg.go.dev/cmd/compile#hdr-Compiler_Directives +// for details of directives used by the Go compiler. +type Directive struct { + Pos token.Pos // of preceding "//" + Tool string + Name string + Args string // may contain internal spaces +} + +// isDirective reports whether c is a comment directive. +// This code is also in go/printer. +func isDirective(c string) bool { + // "//line " is a line directive. + // "//extern " is for gccgo. + // "//export " is for cgo. + // (The // has been removed.) + if strings.HasPrefix(c, "line ") || strings.HasPrefix(c, "extern ") || strings.HasPrefix(c, "export ") { + return true + } + + // "//[a-z0-9]+:[a-z0-9]" + // (The // has been removed.) + colon := strings.Index(c, ":") + if colon <= 0 || colon+1 >= len(c) { + return false + } + for i := 0; i <= colon+1; i++ { + if i == colon { + continue + } + b := c[i] + if !('a' <= b && b <= 'z' || '0' <= b && b <= '9') { + return false + } + } + return true +} + +// Directives returns the directives within the comment. +func Directives(g *ast.CommentGroup) (res []*Directive) { + if g != nil { + // Avoid (*ast.CommentGroup).Text() as it swallows directives. + for _, c := range g.List { + if len(c.Text) > 2 && + c.Text[1] == '/' && + c.Text[2] != ' ' && + isDirective(c.Text[2:]) { + + tool, nameargs, ok := strings.Cut(c.Text[2:], ":") + if !ok { + // Must be one of {line,extern,export}. + tool, nameargs = "", tool + } + name, args, _ := strings.Cut(nameargs, " ") // tab?? + // Permit an additional line comment after the args, chiefly to support + // [golang.org/x/tools/go/analysis/analysistest]. + args, _, _ = strings.Cut(args, "//") + res = append(res, &Directive{ + Pos: c.Slash, + Tool: tool, + Name: name, + Args: strings.TrimSpace(args), + }) + } + } + } + return +} + +// Comments returns an iterator over the comments overlapping the specified interval. +// Comments are sorted by position in the file, so we can use binary search. +func Comments(file *ast.File, start, end token.Pos) iter.Seq[*ast.Comment] { + return func(yield func(*ast.Comment) bool) { + // Find the first comment group that overlaps the range. + i := sort.Search(len(file.Comments), func(i int) bool { + return file.Comments[i].End() >= start + }) + for _, cg := range file.Comments[i:] { + if cg.Pos() > end { + return + } + // Find the first comment in the group that overlaps the range. + j := sort.Search(len(cg.List), func(j int) bool { + return cg.List[j].End() >= start + }) + for _, co := range cg.List[j:] { + if co.Pos() > end { + return + } + if !yield(co) { + return + } + } + } + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/cursor.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/cursor.go new file mode 100644 index 00000000..74e75d14 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/cursor.go @@ -0,0 +1,38 @@ +// Copyright 2026 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 astutil + +import ( + "go/ast" + + "golang.org/x/tools/go/ast/edge" + "golang.org/x/tools/go/ast/inspector" +) + +// UnparenCursor returns the cursor for an expression with any +// enclosing parentheses removed, similar to [ast.Unparen]. +// It is often prudent to call this before switching on the +// type of cur.Node(). +// +// See also [UnparenEnclosingCursor]. +func UnparenCursor(cur inspector.Cursor) inspector.Cursor { + for is[*ast.ParenExpr](cur) { + cur, _ = cur.FirstChild() + } + return cur +} + +// UnparenEnclosingCursor returns the first element of +// the [Cursor.Enclosing] sequence that is not itself enclosed +// in parens. It is often prudent to call this before switching on +// cur.ParentEdge(). +// +// See also [UnparenCursor]. +func UnparenEnclosingCursor(cur inspector.Cursor) inspector.Cursor { + for cur.ParentEdgeKind() == edge.ParenExpr_X { + cur = cur.Parent() + } + return cur +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/equal.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/equal.go new file mode 100644 index 00000000..210f3923 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/equal.go @@ -0,0 +1,107 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil + +import ( + "go/ast" + "go/token" + "reflect" +) + +// Equal reports whether two nodes are structurally equal, +// ignoring fields of type [token.Pos], [ast.Object], +// and [ast.Scope], and comments. +// +// The operands x and y may be nil. +// A nil slice is not equal to an empty slice. +// +// The provided function determines whether two identifiers +// should be considered identical. +func Equal(x, y ast.Node, identical func(x, y *ast.Ident) bool) bool { + if x == nil || y == nil { + return x == y + } + return equal(reflect.ValueOf(x), reflect.ValueOf(y), identical) +} + +// EqualSyntax reports whether x and y are equal. +// Identifiers are considered equal if they are spelled the same. +// Comments are ignored. +func EqualSyntax(x, y ast.Expr) bool { + sameName := func(x, y *ast.Ident) bool { return x.Name == y.Name } + return Equal(x, y, sameName) +} + +func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool { + // Ensure types are the same + if x.Type() != y.Type() { + return false + } + switch x.Kind() { + case reflect.Pointer: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + switch t := x.Interface().(type) { + // Skip fields of types potentially involved in cycles. + case *ast.Object, *ast.Scope, *ast.CommentGroup: + return true + case *ast.Ident: + return identical(t, y.Interface().(*ast.Ident)) + default: + return equal(x.Elem(), y.Elem(), identical) + } + + case reflect.Interface: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + return equal(x.Elem(), y.Elem(), identical) + + case reflect.Struct: + for i := range x.NumField() { + xf := x.Field(i) + yf := y.Field(i) + // Skip position fields. + if xpos, ok := xf.Interface().(token.Pos); ok { + ypos := yf.Interface().(token.Pos) + // Numeric value of a Pos is not significant but its "zeroness" is, + // because it is often significant, e.g. CallExpr.Variadic(Ellipsis), ChanType.Arrow. + if xpos.IsValid() != ypos.IsValid() { + return false + } + } else if !equal(xf, yf, identical) { + return false + } + } + return true + + case reflect.Slice: + if x.IsNil() || y.IsNil() { + return x.IsNil() == y.IsNil() + } + if x.Len() != y.Len() { + return false + } + for i := range x.Len() { + if !equal(x.Index(i), y.Index(i), identical) { + return false + } + } + return true + + case reflect.String: + return x.String() == y.String() + + case reflect.Bool: + return x.Bool() == y.Bool() + + case reflect.Int: + return x.Int() == y.Int() + + default: + panic(x) + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/fields.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/fields.go new file mode 100644 index 00000000..8b81ea47 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/fields.go @@ -0,0 +1,35 @@ +// Copyright 2024 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 astutil + +import ( + "go/ast" + "iter" +) + +// FlatFields 'flattens' an ast.FieldList, returning an iterator over each +// (name, field) combination in the list. For unnamed fields, the identifier is +// nil. +func FlatFields(list *ast.FieldList) iter.Seq2[*ast.Ident, *ast.Field] { + return func(yield func(*ast.Ident, *ast.Field) bool) { + if list == nil { + return + } + + for _, field := range list.List { + if len(field.Names) == 0 { + if !yield(nil, field) { + return + } + } else { + for _, name := range field.Names { + if !yield(name, field) { + return + } + } + } + } + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/purge.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/purge.go new file mode 100644 index 00000000..d0a39415 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/purge.go @@ -0,0 +1,93 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package astutil provides various AST utility functions for gopls. +package astutil + +import ( + "bytes" + "go/scanner" + "go/token" +) + +// PurgeFuncBodies returns a copy of src in which the contents of each +// outermost {...} region have been deleted, except for struct and +// interface type bodies and the bodies of length-elided array +// literals ([...]T), whose element count is part of the type. It +// includes function bodies, function-literal bodies, and the bodies +// of slice, map, and explicitly-sized array composite literals (whose +// contents don't affect the type of the enclosing declaration). This +// reduces the amount of work required to parse the top-level +// declarations. +// +// PurgeFuncBodies does not preserve newlines or position information. +// Also, if the input is invalid, parsing the output of +// PurgeFuncBodies may result in a different tree due to its effects +// on parser error recovery. +func PurgeFuncBodies(src []byte) []byte { + // Destroy the content of any {...}-bracketed regions that are + // not immediately preceded by a "struct" or "interface" token, + // and that are not the body of a length-elided array literal. + // That includes function bodies, switch/select bodies, and most + // composite literals; this will lead to non-void functions that + // don't have return statements, which of course is a type error, + // but that's ok. + + var out bytes.Buffer + file := token.NewFileSet().AddFile("", -1, len(src)) + var sc scanner.Scanner + sc.Init(file, src, nil, 0) + var prev token.Token + var cursor int // last consumed src offset + var braces []token.Pos // stack of unclosed braces, or -1 for a region we preserve + var ellipsis bool // saw "[...]" not yet consumed by a literal-body "{" + for { + pos, tok, _ := sc.Scan() + if tok == token.EOF { + break + } + switch tok { + case token.COMMENT: + // TODO(adonovan): opt: skip, to save an estimated 20% of time. + + case token.SEMICOLON: + ellipsis = false + + case token.RBRACK: + // "...]" occurs only in the array-type prefix of a + // composite literal; variadic "..." is followed by + // a type or ")", never "]". + if prev == token.ELLIPSIS { + ellipsis = true + } + + case token.LBRACE: + if prev == token.STRUCT || prev == token.INTERFACE { + pos = -1 // type body: preserve (don't consume ellipsis) + } else if ellipsis { + pos = -1 // [...]T literal body: preserve + ellipsis = false + } + braces = append(braces, pos) + + case token.RBRACE: + if last := len(braces) - 1; last >= 0 { + top := braces[last] + braces = braces[:last] + if top < 0 { + // preserve + } else if len(braces) == 0 { // toplevel only + // Delete {...} body. + start := file.Offset(top) + end := file.Offset(pos) + out.Write(src[cursor : start+len("{")]) + cursor = end + } + } + } + prev = tok + } + out.Write(src[cursor:]) + return out.Bytes() +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/stringlit.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/stringlit.go new file mode 100644 index 00000000..eb49d451 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/stringlit.go @@ -0,0 +1,103 @@ +// Copyright 2025 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 astutil + +import ( + "fmt" + "go/ast" + "go/token" + "strconv" + "unicode/utf8" +) + +// RangeInStringLiteral calculates the positional range within a string literal +// corresponding to the specified start and end byte offsets within the logical string. +func RangeInStringLiteral(lit *ast.BasicLit, start, end int) (Range, error) { + startPos, err := PosInStringLiteral(lit, start) + if err != nil { + return Range{}, fmt.Errorf("start: %v", err) + } + endPos, err := PosInStringLiteral(lit, end) + if err != nil { + return Range{}, fmt.Errorf("end: %v", err) + } + return Range{startPos, endPos}, nil +} + +// PosInStringLiteral returns the position within a string literal +// corresponding to the specified byte offset within the logical +// string that it denotes. +func PosInStringLiteral(lit *ast.BasicLit, offset int) (token.Pos, error) { + raw := lit.Value + + value, err := strconv.Unquote(raw) + if err != nil { + return 0, err + } + if !(0 <= offset && offset <= len(value)) { + return 0, fmt.Errorf("invalid offset") + } + + pos, _ := walkStringLiteral(lit, lit.End(), offset) + return pos, nil +} + +// OffsetInStringLiteral returns the byte offset within the logical (unquoted) +// string corresponding to the specified source position. +func OffsetInStringLiteral(lit *ast.BasicLit, pos token.Pos) (int, error) { + if !NodeContainsPos(lit, pos) { + return 0, fmt.Errorf("invalid position") + } + + raw := lit.Value + + value, err := strconv.Unquote(raw) + if err != nil { + return 0, err + } + + _, offset := walkStringLiteral(lit, pos, len(value)) + return offset, nil +} + +// walkStringLiteral iterates through the raw string literal to map between +// a file position and a logical byte offset. It stops when it reaches +// either the targetPos or the targetOffset. +// +// TODO(hxjiang): consider making an iterator. +func walkStringLiteral(lit *ast.BasicLit, targetPos token.Pos, targetOffset int) (token.Pos, int) { + raw := lit.Value + norm := int(lit.End()-lit.Pos()) > len(lit.Value) + + // remove quotes + quote := raw[0] // '"' or '`' + raw = raw[1 : len(raw)-1] + + var ( + i = 0 // byte index within logical value + pos = lit.Pos() + 1 // position within literal + ) + + for raw != "" { + r, _, rest, _ := strconv.UnquoteChar(raw, quote) // can't fail + sz := len(raw) - len(rest) // length of literal char in raw bytes + + nextPos := pos + token.Pos(sz) + if norm && r == '\n' { + nextPos++ + } + nextI := i + utf8.RuneLen(r) // length of logical char in "cooked" bytes + + if nextPos > targetPos || nextI > targetOffset { + break + } + + raw = raw[sz:] + i = nextI + pos = nextPos + } + + return pos, i +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/unpack.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/unpack.go new file mode 100644 index 00000000..3d2fb04f --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/unpack.go @@ -0,0 +1,61 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil + +import ( + "go/ast" + + "honnef.co/go/tools/internal/xtools-internal/typeparams" +) + +// UnpackRecv unpacks a receiver type expression, reporting whether it is a +// pointer receiver, along with the type name identifier and any receiver type +// parameter identifiers. +// +// Copied (with modifications) from go/types. +func UnpackRecv(rtyp ast.Expr) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) { +L: // unpack receiver type + // This accepts invalid receivers such as ***T and does not + // work for other invalid receivers, but we don't care. The + // validity of receiver expressions is checked elsewhere. + for { + switch t := rtyp.(type) { + case *ast.ParenExpr: + rtyp = t.X + case *ast.StarExpr: + ptr = true + rtyp = t.X + default: + break L + } + } + + // unpack type parameters, if any + switch rtyp.(type) { + case *ast.IndexExpr, *ast.IndexListExpr: + var indices []ast.Expr + rtyp, _, indices, _ = typeparams.UnpackIndexExpr(rtyp) + for _, arg := range indices { + var par *ast.Ident + switch arg := arg.(type) { + case *ast.Ident: + par = arg + default: + // ignore errors + } + if par == nil { + par = &ast.Ident{NamePos: arg.Pos(), Name: "_"} + } + tparams = append(tparams, par) + } + } + + // unpack receiver name + if name, _ := rtyp.(*ast.Ident); name != nil { + rname = name + } + + return +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/util.go b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/util.go new file mode 100644 index 00000000..6d974db6 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/astutil/util.go @@ -0,0 +1,261 @@ +// Copyright 2025 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 astutil + +import ( + "fmt" + "go/ast" + "go/printer" + "go/token" + "strings" + + "golang.org/x/tools/go/ast/inspector" + "honnef.co/go/tools/internal/xtools-internal/moreiters" +) + +// NodeContains reports whether the Pos/End range of node n encloses +// the given range. +// +// It is inclusive of both end points, to allow hovering (etc) when +// the cursor is immediately after a node. +// +// Like [NodeRange], it treats the range of an [ast.File] as the +// file's complete extent. +// +// Precondition: n must not be nil. +func NodeContains(n ast.Node, rng Range) bool { + return NodeRange(n).Contains(rng) +} + +// NodeContainsPos reports whether the Pos/End range of node n encloses +// the given pos. +// +// Like [NodeRange], it treats the range of an [ast.File] as the +// file's complete extent. +func NodeContainsPos(n ast.Node, pos token.Pos) bool { + return NodeRange(n).ContainsPos(pos) +} + +// EnclosingFile returns the syntax tree for the file enclosing c. +// +// TODO(adonovan): promote this to a method of Cursor. +func EnclosingFile(c inspector.Cursor) *ast.File { + c, _ = moreiters.First(c.Enclosing((*ast.File)(nil))) + return c.Node().(*ast.File) +} + +// DocComment returns the doc comment for a node, if any. +func DocComment(n ast.Node) *ast.CommentGroup { + switch n := n.(type) { + case *ast.FuncDecl: + return n.Doc + case *ast.GenDecl: + return n.Doc + case *ast.ValueSpec: + return n.Doc + case *ast.TypeSpec: + return n.Doc + case *ast.File: + return n.Doc + case *ast.ImportSpec: + return n.Doc + case *ast.Field: + return n.Doc + } + return nil +} + +// Format returns a string representation of the node n. +func Format(fset *token.FileSet, n ast.Node) string { + var buf strings.Builder + printer.Fprint(&buf, fset, n) // ignore errors + return buf.String() +} + +// -- Range -- + +// Range is a Pos interval. +// It implements [analysis.Range] and [ast.Node]. +type Range struct{ Start, EndPos token.Pos } + +// RangeOf constructs a Range. +// +// RangeOf exists to pacify the "unkeyed literal" (composites) vet +// check. It would be nice if there were a way for a type to add +// itself to the allowlist. +func RangeOf(start, end token.Pos) Range { return Range{start, end} } + +// NodeRange returns the extent of node n as a Range. +// +// For unfortunate historical reasons, the Pos/End extent of an +// ast.File runs from the start of its package declaration---excluding +// copyright comments, build tags, and package documentation---to the +// end of its last declaration, excluding any trailing comments. So, +// as a special case, if n is an [ast.File], NodeContains uses +// n.FileStart <= pos && pos <= n.FileEnd to report whether the +// position lies anywhere within the file. +func NodeRange(n ast.Node) Range { + if file, ok := n.(*ast.File); ok { + return Range{file.FileStart, file.FileEnd} // entire file + } + return Range{n.Pos(), n.End()} +} + +func (r Range) Pos() token.Pos { return r.Start } +func (r Range) End() token.Pos { return r.EndPos } + +// ContainsPos reports whether the range (inclusive of both end points) +// includes the specified position. +func (r Range) ContainsPos(pos token.Pos) bool { + return r.Contains(RangeOf(pos, pos)) +} + +// Contains reports whether the range (inclusive of both end points) +// includes the specified range. +func (r Range) Contains(rng Range) bool { + return r.Start <= rng.Start && rng.EndPos <= r.EndPos +} + +// IsValid reports whether the range is valid. +func (r Range) IsValid() bool { return r.Start.IsValid() && r.Start <= r.EndPos } + +// -- + +// Select returns the syntax nodes identified by a user's text +// selection. It returns three nodes: the innermost node that wholly +// encloses the selection; and the first and last nodes that are +// wholly enclosed by the selection. +// +// For example, given this selection: +// +// { f(); g(); /* comment */ } +// ~~~~~~~~~~~ +// +// Select returns the enclosing BlockStmt, the f() CallExpr, and the g() CallExpr. +// +// If the selection does not wholly enclose any nodes, Select returns an error +// and invalid start/end nodes, but it may return a valid enclosing node. +// +// Callers that require exactly one syntax tree (e.g. just f() or just +// g()) should check that the returned start and end nodes are +// identical. +// +// This function is intended to be called early in the handling of a +// user's request, since it is tolerant of sloppy selection including +// extraneous whitespace and comments. Use it in new code instead of +// PathEnclosingInterval. When the exact extent of a node is known, +// use [Cursor.FindByPos] instead. +// +// TODO(hxjiang): Consider refactoring the function signature. It is currently +// confusing that an error is returned even when a valid enclosing node is +// successfully found. Consider grouping all cursors into one struct. +func Select(curFile inspector.Cursor, start, end token.Pos) (_enclosing, _start, _end inspector.Cursor, _ error) { + curEnclosing, ok := curFile.FindByPos(start, end) + if !ok { + return noCursor, noCursor, noCursor, fmt.Errorf("invalid selection") + } + + // Find the first and last node wholly within the (start, end) range. + // We'll narrow the effective selection to them, to exclude whitespace. + // (This matches the functionality of PathEnclosingInterval.) + var curStart, curEnd inspector.Cursor + rng := RangeOf(start, end) + for cur := range curEnclosing.Preorder() { + if rng.Contains(NodeRange(cur.Node())) { + // The start node has the least Pos. + if !curStart.Valid() { + curStart = cur + } + // The end node has the greatest End. + // End positions do not change monotonically, + // so we must compute the max. + if !curEnd.Valid() || + cur.Node().End() > curEnd.Node().End() { + curEnd = cur + } + } + } + if !curStart.Valid() { + // The selection is valid (inside curEnclosing) but contains no + // complete nodes. This happens for point selections (start == end), + // or selections covering only only spaces, comments, and punctuation + // tokens. + // Return the enclosing node so the caller can still use the context. + return curEnclosing, noCursor, noCursor, fmt.Errorf("invalid selection") + } + return curEnclosing, curStart, curEnd, nil +} + +var noCursor inspector.Cursor + +// MaybeParenthesize returns new, possibly wrapped in parens if needed +// to preserve operator precedence when it replaces old, whose parent +// is parentNode. +// +// (This would be more naturally written in terms of Cursor, but one of +// the callers--the inliner--does not have cursors handy.) +func MaybeParenthesize(parentNode ast.Node, old, new ast.Expr) ast.Expr { + if needsParens(parentNode, old, new) { + new = &ast.ParenExpr{X: new} + } + return new +} + +func needsParens(parentNode ast.Node, old, new ast.Expr) bool { + // An expression beneath a non-expression + // has no precedence ambiguity. + parent, ok := parentNode.(ast.Expr) + if !ok { + return false + } + + precedence := func(n ast.Node) int { + switch n := n.(type) { + case *ast.UnaryExpr, *ast.StarExpr: + return token.UnaryPrec + case *ast.BinaryExpr: + return n.Op.Precedence() + } + return -1 + } + + // Parens are not required if the new node + // is not unary or binary. + newprec := precedence(new) + if newprec < 0 { + return false + } + + // Parens are required if parent and child are both + // unary or binary and the parent has higher precedence. + if precedence(parent) > newprec { + return true + } + + // Was the old node the operand of a postfix operator? + // f().sel + // f()[i:j] + // f()[i] + // f().(T) + // f()(x) + switch parent := parent.(type) { + case *ast.SelectorExpr: + return parent.X == old + case *ast.IndexExpr: + return parent.X == old + case *ast.SliceExpr: + return parent.X == old + case *ast.TypeAssertExpr: + return parent.X == old + case *ast.CallExpr: + return parent.Fun == old + } + return false +} + +func is[T any](n any) bool { + _, ok := n.(T) + return ok +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go new file mode 100644 index 00000000..44732557 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/allpaths.go @@ -0,0 +1,24 @@ +// Copyright 2026 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 graph + +// AllPaths returns the set of nodes that are part of at least one path from src to dst. +func AllPaths[NodeID comparable](g Graph[NodeID], src, dst NodeID) map[NodeID]bool { + // We intersect the forward closure of 'src' with + // the reverse closure of 'dst'. This is not the most + // efficient implementation, but it's the clearest, + // and the previous one had bugs. + + fwd := Reachable(g, src) + rev := Reachable(Transpose(g), dst) + + // Intersection + for n := range fwd { + if !rev[n] { + delete(fwd, n) + } + } + return fwd +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go new file mode 100644 index 00000000..ae327067 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/compact.go @@ -0,0 +1,89 @@ +// Copyright 2026 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 graph + +import "iter" + +// A CompactGraph is a Graph with nodes that are compactly numbered from [0, +// NumNodes()). +// +// Compactly numbered graphs are useful for many graph algorithms, and many +// graph representations are naturally compact. +// +// To compact an arbitrary graph, use [Compact]. +type CompactGraph interface { + Graph[int] + IsCompact() +} + +// A nodePreserving graph is a transformation of another graph that preserves +// node IDs. +type nodePreserving interface { + Graph[int] + unwrapPreservingNodes() Graph[int] +} + +// Compact takes a Graph with arbitrary NodeIDs and returns a compact graph. +// +// If g implements [CompactGraph], it assumes g is already compact and simply +// returns g and an identity mapping. +func Compact[NodeID comparable](g Graph[NodeID]) (CompactGraph, *Index[NodeID]) { + // If it's already compact, simply return it. + if gc, ok := g.(CompactGraph); ok { + // The above assertion ensures NodeID is int, so we know this type + // assertion will always succeed. + return gc, any(NewIdentityIndex(gc.NumNodes())).(*Index[NodeID]) + } + + // If it's a transformation and the underlying graph is compact, we can use + // an identity index. Though we still need to build a compactGraph to + // satisfy the CompactGraph interface. + g2, _ := g.(nodePreserving) + for g2 != nil { + unwrapped := g2.unwrapPreservingNodes() + if gc, ok := unwrapped.(CompactGraph); ok { + index := any(NewIdentityIndex(gc.NumNodes())).(*Index[NodeID]) + cg := compactGraph[NodeID]{g, index} + return &cg, index + } + g2, _ = unwrapped.(nodePreserving) + } + + // Nope, just build an index. + cg := compactGraph[NodeID]{g, NewIndex(g.Nodes())} + return &cg, cg.m +} + +type compactGraph[NodeID comparable] struct { + g Graph[NodeID] + m *Index[NodeID] +} + +func (g *compactGraph[NodeID]) Nodes() iter.Seq[int] { + return func(yield func(int) bool) { + for i := range g.g.NumNodes() { + if !yield(i) { + break + } + } + } +} + +func (g *compactGraph[NodeID]) NumNodes() int { + return g.g.NumNodes() +} + +func (g *compactGraph[NodeID]) Out(node int) iter.Seq[int] { + id := g.m.Value(node) + return func(yield func(int) bool) { + for nid := range g.g.Out(id) { + if !yield(g.m.Index(nid)) { + break + } + } + } +} + +func (g *compactGraph[NodeID]) IsCompact() {} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go new file mode 100644 index 00000000..fdea880e --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/graph.go @@ -0,0 +1,33 @@ +// Copyright 2026 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 graph provides a common abstraction for directed graphs and standard +// graph algorithms. +// +// In general, this package does not provide or assume any concrete graph +// representation. It's up to the caller of this package to implement the +// [Graph] interface, either directly or as an adapter around another type. +package graph + +import "iter" + +// A Graph implements a directed graph where nodes in the graph are identified +// by the NodeID type. +// +// If a concrete graph type stores additional information about nodes and/or +// edges, it will conventionally provide methods of the form: +// +// Node(node NodeID) nodeInfo +// Edge(from, to NodeID) edgeInfo +type Graph[NodeID comparable] interface { + // Nodes yields all nodes in this graph. + Nodes() iter.Seq[NodeID] + + // NumNodes returns the total number of nodes in this graph. + NumNodes() int + + // Out yields the out-edges of node. Out must be deterministic, though + // otherwise there is no constraint on the order of the returned sequence. + Out(node NodeID) iter.Seq[NodeID] +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go new file mode 100644 index 00000000..394213e4 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/index.go @@ -0,0 +1,96 @@ +// Copyright 2026 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 graph + +import ( + "fmt" + "iter" + "slices" +) + +// An Index is an immutable, bijective map between [0, N) and an ordered list of keys. +type Index[Key comparable] struct { + // There are three Index representations: + // + // - If identN > 0, an identity map of [0, identN). + // - If index == nil, a sorted integer index in values. + // - Otherwise, a full index in values and index. + + identN int + values []Key + index map[Key]int +} + +// NewIndex returns an index for the specified list of values. +func NewIndex[Key comparable](values iter.Seq[Key]) *Index[Key] { + vs := slices.Collect(values) + if len(vs) == 0 { + return new(Index[Key]) + } + + // Fast path: a naturally sorted list needs no index. (Sadly, there's no way + // to ask "is Key ordered?") + if vi, ok := any(vs).([]int); ok && slices.IsSorted(vi) { + return &Index[Key]{values: vs} + } + + index := make(map[Key]int, len(vs)) + for i, v := range vs { + index[v] = i + } + return &Index[Key]{values: vs, index: index} +} + +// NewIdentityIndex returns an index that maps [0, n) to [0, n). +func NewIdentityIndex(n int) *Index[int] { + if n < 0 { + panic("n < 0") + } + // If n == 0, this is actually a "sorted integer index", but it doesn't + // matter because everything is out of bounds either way. + return &Index[int]{identN: n} +} + +// Value maps an index to a key. +func (ix *Index[Key]) Value(index int) Key { + if ix.identN > 0 { + if index < 0 || index >= ix.identN { + panic(fmt.Sprintf("index %d out of range [0, %d)", index, ix.identN)) + } + return any(index).(Key) + } + if index < 0 || index >= len(ix.values) { + panic(fmt.Sprintf("index %d out of range [0, %d)", index, ix.identN)) + } + return ix.values[index] +} + +// Index maps a key to an index. +func (ix *Index[Key]) Index(key Key) int { + if key, ok := any(key).(int); ok { + // Integer-only optimizations. + switch { + case ix.identN > 0: + // Identity. + if 0 <= key && key < ix.identN { + return key + } + goto oob + + case ix.index == nil: + // Sorted integers. + if i, ok := slices.BinarySearch(any(ix.values).([]int), key); ok { + return i + } + goto oob + } + } + if i, ok := ix.index[key]; ok { + return i + } + +oob: + panic(fmt.Sprintf("key %v not in index", key)) +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go new file mode 100644 index 00000000..795a434d --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/order.go @@ -0,0 +1,94 @@ +// Copyright 2026 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 graph + +import "slices" + +// Postorder returns the sequence of nodes in the spanning DAG of g, in +// postorder. +// +// For rootless subgraphs, it breaks cycles by starting at the lowest numbered +// node. +// +// This algorithm runs in O(V + E) time and O(V + E) space. +func Postorder[NodeID comparable](g Graph[NodeID]) []NodeID { + cg, nodeMap := Compact(g) + + numNodes := cg.NumNodes() + if numNodes == 0 { + return nil + } + + result := make([]NodeID, 0, numNodes) + visited := newBitset(numNodes) + onStack := newBitset(numNodes) + + // visit performs a Depth-First Search. + var visit func(u int) + visit = func(u int) { + if !visited.add(u) { + return + } + onStack.add(u) + + for v := range cg.Out(u) { + if onStack.contains(v) { + // Cycle detected (back-edge). + // To resolve, we simply skip processing this edge further in the + // current recursion, effectively "breaking" the cycle at this point. + continue + } + visit(v) + } + + onStack.remove(u) + // Post-order: add to result after all descendants are processed. + result = append(result, nodeMap.Value(u)) + } + + // Visit every node in ascending order to ensure stability. + for u := range numNodes { + visit(u) + } + + return result +} + +// ReversePostorder returns the nodes of the graph in reverse post-order. +// +// If g is a directed acyclic graph (DAG), the result is a topological sort of +// g. +// +// See [Postorder] for how this handles back-edges and cycles. +// +// This algorithm runs in O(V + E) time and O(V + E) space. +func ReversePostorder[NodeID comparable](g Graph[NodeID]) []NodeID { + result := Postorder(g) + slices.Reverse(result) + return result +} + +// bitset is a simple fixed-size bitset used to reduce memory overhead. +type bitset []uint64 + +func newBitset(n int) bitset { + return make(bitset, (n+63)/64) +} + +func (b bitset) add(u int) bool { + if b.contains(u) { + return false + } + b[u/64] |= 1 << (u % 64) + return true +} + +func (b bitset) remove(u int) { + b[u/64] &= ^(1 << (u % 64)) +} + +func (b bitset) contains(u int) bool { + return b[u/64]&(1<<(u%64)) != 0 +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go new file mode 100644 index 00000000..dd14eae8 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/reachable.go @@ -0,0 +1,23 @@ +// Copyright 2026 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 graph + +// Reachable returns the set of nodes reachable from the given roots. +func Reachable[NodeID comparable](g Graph[NodeID], roots ...NodeID) map[NodeID]bool { + seen := make(map[NodeID]bool) + var visit func(node NodeID) + visit = func(node NodeID) { + if !seen[node] { + seen[node] = true + for e := range g.Out(node) { + visit(e) + } + } + } + for _, root := range roots { + visit(root) + } + return seen +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go new file mode 100644 index 00000000..fb4764f1 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/scc.go @@ -0,0 +1,39 @@ +// Copyright 2026 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 graph + +import "slices" + +// SCCs computes the strongly connected components of the graph g. +func SCCs[NodeID comparable](g Graph[NodeID]) [][]NodeID { + // Use Kosaraju's algorithm. Tarjan is overkill here. + + // Forward pass + S := Postorder(g) + + // Reverse pass + gt := Transpose(g) + seen := make(map[NodeID]bool) + var scc []NodeID + var sccs [][]NodeID + var rvisit func(NodeID) + rvisit = func(u NodeID) { + if !seen[u] { + seen[u] = true + scc = append(scc, u) + for v := range gt.Out(u) { + rvisit(v) + } + } + } + for _, root := range slices.Backward(S) { + if !seen[root] { + scc = nil + rvisit(root) + sccs = append(sccs, scc) + } + } + return sccs +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go new file mode 100644 index 00000000..e7457e8b --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/shortest.go @@ -0,0 +1,45 @@ +// Copyright 2026 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 graph + +import "slices" + +// ShortestPath returns a shortest path from src to dst in g. +// It returns the path as a slice of nodes starting with src and ending with dst. +// If no path is found, it returns nil. +func ShortestPath[NodeID comparable](g Graph[NodeID], src, dst NodeID) []NodeID { + if src == dst { + return []NodeID{src} + } + + pred := make(map[NodeID]NodeID) + queue := []NodeID{src} + // Mark src as seen. + pred[src] = src + + for len(queue) > 0 { + n := queue[0] + queue = queue[1:] + + if n == dst { + // Reconstruct path + var path []NodeID + for curr := dst; curr != src; curr = pred[curr] { + path = append(path, curr) + } + path = append(path, src) + slices.Reverse(path) + return path + } + + for v := range g.Out(n) { + if _, seen := pred[v]; !seen { + pred[v] = n + queue = append(queue, v) + } + } + } + return nil +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go new file mode 100644 index 00000000..431fc5f6 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/graph/transpose.go @@ -0,0 +1,51 @@ +// Copyright 2026 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 graph + +import ( + "iter" + "slices" +) + +type transpose[NodeID comparable] struct { + Graph Graph[NodeID] + preds map[NodeID][]NodeID +} + +// transpose returns a graph like g but with all edges reversed. Node IDs are +// identical to the underlying graph. +// +// Transpose preserves compactness. +func Transpose[NodeID comparable](g Graph[NodeID]) Graph[NodeID] { + if g, ok := g.(transpose[NodeID]); ok { + // Transpose(Transpose(g)) == g + return g.Graph + } + + preds := make(map[NodeID][]NodeID) + for nid := range g.Nodes() { + for succ := range g.Out(nid) { + preds[succ] = append(preds[succ], nid) + } + } + return transpose[NodeID]{g, preds} +} + +func (t transpose[NodeID]) NumNodes() int { + return len(t.preds) +} + +func (t transpose[NodeID]) Nodes() iter.Seq[NodeID] { + return t.Graph.Nodes() +} + +func (t transpose[NodeID]) Out(n NodeID) iter.Seq[NodeID] { + return slices.Values(t.preds[n]) +} + +//lint:ignore U1000 False positive in Staticcheck 2026.1 and older. +func (t transpose[NodeID]) unwrapPreservingNodes() Graph[NodeID] { + return t.Graph +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/moreiters/iters.go b/vendor/honnef.co/go/tools/internal/xtools-internal/moreiters/iters.go new file mode 100644 index 00000000..3dc81c4d --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/moreiters/iters.go @@ -0,0 +1,63 @@ +// Copyright 2025 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 moreiters + +import "iter" + +// First returns the first value of seq and true. +// If seq is empty, it returns the zero value of T and false. +func First[T any](seq iter.Seq[T]) (z T, ok bool) { + for t := range seq { + return t, true + } + return z, false +} + +// Contains reports whether x is an element of the sequence seq. +func Contains[T comparable](seq iter.Seq[T], x T) bool { + for cand := range seq { + if cand == x { + return true + } + } + return false +} + +// Every reports whether every pred(t) for t in seq returns true, +// stopping at the first false element. +func Every[T any](seq iter.Seq[T], pred func(T) bool) bool { + for t := range seq { + if !pred(t) { + return false + } + } + return true +} + +// Any reports whether any pred(t) for t in seq returns true. +func Any[T any](seq iter.Seq[T], pred func(T) bool) bool { + for t := range seq { + if pred(t) { + return true + } + } + return false +} + +// Len returns the number of elements in the sequence (by iterating). +func Len[T any](seq iter.Seq[T]) (n int) { + for range seq { + n++ + } + return +} + +// Empty reports whether the sequence contains no elements. +func Empty[T any](seq iter.Seq[T]) bool { + for range seq { + return false + } + return true +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/common.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/common.go new file mode 100644 index 00000000..cdae2b8e --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/common.go @@ -0,0 +1,68 @@ +// 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 typeparams contains common utilities for writing tools that +// interact with generic Go code, as introduced with Go 1.18. It +// supplements the standard library APIs. Notably, the StructuralTerms +// API computes a minimal representation of the structural +// restrictions on a type parameter. +// +// An external version of these APIs is available in the +// golang.org/x/exp/typeparams module. +package typeparams + +import ( + "go/ast" + "go/token" + "go/types" +) + +// UnpackIndexExpr extracts data from AST nodes that represent index +// expressions. +// +// For an ast.IndexExpr, the resulting indices slice will contain exactly one +// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable +// number of index expressions. +// +// For nodes that don't represent index expressions, the first return value of +// UnpackIndexExpr will be nil. +func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) { + switch e := n.(type) { + case *ast.IndexExpr: + return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack + case *ast.IndexListExpr: + return e.X, e.Lbrack, e.Indices, e.Rbrack + } + return nil, token.NoPos, nil, token.NoPos +} + +// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on +// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0 +// will panic. +func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr { + switch len(indices) { + case 0: + panic("empty indices") + case 1: + return &ast.IndexExpr{ + X: x, + Lbrack: lbrack, + Index: indices[0], + Rbrack: rbrack, + } + default: + return &ast.IndexListExpr{ + X: x, + Lbrack: lbrack, + Indices: indices, + Rbrack: rbrack, + } + } +} + +// IsTypeParam reports whether t is a type parameter (or an alias of one). +func IsTypeParam(t types.Type) bool { + _, ok := types.Unalias(t).(*types.TypeParam) + return ok +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/coretype.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/coretype.go new file mode 100644 index 00000000..2e05de46 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/coretype.go @@ -0,0 +1,157 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typeparams + +import ( + "fmt" + "go/types" +) + +// CoreType returns the core type of T or nil if T does not have a core type. +// +// As of Go1.25, the notion of a core type has been removed from the language spec. +// See https://go.dev/blog/coretypes for more details. +// TODO(mkalil): We should eventually consider removing all uses of CoreType. +func CoreType(T types.Type) types.Type { + U := T.Underlying() + if _, ok := U.(*types.Interface); !ok { + return U // for non-interface types, + } + + terms, err := NormalTerms(U) + if len(terms) == 0 || err != nil { + // len(terms) -> empty type set of interface. + // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set. + return nil // no core type. + } + + U = terms[0].Type().Underlying() + var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying()) + for identical = 1; identical < len(terms); identical++ { + if !types.Identical(U, terms[identical].Type().Underlying()) { + break + } + } + + if identical == len(terms) { + // From the deprecated core types spec: + // "There is a single type U which is the underlying type of all types in the type set of T" + return U + } + ch, ok := U.(*types.Chan) + if !ok { + return nil // no core type as identical < len(terms) and U is not a channel. + } + // From the deprecated core types spec: + // "the type chan E if T contains only bidirectional channels, or the type chan<- E or + // <-chan E depending on the direction of the directional channels present." + for chans := identical; chans < len(terms); chans++ { + curr, ok := terms[chans].Type().Underlying().(*types.Chan) + if !ok { + return nil + } + if !types.Identical(ch.Elem(), curr.Elem()) { + return nil // channel elements are not identical. + } + if ch.Dir() == types.SendRecv { + // ch is bidirectional. We can safely always use curr's direction. + ch = curr + } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() { + // ch and curr are not bidirectional and not the same direction. + return nil + } + } + return ch +} + +// NormalTerms returns a slice of terms representing the normalized structural +// type restrictions of a type, if any. +// +// For all types other than *types.TypeParam, *types.Interface, and +// *types.Union, this is just a single term with Tilde() == false and +// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see +// below. +// +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration type +// T[P interface{~int; m()}] int the structural restriction of the type +// parameter P is ~int. +// +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// NormalTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, NormalTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the type is +// invalid, exceeds complexity bounds, or has an empty type set. In the latter +// case, NormalTerms returns ErrEmptyTypeSet. +// +// NormalTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func NormalTerms(T types.Type) ([]*types.Term, error) { + // typeSetOf(T) == typeSetOf(Unalias(T)) + typ := types.Unalias(T) + if named, ok := typ.(*types.Named); ok { + typ = named.Underlying() + } + switch typ := typ.(type) { + case *types.TypeParam: + return StructuralTerms(typ) + case *types.Union: + return UnionTermSet(typ) + case *types.Interface: + return InterfaceTermSet(typ) + default: + return []*types.Term{types.NewTerm(false, T)}, nil + } +} + +// Deref returns the type of the variable pointed to by t, +// if t's core type is a pointer; otherwise it returns t. +// +// Do not assume that Deref(T)==T implies T is not a pointer: +// consider "type T *T", for example. +// +// TODO(adonovan): ideally this would live in typesinternal, but that +// creates an import cycle. Move there when we melt this package down. +func Deref(t types.Type) types.Type { + if ptr, ok := CoreType(t).(*types.Pointer); ok { + return ptr.Elem() + } + return t +} + +// MustDeref returns the type of the variable pointed to by t. +// It panics if t's core type is not a pointer. +// +// TODO(adonovan): ideally this would live in typesinternal, but that +// creates an import cycle. Move there when we melt this package down. +func MustDeref(t types.Type) types.Type { + if ptr, ok := CoreType(t).(*types.Pointer); ok { + return ptr.Elem() + } + panic(fmt.Sprintf("%v is not a pointer", t)) +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/free.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/free.go new file mode 100644 index 00000000..4c391876 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/free.go @@ -0,0 +1,129 @@ +// Copyright 2024 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 typeparams + +import ( + "go/types" +) + +// Free is a memoization of the set of free type parameters within a +// type. It makes a sequence of calls to [Free.Has] for overlapping +// types more efficient. The zero value is ready for use. +// +// NOTE: Adapted from go/types/infer.go. If it is later exported, factor. +type Free struct { + seen map[types.Type]bool +} + +// Has reports whether the specified type has a free type parameter. +func (w *Free) Has(typ types.Type) (res bool) { + // detect cycles + if x, ok := w.seen[typ]; ok { + return x + } + if w.seen == nil { + w.seen = make(map[types.Type]bool) + } + w.seen[typ] = false + defer func() { + w.seen[typ] = res + }() + + switch t := typ.(type) { + case nil, *types.Basic: // TODO(gri) should nil be handled here? + break + + case *types.Alias: + if t.TypeParams().Len() > t.TypeArgs().Len() { + return true // This is an uninstantiated Alias. + } + // The expansion of an alias can have free type parameters, + // whether or not the alias itself has type parameters: + // + // func _[K comparable]() { + // type Set = map[K]bool // free(Set) = {K} + // type MapTo[V] = map[K]V // free(Map[foo]) = {V} + // } + // + // So, we must Unalias. + return w.Has(types.Unalias(t)) + + case *types.Array: + return w.Has(t.Elem()) + + case *types.Slice: + return w.Has(t.Elem()) + + case *types.Struct: + for i, n := 0, t.NumFields(); i < n; i++ { + if w.Has(t.Field(i).Type()) { + return true + } + } + + case *types.Pointer: + return w.Has(t.Elem()) + + case *types.Tuple: + n := t.Len() + for i := range n { + if w.Has(t.At(i).Type()) { + return true + } + } + + case *types.Signature: + // t.tparams may not be nil if we are looking at a signature + // of a generic function type (or an interface method) that is + // part of the type we're testing. We don't care about these type + // parameters. + // Similarly, the receiver of a method may declare (rather than + // use) type parameters, we don't care about those either. + // Thus, we only need to look at the input and result parameters. + return w.Has(t.Params()) || w.Has(t.Results()) + + case *types.Interface: + for i, n := 0, t.NumMethods(); i < n; i++ { + if w.Has(t.Method(i).Type()) { + return true + } + } + terms, err := InterfaceTermSet(t) + if err != nil { + return false // ill typed + } + for _, term := range terms { + if w.Has(term.Type()) { + return true + } + } + + case *types.Map: + return w.Has(t.Key()) || w.Has(t.Elem()) + + case *types.Chan: + return w.Has(t.Elem()) + + case *types.Named: + args := t.TypeArgs() + if params := t.TypeParams(); params.Len() > args.Len() { + return true // this is an uninstantiated named type. + } + for i, n := 0, args.Len(); i < n; i++ { + if w.Has(args.At(i)) { + return true + } + } + return w.Has(t.Underlying()) // recurse for types local to parameterized functions + + case *types.TypeParam: + return true + + default: + panic(t) // unreachable + } + + return false +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/normalize.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/normalize.go new file mode 100644 index 00000000..ba367871 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/normalize.go @@ -0,0 +1,214 @@ +// 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 typeparams + +import ( + "errors" + "fmt" + "go/types" + "os" + "strings" +) + +const debug = false + +var ErrEmptyTypeSet = errors.New("empty type set") + +// StructuralTerms returns a slice of terms representing the normalized +// structural type restrictions of a type parameter, if any. +// +// Structural type restrictions of a type parameter are created via +// non-interface types embedded in its constraint interface (directly, or via a +// chain of interface embeddings). For example, in the declaration +// +// type T[P interface{~int; m()}] int +// +// the structural restriction of the type parameter P is ~int. +// +// With interface embedding and unions, the specification of structural type +// restrictions may be arbitrarily complex. For example, consider the +// following: +// +// type A interface{ ~string|~[]byte } +// +// type B interface{ int|string } +// +// type C interface { ~string|~int } +// +// type T[P interface{ A|B; C }] int +// +// In this example, the structural type restriction of P is ~string|int: A|B +// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, +// which when intersected with C (~string|~int) yields ~string|int. +// +// StructuralTerms computes these expansions and reductions, producing a +// "normalized" form of the embeddings. A structural restriction is normalized +// if it is a single union containing no interface terms, and is minimal in the +// sense that removing any term changes the set of types satisfying the +// constraint. It is left as a proof for the reader that, modulo sorting, there +// is exactly one such normalized form. +// +// Because the minimal representation always takes this form, StructuralTerms +// returns a slice of tilde terms corresponding to the terms of the union in +// the normalized structural restriction. An error is returned if the +// constraint interface is invalid, exceeds complexity bounds, or has an empty +// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. +// +// StructuralTerms makes no guarantees about the order of terms, except that it +// is deterministic. +func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { + constraint := tparam.Constraint() + if constraint == nil { + return nil, fmt.Errorf("%s has nil constraint", tparam) + } + iface, _ := constraint.Underlying().(*types.Interface) + if iface == nil { + return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) + } + return InterfaceTermSet(iface) +} + +// InterfaceTermSet computes the normalized terms for a constraint interface, +// returning an error if the term set cannot be computed or is empty. In the +// latter case, the error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { + return computeTermSet(iface) +} + +// UnionTermSet computes the normalized terms for a union, returning an error +// if the term set cannot be computed or is empty. In the latter case, the +// error will be ErrEmptyTypeSet. +// +// See the documentation of StructuralTerms for more information on +// normalization. +func UnionTermSet(union *types.Union) ([]*types.Term, error) { + return computeTermSet(union) +} + +func computeTermSet(typ types.Type) ([]*types.Term, error) { + tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) + if err != nil { + return nil, err + } + if tset.terms.isEmpty() { + return nil, ErrEmptyTypeSet + } + if tset.terms.isAll() { + return nil, nil + } + var terms []*types.Term + for _, term := range tset.terms { + terms = append(terms, types.NewTerm(term.tilde, term.typ)) + } + return terms, nil +} + +// A termSet holds the normalized set of terms for a given type. +// +// The name termSet is intentionally distinct from 'type set': a type set is +// all types that implement a type (and includes method restrictions), whereas +// a term set just represents the structural restrictions on a type. +type termSet struct { + complete bool + terms termlist +} + +func indentf(depth int, format string, args ...any) { + fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) +} + +func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { + if t == nil { + panic("nil type") + } + + if debug { + indentf(depth, "%s", t.String()) + defer func() { + if err != nil { + indentf(depth, "=> %s", err) + } else { + indentf(depth, "=> %s", res.terms.String()) + } + }() + } + + const maxTermCount = 100 + if tset, ok := seen[t]; ok { + if !tset.complete { + return nil, fmt.Errorf("cycle detected in the declaration of %s", t) + } + return tset, nil + } + + // Mark the current type as seen to avoid infinite recursion. + tset := new(termSet) + defer func() { + tset.complete = true + }() + seen[t] = tset + + switch u := t.Underlying().(type) { + case *types.Interface: + // The term set of an interface is the intersection of the term sets of its + // embedded types. + tset.terms = allTermlist + for embedded := range u.EmbeddedTypes() { + if _, ok := embedded.Underlying().(*types.TypeParam); ok { + return nil, fmt.Errorf("invalid embedded type %T", embedded) + } + tset2, err := computeTermSetInternal(embedded, seen, depth+1) + if err != nil { + return nil, err + } + tset.terms = tset.terms.intersect(tset2.terms) + } + case *types.Union: + // The term set of a union is the union of term sets of its terms. + tset.terms = nil + for t := range u.Terms() { + var terms termlist + switch t.Type().Underlying().(type) { + case *types.Interface: + tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) + if err != nil { + return nil, err + } + terms = tset2.terms + case *types.TypeParam, *types.Union: + // A stand-alone type parameter or union is not permitted as union + // term. + return nil, fmt.Errorf("invalid union term %T", t) + default: + if t.Type() == types.Typ[types.Invalid] { + continue + } + terms = termlist{{t.Tilde(), t.Type()}} + } + tset.terms = tset.terms.union(terms) + if len(tset.terms) > maxTermCount { + return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) + } + } + case *types.TypeParam: + panic("unreachable") + default: + // For all other types, the term set is just a single non-tilde term + // holding the type itself. + if u != types.Typ[types.Invalid] { + tset.terms = termlist{{false, t}} + } + } + return tset, nil +} + +// under is a facade for the go/types internal function of the same name. It is +// used by typeterm.go. +func under(t types.Type) types.Type { + return t.Underlying() +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/termlist.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/termlist.go new file mode 100644 index 00000000..9bc29143 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/termlist.go @@ -0,0 +1,169 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/termlist.go + +// 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. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import ( + "go/types" + "strings" +) + +// A termlist represents the type set represented by the union +// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. +// A termlist is in normal form if all terms are disjoint. +// termlist operations don't require the operands to be in +// normal form. +type termlist []*term + +// allTermlist represents the set of all types. +// It is in normal form. +var allTermlist = termlist{new(term)} + +// termSep is the separator used between individual terms. +const termSep = " | " + +// String prints the termlist exactly (without normalization). +func (xl termlist) String() string { + if len(xl) == 0 { + return "∅" + } + var buf strings.Builder + for i, x := range xl { + if i > 0 { + buf.WriteString(termSep) + } + buf.WriteString(x.String()) + } + return buf.String() +} + +// isEmpty reports whether the termlist xl represents the empty set of types. +func (xl termlist) isEmpty() bool { + // If there's a non-nil term, the entire list is not empty. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil { + return false + } + } + return true +} + +// isAll reports whether the termlist xl represents the set of all types. +func (xl termlist) isAll() bool { + // If there's a 𝓤 term, the entire list is 𝓤. + // If the termlist is in normal form, this requires at most + // one iteration. + for _, x := range xl { + if x != nil && x.typ == nil { + return true + } + } + return false +} + +// norm returns the normal form of xl. +func (xl termlist) norm() termlist { + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + used := make([]bool, len(xl)) + var rl termlist + for i, xi := range xl { + if xi == nil || used[i] { + continue + } + for j := i + 1; j < len(xl); j++ { + xj := xl[j] + if xj == nil || used[j] { + continue + } + if u1, u2 := xi.union(xj); u2 == nil { + // If we encounter a 𝓤 term, the entire list is 𝓤. + // Exit early. + // (Note that this is not just an optimization; + // if we continue, we may end up with a 𝓤 term + // and other terms and the result would not be + // in normal form.) + if u1.typ == nil { + return allTermlist + } + xi = u1 + used[j] = true // xj is now unioned into xi - ignore it in future iterations + } + } + rl = append(rl, xi) + } + return rl +} + +// union returns the union xl ∪ yl. +func (xl termlist) union(yl termlist) termlist { + return append(xl, yl...).norm() +} + +// intersect returns the intersection xl ∩ yl. +func (xl termlist) intersect(yl termlist) termlist { + if xl.isEmpty() || yl.isEmpty() { + return nil + } + + // Quadratic algorithm, but good enough for now. + // TODO(gri) fix asymptotic performance + var rl termlist + for _, x := range xl { + for _, y := range yl { + if r := x.intersect(y); r != nil { + rl = append(rl, r) + } + } + } + return rl.norm() +} + +// equal reports whether xl and yl represent the same type set. +func (xl termlist) equal(yl termlist) bool { + // TODO(gri) this should be more efficient + return xl.subsetOf(yl) && yl.subsetOf(xl) +} + +// includes reports whether t ∈ xl. +func (xl termlist) includes(t types.Type) bool { + for _, x := range xl { + if x.includes(t) { + return true + } + } + return false +} + +// supersetOf reports whether y ⊆ xl. +func (xl termlist) supersetOf(y *term) bool { + for _, x := range xl { + if y.subsetOf(x) { + return true + } + } + return false +} + +// subsetOf reports whether xl ⊆ yl. +func (xl termlist) subsetOf(yl termlist) bool { + if yl.isEmpty() { + return xl.isEmpty() + } + + // each term x of xl must be a subset of yl + for _, x := range xl { + if !yl.supersetOf(x) { + return false // x is not a subset yl + } + } + return true +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/typeterm.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/typeterm.go new file mode 100644 index 00000000..fa758cdc --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typeparams/typeterm.go @@ -0,0 +1,172 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typeterm.go + +// 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. + +// Code generated by copytermlist.go DO NOT EDIT. + +package typeparams + +import "go/types" + +// A term describes elementary type sets: +// +// ∅: (*term)(nil) == ∅ // set of no types (empty set) +// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t +type term struct { + tilde bool // valid if typ != nil + typ types.Type +} + +func (x *term) String() string { + switch { + case x == nil: + return "∅" + case x.typ == nil: + return "𝓤" + case x.tilde: + return "~" + x.typ.String() + default: + return x.typ.String() + } +} + +// equal reports whether x and y represent the same type set. +func (x *term) equal(y *term) bool { + // easy cases + switch { + case x == nil || y == nil: + return x == y + case x.typ == nil || y.typ == nil: + return x.typ == y.typ + } + // ∅ ⊂ x, y ⊂ 𝓤 + + return x.tilde == y.tilde && types.Identical(x.typ, y.typ) +} + +// union returns the union x ∪ y: zero, one, or two non-nil terms. +func (x *term) union(y *term) (_, _ *term) { + // easy cases + switch { + case x == nil && y == nil: + return nil, nil // ∅ ∪ ∅ == ∅ + case x == nil: + return y, nil // ∅ ∪ y == y + case y == nil: + return x, nil // x ∪ ∅ == x + case x.typ == nil: + return x, nil // 𝓤 ∪ y == 𝓤 + case y.typ == nil: + return y, nil // x ∪ 𝓤 == 𝓤 + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return x, y // x ∪ y == (x, y) if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∪ ~t == ~t + // ~t ∪ T == ~t + // T ∪ ~t == ~t + // T ∪ T == T + if x.tilde || !y.tilde { + return x, nil + } + return y, nil +} + +// intersect returns the intersection x ∩ y. +func (x *term) intersect(y *term) *term { + // easy cases + switch { + case x == nil || y == nil: + return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ + case x.typ == nil: + return y // 𝓤 ∩ y == y + case y.typ == nil: + return x // x ∩ 𝓤 == x + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return nil // x ∩ y == ∅ if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ∩ ~t == ~t + // ~t ∩ T == T + // T ∩ ~t == T + // T ∩ T == T + if !x.tilde || y.tilde { + return x + } + return y +} + +// includes reports whether t ∈ x. +func (x *term) includes(t types.Type) bool { + // easy cases + switch { + case x == nil: + return false // t ∈ ∅ == false + case x.typ == nil: + return true // t ∈ 𝓤 == true + } + // ∅ ⊂ x ⊂ 𝓤 + + u := t + if x.tilde { + u = under(u) + } + return types.Identical(x.typ, u) +} + +// subsetOf reports whether x ⊆ y. +func (x *term) subsetOf(y *term) bool { + // easy cases + switch { + case x == nil: + return true // ∅ ⊆ y == true + case y == nil: + return false // x ⊆ ∅ == false since x != ∅ + case y.typ == nil: + return true // x ⊆ 𝓤 == true + case x.typ == nil: + return false // 𝓤 ⊆ y == false since y != 𝓤 + } + // ∅ ⊂ x, y ⊂ 𝓤 + + if x.disjoint(y) { + return false // x ⊆ y == false if x ∩ y == ∅ + } + // x.typ == y.typ + + // ~t ⊆ ~t == true + // ~t ⊆ T == false + // T ⊆ ~t == true + // T ⊆ T == true + return !x.tilde || y.tilde +} + +// disjoint reports whether x ∩ y == ∅. +// x.typ and y.typ must not be nil. +func (x *term) disjoint(y *term) bool { + if debug && (x.typ == nil || y.typ == nil) { + panic("invalid argument(s)") + } + ux := x.typ + if y.tilde { + ux = under(ux) + } + uy := y.typ + if x.tilde { + uy = under(uy) + } + return !types.Identical(ux, uy) +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/classify_call.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/classify_call.go new file mode 100644 index 00000000..7ebe9768 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/classify_call.go @@ -0,0 +1,137 @@ +// Copyright 2018 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 typesinternal + +import ( + "fmt" + "go/ast" + "go/types" + _ "unsafe" // for go:linkname hack +) + +// CallKind describes the function position of an [*ast.CallExpr]. +type CallKind int + +const ( + CallStatic CallKind = iota // static call to known function + CallInterface // dynamic call through an interface method + CallDynamic // dynamic call of a func value + CallBuiltin // call to a builtin function + CallConversion // a conversion (not a call) +) + +var callKindNames = []string{ + "CallStatic", + "CallInterface", + "CallDynamic", + "CallBuiltin", + "CallConversion", +} + +func (k CallKind) String() string { + if i := int(k); i >= 0 && i < len(callKindNames) { + return callKindNames[i] + } + return fmt.Sprintf("typeutil.CallKind(%d)", k) +} + +// ClassifyCall classifies the function position of a call expression ([*ast.CallExpr]). +// It distinguishes among true function calls, calls to builtins, and type conversions, +// and further classifies function calls as static calls (where the function is known), +// dynamic interface calls, and other dynamic calls. +// +// For the declarations: +// +// func f() {} +// func g[T any]() {} +// var v func() +// var s []func() +// type I interface { M() } +// var i I +// +// ClassifyCall returns the following: +// +// f() CallStatic +// g[int]() CallStatic +// i.M() CallInterface +// min(1, 2) CallBuiltin +// v() CallDynamic +// s[0]() CallDynamic +// int(x) CallConversion +// []byte("") CallConversion +func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind { + if info.Types == nil { + panic("ClassifyCall: info.Types is nil") + } + tv := info.Types[call.Fun] + if tv.IsType() { + return CallConversion + } + if tv.IsBuiltin() { + return CallBuiltin + } + obj := info.Uses[UsedIdent(info, call.Fun)] + // Classify the call by the type of the object, if any. + switch obj := obj.(type) { + case *types.Func: + if interfaceMethod(obj) { + return CallInterface + } + return CallStatic + default: + return CallDynamic + } +} + +// UsedIdent returns the identifier such that info.Uses[UsedIdent(info, e)] +// is the [types.Object] used by e, if any. +// +// If e is one of various forms of reference: +// +// f, c, v, T lexical reference +// pkg.X qualified identifier +// f[T] or pkg.F[K,V] instantiations of the above kinds +// expr.f field or method value selector +// T.f method expression selector +// +// UsedIdent returns the identifier whose is associated value in [types.Info.Uses] +// is the object to which it refers. +// +// For the declarations: +// +// func F[T any] {...} +// type I interface { M() } +// var ( +// x int +// s struct { f int } +// a []int +// i I +// ) +// +// UsedIdent returns the following: +// +// Expr UsedIdent +// x x +// s.f f +// F[int] F +// i.M M +// I.M M +// min min +// int int +// 1 nil +// a[0] nil +// []byte nil +// +// Note: if e is an instantiated function or method, UsedIdent returns +// the corresponding generic function or method on the generic type. +func UsedIdent(info *types.Info, e ast.Expr) *ast.Ident { + return usedIdent(info, e) +} + +//go:linkname usedIdent golang.org/x/tools/go/types/typeutil.usedIdent +func usedIdent(info *types.Info, e ast.Expr) *ast.Ident + +//go:linkname interfaceMethod golang.org/x/tools/go/types/typeutil.interfaceMethod +func interfaceMethod(f *types.Func) bool diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/element.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/element.go new file mode 100644 index 00000000..89eeea16 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/element.go @@ -0,0 +1,137 @@ +// Copyright 2024 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 typesinternal + +import ( + "fmt" + "go/types" + + "golang.org/x/tools/go/types/typeutil" +) + +// ForEachElement calls f for type T and each type reachable from its +// type through reflection. It does this by recursively stripping off +// type constructors; in addition, for each named type N, the type *N +// is added to the result as it may have additional methods. +// +// The caller must provide an initially empty set used to de-duplicate +// identical types, potentially across multiple calls to ForEachElement. +// (Its final value holds all the elements seen, matching the arguments +// passed to f.) +// +// TODO(adonovan): share/harmonize with go/callgraph/rta. +func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T types.Type, f func(types.Type)) { + var visit func(T types.Type, skip bool) + visit = func(T types.Type, skip bool) { + if !skip { + if seen, _ := rtypes.Set(T, true).(bool); seen { + return // de-dup + } + + f(T) // notify caller of new element type + } + + // Recursion over signatures of each method. + tmset := msets.MethodSet(T) + for method := range tmset.Methods() { + sig := method.Type().(*types.Signature) + if sig.TypeParams() != nil { + continue // skip type-parameterized methods + } + + // It is tempting to call visit(sig, false) + // but, as noted in golang.org/cl/65450043, + // the Signature.Recv field is ignored by + // types.Identical and typeutil.Map, which + // is confusing at best. + // + // More importantly, the true signature rtype + // reachable from a method using reflection + // has no receiver but an extra ordinary parameter. + // For the Read method of io.Reader we want: + // func(Reader, []byte) (int, error) + // but here sig is: + // func([]byte) (int, error) + // with .Recv = Reader (though it is hard to + // notice because it doesn't affect Signature.String + // or types.Identical). + // + // TODO(adonovan): construct and visit the correct + // non-method signature with an extra parameter + // (though since unnamed func types have no methods + // there is essentially no actual demand for this). + // + // TODO(adonovan): document whether or not it is + // safe to skip non-exported methods (as RTA does). + visit(sig.Params(), true) // skip the Tuple + visit(sig.Results(), true) // skip the Tuple + } + + switch T := T.(type) { + case *types.Alias: + visit(types.Unalias(T), skip) // emulates the pre-Alias behavior + + case *types.Basic: + // nop + + case *types.Interface: + // nop---handled by recursion over method set. + + case *types.Pointer: + visit(T.Elem(), false) + + case *types.Slice: + visit(T.Elem(), false) + + case *types.Chan: + visit(T.Elem(), false) + + case *types.Map: + visit(T.Key(), false) + visit(T.Elem(), false) + + case *types.Signature: + if T.Recv() != nil { + panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv())) + } + visit(T.Params(), true) // skip the Tuple + visit(T.Results(), true) // skip the Tuple + + case *types.Named: + // A pointer-to-named type can be derived from a named + // type via reflection. It may have methods too. + visit(types.NewPointer(T), false) + + // Consider 'type T struct{S}' where S has methods. + // Reflection provides no way to get from T to struct{S}, + // only to S, so the method set of struct{S} is unwanted, + // so set 'skip' flag during recursion. + visit(T.Underlying(), true) // skip the unnamed type + + case *types.Array: + visit(T.Elem(), false) + + case *types.Struct: + for i, n := 0, T.NumFields(); i < n; i++ { + // TODO(adonovan): document whether or not + // it is safe to skip non-exported fields. + visit(T.Field(i).Type(), false) + } + + case *types.Tuple: + for i, n := 0, T.Len(); i < n; i++ { + visit(T.At(i).Type(), false) + } + + case *types.TypeParam, *types.Union: + // forEachReachable must not be called on parameterized types. + panic(fmt.Sprintf("ForEachElement called on type containing %T", T)) + + default: + panic(fmt.Sprintf("ForEachElement called on unexpected type %T", T)) + } + } + visit(T, false) +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode.go new file mode 100644 index 00000000..bd944741 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode.go @@ -0,0 +1,1558 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +type ErrorCode int + +// This file defines the error codes that can be produced during type-checking. +// Collectively, these codes provide an identifier that may be used to +// implement special handling for certain types of errors. +// +// Error codes should be fine-grained enough that the exact nature of the error +// can be easily determined, but coarse enough that they are not an +// implementation detail of the type checking algorithm. As a rule-of-thumb, +// errors should be considered equivalent if there is a theoretical refactoring +// of the type checker in which they are emitted in exactly one place. For +// example, the type checker emits different error messages for "too many +// arguments" and "too few arguments", but one can imagine an alternative type +// checker where this check instead just emits a single "wrong number of +// arguments", so these errors should have the same code. +// +// Error code names should be as brief as possible while retaining accuracy and +// distinctiveness. In most cases names should start with an adjective +// describing the nature of the error (e.g. "invalid", "unused", "misplaced"), +// and end with a noun identifying the relevant language object. For example, +// "DuplicateDecl" or "InvalidSliceExpr". For brevity, naming follows the +// convention that "bad" implies a problem with syntax, and "invalid" implies a +// problem with types. + +const ( + // InvalidSyntaxTree occurs if an invalid syntax tree is provided + // to the type checker. It should never happen. + InvalidSyntaxTree ErrorCode = -1 +) + +const ( + _ ErrorCode = iota + + // Test is reserved for errors that only apply while in self-test mode. + Test + + /* package names */ + + // BlankPkgName occurs when a package name is the blank identifier "_". + // + // Per the spec: + // "The PackageName must not be the blank identifier." + BlankPkgName + + // MismatchedPkgName occurs when a file's package name doesn't match the + // package name already established by other files. + MismatchedPkgName + + // InvalidPkgUse occurs when a package identifier is used outside of a + // selector expression. + // + // Example: + // import "fmt" + // + // var _ = fmt + InvalidPkgUse + + /* imports */ + + // BadImportPath occurs when an import path is not valid. + BadImportPath + + // BrokenImport occurs when importing a package fails. + // + // Example: + // import "amissingpackage" + BrokenImport + + // ImportCRenamed occurs when the special import "C" is renamed. "C" is a + // pseudo-package, and must not be renamed. + // + // Example: + // import _ "C" + ImportCRenamed + + // UnusedImport occurs when an import is unused. + // + // Example: + // import "fmt" + // + // func main() {} + UnusedImport + + /* initialization */ + + // InvalidInitCycle occurs when an invalid cycle is detected within the + // initialization graph. + // + // Example: + // var x int = f() + // + // func f() int { return x } + InvalidInitCycle + + /* decls */ + + // DuplicateDecl occurs when an identifier is declared multiple times. + // + // Example: + // var x = 1 + // var x = 2 + DuplicateDecl + + // InvalidDeclCycle occurs when a declaration cycle is not valid. + // + // Example: + // import "unsafe" + // + // type T struct { + // a [n]int + // } + // + // var n = unsafe.Sizeof(T{}) + InvalidDeclCycle + + // InvalidTypeCycle occurs when a cycle in type definitions results in a + // type that is not well-defined. + // + // Example: + // import "unsafe" + // + // type T [unsafe.Sizeof(T{})]int + InvalidTypeCycle + + /* decls > const */ + + // InvalidConstInit occurs when a const declaration has a non-constant + // initializer. + // + // Example: + // var x int + // const _ = x + InvalidConstInit + + // InvalidConstVal occurs when a const value cannot be converted to its + // target type. + // + // TODO(findleyr): this error code and example are not very clear. Consider + // removing it. + // + // Example: + // const _ = 1 << "hello" + InvalidConstVal + + // InvalidConstType occurs when the underlying type in a const declaration + // is not a valid constant type. + // + // Example: + // const c *int = 4 + InvalidConstType + + /* decls > var (+ other variable assignment codes) */ + + // UntypedNilUse occurs when the predeclared (untyped) value nil is used to + // initialize a variable declared without an explicit type. + // + // Example: + // var x = nil + UntypedNilUse + + // WrongAssignCount occurs when the number of values on the right-hand side + // of an assignment or initialization expression does not match the number + // of variables on the left-hand side. + // + // Example: + // var x = 1, 2 + WrongAssignCount + + // UnassignableOperand occurs when the left-hand side of an assignment is + // not assignable. + // + // Example: + // func f() { + // const c = 1 + // c = 2 + // } + UnassignableOperand + + // NoNewVar occurs when a short variable declaration (':=') does not declare + // new variables. + // + // Example: + // func f() { + // x := 1 + // x := 2 + // } + NoNewVar + + // MultiValAssignOp occurs when an assignment operation (+=, *=, etc) does + // not have single-valued left-hand or right-hand side. + // + // Per the spec: + // "In assignment operations, both the left- and right-hand expression lists + // must contain exactly one single-valued expression" + // + // Example: + // func f() int { + // x, y := 1, 2 + // x, y += 1 + // return x + y + // } + MultiValAssignOp + + // InvalidIfaceAssign occurs when a value of type T is used as an + // interface, but T does not implement a method of the expected interface. + // + // Example: + // type I interface { + // f() + // } + // + // type T int + // + // var x I = T(1) + InvalidIfaceAssign + + // InvalidChanAssign occurs when a chan assignment is invalid. + // + // Per the spec, a value x is assignable to a channel type T if: + // "x is a bidirectional channel value, T is a channel type, x's type V and + // T have identical element types, and at least one of V or T is not a + // defined type." + // + // Example: + // type T1 chan int + // type T2 chan int + // + // var x T1 + // // Invalid assignment because both types are named + // var _ T2 = x + InvalidChanAssign + + // IncompatibleAssign occurs when the type of the right-hand side expression + // in an assignment cannot be assigned to the type of the variable being + // assigned. + // + // Example: + // var x []int + // var _ int = x + IncompatibleAssign + + // UnaddressableFieldAssign occurs when trying to assign to a struct field + // in a map value. + // + // Example: + // func f() { + // m := make(map[string]struct{i int}) + // m["foo"].i = 42 + // } + UnaddressableFieldAssign + + /* decls > type (+ other type expression codes) */ + + // NotAType occurs when the identifier used as the underlying type in a type + // declaration or the right-hand side of a type alias does not denote a type. + // + // Example: + // var S = 2 + // + // type T S + NotAType + + // InvalidArrayLen occurs when an array length is not a constant value. + // + // Example: + // var n = 3 + // var _ = [n]int{} + InvalidArrayLen + + // BlankIfaceMethod occurs when a method name is '_'. + // + // Per the spec: + // "The name of each explicitly specified method must be unique and not + // blank." + // + // Example: + // type T interface { + // _(int) + // } + BlankIfaceMethod + + // IncomparableMapKey occurs when a map key type does not support the == and + // != operators. + // + // Per the spec: + // "The comparison operators == and != must be fully defined for operands of + // the key type; thus the key type must not be a function, map, or slice." + // + // Example: + // var x map[T]int + // + // type T []int + IncomparableMapKey + + // InvalidIfaceEmbed occurs when a non-interface type is embedded in an + // interface. + // + // Example: + // type T struct {} + // + // func (T) m() + // + // type I interface { + // T + // } + InvalidIfaceEmbed + + // InvalidPtrEmbed occurs when an embedded field is of the pointer form *T, + // and T itself is itself a pointer, an unsafe.Pointer, or an interface. + // + // Per the spec: + // "An embedded field must be specified as a type name T or as a pointer to + // a non-interface type name *T, and T itself may not be a pointer type." + // + // Example: + // type T *int + // + // type S struct { + // *T + // } + InvalidPtrEmbed + + /* decls > func and method */ + + // BadRecv occurs when a method declaration does not have exactly one + // receiver parameter. + // + // Example: + // func () _() {} + BadRecv + + // InvalidRecv occurs when a receiver type expression is not of the form T + // or *T, or T is a pointer type. + // + // Example: + // type T struct {} + // + // func (**T) m() {} + InvalidRecv + + // DuplicateFieldAndMethod occurs when an identifier appears as both a field + // and method name. + // + // Example: + // type T struct { + // m int + // } + // + // func (T) m() {} + DuplicateFieldAndMethod + + // DuplicateMethod occurs when two methods on the same receiver type have + // the same name. + // + // Example: + // type T struct {} + // func (T) m() {} + // func (T) m(i int) int { return i } + DuplicateMethod + + /* decls > special */ + + // InvalidBlank occurs when a blank identifier is used as a value or type. + // + // Per the spec: + // "The blank identifier may appear as an operand only on the left-hand side + // of an assignment." + // + // Example: + // var x = _ + InvalidBlank + + // InvalidIota occurs when the predeclared identifier iota is used outside + // of a constant declaration. + // + // Example: + // var x = iota + InvalidIota + + // MissingInitBody occurs when an init function is missing its body. + // + // Example: + // func init() + MissingInitBody + + // InvalidInitSig occurs when an init function declares parameters or + // results. + // + // Example: + // func init() int { return 1 } + InvalidInitSig + + // InvalidInitDecl occurs when init is declared as anything other than a + // function. + // + // Example: + // var init = 1 + InvalidInitDecl + + // InvalidMainDecl occurs when main is declared as anything other than a + // function, in a main package. + InvalidMainDecl + + /* exprs */ + + // TooManyValues occurs when a function returns too many values for the + // expression context in which it is used. + // + // Example: + // func ReturnTwo() (int, int) { + // return 1, 2 + // } + // + // var x = ReturnTwo() + TooManyValues + + // NotAnExpr occurs when a type expression is used where a value expression + // is expected. + // + // Example: + // type T struct {} + // + // func f() { + // T + // } + NotAnExpr + + /* exprs > const */ + + // TruncatedFloat occurs when a float constant is truncated to an integer + // value. + // + // Example: + // var _ int = 98.6 + TruncatedFloat + + // NumericOverflow occurs when a numeric constant overflows its target type. + // + // Example: + // var x int8 = 1000 + NumericOverflow + + /* exprs > operation */ + + // UndefinedOp occurs when an operator is not defined for the type(s) used + // in an operation. + // + // Example: + // var c = "a" - "b" + UndefinedOp + + // MismatchedTypes occurs when operand types are incompatible in a binary + // operation. + // + // Example: + // var a = "hello" + // var b = 1 + // var c = a - b + MismatchedTypes + + // DivByZero occurs when a division operation is provable at compile + // time to be a division by zero. + // + // Example: + // const divisor = 0 + // var x int = 1/divisor + DivByZero + + // NonNumericIncDec occurs when an increment or decrement operator is + // applied to a non-numeric value. + // + // Example: + // func f() { + // var c = "c" + // c++ + // } + NonNumericIncDec + + /* exprs > ptr */ + + // UnaddressableOperand occurs when the & operator is applied to an + // unaddressable expression. + // + // Example: + // var x = &1 + UnaddressableOperand + + // InvalidIndirection occurs when a non-pointer value is indirected via the + // '*' operator. + // + // Example: + // var x int + // var y = *x + InvalidIndirection + + /* exprs > [] */ + + // NonIndexableOperand occurs when an index operation is applied to a value + // that cannot be indexed. + // + // Example: + // var x = 1 + // var y = x[1] + NonIndexableOperand + + // InvalidIndex occurs when an index argument is not of integer type, + // negative, or out-of-bounds. + // + // Example: + // var s = [...]int{1,2,3} + // var x = s[5] + // + // Example: + // var s = []int{1,2,3} + // var _ = s[-1] + // + // Example: + // var s = []int{1,2,3} + // var i string + // var _ = s[i] + InvalidIndex + + // SwappedSliceIndices occurs when constant indices in a slice expression + // are decreasing in value. + // + // Example: + // var _ = []int{1,2,3}[2:1] + SwappedSliceIndices + + /* operators > slice */ + + // NonSliceableOperand occurs when a slice operation is applied to a value + // whose type is not sliceable, or is unaddressable. + // + // Example: + // var x = [...]int{1, 2, 3}[:1] + // + // Example: + // var x = 1 + // var y = 1[:1] + NonSliceableOperand + + // InvalidSliceExpr occurs when a three-index slice expression (a[x:y:z]) is + // applied to a string. + // + // Example: + // var s = "hello" + // var x = s[1:2:3] + InvalidSliceExpr + + /* exprs > shift */ + + // InvalidShiftCount occurs when the right-hand side of a shift operation is + // either non-integer, negative, or too large. + // + // Example: + // var ( + // x string + // y int = 1 << x + // ) + InvalidShiftCount + + // InvalidShiftOperand occurs when the shifted operand is not an integer. + // + // Example: + // var s = "hello" + // var x = s << 2 + InvalidShiftOperand + + /* exprs > chan */ + + // InvalidReceive occurs when there is a channel receive from a value that + // is either not a channel, or is a send-only channel. + // + // Example: + // func f() { + // var x = 1 + // <-x + // } + InvalidReceive + + // InvalidSend occurs when there is a channel send to a value that is not a + // channel, or is a receive-only channel. + // + // Example: + // func f() { + // var x = 1 + // x <- "hello!" + // } + InvalidSend + + /* exprs > literal */ + + // DuplicateLitKey occurs when an index is duplicated in a slice, array, or + // map literal. + // + // Example: + // var _ = []int{0:1, 0:2} + // + // Example: + // var _ = map[string]int{"a": 1, "a": 2} + DuplicateLitKey + + // MissingLitKey occurs when a map literal is missing a key expression. + // + // Example: + // var _ = map[string]int{1} + MissingLitKey + + // InvalidLitIndex occurs when the key in a key-value element of a slice or + // array literal is not an integer constant. + // + // Example: + // var i = 0 + // var x = []string{i: "world"} + InvalidLitIndex + + // OversizeArrayLit occurs when an array literal exceeds its length. + // + // Example: + // var _ = [2]int{1,2,3} + OversizeArrayLit + + // MixedStructLit occurs when a struct literal contains a mix of positional + // and named elements. + // + // Example: + // var _ = struct{i, j int}{i: 1, 2} + MixedStructLit + + // InvalidStructLit occurs when a positional struct literal has an incorrect + // number of values. + // + // Example: + // var _ = struct{i, j int}{1,2,3} + InvalidStructLit + + // MissingLitField occurs when a struct literal refers to a field that does + // not exist on the struct type. + // + // Example: + // var _ = struct{i int}{j: 2} + MissingLitField + + // DuplicateLitField occurs when a struct literal contains duplicated + // fields. + // + // Example: + // var _ = struct{i int}{i: 1, i: 2} + DuplicateLitField + + // UnexportedLitField occurs when a positional struct literal implicitly + // assigns an unexported field of an imported type. + UnexportedLitField + + // InvalidLitField occurs when a field name is not a valid identifier. + // + // Example: + // var _ = struct{i int}{1: 1} + InvalidLitField + + // UntypedLit occurs when a composite literal omits a required type + // identifier. + // + // Example: + // type outer struct{ + // inner struct { i int } + // } + // + // var _ = outer{inner: {1}} + UntypedLit + + // InvalidLit occurs when a composite literal expression does not match its + // type. + // + // Example: + // type P *struct{ + // x int + // } + // var _ = P {} + InvalidLit + + /* exprs > selector */ + + // AmbiguousSelector occurs when a selector is ambiguous. + // + // Example: + // type E1 struct { i int } + // type E2 struct { i int } + // type T struct { E1; E2 } + // + // var x T + // var _ = x.i + AmbiguousSelector + + // UndeclaredImportedName occurs when a package-qualified identifier is + // undeclared by the imported package. + // + // Example: + // import "go/types" + // + // var _ = types.NotAnActualIdentifier + UndeclaredImportedName + + // UnexportedName occurs when a selector refers to an unexported identifier + // of an imported package. + // + // Example: + // import "reflect" + // + // type _ reflect.flag + UnexportedName + + // UndeclaredName occurs when an identifier is not declared in the current + // scope. + // + // Example: + // var x T + UndeclaredName + + // MissingFieldOrMethod occurs when a selector references a field or method + // that does not exist. + // + // Example: + // type T struct {} + // + // var x = T{}.f + MissingFieldOrMethod + + /* exprs > ... */ + + // BadDotDotDotSyntax occurs when a "..." occurs in a context where it is + // not valid. + // + // Example: + // var _ = map[int][...]int{0: {}} + BadDotDotDotSyntax + + // NonVariadicDotDotDot occurs when a "..." is used on the final argument to + // a non-variadic function. + // + // Example: + // func printArgs(s []string) { + // for _, a := range s { + // println(a) + // } + // } + // + // func f() { + // s := []string{"a", "b", "c"} + // printArgs(s...) + // } + NonVariadicDotDotDot + + // MisplacedDotDotDot occurs when a "..." is used somewhere other than the + // final argument to a function call. + // + // Example: + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func f() { + // a := []int{1,2,3} + // printArgs(0, a...) + // } + MisplacedDotDotDot + + // InvalidDotDotDotOperand occurs when a "..." operator is applied to a + // single-valued operand. + // + // Example: + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func f() { + // a := 1 + // printArgs(a...) + // } + // + // Example: + // func args() (int, int) { + // return 1, 2 + // } + // + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func g() { + // printArgs(args()...) + // } + InvalidDotDotDotOperand + + // InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in + // function. + // + // Example: + // var s = []int{1, 2, 3} + // var l = len(s...) + InvalidDotDotDot + + /* exprs > built-in */ + + // UncalledBuiltin occurs when a built-in function is used as a + // function-valued expression, instead of being called. + // + // Per the spec: + // "The built-in functions do not have standard Go types, so they can only + // appear in call expressions; they cannot be used as function values." + // + // Example: + // var _ = copy + UncalledBuiltin + + // InvalidAppend occurs when append is called with a first argument that is + // not a slice. + // + // Example: + // var _ = append(1, 2) + InvalidAppend + + // InvalidCap occurs when an argument to the cap built-in function is not of + // supported type. + // + // See https://golang.org/ref/spec#Length_and_capacity for information on + // which underlying types are supported as arguments to cap and len. + // + // Example: + // var s = 2 + // var x = cap(s) + InvalidCap + + // InvalidClose occurs when close(...) is called with an argument that is + // not of channel type, or that is a receive-only channel. + // + // Example: + // func f() { + // var x int + // close(x) + // } + InvalidClose + + // InvalidCopy occurs when the arguments are not of slice type or do not + // have compatible type. + // + // See https://golang.org/ref/spec#Appending_and_copying_slices for more + // information on the type requirements for the copy built-in. + // + // Example: + // func f() { + // var x []int + // y := []int64{1,2,3} + // copy(x, y) + // } + InvalidCopy + + // InvalidComplex occurs when the complex built-in function is called with + // arguments with incompatible types. + // + // Example: + // var _ = complex(float32(1), float64(2)) + InvalidComplex + + // InvalidDelete occurs when the delete built-in function is called with a + // first argument that is not a map. + // + // Example: + // func f() { + // m := "hello" + // delete(m, "e") + // } + InvalidDelete + + // InvalidImag occurs when the imag built-in function is called with an + // argument that does not have complex type. + // + // Example: + // var _ = imag(int(1)) + InvalidImag + + // InvalidLen occurs when an argument to the len built-in function is not of + // supported type. + // + // See https://golang.org/ref/spec#Length_and_capacity for information on + // which underlying types are supported as arguments to cap and len. + // + // Example: + // var s = 2 + // var x = len(s) + InvalidLen + + // SwappedMakeArgs occurs when make is called with three arguments, and its + // length argument is larger than its capacity argument. + // + // Example: + // var x = make([]int, 3, 2) + SwappedMakeArgs + + // InvalidMake occurs when make is called with an unsupported type argument. + // + // See https://golang.org/ref/spec#Making_slices_maps_and_channels for + // information on the types that may be created using make. + // + // Example: + // var x = make(int) + InvalidMake + + // InvalidReal occurs when the real built-in function is called with an + // argument that does not have complex type. + // + // Example: + // var _ = real(int(1)) + InvalidReal + + /* exprs > assertion */ + + // InvalidAssert occurs when a type assertion is applied to a + // value that is not of interface type. + // + // Example: + // var x = 1 + // var _ = x.(float64) + InvalidAssert + + // ImpossibleAssert occurs for a type assertion x.(T) when the value x of + // interface cannot have dynamic type T, due to a missing or mismatching + // method on T. + // + // Example: + // type T int + // + // func (t *T) m() int { return int(*t) } + // + // type I interface { m() int } + // + // var x I + // var _ = x.(T) + ImpossibleAssert + + /* exprs > conversion */ + + // InvalidConversion occurs when the argument type cannot be converted to the + // target. + // + // See https://golang.org/ref/spec#Conversions for the rules of + // convertibility. + // + // Example: + // var x float64 + // var _ = string(x) + InvalidConversion + + // InvalidUntypedConversion occurs when there is no valid implicit + // conversion from an untyped value satisfying the type constraints of the + // context in which it is used. + // + // Example: + // var _ = 1 + "" + InvalidUntypedConversion + + /* offsetof */ + + // BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument + // that is not a selector expression. + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Offsetof(x) + BadOffsetofSyntax + + // InvalidOffsetof occurs when unsafe.Offsetof is called with a method + // selector, rather than a field selector, or when the field is embedded via + // a pointer. + // + // Per the spec: + // + // "If f is an embedded field, it must be reachable without pointer + // indirections through fields of the struct. " + // + // Example: + // import "unsafe" + // + // type T struct { f int } + // type S struct { *T } + // var s S + // var _ = unsafe.Offsetof(s.f) + // + // Example: + // import "unsafe" + // + // type S struct{} + // + // func (S) m() {} + // + // var s S + // var _ = unsafe.Offsetof(s.m) + InvalidOffsetof + + /* control flow > scope */ + + // UnusedExpr occurs when a side-effect free expression is used as a + // statement. Such a statement has no effect. + // + // Example: + // func f(i int) { + // i*i + // } + UnusedExpr + + // UnusedVar occurs when a variable is declared but unused. + // + // Example: + // func f() { + // x := 1 + // } + UnusedVar + + // MissingReturn occurs when a function with results is missing a return + // statement. + // + // Example: + // func f() int {} + MissingReturn + + // WrongResultCount occurs when a return statement returns an incorrect + // number of values. + // + // Example: + // func ReturnOne() int { + // return 1, 2 + // } + WrongResultCount + + // OutOfScopeResult occurs when the name of a value implicitly returned by + // an empty return statement is shadowed in a nested scope. + // + // Example: + // func factor(n int) (i int) { + // for i := 2; i < n; i++ { + // if n%i == 0 { + // return + // } + // } + // return 0 + // } + OutOfScopeResult + + /* control flow > if */ + + // InvalidCond occurs when an if condition is not a boolean expression. + // + // Example: + // func checkReturn(i int) { + // if i { + // panic("non-zero return") + // } + // } + InvalidCond + + /* control flow > for */ + + // InvalidPostDecl occurs when there is a declaration in a for-loop post + // statement. + // + // Example: + // func f() { + // for i := 0; i < 10; j := 0 {} + // } + InvalidPostDecl + + // InvalidChanRange occurs when a send-only channel used in a range + // expression. + // + // Example: + // func sum(c chan<- int) { + // s := 0 + // for i := range c { + // s += i + // } + // } + InvalidChanRange + + // InvalidIterVar occurs when two iteration variables are used while ranging + // over a channel. + // + // Example: + // func f(c chan int) { + // for k, v := range c { + // println(k, v) + // } + // } + InvalidIterVar + + // InvalidRangeExpr occurs when the type of a range expression is not array, + // slice, string, map, or channel. + // + // Example: + // func f(i int) { + // for j := range i { + // println(j) + // } + // } + InvalidRangeExpr + + /* control flow > switch */ + + // MisplacedBreak occurs when a break statement is not within a for, switch, + // or select statement of the innermost function definition. + // + // Example: + // func f() { + // break + // } + MisplacedBreak + + // MisplacedContinue occurs when a continue statement is not within a for + // loop of the innermost function definition. + // + // Example: + // func sumeven(n int) int { + // proceed := func() { + // continue + // } + // sum := 0 + // for i := 1; i <= n; i++ { + // if i % 2 != 0 { + // proceed() + // } + // sum += i + // } + // return sum + // } + MisplacedContinue + + // MisplacedFallthrough occurs when a fallthrough statement is not within an + // expression switch. + // + // Example: + // func typename(i interface{}) string { + // switch i.(type) { + // case int64: + // fallthrough + // case int: + // return "int" + // } + // return "unsupported" + // } + MisplacedFallthrough + + // DuplicateCase occurs when a type or expression switch has duplicate + // cases. + // + // Example: + // func printInt(i int) { + // switch i { + // case 1: + // println("one") + // case 1: + // println("One") + // } + // } + DuplicateCase + + // DuplicateDefault occurs when a type or expression switch has multiple + // default clauses. + // + // Example: + // func printInt(i int) { + // switch i { + // case 1: + // println("one") + // default: + // println("One") + // default: + // println("1") + // } + // } + DuplicateDefault + + // BadTypeKeyword occurs when a .(type) expression is used anywhere other + // than a type switch. + // + // Example: + // type I interface { + // m() + // } + // var t I + // var _ = t.(type) + BadTypeKeyword + + // InvalidTypeSwitch occurs when .(type) is used on an expression that is + // not of interface type. + // + // Example: + // func f(i int) { + // switch x := i.(type) {} + // } + InvalidTypeSwitch + + // InvalidExprSwitch occurs when a switch expression is not comparable. + // + // Example: + // func _() { + // var a struct{ _ func() } + // switch a /* ERROR cannot switch on a */ { + // } + // } + InvalidExprSwitch + + /* control flow > select */ + + // InvalidSelectCase occurs when a select case is not a channel send or + // receive. + // + // Example: + // func checkChan(c <-chan int) bool { + // select { + // case c: + // return true + // default: + // return false + // } + // } + InvalidSelectCase + + /* control flow > labels and jumps */ + + // UndeclaredLabel occurs when an undeclared label is jumped to. + // + // Example: + // func f() { + // goto L + // } + UndeclaredLabel + + // DuplicateLabel occurs when a label is declared more than once. + // + // Example: + // func f() int { + // L: + // L: + // return 1 + // } + DuplicateLabel + + // MisplacedLabel occurs when a break or continue label is not on a for, + // switch, or select statement. + // + // Example: + // func f() { + // L: + // a := []int{1,2,3} + // for _, e := range a { + // if e > 10 { + // break L + // } + // println(a) + // } + // } + MisplacedLabel + + // UnusedLabel occurs when a label is declared but not used. + // + // Example: + // func f() { + // L: + // } + UnusedLabel + + // JumpOverDecl occurs when a label jumps over a variable declaration. + // + // Example: + // func f() int { + // goto L + // x := 2 + // L: + // x++ + // return x + // } + JumpOverDecl + + // JumpIntoBlock occurs when a forward jump goes to a label inside a nested + // block. + // + // Example: + // func f(x int) { + // goto L + // if x > 0 { + // L: + // print("inside block") + // } + // } + JumpIntoBlock + + /* control flow > calls */ + + // InvalidMethodExpr occurs when a pointer method is called but the argument + // is not addressable. + // + // Example: + // type T struct {} + // + // func (*T) m() int { return 1 } + // + // var _ = T.m(T{}) + InvalidMethodExpr + + // WrongArgCount occurs when too few or too many arguments are passed by a + // function call. + // + // Example: + // func f(i int) {} + // var x = f() + WrongArgCount + + // InvalidCall occurs when an expression is called that is not of function + // type. + // + // Example: + // var x = "x" + // var y = x() + InvalidCall + + /* control flow > suspended */ + + // UnusedResults occurs when a restricted expression-only built-in function + // is suspended via go or defer. Such a suspension discards the results of + // these side-effect free built-in functions, and therefore is ineffectual. + // + // Example: + // func f(a []int) int { + // defer len(a) + // return i + // } + UnusedResults + + // InvalidDefer occurs when a deferred expression is not a function call, + // for example if the expression is a type conversion. + // + // Example: + // func f(i int) int { + // defer int32(i) + // return i + // } + InvalidDefer + + // InvalidGo occurs when a go expression is not a function call, for example + // if the expression is a type conversion. + // + // Example: + // func f(i int) int { + // go int32(i) + // return i + // } + InvalidGo + + // All codes below were added in Go 1.17. + + /* decl */ + + // BadDecl occurs when a declaration has invalid syntax. + BadDecl + + // RepeatedDecl occurs when an identifier occurs more than once on the left + // hand side of a short variable declaration. + // + // Example: + // func _() { + // x, y, y := 1, 2, 3 + // } + RepeatedDecl + + /* unsafe */ + + // InvalidUnsafeAdd occurs when unsafe.Add is called with a + // length argument that is not of integer type. + // + // Example: + // import "unsafe" + // + // var p unsafe.Pointer + // var _ = unsafe.Add(p, float64(1)) + InvalidUnsafeAdd + + // InvalidUnsafeSlice occurs when unsafe.Slice is called with a + // pointer argument that is not of pointer type or a length argument + // that is not of integer type, negative, or out of bounds. + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Slice(x, 1) + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Slice(&x, float64(1)) + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Slice(&x, -1) + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Slice(&x, uint64(1) << 63) + InvalidUnsafeSlice + + // All codes below were added in Go 1.18. + + /* features */ + + // UnsupportedFeature occurs when a language feature is used that is not + // supported at this Go version. + UnsupportedFeature + + /* type params */ + + // NotAGenericType occurs when a non-generic type is used where a generic + // type is expected: in type or function instantiation. + // + // Example: + // type T int + // + // var _ T[int] + NotAGenericType + + // WrongTypeArgCount occurs when a type or function is instantiated with an + // incorrect number of type arguments, including when a generic type or + // function is used without instantiation. + // + // Errors involving failed type inference are assigned other error codes. + // + // Example: + // type T[p any] int + // + // var _ T[int, string] + // + // Example: + // func f[T any]() {} + // + // var x = f + WrongTypeArgCount + + // CannotInferTypeArgs occurs when type or function type argument inference + // fails to infer all type arguments. + // + // Example: + // func f[T any]() {} + // + // func _() { + // f() + // } + // + // Example: + // type N[P, Q any] struct{} + // + // var _ N[int] + CannotInferTypeArgs + + // InvalidTypeArg occurs when a type argument does not satisfy its + // corresponding type parameter constraints. + // + // Example: + // type T[P ~int] struct{} + // + // var _ T[string] + InvalidTypeArg // arguments? InferenceFailed + + // InvalidInstanceCycle occurs when an invalid cycle is detected + // within the instantiation graph. + // + // Example: + // func f[T any]() { f[*T]() } + InvalidInstanceCycle + + // InvalidUnion occurs when an embedded union or approximation element is + // not valid. + // + // Example: + // type _ interface { + // ~int | interface{ m() } + // } + InvalidUnion + + // MisplacedConstraintIface occurs when a constraint-type interface is used + // outside of constraint position. + // + // Example: + // type I interface { ~int } + // + // var _ I + MisplacedConstraintIface + + // InvalidMethodTypeParams occurs when methods have type parameters. + // + // It cannot be encountered with an AST parsed using go/parser. + InvalidMethodTypeParams + + // MisplacedTypeParam occurs when a type parameter is used in a place where + // it is not permitted. + // + // Example: + // type T[P any] P + // + // Example: + // type T[P any] struct{ *P } + MisplacedTypeParam + + // InvalidUnsafeSliceData occurs when unsafe.SliceData is called with + // an argument that is not of slice type. It also occurs if it is used + // in a package compiled for a language version before go1.20. + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.SliceData(x) + InvalidUnsafeSliceData + + // InvalidUnsafeString occurs when unsafe.String is called with + // a length argument that is not of integer type, negative, or + // out of bounds. It also occurs if it is used in a package + // compiled for a language version before go1.20. + // + // Example: + // import "unsafe" + // + // var b [10]byte + // var _ = unsafe.String(&b[0], -1) + InvalidUnsafeString + + // InvalidUnsafeStringData occurs if it is used in a package + // compiled for a language version before go1.20. + _ // not used anymore + +) diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode_string.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode_string.go new file mode 100644 index 00000000..15ecf7c5 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/errorcode_string.go @@ -0,0 +1,179 @@ +// Code generated by "stringer -type=ErrorCode"; DO NOT EDIT. + +package typesinternal + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[InvalidSyntaxTree - -1] + _ = x[Test-1] + _ = x[BlankPkgName-2] + _ = x[MismatchedPkgName-3] + _ = x[InvalidPkgUse-4] + _ = x[BadImportPath-5] + _ = x[BrokenImport-6] + _ = x[ImportCRenamed-7] + _ = x[UnusedImport-8] + _ = x[InvalidInitCycle-9] + _ = x[DuplicateDecl-10] + _ = x[InvalidDeclCycle-11] + _ = x[InvalidTypeCycle-12] + _ = x[InvalidConstInit-13] + _ = x[InvalidConstVal-14] + _ = x[InvalidConstType-15] + _ = x[UntypedNilUse-16] + _ = x[WrongAssignCount-17] + _ = x[UnassignableOperand-18] + _ = x[NoNewVar-19] + _ = x[MultiValAssignOp-20] + _ = x[InvalidIfaceAssign-21] + _ = x[InvalidChanAssign-22] + _ = x[IncompatibleAssign-23] + _ = x[UnaddressableFieldAssign-24] + _ = x[NotAType-25] + _ = x[InvalidArrayLen-26] + _ = x[BlankIfaceMethod-27] + _ = x[IncomparableMapKey-28] + _ = x[InvalidIfaceEmbed-29] + _ = x[InvalidPtrEmbed-30] + _ = x[BadRecv-31] + _ = x[InvalidRecv-32] + _ = x[DuplicateFieldAndMethod-33] + _ = x[DuplicateMethod-34] + _ = x[InvalidBlank-35] + _ = x[InvalidIota-36] + _ = x[MissingInitBody-37] + _ = x[InvalidInitSig-38] + _ = x[InvalidInitDecl-39] + _ = x[InvalidMainDecl-40] + _ = x[TooManyValues-41] + _ = x[NotAnExpr-42] + _ = x[TruncatedFloat-43] + _ = x[NumericOverflow-44] + _ = x[UndefinedOp-45] + _ = x[MismatchedTypes-46] + _ = x[DivByZero-47] + _ = x[NonNumericIncDec-48] + _ = x[UnaddressableOperand-49] + _ = x[InvalidIndirection-50] + _ = x[NonIndexableOperand-51] + _ = x[InvalidIndex-52] + _ = x[SwappedSliceIndices-53] + _ = x[NonSliceableOperand-54] + _ = x[InvalidSliceExpr-55] + _ = x[InvalidShiftCount-56] + _ = x[InvalidShiftOperand-57] + _ = x[InvalidReceive-58] + _ = x[InvalidSend-59] + _ = x[DuplicateLitKey-60] + _ = x[MissingLitKey-61] + _ = x[InvalidLitIndex-62] + _ = x[OversizeArrayLit-63] + _ = x[MixedStructLit-64] + _ = x[InvalidStructLit-65] + _ = x[MissingLitField-66] + _ = x[DuplicateLitField-67] + _ = x[UnexportedLitField-68] + _ = x[InvalidLitField-69] + _ = x[UntypedLit-70] + _ = x[InvalidLit-71] + _ = x[AmbiguousSelector-72] + _ = x[UndeclaredImportedName-73] + _ = x[UnexportedName-74] + _ = x[UndeclaredName-75] + _ = x[MissingFieldOrMethod-76] + _ = x[BadDotDotDotSyntax-77] + _ = x[NonVariadicDotDotDot-78] + _ = x[MisplacedDotDotDot-79] + _ = x[InvalidDotDotDotOperand-80] + _ = x[InvalidDotDotDot-81] + _ = x[UncalledBuiltin-82] + _ = x[InvalidAppend-83] + _ = x[InvalidCap-84] + _ = x[InvalidClose-85] + _ = x[InvalidCopy-86] + _ = x[InvalidComplex-87] + _ = x[InvalidDelete-88] + _ = x[InvalidImag-89] + _ = x[InvalidLen-90] + _ = x[SwappedMakeArgs-91] + _ = x[InvalidMake-92] + _ = x[InvalidReal-93] + _ = x[InvalidAssert-94] + _ = x[ImpossibleAssert-95] + _ = x[InvalidConversion-96] + _ = x[InvalidUntypedConversion-97] + _ = x[BadOffsetofSyntax-98] + _ = x[InvalidOffsetof-99] + _ = x[UnusedExpr-100] + _ = x[UnusedVar-101] + _ = x[MissingReturn-102] + _ = x[WrongResultCount-103] + _ = x[OutOfScopeResult-104] + _ = x[InvalidCond-105] + _ = x[InvalidPostDecl-106] + _ = x[InvalidChanRange-107] + _ = x[InvalidIterVar-108] + _ = x[InvalidRangeExpr-109] + _ = x[MisplacedBreak-110] + _ = x[MisplacedContinue-111] + _ = x[MisplacedFallthrough-112] + _ = x[DuplicateCase-113] + _ = x[DuplicateDefault-114] + _ = x[BadTypeKeyword-115] + _ = x[InvalidTypeSwitch-116] + _ = x[InvalidExprSwitch-117] + _ = x[InvalidSelectCase-118] + _ = x[UndeclaredLabel-119] + _ = x[DuplicateLabel-120] + _ = x[MisplacedLabel-121] + _ = x[UnusedLabel-122] + _ = x[JumpOverDecl-123] + _ = x[JumpIntoBlock-124] + _ = x[InvalidMethodExpr-125] + _ = x[WrongArgCount-126] + _ = x[InvalidCall-127] + _ = x[UnusedResults-128] + _ = x[InvalidDefer-129] + _ = x[InvalidGo-130] + _ = x[BadDecl-131] + _ = x[RepeatedDecl-132] + _ = x[InvalidUnsafeAdd-133] + _ = x[InvalidUnsafeSlice-134] + _ = x[UnsupportedFeature-135] + _ = x[NotAGenericType-136] + _ = x[WrongTypeArgCount-137] + _ = x[CannotInferTypeArgs-138] + _ = x[InvalidTypeArg-139] + _ = x[InvalidInstanceCycle-140] + _ = x[InvalidUnion-141] + _ = x[MisplacedConstraintIface-142] + _ = x[InvalidMethodTypeParams-143] + _ = x[MisplacedTypeParam-144] + _ = x[InvalidUnsafeSliceData-145] + _ = x[InvalidUnsafeString-146] +} + +const ( + _ErrorCode_name_0 = "InvalidSyntaxTree" + _ErrorCode_name_1 = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilUseWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" +) + +var ( + _ErrorCode_index_1 = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 218, 234, 253, 261, 277, 295, 312, 330, 354, 362, 377, 393, 411, 428, 443, 450, 461, 484, 499, 511, 522, 537, 551, 566, 581, 594, 603, 617, 632, 643, 658, 667, 683, 703, 721, 740, 752, 771, 790, 806, 823, 842, 856, 867, 882, 895, 910, 926, 940, 956, 971, 988, 1006, 1021, 1031, 1041, 1058, 1080, 1094, 1108, 1128, 1146, 1166, 1184, 1207, 1223, 1238, 1251, 1261, 1273, 1284, 1298, 1311, 1322, 1332, 1347, 1358, 1369, 1382, 1398, 1415, 1439, 1456, 1471, 1481, 1490, 1503, 1519, 1535, 1546, 1561, 1577, 1591, 1607, 1621, 1638, 1658, 1671, 1687, 1701, 1718, 1735, 1752, 1767, 1781, 1795, 1806, 1818, 1831, 1848, 1861, 1872, 1885, 1897, 1906, 1913, 1925, 1941, 1959, 1977, 1992, 2009, 2028, 2042, 2062, 2074, 2098, 2121, 2139, 2161, 2180} +) + +func (i ErrorCode) String() string { + switch { + case i == -1: + return _ErrorCode_name_0 + case 1 <= i && i <= 146: + i -= 1 + return _ErrorCode_name_1[_ErrorCode_index_1[i]:_ErrorCode_index_1[i+1]] + default: + return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/fx.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/fx.go new file mode 100644 index 00000000..c846a53d --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/fx.go @@ -0,0 +1,88 @@ +// Copyright 2025 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 typesinternal + +import ( + "go/ast" + "go/token" + "go/types" +) + +// NoEffects reports whether the expression has no side effects, i.e., it +// does not modify the memory state. This function is conservative: it may +// return false even when the expression has no effect. +func NoEffects(info *types.Info, expr ast.Expr) bool { + noEffects := true + ast.Inspect(expr, func(n ast.Node) bool { + switch v := n.(type) { + case nil, *ast.Ident, *ast.BasicLit, *ast.BinaryExpr, *ast.ParenExpr, + *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr, *ast.TypeAssertExpr, + *ast.StarExpr, *ast.CompositeLit, + // non-expressions that may appear within expressions + *ast.KeyValueExpr, + *ast.FieldList, + *ast.Field, + *ast.Ellipsis, + *ast.IndexListExpr: + // No effect. + + case *ast.ArrayType, + *ast.StructType, + *ast.ChanType, + *ast.FuncType, + *ast.MapType, + *ast.InterfaceType: + // Type syntax: no effects, recursively. + // Prune descent. + return false + + case *ast.UnaryExpr: + // Channel send <-ch has effects. + if v.Op == token.ARROW { + noEffects = false + } + + case *ast.CallExpr: + // Type conversion has no effects. + if !info.Types[v.Fun].IsType() { + if CallsPureBuiltin(info, v) { + // A call such as len(e) has no effects of its + // own, though the subexpression e might. + } else { + noEffects = false + } + } + + case *ast.FuncLit: + // A FuncLit has no effects, but do not descend into it. + return false + + default: + // All other expressions have effects + noEffects = false + } + + return noEffects + }) + return noEffects +} + +// CallsPureBuiltin reports whether call is a call of a built-in +// function that is a pure computation over its operands (analogous to +// a + operator). Because it does not depend on program state, it may +// be evaluated at any point--though not necessarily at multiple +// points (consider new, make). +func CallsPureBuiltin(info *types.Info, call *ast.CallExpr) bool { + if id, ok := ast.Unparen(call.Fun).(*ast.Ident); ok { + if b, ok := info.ObjectOf(id).(*types.Builtin); ok { + switch b.Name() { + case "len", "cap", "complex", "imag", "real", "make", "new", "max", "min": + return true + } + // Not: append clear close copy delete panic print println recover + } + } + return false +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/isnamed.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/isnamed.go new file mode 100644 index 00000000..e0d63c46 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/isnamed.go @@ -0,0 +1,71 @@ +// Copyright 2025 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 typesinternal + +import ( + "go/types" + "slices" +) + +// IsTypeNamed reports whether t is (or is an alias for) a +// package-level defined type with the given package path and one of +// the given names. It returns false if t is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsTypeNamed(t types.Type, pkgPath string, names ...string) bool { + if named, ok := types.Unalias(t).(*types.Named); ok { + tname := named.Obj() + return tname != nil && + IsPackageLevel(tname) && + tname.Pkg().Path() == pkgPath && + slices.Contains(names, tname.Name()) + } + return false +} + +// IsPointerToNamed reports whether t is (or is an alias for) a pointer to a +// package-level defined type with the given package path and one of the given +// names. It returns false if t is not a pointer type. +func IsPointerToNamed(t types.Type, pkgPath string, names ...string) bool { + r := Unpointer(t) + if r == t { + return false + } + return IsTypeNamed(r, pkgPath, names...) +} + +// IsFunctionNamed reports whether obj is a package-level function +// defined in the given package and has one of the given names. +// It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool { + f, ok := obj.(*types.Func) + return ok && + IsPackageLevel(obj) && + f.Pkg().Path() == pkgPath && + f.Signature().Recv() == nil && + slices.Contains(names, f.Name()) +} + +// IsMethodNamed reports whether obj is a method defined on a +// package-level type with the given package and type name, and has +// one of the given names. It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.TypeName.Name", +// which is important for the performance of syntax matching. +func IsMethodNamed(obj types.Object, pkgPath string, typeName string, names ...string) bool { + if fn, ok := obj.(*types.Func); ok { + if recv := fn.Signature().Recv(); recv != nil { + _, T := ReceiverNamed(recv) + return T != nil && + IsTypeNamed(T, pkgPath, typeName) && + slices.Contains(names, fn.Name()) + } + } + return false +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/qualifier.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/qualifier.go new file mode 100644 index 00000000..4e2756fc --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/qualifier.go @@ -0,0 +1,54 @@ +// Copyright 2024 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 typesinternal + +import ( + "go/ast" + "go/types" + "strconv" +) + +// FileQualifier returns a [types.Qualifier] function that qualifies +// imported symbols appropriately based on the import environment of a given +// file. +// If the same package is imported multiple times, the last appearance is +// recorded. +// +// TODO(adonovan): this function ignores the effect of shadowing. It +// should accept a [token.Pos] and a [types.Info] and compute only the +// set of imports that are not shadowed at that point, analogous to +// [analysis.AddImport]. It could also compute (as a side +// effect) the set of additional imports required to ensure that there +// is an accessible import for each necessary package, making it +// converge even more closely with AddImport. +func FileQualifier(f *ast.File, pkg *types.Package) types.Qualifier { + // Construct mapping of import paths to their defined names. + // It is only necessary to look at renaming imports. + imports := make(map[string]string) + for _, imp := range f.Imports { + if imp.Name != nil && imp.Name.Name != "_" { + path, _ := strconv.Unquote(imp.Path.Value) + imports[path] = imp.Name.Name + } + } + + // Define qualifier to replace full package paths with names of the imports. + return func(p *types.Package) string { + if p == nil || p == pkg { + return "" + } + + if name, ok := imports[p.Path()]; ok { + if name == "." { + return "" + } else { + return name + } + } + + // If there is no local renaming, fall back to the package name. + return p.Name() + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/recv.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/recv.go new file mode 100644 index 00000000..8352ea76 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/recv.go @@ -0,0 +1,44 @@ +// Copyright 2024 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 typesinternal + +import ( + "go/types" +) + +// ReceiverNamed returns the named type (if any) associated with the +// type of recv, which may be of the form N or *N, or aliases thereof. +// It also reports whether a Pointer was present. +// +// The named result may be nil if recv is from a method on an +// anonymous interface or struct types or in ill-typed code. +func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) { + t := recv.Type() + if ptr, ok := types.Unalias(t).(*types.Pointer); ok { + isPtr = true + t = ptr.Elem() + } + named, _ = types.Unalias(t).(*types.Named) + return +} + +// Unpointer returns T given *T or an alias thereof. +// For all other types it is the identity function. +// It does not look at underlying types. +// The result may be an alias. +// +// Use this function to strip off the optional pointer on a receiver +// in a field or method selection, without losing the named type +// (which is needed to compute the method set). +// +// See also [typeparams.MustDeref], which removes one level of +// indirection from the type, regardless of named types (analogous to +// a LOAD instruction). +func Unpointer(t types.Type) types.Type { + if ptr, ok := types.Unalias(t).(*types.Pointer); ok { + return ptr.Elem() + } + return t +} diff --git a/vendor/honnef.co/go/tools/internal/typesinternal/typeindex/typeindex.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex/typeindex.go similarity index 74% rename from vendor/honnef.co/go/tools/internal/typesinternal/typeindex/typeindex.go rename to vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex/typeindex.go index fccc2ba7..9a8ac36e 100644 --- a/vendor/honnef.co/go/tools/internal/typesinternal/typeindex/typeindex.go +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex/typeindex.go @@ -17,13 +17,10 @@ import ( "golang.org/x/tools/go/ast/edge" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "honnef.co/go/tools/internal/xtools-internal/astutil" + "honnef.co/go/tools/internal/xtools-internal/typesinternal" ) -// IsPackageLevel reports whether obj is a package-level symbol. -func IsPackageLevel(obj types.Object) bool { - return obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() -} - // New constructs an Index for the package of type-annotated syntax // // TODO(adonovan): accept a FileSet too? @@ -59,28 +56,63 @@ func New(inspect *inspector.Inspector, pkg *types.Package, info *types.Info) *In if obj := info.Uses[n]; obj != nil { // Index indirect dependencies (via fields and methods). - if !IsPackageLevel(obj) { + if !typesinternal.IsPackageLevel(obj) { addPackage(obj.Pkg()) } - us, ok := ix.uses[obj] - if !ok { - us = &uses{} - us.code = us.initial[:0] - ix.uses[obj] = us - } - delta := cur.Index() - us.last - if delta < 0 { - panic("non-monotonic") + for { + us, ok := ix.uses[obj] + if !ok { + us = &uses{} + us.code = us.initial[:0] + ix.uses[obj] = us + } + delta := cur.Index() - us.last + if delta < 0 { + panic("non-monotonic") + } + us.code = binary.AppendUvarint(us.code, uint64(delta)) + us.last = cur.Index() + + // If n is a selection of a field or method of an instantiated + // type, also record a use of the generic field or method. + obj, ok = objectOrigin(obj) + if !ok { + break + } } - us.code = binary.AppendUvarint(us.code, uint64(delta)) - us.last = cur.Index() } } } return ix } +// objectOrigin returns the generic object for obj if it is a field or +// method of an instantied type; zero otherwise. +// +// (This operation is appropriate only for selections. +// Lexically resolved references always resolve to the generic. +// Although Named and Alias types also use Origin to express +// an instance/generic distinction, that's in the domain +// of Types; their TypeName objects always refer to the generic.) +func objectOrigin(obj types.Object) (types.Object, bool) { + var origin types.Object + switch obj := obj.(type) { + case *types.Func: + if obj.Signature().Recv() != nil { + origin = obj.Origin() // G[int].method -> G[T].method + } + case *types.Var: + if obj.IsField() { + origin = obj.Origin() // G[int].field -> G[T].field + } + } + if origin != nil && origin != obj { + return origin, true + } + return nil, false +} + // An Index holds an index mapping [types.Object] symbols to their syntax. // In effect, it is the inverse of [types.Info]. type Index struct { @@ -110,6 +142,10 @@ type uses struct { // Uses returns the sequence of Cursors of [*ast.Ident]s in this package // that refer to obj. If obj is nil, the sequence is empty. +// +// Uses, unlike the Uses field of [types.Info], records additional +// entries mapping fields and methods of generic types to references +// through their corresponding instantiated objects. func (ix *Index) Uses(obj types.Object) iter.Seq[inspector.Cursor] { return func(yield func(inspector.Cursor) bool) { if uses := ix.uses[obj]; uses != nil { @@ -182,10 +218,9 @@ func (ix *Index) Selection(path, typename, name string) types.Object { func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] { return func(yield func(inspector.Cursor) bool) { for cur := range ix.Uses(callee) { - ek, _ := cur.ParentEdge() - // The call may be of the form f() or x.f(), // optionally with parens; ascend from f to call. + // See logic in [typesinternal.UsedIdent], to which this is dual. // // It is tempting but wrong to use the first // CallExpr ancestor: we have to make sure the @@ -194,25 +229,20 @@ func (ix *Index) Calls(callee types.Object) iter.Seq[inspector.Cursor] { // Avoiding Enclosing is also significantly faster. // inverse unparen: f -> (f) - for ek == edge.ParenExpr_X { - cur = cur.Parent() - ek, _ = cur.ParentEdge() - } + cur = astutil.UnparenEnclosingCursor(cur) - // ascend selector: f -> x.f - if ek == edge.SelectorExpr_Sel { - cur = cur.Parent() - ek, _ = cur.ParentEdge() + // ascend selector (or qualified identifier): f -> x.f + if cur.ParentEdgeKind() == edge.SelectorExpr_Sel { + cur = astutil.UnparenEnclosingCursor(cur.Parent()) } - // inverse unparen again - for ek == edge.ParenExpr_X { - cur = cur.Parent() - ek, _ = cur.ParentEdge() + // ascend typeparams: f -> f[T]; f -> f[T1, T2] + if ek := cur.ParentEdgeKind(); ek == edge.IndexExpr_X || ek == edge.IndexListExpr_X { + cur = astutil.UnparenEnclosingCursor(cur.Parent()) } // ascend from f or x.f to call - if ek == edge.CallExpr_Fun { + if cur.ParentEdgeKind() == edge.CallExpr_Fun { curCall := cur.Parent() call := curCall.Node().(*ast.CallExpr) if typeutil.Callee(ix.info, call) == callee { diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/types.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/types.go new file mode 100644 index 00000000..50942b77 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/types.go @@ -0,0 +1,272 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package typesinternal provides helpful operators for dealing with +// go/types: +// +// - operators for querying typed syntax trees (e.g. [Imports], [IsFunctionNamed]); +// - functions for converting types to strings or syntax (e.g. [TypeExpr], FileQualifier]); +// - helpers for working with the [go/types] API (e.g. [NewTypesInfo]); +// - access to internal go/types APIs that are not yet +// exported (e.g. [SetUsesCgo], [ErrorCodeStartEnd], [VarKind]); and +// - common algorithms related to types (e.g. [TooNewStdSymbols]). +// +// See also: +// - [honnef.co/go/tools/internal/xtools-internal/astutil], for operations on untyped syntax; +// - [honnef.co/go/tools/internal/xtools-internal/analysisinernal], for helpers for analyzers; +// - [honnef.co/go/tools/internal/xtools-internal/refactor], for operators to compute text edits. +package typesinternal + +import ( + "go/ast" + "go/token" + "go/types" + "iter" + "reflect" + + "golang.org/x/tools/go/ast/inspector" +) + +func SetUsesCgo(conf *types.Config) bool { + v := reflect.ValueOf(conf).Elem() + + f := v.FieldByName("go115UsesCgo") + if !f.IsValid() { + f = v.FieldByName("UsesCgo") + if !f.IsValid() { + return false + } + } + + *(*bool)(f.Addr().UnsafePointer()) = true + + return true +} + +// ErrorCodeStartEnd extracts additional information from types.Error values +// generated by Go version 1.16 and later: the error code, start position, and +// end position. If all positions are valid, start <= err.Pos <= end. +// +// If the data could not be read, the final result parameter will be false. +// +// TODO(adonovan): eliminate start/end when proposal #71803 is accepted. +func ErrorCodeStartEnd(err types.Error) (code ErrorCode, start, end token.Pos, ok bool) { + var data [3]int + // By coincidence all of these fields are ints, which simplifies things. + v := reflect.ValueOf(err) + for i, name := range []string{"go116code", "go116start", "go116end"} { + f := v.FieldByName(name) + if !f.IsValid() { + return 0, 0, 0, false + } + data[i] = int(f.Int()) + } + return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true +} + +// NameRelativeTo returns a types.Qualifier that qualifies members of +// all packages other than pkg, using only the package name. +// (By contrast, [types.RelativeTo] uses the complete package path, +// which is often excessive.) +// +// If pkg is nil, it is equivalent to [*types.Package.Name]. +// +// TODO(adonovan): all uses of this with TypeString should be +// eliminated when https://go.dev/issues/75604 is resolved. +func NameRelativeTo(pkg *types.Package) types.Qualifier { + return func(other *types.Package) string { + if pkg != nil && pkg == other { + return "" // same package; unqualified + } + return other.Name() + } +} + +// TypeNameFor returns the type name symbol for the specified type, if +// it is a [*types.Alias], [*types.Named], [*types.TypeParam], or a +// [*types.Basic] representing a type. +// +// For all other types, and for Basic types representing a builtin, +// constant, or nil, it returns nil. Be careful not to convert the +// resulting nil pointer to a [types.Object]! +// +// If t is the type of a constant, it may be an "untyped" type, which +// has no TypeName. To access the name of such types (e.g. "untyped +// int"), use [types.Basic.Name]. +func TypeNameFor(t types.Type) *types.TypeName { + switch t := t.(type) { + case *types.Alias: + return t.Obj() + case *types.Named: + return t.Obj() + case *types.TypeParam: + return t.Obj() + case *types.Basic: + // See issues #71886 and #66890 for some history. + if tname, ok := types.Universe.Lookup(t.Name()).(*types.TypeName); ok { + return tname + } + } + return nil +} + +// A NamedOrAlias is a [types.Type] that is named (as +// defined by the spec) and capable of bearing type parameters: it +// abstracts aliases ([types.Alias]) and defined types +// ([types.Named]). +// +// Every type declared by an explicit "type" declaration is a +// NamedOrAlias. (Built-in type symbols may additionally +// have type [types.Basic], which is not a NamedOrAlias, +// though the spec regards them as "named"; see [TypeNameFor].) +// +// NamedOrAlias cannot expose the Origin method, because +// [types.Alias.Origin] and [types.Named.Origin] have different +// (covariant) result types; use [Origin] instead. +type NamedOrAlias interface { + types.Type + Obj() *types.TypeName + TypeArgs() *types.TypeList + TypeParams() *types.TypeParamList + SetTypeParams(tparams []*types.TypeParam) +} + +var ( + _ NamedOrAlias = (*types.Alias)(nil) + _ NamedOrAlias = (*types.Named)(nil) +) + +// Origin returns the generic type of the Named or Alias type t if it +// is instantiated, otherwise it returns t. +func Origin(t NamedOrAlias) NamedOrAlias { + switch t := t.(type) { + case *types.Alias: + return t.Origin() + case *types.Named: + return t.Origin() + } + return t +} + +// IsPackageLevel reports whether obj is a package-level symbol. +func IsPackageLevel(obj types.Object) bool { + return obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() +} + +// NewTypesInfo returns a *types.Info with all maps populated. +func NewTypesInfo() *types.Info { + return &types.Info{ + Types: map[ast.Expr]types.TypeAndValue{}, + Instances: map[*ast.Ident]types.Instance{}, + Defs: map[*ast.Ident]types.Object{}, + Uses: map[*ast.Ident]types.Object{}, + Implicits: map[ast.Node]types.Object{}, + Selections: map[*ast.SelectorExpr]*types.Selection{}, + Scopes: map[ast.Node]*types.Scope{}, + FileVersions: map[*ast.File]string{}, + } +} + +// EnclosingScope returns the innermost block logically enclosing the cursor. +func EnclosingScope(info *types.Info, cur inspector.Cursor) *types.Scope { + for cur := range cur.Enclosing() { + n := cur.Node() + // A function's Scope is associated with its FuncType. + switch f := n.(type) { + case *ast.FuncDecl: + n = f.Type + case *ast.FuncLit: + n = f.Type + } + if b := info.Scopes[n]; b != nil { + return b + } + } + panic("no Scope for *ast.File") +} + +// Imports reports whether path is imported by pkg. +func Imports(pkg *types.Package, path string) bool { + for _, imp := range pkg.Imports() { + if imp.Path() == path { + return true + } + } + return false +} + +// ObjectKind returns a description of the object's kind. +// +// from objectKind in go/types +func ObjectKind(obj types.Object) string { + switch obj := obj.(type) { + case *types.PkgName: + return "package name" + case *types.Const: + return "constant" + case *types.TypeName: + if obj.IsAlias() { + return "type alias" + } else if _, ok := obj.Type().(*types.TypeParam); ok { + return "type parameter" + } else { + return "defined type" + } + case *types.Var: + switch obj.Kind() { + case PackageVar: + return "package-level variable" + case LocalVar: + return "local variable" + case RecvVar: + return "receiver" + case ParamVar: + return "parameter" + case ResultVar: + return "result variable" + case FieldVar: + return "struct field" + } + case *types.Func: + if obj.Signature().Recv() != nil { + return "method" + } else { + return "function" + } + case *types.Label: + return "label" + case *types.Builtin: + return "built-in function" + case *types.Nil: + return "untyped nil" + } + return "unknown symbol" +} + +// ImplicitFieldSelections returns the sequence of implicit embedded fields +// traversed by the given selection. It skips the final leaf field or method. +// The boolean component indicates whether the traversal traversed a pointer. +func ImplicitFieldSelections(seln types.Selection) iter.Seq2[*types.Var, bool] { + return func(yield func(*types.Var, bool) bool) { + var ( + t = seln.Recv() + indices = seln.Index() + ) + for _, idx := range indices[:len(indices)-1] { + ptr, isPtr := t.Underlying().(*types.Pointer) + if isPtr { + t = ptr.Elem() + } + structType, ok := t.Underlying().(*types.Struct) + if !ok { + break + } + field := structType.Field(idx) + if !yield(field, isPtr) { + break + } + t = field.Type() + } + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind.go new file mode 100644 index 00000000..26499cdd --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind.go @@ -0,0 +1,23 @@ +// Copyright 2024 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 go1.25 + +package typesinternal + +import "go/types" + +type VarKind = types.VarKind + +const ( + PackageVar = types.PackageVar + LocalVar = types.LocalVar + RecvVar = types.RecvVar + ParamVar = types.ParamVar + ResultVar = types.ResultVar + FieldVar = types.FieldVar +) + +func GetVarKind(v *types.Var) VarKind { return v.Kind() } +func SetVarKind(v *types.Var, kind VarKind) { v.SetKind(kind) } diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind_go124.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind_go124.go new file mode 100644 index 00000000..17b1804b --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/varkind_go124.go @@ -0,0 +1,39 @@ +// Copyright 2024 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 !go1.25 + +package typesinternal + +import "go/types" + +type VarKind uint8 + +const ( + _ VarKind = iota // (not meaningful) + PackageVar // a package-level variable + LocalVar // a local variable + RecvVar // a method receiver variable + ParamVar // a function parameter variable + ResultVar // a function result variable + FieldVar // a struct field +) + +func (kind VarKind) String() string { + return [...]string{ + 0: "VarKind(0)", + PackageVar: "PackageVar", + LocalVar: "LocalVar", + RecvVar: "RecvVar", + ParamVar: "ParamVar", + ResultVar: "ResultVar", + FieldVar: "FieldVar", + }[kind] +} + +// GetVarKind returns an invalid VarKind. +func GetVarKind(v *types.Var) VarKind { return 0 } + +// SetVarKind has no effect. +func SetVarKind(v *types.Var, kind VarKind) {} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/zerovalue.go b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/zerovalue.go new file mode 100644 index 00000000..d612a710 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/typesinternal/zerovalue.go @@ -0,0 +1,381 @@ +// Copyright 2024 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 typesinternal + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "strings" +) + +// ZeroString returns the string representation of the zero value for any type t. +// The boolean result indicates whether the type is or contains an invalid type +// or a non-basic (constraint) interface type. +// +// Even for invalid input types, ZeroString may return a partially correct +// string representation. The caller should use the returned isValid boolean +// to determine the validity of the expression. +// +// When assigning to a wider type (such as 'any'), it's the caller's +// responsibility to handle any necessary type conversions. +// +// This string can be used on the right-hand side of an assignment where the +// left-hand side has that explicit type. +// References to named types are qualified by an appropriate (optional) +// qualifier function. +// Exception: This does not apply to tuples. Their string representation is +// informational only and cannot be used in an assignment. +// +// See [ZeroExpr] for a variant that returns an [ast.Expr]. +func ZeroString(t types.Type, qual types.Qualifier) (_ string, isValid bool) { + switch t := t.(type) { + case *types.Basic: + switch { + case t.Info()&types.IsBoolean != 0: + return "false", true + case t.Info()&types.IsNumeric != 0: + return "0", true + case t.Info()&types.IsString != 0: + return `""`, true + case t.Kind() == types.UnsafePointer: + fallthrough + case t.Kind() == types.UntypedNil: + return "nil", true + case t.Kind() == types.Invalid: + return "invalid", false + default: + panic(fmt.Sprintf("ZeroString for unexpected type %v", t)) + } + + case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: + return "nil", true + + case *types.Interface: + if !t.IsMethodSet() { + return "invalid", false + } + return "nil", true + + case *types.Named: + switch under := t.Underlying().(type) { + case *types.Struct, *types.Array: + return types.TypeString(t, qual) + "{}", true + default: + return ZeroString(under, qual) + } + + case *types.Alias: + switch t.Underlying().(type) { + case *types.Struct, *types.Array: + return types.TypeString(t, qual) + "{}", true + default: + // A type parameter can have alias but alias type's underlying type + // can never be a type parameter. + // Use types.Unalias to preserve the info of type parameter instead + // of call Underlying() going right through and get the underlying + // type of the type parameter which is always an interface. + return ZeroString(types.Unalias(t), qual) + } + + case *types.Array, *types.Struct: + return types.TypeString(t, qual) + "{}", true + + case *types.TypeParam: + // Assumes func new is not shadowed. + return "*new(" + types.TypeString(t, qual) + ")", true + + case *types.Tuple: + // Tuples are not normal values. + // We are currently format as "(t[0], ..., t[n])". Could be something else. + isValid := true + components := make([]string, t.Len()) + for i := 0; i < t.Len(); i++ { + comp, ok := ZeroString(t.At(i).Type(), qual) + + components[i] = comp + isValid = isValid && ok + } + return "(" + strings.Join(components, ", ") + ")", isValid + + case *types.Union: + // Variables of these types cannot be created, so it makes + // no sense to ask for their zero value. + panic(fmt.Sprintf("invalid type for a variable: %v", t)) + + default: + panic(t) // unreachable. + } +} + +// ZeroExpr returns the ast.Expr representation of the zero value for any type t. +// The boolean result indicates whether the type is or contains an invalid type +// or a non-basic (constraint) interface type. +// +// Even for invalid input types, ZeroExpr may return a partially correct ast.Expr +// representation. The caller should use the returned isValid boolean to determine +// the validity of the expression. +// +// This function is designed for types suitable for variables and should not be +// used with Tuple or Union types.References to named types are qualified by an +// appropriate (optional) qualifier function. +// +// See [ZeroString] for a variant that returns a string. +func ZeroExpr(t types.Type, qual types.Qualifier) (_ ast.Expr, isValid bool) { + switch t := t.(type) { + case *types.Basic: + switch { + case t.Info()&types.IsBoolean != 0: + return &ast.Ident{Name: "false"}, true + case t.Info()&types.IsNumeric != 0: + return &ast.BasicLit{Kind: token.INT, Value: "0"}, true + case t.Info()&types.IsString != 0: + return &ast.BasicLit{Kind: token.STRING, Value: `""`}, true + case t.Kind() == types.UnsafePointer: + fallthrough + case t.Kind() == types.UntypedNil: + return ast.NewIdent("nil"), true + case t.Kind() == types.Invalid: + return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false + default: + panic(fmt.Sprintf("ZeroExpr for unexpected type %v", t)) + } + + case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: + return ast.NewIdent("nil"), true + + case *types.Interface: + if !t.IsMethodSet() { + return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false + } + return ast.NewIdent("nil"), true + + case *types.Named: + switch under := t.Underlying().(type) { + case *types.Struct, *types.Array: + return &ast.CompositeLit{ + Type: TypeExpr(t, qual), + }, true + default: + return ZeroExpr(under, qual) + } + + case *types.Alias: + switch t.Underlying().(type) { + case *types.Struct, *types.Array: + return &ast.CompositeLit{ + Type: TypeExpr(t, qual), + }, true + default: + return ZeroExpr(types.Unalias(t), qual) + } + + case *types.Array, *types.Struct: + return &ast.CompositeLit{ + Type: TypeExpr(t, qual), + }, true + + case *types.TypeParam: + return &ast.StarExpr{ // *new(T) + X: &ast.CallExpr{ + // Assumes func new is not shadowed. + Fun: ast.NewIdent("new"), + Args: []ast.Expr{ + ast.NewIdent(t.Obj().Name()), + }, + }, + }, true + + case *types.Tuple: + // Unlike ZeroString, there is no ast.Expr can express tuple by + // "(t[0], ..., t[n])". + panic(fmt.Sprintf("invalid type for a variable: %v", t)) + + case *types.Union: + // Variables of these types cannot be created, so it makes + // no sense to ask for their zero value. + panic(fmt.Sprintf("invalid type for a variable: %v", t)) + + default: + panic(t) // unreachable. + } +} + +// TypeExpr returns syntax for the specified type. References to named types +// are qualified by an appropriate (optional) qualifier function. +// It may panic for types such as Tuple or Union. +// +// See also https://go.dev/issues/75604, which will provide a robust +// Type-to-valid-Go-syntax formatter. +func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr { + switch t := t.(type) { + case *types.Basic: + switch t.Kind() { + case types.UnsafePointer: + return &ast.SelectorExpr{X: ast.NewIdent(qual(types.NewPackage("unsafe", "unsafe"))), Sel: ast.NewIdent("Pointer")} + default: + return ast.NewIdent(t.Name()) + } + + case *types.Pointer: + return &ast.UnaryExpr{ + Op: token.MUL, + X: TypeExpr(t.Elem(), qual), + } + + case *types.Array: + return &ast.ArrayType{ + Len: &ast.BasicLit{ + Kind: token.INT, + Value: fmt.Sprintf("%d", t.Len()), + }, + Elt: TypeExpr(t.Elem(), qual), + } + + case *types.Slice: + return &ast.ArrayType{ + Elt: TypeExpr(t.Elem(), qual), + } + + case *types.Map: + return &ast.MapType{ + Key: TypeExpr(t.Key(), qual), + Value: TypeExpr(t.Elem(), qual), + } + + case *types.Chan: + dir := ast.ChanDir(t.Dir()) + if t.Dir() == types.SendRecv { + dir = ast.SEND | ast.RECV + } + return &ast.ChanType{ + Dir: dir, + Value: TypeExpr(t.Elem(), qual), + } + + case *types.Signature: + var params []*ast.Field + for v := range t.Params().Variables() { + params = append(params, &ast.Field{ + Type: TypeExpr(v.Type(), qual), + Names: []*ast.Ident{ + { + Name: v.Name(), + }, + }, + }) + } + if t.Variadic() { + last := params[len(params)-1] + last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt} + } + var returns []*ast.Field + for v := range t.Results().Variables() { + returns = append(returns, &ast.Field{ + Type: TypeExpr(v.Type(), qual), + }) + } + return &ast.FuncType{ + Params: &ast.FieldList{ + List: params, + }, + Results: &ast.FieldList{ + List: returns, + }, + } + + case *types.TypeParam: + pkgName := qual(t.Obj().Pkg()) + if pkgName == "" || t.Obj().Pkg() == nil { + return ast.NewIdent(t.Obj().Name()) + } + return &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: ast.NewIdent(t.Obj().Name()), + } + + // types.TypeParam also implements interface NamedOrAlias. To differentiate, + // case TypeParam need to be present before case NamedOrAlias. + // TODO(hxjiang): remove this comment once TypeArgs() is added to interface + // NamedOrAlias. + case NamedOrAlias: + var expr ast.Expr = ast.NewIdent(t.Obj().Name()) + if pkgName := qual(t.Obj().Pkg()); pkgName != "." && pkgName != "" { + expr = &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: expr.(*ast.Ident), + } + } + + // TODO(hxjiang): call t.TypeArgs after adding method TypeArgs() to + // typesinternal.NamedOrAlias. + if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok { + if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 { + var indices []ast.Expr + for t0 := range typeArgs.Types() { + indices = append(indices, TypeExpr(t0, qual)) + } + expr = &ast.IndexListExpr{ + X: expr, + Indices: indices, + } + } + } + + return expr + + case *types.Struct: + return ast.NewIdent(t.String()) + + case *types.Interface: + return ast.NewIdent(t.String()) + + case *types.Union: + if t.Len() == 0 { + panic("Union type should have at least one term") + } + // Same as go/ast, the return expression will put last term in the + // Y field at topmost level of BinaryExpr. + // For union of type "float32 | float64 | int64", the structure looks + // similar to: + // { + // X: { + // X: float32, + // Op: | + // Y: float64, + // } + // Op: |, + // Y: int64, + // } + var union ast.Expr + for i := range t.Len() { + term := t.Term(i) + termExpr := TypeExpr(term.Type(), qual) + if term.Tilde() { + termExpr = &ast.UnaryExpr{ + Op: token.TILDE, + X: termExpr, + } + } + if i == 0 { + union = termExpr + } else { + union = &ast.BinaryExpr{ + X: union, + Op: token.OR, + Y: termExpr, + } + } + } + return union + + case *types.Tuple: + panic("invalid input type types.Tuple") + + default: + panic("unreachable") + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/versions/features.go b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/features.go new file mode 100644 index 00000000..360a5b55 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/features.go @@ -0,0 +1,49 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +// This file contains predicates for working with file versions to +// decide when a tool should consider a language feature enabled. + +// named constants, to avoid misspelling +const ( + Go1_17 = "go1.17" + Go1_18 = "go1.18" + Go1_19 = "go1.19" + Go1_20 = "go1.20" + Go1_21 = "go1.21" + Go1_22 = "go1.22" + Go1_23 = "go1.23" + Go1_24 = "go1.24" + Go1_25 = "go1.25" + Go1_26 = "go1.26" + Go1_27 = "go1.27" +) + +// Future is an invalid unknown Go version sometime in the future. +// Do not use directly with Compare. +const Future = "" + +// AtLeast reports whether the file version v comes after a Go release. +// +// Use this predicate to enable a behavior once a certain Go release +// has happened (and stays enabled in the future). +func AtLeast(v, release string) bool { + if v == Future { + return true // an unknown future version is always after y. + } + return Compare(Lang(v), Lang(release)) >= 0 +} + +// Before reports whether the file version v is strictly before a Go release. +// +// Use this predicate to disable a behavior once a certain Go release +// has happened (and stays enabled in the future). +func Before(v, release string) bool { + if v == Future { + return false // an unknown future version happens after y. + } + return Compare(Lang(v), Lang(release)) < 0 +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/versions/gover.go b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/gover.go new file mode 100644 index 00000000..bbabcd22 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/gover.go @@ -0,0 +1,172 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a fork of internal/gover for use by x/tools until +// go1.21 and earlier are no longer supported by x/tools. + +package versions + +import "strings" + +// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]] +// The numbers are the original decimal strings to avoid integer overflows +// and since there is very little actual math. (Probably overflow doesn't matter in practice, +// but at the time this code was written, there was an existing test that used +// go1.99999999999, which does not fit in an int on 32-bit platforms. +// The "big decimal" representation avoids the problem entirely.) +type gover struct { + major string // decimal + minor string // decimal or "" + patch string // decimal or "" + kind string // "", "alpha", "beta", "rc" + pre string // decimal or "" +} + +// compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as toolchain versions. +// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21". +// Malformed versions compare less than well-formed versions and equal to each other. +// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0". +func compare(x, y string) int { + vx := parse(x) + vy := parse(y) + + if c := cmpInt(vx.major, vy.major); c != 0 { + return c + } + if c := cmpInt(vx.minor, vy.minor); c != 0 { + return c + } + if c := cmpInt(vx.patch, vy.patch); c != 0 { + return c + } + if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc + return c + } + if c := cmpInt(vx.pre, vy.pre); c != 0 { + return c + } + return 0 +} + +// lang returns the Go language version. For example, lang("1.2.3") == "1.2". +func lang(x string) string { + v := parse(x) + if v.minor == "" || v.major == "1" && v.minor == "0" { + return v.major + } + return v.major + "." + v.minor +} + +// isValid reports whether the version x is valid. +func isValid(x string) bool { + return parse(x) != gover{} +} + +// parse parses the Go version string x into a version. +// It returns the zero version if x is malformed. +func parse(x string) gover { + var v gover + + // Parse major version. + var ok bool + v.major, x, ok = cutInt(x) + if !ok { + return gover{} + } + if x == "" { + // Interpret "1" as "1.0.0". + v.minor = "0" + v.patch = "0" + return v + } + + // Parse . before minor version. + if x[0] != '.' { + return gover{} + } + + // Parse minor version. + v.minor, x, ok = cutInt(x[1:]) + if !ok { + return gover{} + } + if x == "" { + // Patch missing is same as "0" for older versions. + // Starting in Go 1.21, patch missing is different from explicit .0. + if cmpInt(v.minor, "21") < 0 { + v.patch = "0" + } + return v + } + + // Parse patch if present. + if x[0] == '.' { + v.patch, x, ok = cutInt(x[1:]) + if !ok || x != "" { + // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != ""). + // Allowing them would be a bit confusing because we already have: + // 1.21 < 1.21rc1 + // But a prerelease of a patch would have the opposite effect: + // 1.21.3rc1 < 1.21.3 + // We've never needed them before, so let's not start now. + return gover{} + } + return v + } + + // Parse prerelease. + i := 0 + for i < len(x) && (x[i] < '0' || '9' < x[i]) { + if x[i] < 'a' || 'z' < x[i] { + return gover{} + } + i++ + } + if i == 0 { + return gover{} + } + v.kind, x = x[:i], x[i:] + if x == "" { + return v + } + v.pre, x, ok = cutInt(x) + if !ok || x != "" { + return gover{} + } + + return v +} + +// cutInt scans the leading decimal number at the start of x to an integer +// and returns that value and the rest of the string. +func cutInt(x string) (n, rest string, ok bool) { + i := 0 + for i < len(x) && '0' <= x[i] && x[i] <= '9' { + i++ + } + if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero + return "", "", false + } + return x[:i], x[i:], true +} + +// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers. +// (Copied from golang.org/x/mod/semver's compareInt.) +func cmpInt(x, y string) int { + if x == y { + return 0 + } + if len(x) < len(y) { + return -1 + } + if len(x) > len(y) { + return +1 + } + if x < y { + return -1 + } else { + return +1 + } +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/versions/types.go b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/types.go new file mode 100644 index 00000000..0fc10ce4 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/types.go @@ -0,0 +1,33 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +import ( + "go/ast" + "go/types" +) + +// FileVersion returns a file's Go version. +// The reported version is an unknown Future version if a +// version cannot be determined. +func FileVersion(info *types.Info, file *ast.File) string { + // In tools built with Go >= 1.22, the Go version of a file + // follow a cascades of sources: + // 1) types.Info.FileVersion, which follows the cascade: + // 1.a) file version (ast.File.GoVersion), + // 1.b) the package version (types.Config.GoVersion), or + // 2) is some unknown Future version. + // + // File versions require a valid package version to be provided to types + // in Config.GoVersion. Config.GoVersion is either from the package's module + // or the toolchain (go run). This value should be provided by go/packages + // or unitchecker.Config.GoVersion. + if v := info.FileVersions[file]; IsValid(v) { + return v + } + // Note: we could instead return runtime.Version() [if valid]. + // This would act as a max version on what a tool can support. + return Future +} diff --git a/vendor/honnef.co/go/tools/internal/xtools-internal/versions/versions.go b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/versions.go new file mode 100644 index 00000000..8d1f7453 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/xtools-internal/versions/versions.go @@ -0,0 +1,57 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package versions + +import ( + "strings" +) + +// Note: If we use build tags to use go/versions when go >=1.22, +// we run into go.dev/issue/53737. Under some operations users would see an +// import of "go/versions" even if they would not compile the file. +// For example, during `go get -u ./...` (go.dev/issue/64490) we do not try to include +// For this reason, this library just a clone of go/versions for the moment. + +// Lang returns the Go language version for version x. +// If x is not a valid version, Lang returns the empty string. +// For example: +// +// Lang("go1.21rc2") = "go1.21" +// Lang("go1.21.2") = "go1.21" +// Lang("go1.21") = "go1.21" +// Lang("go1") = "go1" +// Lang("bad") = "" +// Lang("1.21") = "" +func Lang(x string) string { + v := lang(stripGo(x)) + if v == "" { + return "" + } + return x[:2+len(v)] // "go"+v without allocation +} + +// Compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as Go versions. +// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21". +// Invalid versions, including the empty string, compare less than +// valid versions and equal to each other. +// The language version "go1.21" compares less than the +// release candidate and eventual releases "go1.21rc1" and "go1.21.0". +// Custom toolchain suffixes are ignored during comparison: +// "go1.21.0" and "go1.21.0-bigcorp" are equal. +func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) } + +// IsValid reports whether the version x is valid. +func IsValid(x string) bool { return isValid(stripGo(x)) } + +// stripGo converts from a "go1.21" version to a "1.21" version. +// If v does not start with "go", stripGo returns the empty string (a known invalid version). +func stripGo(v string) string { + v, _, _ = strings.Cut(v, "-") // strip -bigcorp suffix. + if len(v) < 2 || v[:2] != "go" { + return "" + } + return v[2:] +} diff --git a/vendor/honnef.co/go/tools/knowledge/arg.go b/vendor/honnef.co/go/tools/knowledge/arg.go index 4fab2eba..c477ec4f 100644 --- a/vendor/honnef.co/go/tools/knowledge/arg.go +++ b/vendor/honnef.co/go/tools/knowledge/arg.go @@ -28,6 +28,7 @@ var Args = map[string]int{ "fmt.Sprintf.a[0]": 1, "fmt.Sprintf.format": 0, "json.Marshal.v": 0, + "json.MarshalIndent.v": 0, "json.Unmarshal.v": 1, "len.v": 0, "make.size[0]": 1, @@ -60,6 +61,7 @@ var Args = map[string]int{ "time.Parse.layout": 0, "time.Sleep.d": 0, "xml.Marshal.v": 0, + "xml.MarshalIndent.v": 0, "xml.Unmarshal.v": 1, } diff --git a/vendor/honnef.co/go/tools/knowledge/deprecated.go b/vendor/honnef.co/go/tools/knowledge/deprecated.go index 89ff8d9e..256f3756 100644 --- a/vendor/honnef.co/go/tools/knowledge/deprecated.go +++ b/vendor/honnef.co/go/tools/knowledge/deprecated.go @@ -246,6 +246,11 @@ var StdlibDeprecations = map[string]Deprecation{ "crypto/rsa.EncryptPKCS1v15": {"go1.26", DeprecatedNeverUse}, "(net/http/httputil.ReverseProxy).Director": {"go1.26", "go1.20"}, + + // Note that the available alternative, testing/cryptotest.SetGlobalRandom + // is only an alternative for testing, not all possible uses of the + // deprecated field. + "(crypto/tls.Config).Rand": {"go1.27", "go1.26"}, } // Last imported from GOROOT/api/go1.26.txt at d3ddc4854429185e6e06ca1f7628bb790404abb5. diff --git a/vendor/honnef.co/go/tools/quickfix/qf1002/qf1002.go b/vendor/honnef.co/go/tools/quickfix/qf1002/qf1002.go index 84b84723..dd522167 100644 --- a/vendor/honnef.co/go/tools/quickfix/qf1002/qf1002.go +++ b/vendor/honnef.co/go/tools/quickfix/qf1002/qf1002.go @@ -121,7 +121,7 @@ func run(pass *analysis.Pass) (any, error) { } func findSwitchPairs(pass *analysis.Pass, expr ast.Expr, pairs *[]*ast.BinaryExpr) bool { - binexpr, ok := astutil.Unparen(expr).(*ast.BinaryExpr) + binexpr, ok := ast.Unparen(expr).(*ast.BinaryExpr) if !ok { return false } diff --git a/vendor/honnef.co/go/tools/quickfix/qf1003/qf1003.go b/vendor/honnef.co/go/tools/quickfix/qf1003/qf1003.go index f8be70d4..7958795a 100644 --- a/vendor/honnef.co/go/tools/quickfix/qf1003/qf1003.go +++ b/vendor/honnef.co/go/tools/quickfix/qf1003/qf1003.go @@ -180,7 +180,7 @@ nodeLoop: } func findSwitchPairs(pass *analysis.Pass, expr ast.Expr, pairs *[]*ast.BinaryExpr) bool { - binexpr, ok := astutil.Unparen(expr).(*ast.BinaryExpr) + binexpr, ok := ast.Unparen(expr).(*ast.BinaryExpr) if !ok { return false } diff --git a/vendor/honnef.co/go/tools/quickfix/qf1004/qf1004.go b/vendor/honnef.co/go/tools/quickfix/qf1004/qf1004.go index e18c4d53..bde8c671 100644 --- a/vendor/honnef.co/go/tools/quickfix/qf1004/qf1004.go +++ b/vendor/honnef.co/go/tools/quickfix/qf1004/qf1004.go @@ -8,8 +8,8 @@ import ( "honnef.co/go/tools/analysis/edit" "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" - typeindexanalyzer "honnef.co/go/tools/internal/analysisinternal/typeindex" - "honnef.co/go/tools/internal/typesinternal/typeindex" + typeindexanalyzer "honnef.co/go/tools/internal/xtools-internal/analysis/typeindex" + "honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex" "golang.org/x/tools/go/analysis" ) diff --git a/vendor/honnef.co/go/tools/simple/s1005/s1005.go b/vendor/honnef.co/go/tools/simple/s1005/s1005.go index 466f38a4..bd3dcbdd 100644 --- a/vendor/honnef.co/go/tools/simple/s1005/s1005.go +++ b/vendor/honnef.co/go/tools/simple/s1005/s1005.go @@ -27,11 +27,9 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Text: `In many cases, assigning to the blank identifier is unnecessary.`, Before: ` for _ = range s {} -x, _ = someMap[key] _ = <-ch`, After: ` for range s{} -x = someMap[key] <-ch`, Since: "2017.1", MergeIf: lint.MergeIfAny, @@ -45,9 +43,7 @@ var ( (AssignStmt [_ (Ident "_")] _ - (Or - (IndexExpr _ _) - (UnaryExpr "<-" _))) `) + (UnaryExpr "<-" _)) `) checkUnnecessaryBlankQ2 = pattern.MustParse(` (AssignStmt (Ident "_") _ recv@(UnaryExpr "<-" _))`) @@ -55,6 +51,10 @@ var ( func run(pass *analysis.Pass) (any, error) { fn1 := func(node ast.Node) { + // We don't check for 'x, _ = m[k]', which might be used to indicate + // that one knows that there might be no entry and that one doesn't + // care. + if _, ok := code.Match(pass, checkUnnecessaryBlankQ1, node); ok { r := *node.(*ast.AssignStmt) r.Lhs = r.Lhs[0:1] diff --git a/vendor/honnef.co/go/tools/staticcheck/analysis.go b/vendor/honnef.co/go/tools/staticcheck/analysis.go index fe8642ab..81ab81c9 100644 --- a/vendor/honnef.co/go/tools/staticcheck/analysis.go +++ b/vendor/honnef.co/go/tools/staticcheck/analysis.go @@ -82,7 +82,6 @@ import ( "honnef.co/go/tools/staticcheck/sa5008" "honnef.co/go/tools/staticcheck/sa5009" "honnef.co/go/tools/staticcheck/sa5010" - "honnef.co/go/tools/staticcheck/sa5011" "honnef.co/go/tools/staticcheck/sa5012" "honnef.co/go/tools/staticcheck/sa6000" "honnef.co/go/tools/staticcheck/sa6001" @@ -99,6 +98,7 @@ import ( "honnef.co/go/tools/staticcheck/sa9007" "honnef.co/go/tools/staticcheck/sa9008" "honnef.co/go/tools/staticcheck/sa9009" + "honnef.co/go/tools/staticcheck/sa9010" ) var Analyzers = []*lint.Analyzer{ @@ -180,7 +180,6 @@ var Analyzers = []*lint.Analyzer{ sa5008.SCAnalyzer, sa5009.SCAnalyzer, sa5010.SCAnalyzer, - sa5011.SCAnalyzer, sa5012.SCAnalyzer, sa6000.SCAnalyzer, sa6001.SCAnalyzer, @@ -197,4 +196,5 @@ var Analyzers = []*lint.Analyzer{ sa9007.SCAnalyzer, sa9008.SCAnalyzer, sa9009.SCAnalyzer, + sa9010.SCAnalyzer, } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1002/sa1002.go b/vendor/honnef.co/go/tools/staticcheck/sa1002/sa1002.go index ddc20767..4f7159af 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1002/sa1002.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1002/sa1002.go @@ -20,7 +20,10 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Run: callcheck.Analyzer(rules), }, Doc: &lint.RawDocumentation{ - Title: `Invalid format in \'time.Parse\'`, + Title: `Invalid format in \'time.Parse\'`, + Text: `\'time.Parse\' requires a layout string that uses Go's reference time: +\"Mon Jan 2 15:04:05 MST 2006\". The layout must represent this date and time +exactly. See https://pkg.go.dev/time#pkg-constants for layout examples.`, Since: "2017.1", Severity: lint.SeverityError, MergeIf: lint.MergeIfAny, diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1012/sa1012.go b/vendor/honnef.co/go/tools/staticcheck/sa1012/sa1012.go index 16bd0798..b04fd8c8 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1012/sa1012.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1012/sa1012.go @@ -21,7 +21,10 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Requires: code.RequiredAnalyzers, }, Doc: &lint.RawDocumentation{ - Title: `A nil \'context.Context\' is being passed to a function, consider using \'context.TODO\' instead`, + Title: `A nil \'context.Context\' is being passed to a function, consider using \'context.TODO\' instead`, + Text: `The context package prohibits the use of a \'nil\' context. +If no parent context is available, a new context should be used, +e.g. \'context.TODO\' or \'context.Background\'.`, Since: "2017.1", Severity: lint.SeverityWarning, MergeIf: lint.MergeIfAny, diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1014/sa1014.go b/vendor/honnef.co/go/tools/staticcheck/sa1014/sa1014.go index 90d676af..528aa339 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1014/sa1014.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1014/sa1014.go @@ -18,7 +18,11 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Run: callcheck.Analyzer(checkUnmarshalPointerRules), }, Doc: &lint.RawDocumentation{ - Title: `Non-pointer value passed to \'Unmarshal\' or \'Decode\'`, + Title: `Non-pointer value passed to \'Unmarshal\' or \'Decode\'`, + Text: `Functions such as \'encoding/json.Unmarshal\' and +\'(*encoding/json.Decoder).Decode\' require a pointer to the value that should +be populated. Passing a non-pointer value results in the function returning an +error at runtime, as it cannot modify the target value.`, Since: "2017.1", Severity: lint.SeverityError, MergeIf: lint.MergeIfAny, diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1019/sa1019.go b/vendor/honnef.co/go/tools/staticcheck/sa1019/sa1019.go index 97040e8f..0fb9b307 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1019/sa1019.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1019/sa1019.go @@ -99,50 +99,33 @@ func run(pass *analysis.Pass) (any, error) { case knowledge.DeprecatedNeverUse: report.Report(pass, node, fmt.Sprintf("%s has been deprecated since %s because it shouldn't be used: %s", - report.Render(pass, node), formatGoVersion(std.DeprecatedSince), depr.Msg)) + deprecatedObjName, formatGoVersion(std.DeprecatedSince), depr.Msg)) case std.DeprecatedSince, knowledge.DeprecatedUseNoLonger: report.Report(pass, node, fmt.Sprintf("%s has been deprecated since %s: %s", - report.Render(pass, node), formatGoVersion(std.DeprecatedSince), depr.Msg)) + deprecatedObjName, formatGoVersion(std.DeprecatedSince), depr.Msg)) default: report.Report(pass, node, fmt.Sprintf("%s has been deprecated since %s and an alternative has been available since %s: %s", - report.Render(pass, node), formatGoVersion(std.DeprecatedSince), formatGoVersion(std.AlternativeAvailableSince), depr.Msg)) + deprecatedObjName, formatGoVersion(std.DeprecatedSince), formatGoVersion(std.AlternativeAvailableSince), depr.Msg)) } } else { - report.Report(pass, node, fmt.Sprintf("%s is deprecated: %s", report.Render(pass, node), depr.Msg)) + report.Report(pass, node, fmt.Sprintf("%s is deprecated: %s", deprecatedObjName, depr.Msg)) } } var tfn types.Object stack := 0 - fn := func(node ast.Node, push bool) bool { - if !push { - stack-- - return false - } - stack++ - if stack == 1 { - tfn = nil - } - if fn, ok := node.(*ast.FuncDecl); ok { - tfn = pass.TypesInfo.ObjectOf(fn.Name) - } - - // FIXME(dh): this misses dot-imported objects - sel, ok := node.(*ast.SelectorExpr) - if !ok { - return true - } + checkIdentObj := func(sel *ast.SelectorExpr) bool { obj := pass.TypesInfo.ObjectOf(sel.Sel) + if obj_, ok := obj.(*types.Func); ok { obj = obj_.Origin() } if obj.Pkg() == nil { return true } - if obj.Pkg() == pass.Pkg { // A package is allowed to use its own deprecated objects return true @@ -165,8 +148,59 @@ func run(pass *analysis.Pass) (any, error) { return true } + node := ast.Node(sel) + if pass.TypesInfo.Types[sel.X].IsType() { + node = sel.Sel + } if depr, ok := deprs.Objects[obj]; ok { - handleDeprecation(depr, sel, code.SelectorName(pass, sel), obj.Pkg().Path(), tfn) + handleDeprecation(depr, node, code.SelectorName(pass, sel), obj.Pkg().Path(), tfn) + } + return true + } + + fn := func(node ast.Node, push bool) bool { + if !push { + stack-- + return false + } + stack++ + if stack == 1 { + tfn = nil + } + if fn, ok := node.(*ast.FuncDecl); ok { + tfn = pass.TypesInfo.ObjectOf(fn.Name) + } + + switch v := node.(type) { + // FIXME(dh): this misses dot-imported objects + case *ast.SelectorExpr: + return checkIdentObj(v) + + case *ast.CompositeLit: + litType := pass.TypesInfo.Types[v.Type] + if !litType.IsType() { + // This is probably unreachable. + return true + } + if _, ok := litType.Type.Underlying().(*types.Struct); !ok { + // We don't want to look at expressions in map initializers, for + // example. + return true + } + for _, elt := range v.Elts { + kv, ok := elt.(*ast.KeyValueExpr) + if !ok { + return true + } + key, ok := kv.Key.(*ast.Ident) + if !ok { + // This is probably unreachable, since we're looking at keys + // in a struct initializer. + return true + } + sel := &ast.SelectorExpr{X: v.Type, Sel: key} + checkIdentObj(sel) + } } return true } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1020/sa1020.go b/vendor/honnef.co/go/tools/staticcheck/sa1020/sa1020.go index aa1aeae6..9d6256a2 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1020/sa1020.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1020/sa1020.go @@ -20,7 +20,12 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Run: callcheck.Analyzer(checkListenAddressRules), }, Doc: &lint.RawDocumentation{ - Title: `Using an invalid host:port pair with a \'net.Listen\'-related function`, + Title: `Using an invalid host:port pair with a \'net.Listen\'-related function`, + Text: `Functions such as \'net.Listen\', \'net.ListenTCP\', and similar, +expect a valid network address in the form of host:port. The host, the port, +or both, can be omitted, e.g. \'localhost:8080\', \':8080\' or \':\' are valid +host:port pairs. +See https://pkg.go.dev/net#Listen for the full documentation.`, Since: "2017.1", Severity: lint.SeverityError, MergeIf: lint.MergeIfAny, diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1025/sa1025.go b/vendor/honnef.co/go/tools/staticcheck/sa1025/sa1025.go index 9b7b6afc..2ac361ae 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1025/sa1025.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1025/sa1025.go @@ -43,7 +43,7 @@ func run(pass *analysis.Pass) (any, error) { if refs == nil { continue } - for _, ref := range irutil.FilterDebug(*refs) { + for _, ref := range *refs { ifstmt, ok := ref.(*ir.If) if !ok { continue diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1026/sa1026.go b/vendor/honnef.co/go/tools/staticcheck/sa1026/sa1026.go index 0c685c3a..0aa99fc6 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1026/sa1026.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1026/sa1026.go @@ -31,7 +31,9 @@ var Analyzer = SCAnalyzer.Analyzer var rules = map[string]callcheck.Check{ "encoding/json.Marshal": checkJSON, + "encoding/json.MarshalIndent": checkJSON, "encoding/xml.Marshal": checkXML, + "encoding/xml.MarshalIndent": checkXML, "(*encoding/json.Encoder).Encode": checkJSON, "(*encoding/xml.Encoder).Encode": checkXML, } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa1030/sa1030.go b/vendor/honnef.co/go/tools/staticcheck/sa1030/sa1030.go index 1a274ce1..05069387 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa1030/sa1030.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa1030/sa1030.go @@ -128,7 +128,7 @@ func validateFloatFormat(arg *callcheck.Argument) { switch val { case 'b', 'e', 'E', 'f', 'g', 'G', 'x', 'X': default: - arg.Invalid(fmt.Sprintf("'fmt' argument is invalid: unknown format %q", val)) + arg.Invalid(fmt.Sprintf("'fmt' argument is invalid: unknown format %q", rune(val))) } } } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa2000/sa2000.go b/vendor/honnef.co/go/tools/staticcheck/sa2000/sa2000.go index 00874292..721f269d 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa2000/sa2000.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa2000/sa2000.go @@ -19,7 +19,10 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Requires: code.RequiredAnalyzers, }, Doc: &lint.RawDocumentation{ - Title: `\'sync.WaitGroup.Add\' called inside the goroutine, leading to a race condition`, + Title: `\'(*sync.WaitGroup).Add\' called inside the goroutine, leading to a race condition`, + Text: `\'(*sync.WaitGroup).Add\' must be called before starting the goroutine +it is meant to wait for. Calling \'Add\' inside the goroutine creates a race +condition between the call to \'Add\' and the call to \'Wait\'.`, Since: "2017.1", Severity: lint.SeverityWarning, MergeIf: lint.MergeIfAny, diff --git a/vendor/honnef.co/go/tools/staticcheck/sa2001/sa2001.go b/vendor/honnef.co/go/tools/staticcheck/sa2001/sa2001.go index e248250f..5e3f83e1 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa2001/sa2001.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa2001/sa2001.go @@ -7,7 +7,6 @@ import ( "honnef.co/go/tools/analysis/code" "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" - "honnef.co/go/tools/go/ast/astutil" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -67,7 +66,7 @@ func run(pass *analysis.Pass) (any, error) { if !ok { return nil, "", false } - call, ok := astutil.Unparen(expr.X).(*ast.CallExpr) + call, ok := ast.Unparen(expr.X).(*ast.CallExpr) if !ok { return nil, "", false } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa2003/sa2003.go b/vendor/honnef.co/go/tools/staticcheck/sa2003/sa2003.go index a7163493..c6fb7f0f 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa2003/sa2003.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa2003/sa2003.go @@ -20,7 +20,19 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Requires: []*analysis.Analyzer{buildir.Analyzer}, }, Doc: &lint.RawDocumentation{ - Title: `Deferred \'Lock\' right after locking, likely meant to defer \'Unlock\' instead`, + Title: `Deferred \'Lock\' right after locking, likely meant to defer \'Unlock\' instead`, + Text: `Deferring a call to \'Lock\' immediately after locking is almost always +a typo. For example: + + mu.Lock() + defer mu.Lock() + +While this does not strictly guarantee a deadlock depending on how the +surrounding code is structured, it is highly likely to be a mistake. +The intended code was likely this: + + mu.Lock() + defer mu.Unlock()`, Since: "2017.1", Severity: lint.SeverityWarning, MergeIf: lint.MergeIfAny, @@ -32,7 +44,7 @@ var Analyzer = SCAnalyzer.Analyzer func run(pass *analysis.Pass) (any, error) { for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { for _, block := range fn.Blocks { - instrs := irutil.FilterDebug(block.Instrs) + instrs := block.Instrs if len(instrs) < 2 { continue } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4003/sa4003.go b/vendor/honnef.co/go/tools/staticcheck/sa4003/sa4003.go index a399c338..eb36c418 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4003/sa4003.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4003/sa4003.go @@ -49,12 +49,10 @@ func run(pass *analysis.Pass) (any, error) { fn := func(node ast.Node) { expr := node.(*ast.BinaryExpr) tx := pass.TypesInfo.TypeOf(expr.X) - basic, ok := tx.Underlying().(*types.Basic) - if !ok { - return - } + tset := typeutil.NewTypeSet(tx) - // We only check for the math constants and integer literals, not for all constant expressions. This is to avoid + // We only check for the math constants and integer literals, not for + // all constant expressions. This is to avoid // false positives when constant values differ under different build tags. var ( maxMathConst string @@ -63,6 +61,54 @@ func run(pass *analysis.Pass) (any, error) { minLiteral constant.Value ) + allUnsigned := tset.All(func(t *types.Term) bool { + if basic, ok := t.Type().Underlying().(*types.Basic); ok { + return basic.Info()&types.IsUnsigned != 0 + } + return false + }) + + if allUnsigned { + isZeroLiteral := func(expr ast.Expr) bool { + return code.IsIntegerLiteral(pass, expr, constant.MakeInt64(0)) + } + if (expr.Op == token.LSS && isZeroLiteral(expr.Y)) || + (expr.Op == token.GTR && isZeroLiteral(expr.X)) { + report.Report( + pass, + expr, + fmt.Sprintf("no value of type %s is less than 0", tx), + report.FilterGenerated(), + ) + } + if expr.Op == token.GEQ && isZeroLiteral(expr.Y) || + expr.Op == token.LEQ && isZeroLiteral(expr.X) { + report.Report( + pass, + expr, + fmt.Sprintf("every value of type %s is >= 0", tx), + report.FilterGenerated(), + ) + } + } + + core := tset.CoreType() + if core == nil { + // All remaining checks are only relevant when the type set + // contains a single underlying type. + // + // If we had a 'var x uint8 | uint16', + // then the type checker wouldn't permit a check such as + // 'if x <= math.MaxUint16', because the constant cannot be converted to all + // types in the type set. + return + } + + basic, ok := core.(*types.Basic) + if !ok { + return + } + switch basic.Kind() { case types.Uint8: maxMathConst = "math.MaxUint8" @@ -81,7 +127,8 @@ func run(pass *analysis.Pass) (any, error) { minLiteral = constant.MakeUint64(0) maxLiteral = constant.MakeUint64(math.MaxUint64) case types.Uint: - // TODO(dh): we could chose 32 bit vs 64 bit depending on the file's build tags + // TODO(dh): we could chose 32 bit vs 64 bit depending on the + // file's build tags maxMathConst = "math.MaxUint64" minLiteral = constant.MakeUint64(0) maxLiteral = constant.MakeUint64(math.MaxUint64) @@ -107,7 +154,8 @@ func run(pass *analysis.Pass) (any, error) { minLiteral = constant.MakeInt64(math.MinInt64) maxLiteral = constant.MakeInt64(math.MaxInt64) case types.Int: - // TODO(dh): we could chose 32 bit vs 64 bit depending on the file's build tags + // TODO(dh): we could chose 32 bit vs 64 bit depending on the + // file's build tags minMathConst = "math.MinInt64" maxMathConst = "math.MaxInt64" minLiteral = constant.MakeInt64(math.MinInt64) @@ -120,37 +168,53 @@ func run(pass *analysis.Pass) (any, error) { } return code.IsIntegerLiteral(pass, expr, c) } - isZeroLiteral := func(expr ast.Expr) bool { - return code.IsIntegerLiteral(pass, expr, constant.MakeInt64(0)) - } - if (expr.Op == token.GTR || expr.Op == token.GEQ) && (isobj(expr.Y, maxMathConst) || isLiteral(expr.Y, maxLiteral)) || - (expr.Op == token.LSS || expr.Op == token.LEQ) && (isobj(expr.X, maxMathConst) || isLiteral(expr.X, maxLiteral)) { - report.Report(pass, expr, fmt.Sprintf("no value of type %s is greater than %s", basic, maxMathConst), report.FilterGenerated()) + x, y, op := expr.X, expr.Y, expr.Op + switch op { + case token.GEQ, token.GTR: + case token.LEQ: + x, y = y, x + op = token.GEQ + case token.LSS: + x, y = y, x + op = token.GTR + default: + return } - if expr.Op == token.LEQ && (isobj(expr.Y, maxMathConst) || isLiteral(expr.Y, maxLiteral)) || - expr.Op == token.GEQ && (isobj(expr.X, maxMathConst) || isLiteral(expr.X, maxLiteral)) { - report.Report(pass, expr, fmt.Sprintf("every value of type %s is <= %s", basic, maxMathConst), report.FilterGenerated()) + if isobj(y, maxMathConst) || isLiteral(y, maxLiteral) { + report.Report( + pass, + expr, + fmt.Sprintf("no value of type %s is greater than %s", tx, maxMathConst), + report.FilterGenerated(), + ) + } + if op == token.GEQ && (isobj(x, maxMathConst) || isLiteral(x, maxLiteral)) { + report.Report( + pass, + expr, + fmt.Sprintf("every value of type %s is <= %s", tx, maxMathConst), + report.FilterGenerated(), + ) } - if (basic.Info() & types.IsUnsigned) != 0 { - if (expr.Op == token.LSS && isZeroLiteral(expr.Y)) || - (expr.Op == token.GTR && isZeroLiteral(expr.X)) { - report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than 0", basic), report.FilterGenerated()) - } - if expr.Op == token.GEQ && isZeroLiteral(expr.Y) || - expr.Op == token.LEQ && isZeroLiteral(expr.X) { - report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= 0", basic), report.FilterGenerated()) - } - } else { - if (expr.Op == token.LSS || expr.Op == token.LEQ) && (isobj(expr.Y, minMathConst) || isLiteral(expr.Y, minLiteral)) || - (expr.Op == token.GTR || expr.Op == token.GEQ) && (isobj(expr.X, minMathConst) || isLiteral(expr.X, minLiteral)) { - report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than %s", basic, minMathConst), report.FilterGenerated()) + if !allUnsigned { + if isobj(x, minMathConst) || isLiteral(x, minLiteral) { + report.Report( + pass, + expr, + fmt.Sprintf("no value of type %s is less than %s", tx, minMathConst), + report.FilterGenerated(), + ) } - if expr.Op == token.GEQ && (isobj(expr.Y, minMathConst) || isLiteral(expr.Y, minLiteral)) || - expr.Op == token.LEQ && (isobj(expr.X, minMathConst) || isLiteral(expr.X, minLiteral)) { - report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= %s", basic, minMathConst), report.FilterGenerated()) + if op == token.GEQ && (isobj(y, minMathConst) || isLiteral(y, minLiteral)) { + report.Report( + pass, + expr, + fmt.Sprintf("every value of type %s is >= %s", tx, minMathConst), + report.FilterGenerated(), + ) } } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4005/sa4005.go b/vendor/honnef.co/go/tools/staticcheck/sa4005/sa4005.go index f900ed21..c46a038e 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4005/sa4005.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4005/sa4005.go @@ -50,7 +50,7 @@ fnLoop: } recv := fn.Params[0] - refs := irutil.FilterDebug(*recv.Referrers()) + refs := *recv.Referrers() if len(refs) != 1 { continue } @@ -74,8 +74,6 @@ fnLoop: writes[ref.Field] = append(writes[ref.Field], refref) case *ir.Load: reads[ref.Field] = append(reads[ref.Field], refref) - case *ir.DebugRef: - continue default: // this should be safe… if the field address // escapes, then alloc.Heap will be true. @@ -98,8 +96,6 @@ fnLoop: for i := 0; i < recv.Type().Underlying().(*types.Struct).NumFields(); i++ { reads[i] = append(reads[i], ref) } - case *ir.DebugRef: - continue default: continue fnLoop } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4006/sa4006.go b/vendor/honnef.co/go/tools/staticcheck/sa4006/sa4006.go index dac27b75..04865002 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4006/sa4006.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4006/sa4006.go @@ -3,6 +3,7 @@ package sa4006 import ( "fmt" "go/ast" + "go/token" "honnef.co/go/tools/analysis/code" "honnef.co/go/tools/analysis/facts/generated" @@ -74,15 +75,6 @@ func run(pass *analysis.Pass) (any, error) { } for _, ref := range *refs { switch ref := ref.(type) { - case *ir.DebugRef: - case *ir.Sigma: - if seen == nil { - seen = map[ir.Value]struct{}{} - } - seen[v] = struct{}{} - if hasUse(ref, seen) { - return true - } case *ir.Phi: if seen == nil { seen = map[ir.Value]struct{}{} @@ -99,6 +91,22 @@ func run(pass *analysis.Pass) (any, error) { } ast.Inspect(node, func(node ast.Node) bool { + inc, ok := node.(*ast.IncDecStmt) + if ok { + val, _ := fn.ValueForExpr(inc.X) + if val == nil { + return true + } + if _, ok := val.(*ir.Const); ok { + // a zero-valued constant, for example in 'foo := []string(nil)' + return true + } + if !hasUse(val, nil) { + report.Report(pass, inc, fmt.Sprintf("this value of %s is never used", inc.X)) + } + return true + } + assign, ok := node.(*ast.AssignStmt) if !ok { return true @@ -137,7 +145,12 @@ func run(pass *analysis.Pass) (any, error) { } val, _ := fn.ValueForExpr(rhs) if val == nil { - continue + if assign.Tok != token.ASSIGN { // +=, *=, etc. + val, _ = fn.ValueForExpr(lhs) + } + if val == nil { + continue + } } if _, ok := val.(*ir.Const); ok { diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4008/sa4008.go b/vendor/honnef.co/go/tools/staticcheck/sa4008/sa4008.go index 41c56e35..f6c89eee 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4008/sa4008.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4008/sa4008.go @@ -82,23 +82,9 @@ func run(pass *analysis.Pass) (any, error) { if v == nil || isAddr { return true } - switch v := v.(type) { + switch v.(type) { case *ir.Phi: - ops := v.Operands(nil) - if len(ops) != 2 { - return true - } - _, ok := (*ops[0]).(*ir.Const) - if !ok { - return true - } - sigma, ok := (*ops[1]).(*ir.Sigma) - if !ok { - return true - } - if sigma.X != v { - return true - } + return true case *ir.Load: return true } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4009/sa4009.go b/vendor/honnef.co/go/tools/staticcheck/sa4009/sa4009.go index 8ae8dd27..7c94d5e3 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4009/sa4009.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4009/sa4009.go @@ -7,7 +7,6 @@ import ( "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" "honnef.co/go/tools/go/ir" - "honnef.co/go/tools/go/ir/irutil" "honnef.co/go/tools/internal/passes/buildir" "golang.org/x/tools/go/analysis" @@ -65,7 +64,7 @@ func run(pass *analysis.Pass) (any, error) { if refs == nil { continue } - if len(irutil.FilterDebug(*refs)) != 0 { + if len(*refs) != 0 { continue } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4010/sa4010.go b/vendor/honnef.co/go/tools/staticcheck/sa4010/sa4010.go index 2e11e6f2..f445aa7c 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4010/sa4010.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4010/sa4010.go @@ -16,7 +16,10 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Requires: []*analysis.Analyzer{buildir.Analyzer}, }, Doc: &lint.RawDocumentation{ - Title: `The result of \'append\' will never be observed anywhere`, + Title: `The result of \'append\' will never be observed anywhere`, + Text: `Calls to \'append\' produce a new slice value. When the result of +\'append\' is assigned to a variable that is never subsequently read, the +append operation may have an unintended effect.`, Since: "2017.1", Severity: lint.SeverityWarning, MergeIf: lint.MergeIfAll, @@ -54,7 +57,6 @@ func run(pass *analysis.Pass) (any, error) { // This graph must only consist of the following instructions: // // - phi - // - sigma // - slice // - const nil // - MakeSlice @@ -62,8 +64,7 @@ func run(pass *analysis.Pass) (any, error) { // - calls to append // // If this step succeeds, we look at all referrers of the values found in the first step, recursively. - // These referrers must either be in the set of values found in the first step, - // be DebugRefs, + // These referrers must either be in the set of values found in the first step // or fulfill the same type requirements as step 1, with the exception of appends, which are forbidden. // // If both steps succeed then we know that the backing array hasn't been aliased in an observable manner. @@ -90,8 +91,6 @@ func run(pass *analysis.Pass) (any, error) { } } return true - case *ir.Sigma: - return validateArgument(v.X, seen) case *ir.Slice: return validateArgument(v.X, seen) case *ir.Const: @@ -112,28 +111,27 @@ func run(pass *analysis.Pass) (any, error) { var validateReferrers func(v ir.Value, seen map[ir.Instruction]struct{}) bool validateReferrers = func(v ir.Value, seen map[ir.Instruction]struct{}) bool { - for _, ref := range *v.Referrers() { - if _, ok := seen[ref]; ok { - continue - } - - seen[ref] = struct{}{} - switch ref.(type) { - case *ir.Phi: - case *ir.Sigma: - case *ir.Slice: - case *ir.Const: - case *ir.MakeSlice: - case *ir.Alloc: - case *ir.DebugRef: - default: - return false - } + if refs := v.Referrers(); refs != nil { + for _, ref := range *refs { + if _, ok := seen[ref]; ok { + continue + } - if ref, ok := ref.(ir.Value); ok { - if !validateReferrers(ref, seen) { + seen[ref] = struct{}{} + switch ref.(type) { + case *ir.Phi: + case *ir.Slice: + case *ir.MakeSlice: + case *ir.Alloc: + default: return false } + + if ref, ok := ref.(ir.Value); ok { + if !validateReferrers(ref, seen) { + return false + } + } } } return true @@ -157,14 +155,9 @@ func run(pass *analysis.Pass) (any, error) { continue } visited[ref] = true - if _, ok := ref.(*ir.DebugRef); ok { - continue - } switch ref := ref.(type) { case *ir.Phi: walkRefs(*ref.Referrers()) - case *ir.Sigma: - walkRefs(*ref.Referrers()) case ir.Value: if !isAppend(ref) { isUsed = true @@ -195,8 +188,9 @@ func run(pass *analysis.Pass) (any, error) { seen2 := map[ir.Instruction]struct{}{} for k := range seen { - // the only values we allow are also instructions, so this type assertion cannot fail - seen2[k.(ir.Instruction)] = struct{}{} + if k, ok := k.(ir.Instruction); ok { + seen2[k] = struct{}{} + } } seen2[ins] = struct{}{} failed := false diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4017/sa4017.go b/vendor/honnef.co/go/tools/staticcheck/sa4017/sa4017.go index 6177d17e..8302249f 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4017/sa4017.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4017/sa4017.go @@ -9,7 +9,6 @@ import ( "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" "honnef.co/go/tools/go/ir" - "honnef.co/go/tools/go/ir/irutil" "honnef.co/go/tools/go/types/typeutil" "honnef.co/go/tools/internal/passes/buildir" @@ -60,7 +59,7 @@ fnLoop: continue } refs := ins.Referrers() - if refs == nil || len(irutil.FilterDebug(*refs)) > 0 { + if refs == nil || len(*refs) > 0 { continue } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4023/sa4023.go b/vendor/honnef.co/go/tools/staticcheck/sa4023/sa4023.go index 4ab13c83..3f1e866f 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4023/sa4023.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4023/sa4023.go @@ -7,7 +7,6 @@ import ( "honnef.co/go/tools/analysis/code" "honnef.co/go/tools/analysis/facts/nilness" - "honnef.co/go/tools/analysis/facts/typedness" "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" "honnef.co/go/tools/go/ir" @@ -23,7 +22,7 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Analyzer: &analysis.Analyzer{ Name: "SA4023", Run: run, - Requires: []*analysis.Analyzer{buildir.Analyzer, typedness.Analysis, nilness.Analysis}, + Requires: []*analysis.Analyzer{buildir.Analyzer, nilness.Analysis}, }, Doc: &lint.RawDocumentation{ Title: `Impossible comparison of interface value with untyped nil`, @@ -102,8 +101,7 @@ func run(pass *analysis.Pass) (any, error) { // known typed nils, or typed unknown nilness are being returned. irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR) - typedness := pass.ResultOf[typedness.Analysis].(*typedness.Result) - nilness := pass.ResultOf[nilness.Analysis].(*nilness.Result) + nilnessRes := pass.ResultOf[nilness.Analysis].(*nilness.Result) for _, fn := range irpkg.SrcFuncs { for _, b := range fn.Blocks { for _, instr := range b.Instrs { @@ -111,17 +109,16 @@ func run(pass *analysis.Pass) (any, error) { if !ok || !(binop.Op == token.EQL || binop.Op == token.NEQ) { continue } - if _, ok := binop.X.Type().Underlying().(*types.Interface); !ok || typeparams.IsTypeParam(binop.X.Type()) { + if !types.IsInterface(binop.X.Type()) || typeparams.IsTypeParam(binop.X.Type()) { // TODO support swapped X and Y continue } k, ok := binop.Y.(*ir.Const) if !ok || !k.IsNil() { - // if binop.X is an interface, then binop.Y can - // only be a Const if its untyped. A typed nil - // constant would first be passed to - // MakeInterface. + // if binop.X is an interface, then binop.Y can only be a + // Const if its untyped. A typed nil constant would first + // be passed to MakeInterface. continue } @@ -159,8 +156,9 @@ func run(pass *analysis.Pass) (any, error) { terms, err := typeparams.NormalTerms(x.X.Type()) if len(terms) == 0 || err != nil { - // Type is a type parameter with no type terms (or we couldn't determine the terms). Such a type - // _can_ be nil when put in an interface value. + // Type is a type parameter with no type terms (or we + // couldn't determine the terms). Such a type _can_ be + // nil when put in an interface value. continue } @@ -168,8 +166,11 @@ func run(pass *analysis.Pass) (any, error) { report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier), report.Related(x.X, "the lhs of the comparison gets its value from here and has a concrete type")) } else { - // we can't generate related information for this, so make the diagnostic itself slightly more useful - report.Report(pass, binop, fmt.Sprintf("this comparison is %s true; the lhs of the comparison has been assigned a concretely typed value", qualifier)) + // we can't generate related information for this, so + // make the diagnostic itself slightly more useful + report.Report(pass, binop, + fmt.Sprintf("this comparison is %s true; the lhs of the comparison has been assigned a concretely typed value", + qualifier)) } continue } @@ -177,11 +178,13 @@ func run(pass *analysis.Pass) (any, error) { continue } - isNil, onlyGlobal := nilness.MayReturnNil(obj, idx) - if typedness.MustReturnTyped(obj, idx) && isNil && !onlyGlobal && !code.IsInTest(pass, binop) { - // Don't flag these comparisons in tests. Tests - // may be explicitly enforcing the invariant that - // a value isn't nil. + nillity := nilnessRes.Nilness(obj, idx) + if nillity.Outer == nilness.NeverNil && + !code.IsInTest(pass, binop) && + !irutil.IsTrivial(irpkg.Pkg.Prog.FuncValue(obj)) { + // Don't flag these comparisons in tests. Tests may be + // explicitly enforcing the invariant that a value isn't + // nil. var qualifier string switch binop.Op { @@ -194,8 +197,11 @@ func run(pass *analysis.Pass) (any, error) { } report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier), // TODO support swapped X and Y - report.Related(binop.X, fmt.Sprintf("the lhs of the comparison is the %s return value of this function call", report.Ordinal(idx+1))), - report.Related(obj, fmt.Sprintf("%s never returns a nil interface value", typeutil.FuncName(obj)))) + report.Related(binop.X, + fmt.Sprintf("the lhs of the comparison is the %s return value of this function call", + report.Ordinal(idx+1))), + report.Related(obj, + fmt.Sprintf("%s never returns a nil interface value", typeutil.FuncName(obj)))) } } } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa4031/sa4031.go b/vendor/honnef.co/go/tools/staticcheck/sa4031/sa4031.go index e91e5ecd..3da5ba0b 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa4031/sa4031.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa4031/sa4031.go @@ -95,8 +95,6 @@ func run(pass *analysis.Pass) (any, error) { values = append(values, v) } return neverNil(v.X, false) - case *ir.Sigma: - return neverNil(v.X, true) case *ir.Phi: for _, e := range v.Edges { if !neverNil(e, true) { diff --git a/vendor/honnef.co/go/tools/staticcheck/sa5007/sa5007.go b/vendor/honnef.co/go/tools/staticcheck/sa5007/sa5007.go index d9a1dd7e..f0819c8a 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa5007/sa5007.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa5007/sa5007.go @@ -47,16 +47,11 @@ func run(pass *analysis.Pass) (any, error) { } block := site.Block() - for _, b := range fn.Blocks { + for b := range fn.Exits() { if block.Dominates(b) { continue } - if len(b.Instrs) == 0 { - continue - } - if _, ok := b.Control().(*ir.Return); ok { - return - } + return } report.Report(pass, site, "infinite recursive call") }) diff --git a/vendor/honnef.co/go/tools/staticcheck/sa5008/jsonv2.go b/vendor/honnef.co/go/tools/staticcheck/sa5008/jsonv2.go index be5339d5..6724ae1a 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa5008/jsonv2.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa5008/jsonv2.go @@ -141,7 +141,7 @@ func validateJSONTag(pass *analysis.Pass, field *ast.Field, tag string) { report.Report(pass, field.Tag, fmt.Sprintf("invalid appearance of unknown `case:%s` tag value", rawOpt)) } - case "inline": + case "embed", "inline": case "unknown": case "omitzero": case "omitempty": diff --git a/vendor/honnef.co/go/tools/staticcheck/sa5011/sa5011.go b/vendor/honnef.co/go/tools/staticcheck/sa5011/sa5011.go deleted file mode 100644 index 7b1b1333..00000000 --- a/vendor/honnef.co/go/tools/staticcheck/sa5011/sa5011.go +++ /dev/null @@ -1,221 +0,0 @@ -package sa5011 - -import ( - "go/types" - - "honnef.co/go/tools/analysis/lint" - "honnef.co/go/tools/analysis/report" - "honnef.co/go/tools/go/ir" - "honnef.co/go/tools/go/types/typeutil" - "honnef.co/go/tools/internal/passes/buildir" - - "golang.org/x/tools/go/analysis" -) - -var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ - Analyzer: &analysis.Analyzer{ - Name: "SA5011", - Run: run, - Requires: []*analysis.Analyzer{buildir.Analyzer}, - }, - Doc: &lint.RawDocumentation{ - Title: `Possible nil pointer dereference`, - - Text: `A pointer is being dereferenced unconditionally, while -also being checked against nil in another place. This suggests that -the pointer may be nil and dereferencing it may panic. This is -commonly a result of improperly ordered code or missing return -statements. Consider the following examples: - - func fn(x *int) { - fmt.Println(*x) - - // This nil check is equally important for the previous dereference - if x != nil { - foo(*x) - } - } - - func TestFoo(t *testing.T) { - x := compute() - if x == nil { - t.Errorf("nil pointer received") - } - - // t.Errorf does not abort the test, so if x is nil, the next line will panic. - foo(*x) - } - -Staticcheck tries to deduce which functions abort control flow. -For example, it is aware that a function will not continue -execution after a call to \'panic\' or \'log.Fatal\'. However, sometimes -this detection fails, in particular in the presence of -conditionals. Consider the following example: - - func Log(msg string, level int) { - fmt.Println(msg) - if level == levelFatal { - os.Exit(1) - } - } - - func Fatal(msg string) { - Log(msg, levelFatal) - } - - func fn(x *int) { - if x == nil { - Fatal("unexpected nil pointer") - } - fmt.Println(*x) - } - -Staticcheck will flag the dereference of \'x\', even though it is perfectly -safe. Staticcheck is not able to deduce that a call to -Fatal will exit the program. For the time being, the easiest -workaround is to modify the definition of Fatal like so: - - func Fatal(msg string) { - Log(msg, levelFatal) - panic("unreachable") - } - -We also hard-code functions from common logging packages such as -logrus. Please file an issue if we're missing support for a -popular package.`, - Since: "2020.1", - Severity: lint.SeverityWarning, - MergeIf: lint.MergeIfAny, - }, -}) - -var Analyzer = SCAnalyzer.Analyzer - -func run(pass *analysis.Pass) (any, error) { - // This is an extremely trivial check that doesn't try to reason - // about control flow. That is, phis and sigmas do not propagate - // any information. As such, we can flag this: - // - // _ = *x - // if x == nil { return } - // - // but we cannot flag this: - // - // if x == nil { println(x) } - // _ = *x - // - // but we can flag this, because the if's body doesn't use x: - // - // if x == nil { println("this is bad") } - // _ = *x - // - // nor many other variations of conditional uses of or assignments to x. - // - // However, even this trivial implementation finds plenty of - // real-world bugs, such as dereference before nil pointer check, - // or using t.Error instead of t.Fatal when encountering nil - // pointers. - // - // On the flip side, our naive implementation avoids false positives in branches, such as - // - // if x != nil { _ = *x } - // - // due to the same lack of propagating information through sigma - // nodes. x inside the branch will be independent of the x in the - // nil pointer check. - // - // - // We could implement a more powerful check, but then we'd be - // getting false positives instead of false negatives because - // we're incapable of deducing relationships between variables. - // For example, a function might return a pointer and an error, - // and the error being nil guarantees that the pointer is not nil. - // Depending on the surrounding code, the pointer may still end up - // being checked against nil in one place, and guarded by a check - // on the error in another, which would lead to us marking some - // loads as unsafe. - // - // Unfortunately, simply hard-coding the relationship between - // return values wouldn't eliminate all false positives, either. - // Many other more subtle relationships exist. An abridged example - // from real code: - // - // if a == nil && b == nil { return } - // c := fn(a) - // if c != "" { _ = *a } - // - // where `fn` is guaranteed to return a non-empty string if a - // isn't nil. - // - // We choose to err on the side of false negatives. - - isNilConst := func(v ir.Value) bool { - if typeutil.IsPointerLike(v.Type()) { - if k, ok := v.(*ir.Const); ok { - return k.IsNil() - } - } - return false - } - - for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { - maybeNil := map[ir.Value]ir.Instruction{} - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - // Originally we looked at all ir.BinOp, but that would lead to calls like 'assert(x != nil)' causing false positives. - // Restrict ourselves to actual if statements, as these are more likely to affect control flow in a way we can observe. - if instr, ok := instr.(*ir.If); ok { - if cond, ok := instr.Cond.(*ir.BinOp); ok { - if isNilConst(cond.X) { - maybeNil[cond.Y] = cond - } - if isNilConst(cond.Y) { - maybeNil[cond.X] = cond - } - } - } - } - } - - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - var ptr ir.Value - switch instr := instr.(type) { - case *ir.Load: - ptr = instr.X - case *ir.Store: - ptr = instr.Addr - case *ir.IndexAddr: - ptr = instr.X - if typeutil.All(ptr.Type(), func(term *types.Term) bool { - if _, ok := term.Type().Underlying().(*types.Slice); ok { - return true - } - return false - }) { - // indexing a nil slice does not cause a nil pointer panic - // - // Note: This also works around the bad lowering of range loops over slices - // (https://github.com/dominikh/go-tools/issues/1053) - continue - } - case *ir.FieldAddr: - ptr = instr.X - } - if ptr != nil { - switch ptr.(type) { - case *ir.Alloc, *ir.FieldAddr, *ir.IndexAddr: - // these cannot be nil - continue - } - if r, ok := maybeNil[ptr]; ok { - report.Report(pass, instr, "possible nil pointer dereference", - report.Related(r, "this check suggests that the pointer can be nil")) - } - } - } - } - } - - return nil, nil -} diff --git a/vendor/honnef.co/go/tools/staticcheck/sa5012/sa5012.go b/vendor/honnef.co/go/tools/staticcheck/sa5012/sa5012.go index 4c391198..51dc39fc 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa5012/sa5012.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa5012/sa5012.go @@ -12,6 +12,7 @@ import ( "honnef.co/go/tools/go/ir" "honnef.co/go/tools/go/ir/irutil" "honnef.co/go/tools/go/types/typeutil" + "honnef.co/go/tools/internal/iterutil" "honnef.co/go/tools/internal/passes/buildir" "golang.org/x/tools/go/analysis" @@ -140,7 +141,7 @@ func findSliceLenChecks(pass *analysis.Pass) { for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { for _, b := range fn.Blocks { // all paths go through this block - if !b.Dominates(fn.Exit) { + if !iterutil.All(fn.Returns(), b.Dominates) { continue } @@ -220,7 +221,7 @@ func findIndirectSliceLenChecks(pass *analysis.Pass) { for _, b := range fn.Blocks { // all paths go through this block - if !b.Dominates(fn.Exit) { + if !iterutil.All(fn.Returns(), b.Dominates) { continue } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa6001/sa6001.go b/vendor/honnef.co/go/tools/staticcheck/sa6001/sa6001.go index 9a1c86ab..c164967d 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa6001/sa6001.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa6001/sa6001.go @@ -85,25 +85,18 @@ func run(pass *analysis.Pass) (any, error) { continue } refs := ins.Referrers() - // need at least two (DebugRef) references: the - // conversion and the *ast.Ident - if refs == nil || len(*refs) < 2 { - continue - } - ident := false - // skip first reference, that's the conversion itself - for _, ref := range (*refs)[1:] { + anyUses := false + for _, ref := range *refs { switch ref := ref.(type) { - case *ir.DebugRef: - if _, ok := ref.Expr.(*ast.Ident); !ok { - // the string seems to be used somewhere - // unexpected; the default branch should - // catch this already, but be safe - continue insLoop + case *ir.MapLookup: + anyUses = true + if src, ok := ref.Source().(*ast.IndexExpr); ok { + if _, ok := src.Index.(*ast.Ident); !ok { + continue insLoop + } } else { - ident = true + continue insLoop } - case *ir.MapLookup: default: // the string is used somewhere else than a // map lookup @@ -111,9 +104,7 @@ func run(pass *analysis.Pass) (any, error) { } } - // the result of the conversion wasn't assigned to an - // identifier - if !ident { + if !anyUses { continue } report.Report(pass, ins, "m[string(key)] would be more efficient than k := string(key); m[k]") diff --git a/vendor/honnef.co/go/tools/staticcheck/sa6005/sa6005.go b/vendor/honnef.co/go/tools/staticcheck/sa6005/sa6005.go index 387875a7..05cfc1cd 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa6005/sa6005.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa6005/sa6005.go @@ -1,6 +1,7 @@ package sa6005 import ( + "fmt" "go/ast" "go/token" @@ -60,16 +61,18 @@ var ( func run(pass *analysis.Pass) (any, error) { for node, m := range code.Matches(pass, checkToLowerToUpperComparisonQ) { rn := pattern.NodeToAST(checkToLowerToUpperComparisonR.Root, m.State).(ast.Expr) + method := "strings.EqualFold" if m.State["tok"].(token.Token) == token.NEQ { rn = &ast.UnaryExpr{ Op: token.NOT, X: rn, } + method = "!" + method } report.Report(pass, node, - "should use strings.EqualFold instead", - report.Fixes(edit.Fix("Replace with strings.EqualFold", edit.ReplaceWithNode(pass.Fset, node, rn)))) + fmt.Sprintf("should use %s instead", method), + report.Fixes(edit.Fix("replace with "+method, edit.ReplaceWithNode(pass.Fset, node, rn)))) } return nil, nil } diff --git a/vendor/honnef.co/go/tools/staticcheck/sa9005/sa9005.go b/vendor/honnef.co/go/tools/staticcheck/sa9005/sa9005.go index 94c1f5dc..d367ecd6 100644 --- a/vendor/honnef.co/go/tools/staticcheck/sa9005/sa9005.go +++ b/vendor/honnef.co/go/tools/staticcheck/sa9005/sa9005.go @@ -50,7 +50,9 @@ var rules = map[string]callcheck.Check{ // // Also, should we flag gob? "encoding/json.Marshal": check(knowledge.Arg("json.Marshal.v"), "MarshalJSON", "MarshalText"), + "encoding/json.MarshalIndent": check(knowledge.Arg("json.MarshalIndent.v"), "MarshalJSON", "MarshalText"), "encoding/xml.Marshal": check(knowledge.Arg("xml.Marshal.v"), "MarshalXML", "MarshalText"), + "encoding/xml.MarshalIndent": check(knowledge.Arg("xml.MarshalIndent.v"), "MarshalXML", "MarshalText"), "(*encoding/json.Encoder).Encode": check(knowledge.Arg("(*encoding/json.Encoder).Encode.v"), "MarshalJSON", "MarshalText"), "(*encoding/xml.Encoder).Encode": check(knowledge.Arg("(*encoding/xml.Encoder).Encode.v"), "MarshalXML", "MarshalText"), diff --git a/vendor/honnef.co/go/tools/staticcheck/sa9010/sa9010.go b/vendor/honnef.co/go/tools/staticcheck/sa9010/sa9010.go new file mode 100644 index 00000000..c171ba1b --- /dev/null +++ b/vendor/honnef.co/go/tools/staticcheck/sa9010/sa9010.go @@ -0,0 +1,60 @@ +package sa9010 + +import ( + "go/ast" + "go/types" + + "honnef.co/go/tools/analysis/code" + "honnef.co/go/tools/analysis/lint" + "honnef.co/go/tools/analysis/report" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" +) + +var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ + Analyzer: &analysis.Analyzer{ + Name: "SA9010", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + }, + Doc: &lint.RawDocumentation{ + Title: `Returned function should be called in defer`, + Text: ` +If you have a function such as: + + func f() func() { + // Do something. + return func() { + // Do something. + } + } + +Then calling that in defer: + + defer f() + +Is almost always a mistake, since you typically want to call the returned +function: + + defer f()() +`, + Since: "2026.2", + Severity: lint.SeverityWarning, + MergeIf: lint.MergeIfAll, + }, +}) + +var Analyzer = SCAnalyzer.Analyzer + +func run(pass *analysis.Pass) (any, error) { + fn := func(n ast.Node) { + def := n.(*ast.DeferStmt) + if _, ok := pass.TypesInfo.TypeOf(def.Call).Underlying().(*types.Signature); ok { + report.Report(pass, def, "deferred return function not called") + } + } + + code.Preorder(pass, fn, (*ast.DeferStmt)(nil)) + return nil, nil +} diff --git a/vendor/honnef.co/go/tools/unused/implements.go b/vendor/honnef.co/go/tools/unused/implements.go index 1207e4a8..f7c37966 100644 --- a/vendor/honnef.co/go/tools/unused/implements.go +++ b/vendor/honnef.co/go/tools/unused/implements.go @@ -2,6 +2,8 @@ package unused import ( "go/types" + + "honnef.co/go/tools/go/types/typeutil" ) // lookupMethod returns the index of and method with matching package and name, or (-1, nil). @@ -61,7 +63,8 @@ func implements(V types.Type, T *types.Interface, msV *types.MethodSet) ([]*type // A concrete type implements T if it implements all methods of T. var sels []*types.Selection - var c methodsChecker + + mapping := map[*types.TypeParam]types.Type{} for m := range T.Methods() { sel := msV.Lookup(m.Pkg(), m.Name()) if sel == nil { @@ -73,77 +76,27 @@ func implements(V types.Type, T *types.Interface, msV *types.MethodSet) ([]*type return nil, false } - if !c.methodIsCompatible(f, m) { + if ok := typeutil.Unify(f.Type(), m.Type(), mapping); !ok { return nil, false } sels = append(sels, sel) } - return sels, true -} - -type methodsChecker struct { - typeParams map[*types.TypeParam]types.Type -} - -// Currently, this doesn't support methods like `foo(x []T)`. -func (c *methodsChecker) methodIsCompatible(implFunc *types.Func, interfaceFunc *types.Func) bool { - if types.Identical(implFunc.Type(), interfaceFunc.Type()) { - return true - } - implSig, implOk := implFunc.Type().(*types.Signature) - interfaceSig, interfaceOk := interfaceFunc.Type().(*types.Signature) - if !implOk || !interfaceOk { - // probably not reachable. handle conservatively. - return false - } - - if !c.typesAreCompatible(implSig.Params(), interfaceSig.Params()) { - return false - } - - if !c.typesAreCompatible(implSig.Results(), interfaceSig.Results()) { - return false - } - - return true -} - -func (c *methodsChecker) typesAreCompatible(implTypes, interfaceTypes *types.Tuple) bool { - if implTypes.Len() != interfaceTypes.Len() { - return false - } - for i := 0; i < implTypes.Len(); i++ { - if !c.typeIsCompatible(implTypes.At(i).Type(), interfaceTypes.At(i).Type()) { - return false + for tparam, targ := range mapping { + // This checks constraints on a best-effort basis, erring on the side + // of accepting too many types. + if !satisfiesConstraint(targ, tparam) { + return nil, false } } - return true + return sels, true } -func (c *methodsChecker) typeIsCompatible(implType, interfaceType types.Type) bool { - if types.Identical(implType, interfaceType) { - return true - } - // We only support trivial use of type parameters. This isn't fully compatible with compiler type checking yet. - tp, ok := interfaceType.(*types.TypeParam) - if !ok { - return false - } - if c.typeParams == nil { - c.typeParams = make(map[*types.TypeParam]types.Type) - } - if c.typeParams[tp] == nil { - if !satisfiesConstraint(implType, tp) { - return false - } - c.typeParams[tp] = implType +func satisfiesConstraint(t types.Type, tp *types.TypeParam) bool { + if t == nil { + // t is nil when we unify two type parameters. return true } - return types.Identical(c.typeParams[tp], implType) -} - -func satisfiesConstraint(t types.Type, tp *types.TypeParam) bool { bound := tp.Constraint().Underlying().(*types.Interface) return types.Satisfies(t, bound) } diff --git a/vendor/honnef.co/go/tools/unused/unused.go b/vendor/honnef.co/go/tools/unused/unused.go index 99060a35..fd7b5c04 100644 --- a/vendor/honnef.co/go/tools/unused/unused.go +++ b/vendor/honnef.co/go/tools/unused/unused.go @@ -748,6 +748,20 @@ func (g *graph) read(node ast.Node, by types.Object) { g.read(kv.Value, by) } } + if g.opts.FieldWritesAreUses && !unkeyed { + for _, elt := range node.Elts { + kv := elt.(*ast.KeyValueExpr) + fname := kv.Key.(*ast.Ident).Name + _, index, _ := types.LookupFieldOrMethod(typ, true, g.pkg, fname) + + cur := typ + for _, step := range index[:len(index)-1] { + field := cur.Field(step) + g.use(field, by) + cur = typeutil.CoreType(field.Type()).(*types.Struct) + } + } + } } else { for _, elt := range node.Elts { g.read(elt, by) @@ -1340,7 +1354,7 @@ func (g *graph) stmt(stmt ast.Stmt, by types.Object) { g.read(comm.Chan, by) g.read(comm.Value, by) case *ast.ExprStmt: - g.read(astutil.Unparen(comm.X).(*ast.UnaryExpr).X, by) + g.read(ast.Unparen(comm.X).(*ast.UnaryExpr).X, by) case *ast.AssignStmt: for _, lhs := range comm.Lhs { g.write(lhs, by) diff --git a/vendor/modules.txt b/vendor/modules.txt index e197e28c..afa94ce7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,10 +1,10 @@ -# 4d63.com/gocheckcompilerdirectives v1.3.0 +# 4d63.com/gocheckcompilerdirectives v1.4.0 ## explicit; go 1.22.0 4d63.com/gocheckcompilerdirectives/checkcompilerdirectives # 4d63.com/gochecknoglobals v0.2.2 ## explicit; go 1.18 4d63.com/gochecknoglobals/checknoglobals -# charm.land/lipgloss/v2 v2.0.3 +# charm.land/lipgloss/v2 v2.0.6 ## explicit; go 1.25.0 charm.land/lipgloss/v2 # code.cloudfoundry.org/credhub-cli v0.0.0-20260727130059-9e78db728bcf @@ -32,27 +32,35 @@ dev.gaijin.team/go/exhaustruct/v4/analyzer dev.gaijin.team/go/exhaustruct/v4/internal/comment dev.gaijin.team/go/exhaustruct/v4/internal/pattern dev.gaijin.team/go/exhaustruct/v4/internal/structure -# dev.gaijin.team/go/golib v0.6.0 +# dev.gaijin.team/go/exhaustruct/v5 v5.0.3 +## explicit; go 1.24.0 +dev.gaijin.team/go/exhaustruct/v5/analyzer +dev.gaijin.team/go/exhaustruct/v5/internal/astutil +dev.gaijin.team/go/exhaustruct/v5/internal/cache +dev.gaijin.team/go/exhaustruct/v5/internal/directive +dev.gaijin.team/go/exhaustruct/v5/internal/pattern +dev.gaijin.team/go/exhaustruct/v5/internal/structure +# dev.gaijin.team/go/golib v0.8.1 ## explicit; go 1.24 dev.gaijin.team/go/golib/e dev.gaijin.team/go/golib/fields # github.com/4meepo/tagalign v1.4.3 ## explicit; go 1.22.0 github.com/4meepo/tagalign -# github.com/Abirdcfly/dupword v0.1.7 -## explicit; go 1.24.0 +# github.com/Abirdcfly/dupword v0.1.8 +## explicit; go 1.25.0 github.com/Abirdcfly/dupword # github.com/AdminBenni/iota-mixing v1.0.0 ## explicit; go 1.23.3 github.com/AdminBenni/iota-mixing/pkg/analyzer github.com/AdminBenni/iota-mixing/pkg/analyzer/flags -# github.com/AlwxSin/noinlineerr v1.0.5 +# github.com/AlwxSin/noinlineerr v1.0.6 ## explicit; go 1.23.0 github.com/AlwxSin/noinlineerr -# github.com/Antonboom/errname v1.1.1 -## explicit; go 1.23.0 +# github.com/Antonboom/errname v1.1.2 +## explicit; go 1.24.0 github.com/Antonboom/errname/pkg/analyzer -# github.com/Antonboom/nilnil v1.1.1 +# github.com/Antonboom/nilnil v1.1.2 ## explicit; go 1.24.0 github.com/Antonboom/nilnil/pkg/analyzer # github.com/Antonboom/testifylint v1.6.4 @@ -100,7 +108,7 @@ github.com/Azure/go-autorest/tracing ## explicit; go 1.18 github.com/BurntSushi/toml github.com/BurntSushi/toml/internal -# github.com/ClickHouse/clickhouse-go-linter v1.2.0 +# github.com/ClickHouse/clickhouse-go-linter v1.2.1 ## explicit; go 1.24.0 github.com/ClickHouse/clickhouse-go-linter/internal/util github.com/ClickHouse/clickhouse-go-linter/passes/chbatchclose @@ -131,8 +139,8 @@ github.com/OpenPeeDeeP/depguard/v2/internal/utils # github.com/agext/levenshtein v1.2.3 ## explicit github.com/agext/levenshtein -# github.com/alecthomas/chroma/v2 v2.24.1 -## explicit; go 1.22 +# github.com/alecthomas/chroma/v2 v2.27.0 +## explicit; go 1.25 github.com/alecthomas/chroma/v2 github.com/alecthomas/chroma/v2/formatters github.com/alecthomas/chroma/v2/formatters/html @@ -305,8 +313,8 @@ github.com/blizzy78/varnamelen # github.com/bombsimon/wsl/v4 v4.7.0 ## explicit; go 1.23 github.com/bombsimon/wsl/v4 -# github.com/bombsimon/wsl/v5 v5.8.0 -## explicit; go 1.25.0 +# github.com/bombsimon/wsl/v5 v5.9.0 +## explicit; go 1.26.0 github.com/bombsimon/wsl/v5 # github.com/breml/bidichk v0.3.3 ## explicit; go 1.23.0 @@ -368,8 +376,8 @@ github.com/buildpacks/pack/pkg/logging github.com/butuzov/ireturn/analyzer github.com/butuzov/ireturn/analyzer/internal/config github.com/butuzov/ireturn/analyzer/internal/types -# github.com/butuzov/mirror v1.3.0 -## explicit; go 1.19 +# github.com/butuzov/mirror v1.3.3 +## explicit; go 1.25.0 github.com/butuzov/mirror github.com/butuzov/mirror/internal/checker # github.com/catenacyber/perfsprint v0.10.1 @@ -398,10 +406,10 @@ github.com/charithe/durationcheck # github.com/charmbracelet/colorprofile v0.4.3 ## explicit; go 1.25.0 github.com/charmbracelet/colorprofile -# github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 -## explicit; go 1.24.2 +# github.com/charmbracelet/ultraviolet v0.0.0-20260811164956-006e29f97886 +## explicit; go 1.25.0 github.com/charmbracelet/ultraviolet -# github.com/charmbracelet/x/ansi v0.11.7 +# github.com/charmbracelet/x/ansi v0.11.8 ## explicit; go 1.24.2 github.com/charmbracelet/x/ansi github.com/charmbracelet/x/ansi/kitty @@ -477,9 +485,6 @@ github.com/dave/dst/decorator/resolver github.com/dave/dst/decorator/resolver/gopackages github.com/dave/dst/decorator/resolver/gotypes github.com/dave/dst/dstutil -# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc -## explicit -github.com/davecgh/go-spew/spew # github.com/denis-tingaikin/go-header v0.5.0 ## explicit; go 1.21 github.com/denis-tingaikin/go-header @@ -489,10 +494,11 @@ github.com/dimchansky/utfbom # github.com/distribution/reference v0.6.0 ## explicit; go 1.20 github.com/distribution/reference -# github.com/dlclark/regexp2 v1.12.0 -## explicit; go 1.13 -github.com/dlclark/regexp2 -github.com/dlclark/regexp2/syntax +# github.com/dlclark/regexp2/v2 v2.2.1 +## explicit; go 1.25 +github.com/dlclark/regexp2/v2 +github.com/dlclark/regexp2/v2/helpers +github.com/dlclark/regexp2/v2/syntax # github.com/docker/cli v29.6.2+incompatible ## explicit github.com/docker/cli/cli/config @@ -534,7 +540,7 @@ github.com/docker/go-metrics # github.com/docker/go-units v0.5.0 ## explicit github.com/docker/go-units -# github.com/ebitengine/purego v0.10.0 +# github.com/ebitengine/purego v0.10.2 ## explicit; go 1.18 github.com/ebitengine/purego github.com/ebitengine/purego/internal/cgo @@ -550,11 +556,11 @@ github.com/fatih/color # github.com/fatih/structtag v1.2.0 ## explicit; go 1.12 github.com/fatih/structtag -# github.com/felixge/httpsnoop v1.0.4 -## explicit; go 1.13 +# github.com/felixge/httpsnoop v1.1.0 +## explicit; go 1.25 github.com/felixge/httpsnoop -# github.com/firefart/nonamedreturns v1.0.6 -## explicit; go 1.23.0 +# github.com/firefart/nonamedreturns v1.0.8 +## explicit; go 1.25.0 github.com/firefart/nonamedreturns/analyzer # github.com/fsnotify/fsnotify v1.9.0 ## explicit; go 1.17 @@ -563,10 +569,10 @@ github.com/fsnotify/fsnotify/internal # github.com/fzipp/gocyclo v0.6.0 ## explicit; go 1.18 github.com/fzipp/gocyclo -# github.com/ghostiam/protogetter v0.3.20 -## explicit; go 1.24.0 +# github.com/ghostiam/protogetter v0.3.21 +## explicit; go 1.25.0 github.com/ghostiam/protogetter -# github.com/go-critic/go-critic v0.14.3 +# github.com/go-critic/go-critic v0.14.4 ## explicit; go 1.24.0 github.com/go-critic/go-critic/checkers github.com/go-critic/go-critic/checkers/internal/astwalk @@ -666,11 +672,12 @@ github.com/golangci/dupl/syntax/golang # github.com/golangci/go-printf-func-name v0.1.1 ## explicit; go 1.23.0 github.com/golangci/go-printf-func-name/pkg/analyzer -# github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d -## explicit; go 1.22.0 -github.com/golangci/gofmt/gofmt -# github.com/golangci/golangci-lint/v2 v2.12.2 -## explicit; go 1.25.0 +# github.com/golangci/gofmt v0.0.0-20260820135601-e84e05053792 +## explicit; go 1.26.0 +github.com/golangci/gofmt +github.com/golangci/gofmt/internal +# github.com/golangci/golangci-lint/v2 v2.13.1 +## explicit; go 1.26.0 github.com/golangci/golangci-lint/v2/cmd/golangci-lint github.com/golangci/golangci-lint/v2/internal/cache github.com/golangci/golangci-lint/v2/internal/errorutil @@ -964,7 +971,7 @@ github.com/inconshreveable/mousetrap ## explicit; go 1.18 github.com/jarcoal/httpmock github.com/jarcoal/httpmock/internal -# github.com/jgautheron/goconst v1.10.0 +# github.com/jgautheron/goconst v1.11.0 ## explicit; go 1.23 github.com/jgautheron/goconst # github.com/jjti/go-spancheck v0.6.5 @@ -976,8 +983,8 @@ github.com/julz/importas # github.com/karamaru-alpha/copyloopvar v1.2.2 ## explicit; go 1.24.0 github.com/karamaru-alpha/copyloopvar -# github.com/kisielk/errcheck v1.10.0 -## explicit; go 1.22.0 +# github.com/kisielk/errcheck v1.20.0 +## explicit; go 1.25.0 github.com/kisielk/errcheck/errcheck # github.com/kkHAIKE/contextcheck v1.1.6 ## explicit; go 1.23.0 @@ -1004,8 +1011,8 @@ github.com/lasiar/canonicalheader # github.com/ldez/exptostd v0.4.5 ## explicit; go 1.24.0 github.com/ldez/exptostd -# github.com/ldez/gomoddirectives v0.8.0 -## explicit; go 1.24.0 +# github.com/ldez/gomoddirectives v0.9.0 +## explicit; go 1.25.0 github.com/ldez/gomoddirectives # github.com/ldez/grignotin v0.10.1 ## explicit; go 1.24.0 @@ -1028,7 +1035,7 @@ github.com/leonklingele/grouper/pkg/analyzer/globals github.com/leonklingele/grouper/pkg/analyzer/imports github.com/leonklingele/grouper/pkg/analyzer/types github.com/leonklingele/grouper/pkg/analyzer/vars -# github.com/lucasb-eyer/go-colorful v1.4.0 +# github.com/lucasb-eyer/go-colorful v1.4.1 ## explicit; go 1.12 github.com/lucasb-eyer/go-colorful # github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 @@ -1063,7 +1070,7 @@ github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.24 ## explicit; go 1.20 github.com/mattn/go-isatty -# github.com/mattn/go-runewidth v0.0.23 +# github.com/mattn/go-runewidth v0.0.24 ## explicit; go 1.20 github.com/mattn/go-runewidth # github.com/mgechev/revive v1.15.0 @@ -1170,8 +1177,8 @@ github.com/nishanths/exhaustive # github.com/nishanths/predeclared v0.2.2 ## explicit; go 1.14 github.com/nishanths/predeclared/passes/predeclared -# github.com/nunnatsa/ginkgolinter v0.23.0 -## explicit; go 1.25.0 +# github.com/nunnatsa/ginkgolinter v0.24.0 +## explicit; go 1.26.0 github.com/nunnatsa/ginkgolinter github.com/nunnatsa/ginkgolinter/config github.com/nunnatsa/ginkgolinter/internal/expression @@ -1235,10 +1242,10 @@ github.com/opencontainers/go-digest ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/pelletier/go-toml/v2 v2.3.1 +# github.com/pelletier/go-toml/v2 v2.4.3 ## explicit; go 1.21.0 github.com/pelletier/go-toml/v2 -github.com/pelletier/go-toml/v2/internal/characters +github.com/pelletier/go-toml/v2/internal/parserbridge github.com/pelletier/go-toml/v2/internal/tracker github.com/pelletier/go-toml/v2/unstable # github.com/pkg/errors v0.9.1 @@ -1247,9 +1254,6 @@ github.com/pkg/errors # github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 ## explicit; go 1.20 github.com/planetscale/vtprotobuf/protohelpers -# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 -## explicit -github.com/pmezard/go-difflib/difflib # github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 ## explicit; go 1.14 github.com/power-devops/perfstat @@ -1307,14 +1311,14 @@ github.com/quasilyte/regex/syntax # github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 ## explicit; go 1.17 github.com/quasilyte/stdinfo -# github.com/raeperd/recvcheck v0.2.0 -## explicit; go 1.22.0 +# github.com/raeperd/recvcheck v0.3.0 +## explicit; go 1.25.0 github.com/raeperd/recvcheck # github.com/rivo/uniseg v0.4.7 ## explicit; go 1.18 github.com/rivo/uniseg -# github.com/rogpeppe/go-internal v1.14.1 -## explicit; go 1.23 +# github.com/rogpeppe/go-internal v1.16.0 +## explicit; go 1.25 github.com/rogpeppe/go-internal/diff github.com/rogpeppe/go-internal/internal/syscall/windows github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll @@ -1339,7 +1343,7 @@ github.com/sagikazarmark/slog-shim # github.com/sanposhiho/wastedassign/v2 v2.1.0 ## explicit; go 1.18 github.com/sanposhiho/wastedassign/v2 -# github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 +# github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 ## explicit; go 1.21 github.com/santhosh-tekuri/jsonschema/v6 github.com/santhosh-tekuri/jsonschema/v6/kind @@ -1350,8 +1354,8 @@ github.com/sashamelentyev/interfacebloat/pkg/analyzer ## explicit; go 1.23.0 github.com/sashamelentyev/usestdlibvars/pkg/analyzer github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping -# github.com/securego/gosec/v2 v2.26.1 -## explicit; go 1.25.0 +# github.com/securego/gosec/v2 v2.28.0 +## explicit; go 1.25.8 github.com/securego/gosec/v2 github.com/securego/gosec/v2/analyzers github.com/securego/gosec/v2/cwe @@ -1359,7 +1363,7 @@ github.com/securego/gosec/v2/internal/ssautil github.com/securego/gosec/v2/issue github.com/securego/gosec/v2/rules github.com/securego/gosec/v2/taint -# github.com/shirou/gopsutil/v4 v4.26.5 +# github.com/shirou/gopsutil/v4 v4.26.7 ## explicit; go 1.24.0 github.com/shirou/gopsutil/v4/common github.com/shirou/gopsutil/v4/cpu @@ -1367,8 +1371,8 @@ github.com/shirou/gopsutil/v4/internal/common github.com/shirou/gopsutil/v4/mem github.com/shirou/gopsutil/v4/net github.com/shirou/gopsutil/v4/process -# github.com/sirupsen/logrus v1.9.4 -## explicit; go 1.17 +# github.com/sirupsen/logrus v1.10.1 +## explicit; go 1.23 github.com/sirupsen/logrus # github.com/sivchari/containedctx v1.0.3 ## explicit; go 1.17 @@ -1420,10 +1424,12 @@ github.com/stbenjam/no-sprintf-host-port/pkg/analyzer # github.com/stretchr/objx v0.5.3 ## explicit; go 1.20 github.com/stretchr/objx -# github.com/stretchr/testify v1.11.1 +# github.com/stretchr/testify v1.12.1 ## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/assert/yaml +github.com/stretchr/testify/internal/difflib +github.com/stretchr/testify/internal/spew github.com/stretchr/testify/mock github.com/stretchr/testify/require # github.com/subosito/gotenv v1.6.0 @@ -1479,13 +1485,14 @@ github.com/ultraware/whitespace # github.com/uudashr/gocognit v1.2.1 ## explicit; go 1.24.0 github.com/uudashr/gocognit -# github.com/uudashr/iface v1.4.2 +# github.com/uudashr/iface v1.5.0 ## explicit; go 1.23.0 github.com/uudashr/iface/identical github.com/uudashr/iface/internal/directive github.com/uudashr/iface/opaque github.com/uudashr/iface/unexported github.com/uudashr/iface/unused +github.com/uudashr/iface/unusedmethod # github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb ## explicit # github.com/xen0n/gosmopolitan v1.3.0 @@ -1520,14 +1527,14 @@ go-simpler.org/sloglint # go.augendre.info/arangolint v0.4.0 ## explicit; go 1.24.0 go.augendre.info/arangolint/pkg/analyzer -# go.augendre.info/fatcontext v0.9.0 -## explicit; go 1.23.0 +# go.augendre.info/fatcontext v0.10.0 +## explicit; go 1.25.0 go.augendre.info/fatcontext/pkg/analyzer # go.opentelemetry.io/auto/sdk v1.2.1 ## explicit; go 1.24.0 go.opentelemetry.io/auto/sdk go.opentelemetry.io/auto/sdk/internal/telemetry -# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 +# go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 ## explicit; go 1.25.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request @@ -1545,9 +1552,8 @@ go.opentelemetry.io/otel/internal/errorhandler go.opentelemetry.io/otel/internal/global go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/semconv/v1.37.0 -go.opentelemetry.io/otel/semconv/v1.40.0 -go.opentelemetry.io/otel/semconv/v1.40.0/httpconv go.opentelemetry.io/otel/semconv/v1.41.0 +go.opentelemetry.io/otel/semconv/v1.41.0/httpconv # go.opentelemetry.io/otel/metric v1.44.0 ## explicit; go 1.25.0 go.opentelemetry.io/otel/metric @@ -1579,7 +1585,7 @@ go.yaml.in/yaml/v2 # go.yaml.in/yaml/v3 v3.0.5 ## explicit; go 1.16 go.yaml.in/yaml/v3 -# golang.org/x/crypto v0.54.0 +# golang.org/x/crypto v0.55.0 ## explicit; go 1.25.0 golang.org/x/crypto/blowfish golang.org/x/crypto/chacha20 @@ -1598,17 +1604,17 @@ golang.org/x/exp/slices golang.org/x/exp/slog golang.org/x/exp/slog/internal golang.org/x/exp/slog/internal/buffer -# golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 -## explicit; go 1.24.0 +# golang.org/x/exp/typeparams v0.0.0-20260811152304-ee035b5b010f +## explicit; go 1.25.0 golang.org/x/exp/typeparams -# golang.org/x/mod v0.38.0 +# golang.org/x/mod v0.40.0 ## explicit; go 1.25.0 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver golang.org/x/mod/sumdb/dirhash -# golang.org/x/net v0.57.0 +# golang.org/x/net v0.58.0 ## explicit; go 1.25.0 golang.org/x/net/context golang.org/x/net/html @@ -1630,7 +1636,7 @@ golang.org/x/sys/windows/registry # golang.org/x/term v0.45.0 ## explicit; go 1.25.0 golang.org/x/term -# golang.org/x/text v0.40.0 +# golang.org/x/text v0.41.0 ## explicit; go 1.25.0 golang.org/x/text/encoding golang.org/x/text/encoding/charmap @@ -1659,7 +1665,7 @@ golang.org/x/text/runes golang.org/x/text/transform golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/tools v0.48.0 +# golang.org/x/tools v0.49.0 ## explicit; go 1.25.0 golang.org/x/tools/cover golang.org/x/tools/go/analysis @@ -1748,6 +1754,7 @@ golang.org/x/tools/internal/gopathwalk golang.org/x/tools/internal/imports golang.org/x/tools/internal/modindex golang.org/x/tools/internal/moreiters +golang.org/x/tools/internal/moremaps golang.org/x/tools/internal/packagepath golang.org/x/tools/internal/packagesinternal golang.org/x/tools/internal/pkgbits @@ -1798,10 +1805,12 @@ gopkg.in/ini.v1 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# honnef.co/go/tools v0.7.0 -## explicit; go 1.25.0 +# honnef.co/go/tools v0.8.0 +## explicit; go 1.26.0 honnef.co/go/tools/analysis/callcheck honnef.co/go/tools/analysis/code +honnef.co/go/tools/analysis/dfa +honnef.co/go/tools/analysis/dfa/dense honnef.co/go/tools/analysis/edit honnef.co/go/tools/analysis/facts/deprecated honnef.co/go/tools/analysis/facts/directives @@ -1809,7 +1818,6 @@ honnef.co/go/tools/analysis/facts/generated honnef.co/go/tools/analysis/facts/nilness honnef.co/go/tools/analysis/facts/purity honnef.co/go/tools/analysis/facts/tokenfile -honnef.co/go/tools/analysis/facts/typedness honnef.co/go/tools/analysis/lint honnef.co/go/tools/analysis/report honnef.co/go/tools/config @@ -1817,10 +1825,18 @@ honnef.co/go/tools/go/ast/astutil honnef.co/go/tools/go/ir honnef.co/go/tools/go/ir/irutil honnef.co/go/tools/go/types/typeutil -honnef.co/go/tools/internal/analysisinternal/typeindex +honnef.co/go/tools/internal/iterutil honnef.co/go/tools/internal/passes/buildir honnef.co/go/tools/internal/sharedcheck -honnef.co/go/tools/internal/typesinternal/typeindex +honnef.co/go/tools/internal/xtools-internal/aliases +honnef.co/go/tools/internal/xtools-internal/analysis/typeindex +honnef.co/go/tools/internal/xtools-internal/astutil +honnef.co/go/tools/internal/xtools-internal/graph +honnef.co/go/tools/internal/xtools-internal/moreiters +honnef.co/go/tools/internal/xtools-internal/typeparams +honnef.co/go/tools/internal/xtools-internal/typesinternal +honnef.co/go/tools/internal/xtools-internal/typesinternal/typeindex +honnef.co/go/tools/internal/xtools-internal/versions honnef.co/go/tools/knowledge honnef.co/go/tools/pattern honnef.co/go/tools/printf @@ -1955,7 +1971,6 @@ honnef.co/go/tools/staticcheck/sa5007 honnef.co/go/tools/staticcheck/sa5008 honnef.co/go/tools/staticcheck/sa5009 honnef.co/go/tools/staticcheck/sa5010 -honnef.co/go/tools/staticcheck/sa5011 honnef.co/go/tools/staticcheck/sa5012 honnef.co/go/tools/staticcheck/sa6000 honnef.co/go/tools/staticcheck/sa6001 @@ -1972,6 +1987,7 @@ honnef.co/go/tools/staticcheck/sa9006 honnef.co/go/tools/staticcheck/sa9007 honnef.co/go/tools/staticcheck/sa9008 honnef.co/go/tools/staticcheck/sa9009 +honnef.co/go/tools/staticcheck/sa9010 honnef.co/go/tools/stylecheck honnef.co/go/tools/stylecheck/st1000 honnef.co/go/tools/stylecheck/st1001 @@ -1992,13 +2008,13 @@ honnef.co/go/tools/stylecheck/st1021 honnef.co/go/tools/stylecheck/st1022 honnef.co/go/tools/stylecheck/st1023 honnef.co/go/tools/unused -# mvdan.cc/gofumpt v0.9.2 -## explicit; go 1.24.0 +# mvdan.cc/gofumpt v0.11.0 +## explicit; go 1.25.0 mvdan.cc/gofumpt/format mvdan.cc/gofumpt/internal/govendor/go/doc/comment mvdan.cc/gofumpt/internal/govendor/go/format mvdan.cc/gofumpt/internal/govendor/go/printer mvdan.cc/gofumpt/internal/version -# mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 -## explicit; go 1.24.0 +# mvdan.cc/unparam v0.0.0-20260818115549-3f964bcb5673 +## explicit; go 1.25.0 mvdan.cc/unparam/check diff --git a/vendor/mvdan.cc/gofumpt/format/format.go b/vendor/mvdan.cc/gofumpt/format/format.go index 879969da..438a73b5 100644 --- a/vendor/mvdan.cc/gofumpt/format/format.go +++ b/vendor/mvdan.cc/gofumpt/format/format.go @@ -23,7 +23,6 @@ import ( "unicode" "unicode/utf8" - "github.com/google/go-cmp/cmp" "golang.org/x/tools/go/ast/astutil" "mvdan.cc/gofumpt/internal/govendor/go/format" @@ -57,11 +56,81 @@ type Options struct { // is formatted as if it weren't inside a module. ModulePath string - // ExtraRules enables extra formatting rules, such as grouping function + // ExtraRules enables all extra formatting rules, such as grouping function // parameters with repeated types together. + // + // Deprecated: use [Options.Extra] instead. ExtraRules bool + + // Extra allows enabling extra formatting rules which are disabled by default. + Extra Extra +} + +// Extra is the set of extra formatting rules which are available. +// +// As the formatter evolves, we might add or remove boolean fields here. +// Go API users who wish to avoid build errors in such cases +// can use the string API in [Extra.Set]. +type Extra struct { + // TODO: should we have "All" to turn them all on, + // akin to how the CLI has -extra=true for historical reasons? + // I lean against it, as it should be a conscious choice to turn on + // each of these extra rules, and we should be able to add more rules + // without fear of causing unexpected changes for users. + + // GroupParams groups function parameters with repeated types. + GroupParams bool + + // ClotheReturns clothes naked returns in functions with named results. + ClotheReturns bool + + // BalanceCalls places a multi-line call's closing parenthesis on its + // own line when the opening parenthesis ends a line. + BalanceCalls bool +} + +func (e *Extra) String() string { + var active []string + if e.GroupParams { + active = append(active, "group_params") + } + if e.ClotheReturns { + active = append(active, "clothe_returns") + } + if e.BalanceCalls { + active = append(active, "balance_calls") + } + return strings.Join(active, ",") +} + +func (e *Extra) Set(v string) error { + if v == "true" { + e.GroupParams = true + e.ClotheReturns = true + e.BalanceCalls = true + return nil + } + *e = Extra{} + if v == "false" { + return nil + } + for s := range strings.SplitSeq(v, ",") { + switch s { + case "group_params": + e.GroupParams = true + case "clothe_returns": + e.ClotheReturns = true + case "balance_calls": + e.BalanceCalls = true + default: + return fmt.Errorf("unknown rule: %q", s) + } + } + return nil } +func (e *Extra) IsBoolFlag() bool { return true } + // Source formats src in gofumpt's format, assuming that src holds a valid Go // source file. func Source(src []byte, opts Options) ([]byte, error) { @@ -91,6 +160,10 @@ func Source(src []byte, opts Options) ([]byte, error) { func File(fset *token.FileSet, file *ast.File, opts Options) { simplify(file) + if opts.ExtraRules { + opts.Extra.Set("true") // enable all the extra rules + } + if opts.LangVersion == "" { opts.LangVersion = "go1" } else { @@ -258,6 +331,37 @@ func (f *fumpter) removeLinesBetween(from, to token.Pos) { f.removeLines(f.Line(from)+1, f.Line(to)) } +// removeParens unwraps a single-spec var group like "var (\n\tx = 1\n)" into a +// lone "var x = 1". It only acts on such groups without a doc comment. +func (f *fumpter) removeParens(node *ast.GenDecl) { + if node.Tok != token.VAR || len(node.Specs) != 1 || + !node.Lparen.IsValid() || node.Doc != nil { + return + } + specPos := node.Specs[0].Pos() + specEnd := node.Specs[0].End() + + if len(f.commentsBetween(node.TokPos, specPos)) > 0 { + // If the single spec has a comment on the line above, + // the comment must go before the entire declaration now. + node.TokPos = specPos + } else { + f.removeLines(f.Line(node.TokPos), f.Line(specPos)) + } + if len(f.commentsBetween(specEnd, node.Rparen)) > 0 { + // Leave one newline to not force a comment on the next line to + // become an inline comment. + f.removeLines(f.Line(specEnd)+1, f.Line(node.Rparen)) + } else { + f.removeLines(f.Line(specEnd), f.Line(node.Rparen)) + } + + // Remove the parentheses. go/printer will automatically + // get rid of the newlines. + node.Lparen = token.NoPos + node.Rparen = token.NoPos +} + func (f *fumpter) Position(p token.Pos) token.Position { return f.file.PositionFor(p, false) } @@ -337,11 +441,68 @@ var rxCommentDirective = regexp.MustCompile( `|sys(?:nb)?\b` + `)`) +// rxShebangComment matches a shebang like `//usr/bin/env go run`. +var rxShebangComment = regexp.MustCompile(`^//[^ /].*\bbin/`) + +// commentGroupLooksLikeCode reports whether the lines of a //-style comment +// group parse as Go statements with at least one non-trivial statement. +// A bare identifier path or label is treated as trivial, since prose like +// "// foo" or "// TODO: bar" parses but is not commented-out code. +func commentGroupLooksLikeCode(group *ast.CommentGroup) bool { + src := "package p\nfunc _() {\n" + group.Text() + "}\n" + // AllErrors avoids the parser's panic/recover bailout on too many errors, + // which crashes under tinygo's Wasm target as it lacks recover support. + file, err := parser.ParseFile(token.NewFileSet(), "", src, parser.SkipObjectResolution|parser.AllErrors) + if err != nil { + return false + } + fn, _ := file.Decls[0].(*ast.FuncDecl) + if fn == nil || fn.Body == nil { + return false + } + for _, stmt := range fn.Body.List { + if !isTrivialStmt(stmt) { + return true + } + } + return false +} + +func isTrivialStmt(stmt ast.Stmt) bool { + switch s := stmt.(type) { + case *ast.ExprStmt: + return isIdentPath(s.X) + case *ast.LabeledStmt: + return isTrivialStmt(s.Stmt) + case *ast.EmptyStmt: + return true + } + return false +} + +func isIdentPath(expr ast.Expr) bool { + switch e := expr.(type) { + case *ast.Ident: + return true + case *ast.SelectorExpr: + return isIdentPath(e.X) + } + return false +} + func (f *fumpter) applyPre(c *astutil.Cursor) { f.splitLongLine(c) switch node := c.Node().(type) { case *ast.File: + // Unwrap single-spec var groups before the joining below, + // so an adjacent var line and var group merge in one pass. + for _, decl := range node.Decls { + if decl, ok := decl.(*ast.GenDecl); ok { + f.removeParens(decl) + } + } + // Join contiguous lone var/const/import lines. // Abort if there are empty lines in between, // including a leading comment if it's a directive. @@ -354,6 +515,7 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { continue } lastPos := start.Pos() + merged := false contLoop: for i++; i < len(node.Decls); { cont, ok := node.Decls[i].(*ast.GenDecl) @@ -377,17 +539,25 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { } start.Specs = append(start.Specs, cont.Specs...) + merged = true + end := cont.End() if c := f.inlineComment(cont.End()); c != nil { // don't move an inline comment outside - start.Rparen = c.End() - } else { - // so the code below treats the joined - // decl group as multi-line - start.Rparen = cont.End() + end = c.End() } + // Point Rparen at the last content character, like a real + // ')', so start.End() stays on the content's final line and + // the empty-line separator below is idempotent in one pass. + start.Rparen = end - 1 lastPos = cont.Pos() i++ } + // Re-sort imports in the new group so the output is idempotent. + // Set Lparen so ast.SortImports doesn't skip the merged decl. + if merged && start.Tok == token.IMPORT { + start.Lparen = start.TokPos + token.Pos(len("import")) + ast.SortImports(f.fset, f.astFile) + } } node.Decls = newDecls @@ -399,15 +569,30 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { var lastEnd token.Pos for _, decl := range node.Decls { pos := decl.Pos() - comments := f.commentsBetween(lastEnd, pos) - if len(comments) > 0 { - pos = comments[0].Pos() + // Trailing inline comments on lastEnd's line belong to the + // previous decl and extend its effective end. + effectiveEnd := lastEnd + lastEndLine := f.Line(lastEnd) + for _, cg := range f.commentsBetween(lastEnd, pos) { + if f.Line(cg.Pos()) != lastEndLine { + pos = cg.Pos() + break + } + effectiveEnd = cg.End() } // Note that we want End-1, as End is the character after the node. multi := f.Line(pos) < f.Line(decl.End()-1) - if multi && lastMulti && f.Line(lastEnd)+1 == f.Line(pos) { - f.addNewline(lastEnd) + // A func declaration which fits on a single source line may + // still be printed across multiple lines: go/printer's funcBody + // breaks the body onto its own lines once header+body exceeds + // 100 bytes. Approximate that with the source byte length. + if fn, _ := decl.(*ast.FuncDecl); fn != nil && !multi && fn.Body != nil && + f.Offset(fn.End())-f.Offset(fn.Pos()) > 100 { + multi = true + } + if multi && lastMulti && f.Line(effectiveEnd)+1 == f.Line(pos) { + f.addNewline(effectiveEnd) } lastMulti = multi @@ -418,6 +603,10 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { groupLoop: for _, group := range node.Comments { for _, comment := range group.List { + // Leave shebang lines like `//usr/bin/env go run` alone. + if f.Line(comment.Slash) == 1 && rxShebangComment.MatchString(comment.Text) { + continue groupLoop + } if comment.Text == "//gofumpt:diagnose" || strings.HasPrefix(comment.Text, "//gofumpt:diagnose ") { slc := []string{ "//gofumpt:diagnose", @@ -427,8 +616,8 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { "-lang=" + f.LangVersion, "-modpath=" + f.ModulePath, } - if f.ExtraRules { - slc = append(slc, "-extra") + if s := f.Extra.String(); s != "" { + slc = append(slc, "-extra="+s) } comment.Text = strings.Join(slc, " ") } @@ -447,6 +636,9 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { continue groupLoop } } + if commentGroupLooksLikeCode(group) { + continue groupLoop + } // If none of the comment group's lines look like a // directive or code, add spaces, if needed. for _, comment := range group.List { @@ -488,31 +680,7 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { // Single var declarations shouldn't use parentheses, unless // there's a comment on the grouped declaration. - if node.Tok == token.VAR && len(node.Specs) == 1 && - node.Lparen.IsValid() && node.Doc == nil { - specPos := node.Specs[0].Pos() - specEnd := node.Specs[0].End() - - if len(f.commentsBetween(node.TokPos, specPos)) > 0 { - // If the single spec has a comment on the line above, - // the comment must go before the entire declaration now. - node.TokPos = specPos - } else { - f.removeLines(f.Line(node.TokPos), f.Line(specPos)) - } - if len(f.commentsBetween(specEnd, node.Rparen)) > 0 { - // Leave one newline to not force a comment on the next line to - // become an inline comment. - f.removeLines(f.Line(specEnd)+1, f.Line(node.Rparen)) - } else { - f.removeLines(f.Line(specEnd), f.Line(node.Rparen)) - } - - // Remove the parentheses. go/printer will automatically - // get rid of the newlines. - node.Lparen = token.NoPos - node.Rparen = token.NoPos - } + f.removeParens(node) case *ast.InterfaceType: if len(node.Methods.List) > 0 { @@ -682,8 +850,7 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { f.removeLinesBetween(bodyEnd, node.End()) } - // Merging adjacent fields (e.g. parameters) is disabled by default. - if !f.ExtraRules { + if !f.Extra.GroupParams { break } switch c.Parent().(type) { @@ -694,6 +861,14 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { // Do not merge adjacent fields in structs. } + case *ast.ParenExpr: + // Unwrap any chain of redundant inner parens first, + // since astutil.Apply does not walk replacement nodes. + node.X = ast.Unparen(node.X) + if f.canRemoveParens(node) { + c.Replace(node.X) + } + case *ast.BasicLit: // Octal number literals were introduced in Go 1.13. if goversion.Compare(f.LangVersion, "go1.13") >= 0 { @@ -704,15 +879,21 @@ func (f *fumpter) applyPre(c *astutil.Cursor) { } case *ast.AssignStmt: - // Only remove lines between the assignment token and the first right-hand side expression - f.removeLines(f.Line(node.TokPos), f.Line(node.Rhs[0].Pos())) + // Only remove lines between the assignment token and the right-hand side + // for simple single-value assignments. Skip multi-value assignments and + // binary expressions like long string concatenations, where a line break + // after the assignment token can improve readability. + if len(node.Rhs) == 1 { + if _, ok := node.Rhs[0].(*ast.BinaryExpr); !ok { + f.removeLines(f.Line(node.TokPos), f.Line(node.Rhs[0].Pos())) + } + } case *ast.ReturnStmt: if len(node.Results) > 0 { break } - // Clothing naked returns is disabled by default. - if !f.ExtraRules { + if !f.Extra.ClotheReturns { break } results := f.parentFuncTypes[len(f.parentFuncTypes)-1].Results @@ -822,6 +1003,33 @@ func (f *fumpter) applyPost(c *astutil.Cursor) { f.addNewline(elem1.End()) } } + + // In a multi-line call, if the opening parenthesis is at the end of a + // line, the closing parenthesis should be at the start of a line. + // See https://github.com/mvdan/gofumpt/issues/74. + case *ast.CallExpr: + if !f.Extra.BalanceCalls { + break + } + if len(node.Args) == 0 { + break + } + openLine := f.Line(node.Lparen) + closeLine := f.Line(node.Rparen) + if openLine == closeLine { + break + } + firstLine := f.Line(node.Args[0].Pos()) + lastEnd := node.Args[len(node.Args)-1].End() + if comment := f.inlineComment(lastEnd); comment != nil { + lastEnd = comment.End() + } + lastLine := f.Line(lastEnd) + openAtEOL := openLine != firstLine + closeAtBOL := closeLine != lastLine + if openAtEOL && !closeAtBOL { + f.addNewline(node.Rparen) + } } } @@ -908,6 +1116,46 @@ func (f *fumpter) splitLongLine(c *astutil.Cursor) { } } +// canRemoveParens reports whether the parentheses around node are definitely +// useless and can be safely removed without changing intent. +func (f *fumpter) canRemoveParens(node *ast.ParenExpr) bool { + // Don't drop parens which contain comments, + // as the printer may not place them well without the parens. + if len(f.commentsBetween(node.Lparen, node.Rparen)) > 0 { + return false + } + return !keepParens(node.X, true) +} + +// keepParens reports whether the parentheses directly around expr should be +// kept: around binary, unary, and type expressions for readability and for +// conversions like `(<-chan T)(v)`, but only when outermost; and around an +// expression whose leftmost operand is a composite literal, whose brace would +// otherwise open an if, for, or switch body. +func keepParens(expr ast.Expr, outermost bool) bool { + switch expr := expr.(type) { + case *ast.CompositeLit: + return true + case *ast.CallExpr: + return keepParens(expr.Fun, false) + case *ast.SelectorExpr: + return keepParens(expr.X, false) + case *ast.IndexExpr: + return keepParens(expr.X, false) + case *ast.IndexListExpr: + return keepParens(expr.X, false) + case *ast.SliceExpr: + return keepParens(expr.X, false) + case *ast.TypeAssertExpr: + return keepParens(expr.X, false) + case *ast.BinaryExpr, *ast.UnaryExpr, *ast.StarExpr, + *ast.ChanType, *ast.ArrayType, *ast.MapType, + *ast.FuncType, *ast.InterfaceType, *ast.StructType: + return outermost + } + return false +} + func isComposite(node ast.Node) *ast.CompositeLit { switch node := node.(type) { case *ast.CompositeLit: @@ -1093,16 +1341,28 @@ func (f *fumpter) shouldMergeAdjacentFields(f1, f2 *ast.Field) bool { // Only merge if the types that the syntax nodes represent are equal, // e.g. two *ast.Ident nodes "int" are equal, but the two *ast.Ident nodes - // "string" and "bool" are not. Hence we use go-cmp to do deep comparisons - // while ignoring position information, as it is irrelevant. + // "string" and "bool" are not. We use reflection to quickly discard most cases. + // + // We use an empty [token.FileSet] so that positions are ignored when printing, + // and two syntax nodes with different uses of newlines end up the same. // // Note that we could in theory use go/types here, but in practice gofumpt // needs to be fast, hence it shouldn't rely on expensive typechecking. - opt := cmp.Comparer(func(x, y token.Pos) bool { return true }) - return cmp.Equal(f1.Type, f2.Type, opt) + if reflect.TypeOf(f1.Type) != reflect.TypeOf(f2.Type) { + return false + } + emptyFset := token.NewFileSet() + var b1, b2 bytes.Buffer + if err := format.Node(&b1, emptyFset, f1.Type); err != nil { + return false + } + if err := format.Node(&b2, emptyFset, f2.Type); err != nil { + return false + } + return bytes.Equal(b1.Bytes(), b2.Bytes()) } -var posType = reflect.TypeOf(token.NoPos) +var posType = reflect.TypeFor[token.Pos]() // setPos recursively sets all position fields in the node v to pos. func setPos(v reflect.Value, pos token.Pos) { diff --git a/vendor/mvdan.cc/gofumpt/format/rewrite.go b/vendor/mvdan.cc/gofumpt/format/rewrite.go index ec7a2e5d..47ff5ee7 100644 --- a/vendor/mvdan.cc/gofumpt/format/rewrite.go +++ b/vendor/mvdan.cc/gofumpt/format/rewrite.go @@ -2,6 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// NOTE(gofumpt): the original cmd/gofmt/rewrite.go is mostly stripped here. +// gofumpt drops the -r flag (use `gofmt -r` instead), so the rewrite engine +// (initRewrite, parseExpr, rewriteFile, apply, set, subst) and its +// reflect-helpers (objectPtrNil, scopePtrNil, scopePtrType) are gone. Only +// match/isWildcard remain because simplify.go still uses them to compare +// AST literals when omitting redundant types in composite literals. + package format import ( @@ -14,10 +21,10 @@ import ( // Values/types for special cases. var ( - identType = reflect.TypeOf((*ast.Ident)(nil)) - objectPtrType = reflect.TypeOf((*ast.Object)(nil)) - positionType = reflect.TypeOf(token.NoPos) - callExprType = reflect.TypeOf((*ast.CallExpr)(nil)) + identType = reflect.TypeFor[*ast.Ident]() + objectPtrType = reflect.TypeFor[*ast.Object]() + positionType = reflect.TypeFor[token.Pos]() + callExprType = reflect.TypeFor[*ast.CallExpr]() ) func isWildcard(s string) bool { diff --git a/vendor/mvdan.cc/gofumpt/format/simplify.go b/vendor/mvdan.cc/gofumpt/format/simplify.go index 11764646..363f8d05 100644 --- a/vendor/mvdan.cc/gofumpt/format/simplify.go +++ b/vendor/mvdan.cc/gofumpt/format/simplify.go @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// NOTE(gofumpt): moved into the format package (from package main) so that +// syntax simplification is exported via the Go API. gofumpt always simplifies, +// so the -s flag was dropped; see also the removal of the -r rewrite logic in +// rewrite.go, which left this file as the sole user of match/isWildcard. + package format import ( diff --git a/vendor/mvdan.cc/gofumpt/internal/govendor/go/format/internal.go b/vendor/mvdan.cc/gofumpt/internal/govendor/go/format/internal.go index 383655f1..df035871 100644 --- a/vendor/mvdan.cc/gofumpt/internal/govendor/go/format/internal.go +++ b/vendor/mvdan.cc/gofumpt/internal/govendor/go/format/internal.go @@ -33,7 +33,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( // package line and source fragments are ok, fall through to // try as a source fragment. Stop and return on any other error. if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { - return file, sourceAdj, indentAdj, err + return } // If this is a declaration list, make it a source file @@ -49,13 +49,13 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( src = src[indent+len("package p\n"):] return bytes.TrimSpace(src) } - return file, sourceAdj, indentAdj, err + return } // If the error is that the source file didn't begin with a // declaration, fall through to try as a statement list. // Stop and return on any other error. if !strings.Contains(err.Error(), "expected declaration") { - return file, sourceAdj, indentAdj, err + return } // If this is a statement list, make it a source file @@ -86,7 +86,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( } // Succeeded, or out of options. - return file, sourceAdj, indentAdj, err + return } // format formats the given package file originally obtained from src diff --git a/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/nodes.go b/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/nodes.go index df3b7250..c7d2b0f1 100644 --- a/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/nodes.go +++ b/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/nodes.go @@ -57,7 +57,7 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (nbre p.print(newline) } } - return nbreaks + return } // setComment sets g as the next comment if g != nil and if node comments @@ -465,7 +465,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) { break } } - return size + return } func (p *printer) isOneLineFieldList(list []*ast.Field) bool { @@ -693,7 +693,7 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { maxProblem = max(maxProblem, 4) } } - return has4, has5, maxProblem + return } func cutoff(e *ast.BinaryExpr, depth int) int { @@ -1818,14 +1818,14 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { cfg := Config{Mode: RawFormat} var counter sizeCounter if err := cfg.fprint(&counter, p.fset, n, p.nodeSizes); err != nil { - return size + return } if counter.size <= maxSize && !counter.hasNewline { // n fits in a single line size = counter.size p.nodeSizes[n] = size } - return size + return } // numLines returns the number of lines spanned by node n in the original source. @@ -1959,7 +1959,7 @@ func declToken(decl ast.Decl) (tok token.Token) { case *ast.FuncDecl: tok = token.FUNC } - return tok + return } func (p *printer) declList(list []ast.Decl) { diff --git a/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/printer.go b/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/printer.go index 00713309..a6c74c72 100644 --- a/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/printer.go +++ b/vendor/mvdan.cc/gofumpt/internal/govendor/go/printer/printer.go @@ -715,7 +715,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, dropped wroteNewline = true } - return wroteNewline, droppedFF + return } // containsLinebreak reports whether the whitespace buffer contains any line breaks. @@ -809,7 +809,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro // no comment was written - we should never reach here since // intersperseComments should not be called in that case p.internalError("intersperseComments called without pending comments") - return wroteNewline, droppedFF + return } // writeWhitespace writes the first n whitespace entries. @@ -878,7 +878,7 @@ func mayCombine(prev token.Token, next byte) (b bool) { case token.AND: b = next == '&' || next == '^' // && or &^ } - return b + return } func (p *printer) setPos(pos token.Pos) { @@ -1041,7 +1041,7 @@ func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, dro // otherwise, write any leftover whitespace p.writeWhitespace(len(p.wsbuf)) } - return wroteNewline, droppedFF + return } // getDoc returns the ast.CommentGroup associated with n, if any. @@ -1269,7 +1269,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) { panic("unreachable") } if err != nil { - return n, err + return } } n = len(data) @@ -1280,7 +1280,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) { p.resetSpace() } - return n, err + return } // ---------------------------------------------------------------------------- @@ -1361,7 +1361,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node any, nodeS p := newPrinter(cfg, fset, nodeSizes) defer p.free() if err = p.printNode(node); err != nil { - return err + return } // print outstanding comments p.impliedSemi = false // EOF acts like a newline @@ -1397,7 +1397,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node any, nodeS // write printer result via tabwriter/trimmer to output if _, err = output.Write(p.output); err != nil { - return err + return } // flush tabwriter, if any @@ -1405,7 +1405,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node any, nodeS err = tw.Flush() } - return err + return } // A CommentedNode bundles an AST node and corresponding comments. diff --git a/vendor/mvdan.cc/unparam/check/check.go b/vendor/mvdan.cc/unparam/check/check.go index 7ca02c29..6bd6fdb6 100644 --- a/vendor/mvdan.cc/unparam/check/check.go +++ b/vendor/mvdan.cc/unparam/check/check.go @@ -73,6 +73,11 @@ type Checker struct { // to typecheck properly, as they're required to implement interfaces. typesImplementing map[*types.Named][]string + // linknamed records the funcs with a go:linkname directive in their + // doc comment, keyed by the position of the func's name, as their + // signatures cannot change. + linknamed map[token.Pos]bool + // localCallSites is a very simple form of a callgraph, only recording // direct function calls within a single package. localCallSites map[*ssa.Function][]ssa.CallInstruction @@ -100,6 +105,9 @@ func (c *Checker) lines(args ...string) ([]string, error) { if packages.PrintErrors(pkgs) > 0 { return nil, fmt.Errorf("encountered errors") } + if len(pkgs) == 0 { + return nil, fmt.Errorf("no packages to check") + } prog, _ := ssautil.Packages(pkgs, 0) prog.Build() @@ -113,7 +121,7 @@ func (c *Checker) lines(args ...string) ([]string, error) { prevLine := "" for _, issue := range issues { fpos := prog.Fset.Position(issue.Pos()).String() - if strings.HasPrefix(fpos, c.wd) { + if strings.HasPrefix(fpos, c.wd+string(filepath.Separator)) { fpos = fpos[len(c.wd)+1:] } line := fmt.Sprintf("%s: %s", fpos, issue.Message()) @@ -167,12 +175,25 @@ func generatedDoc(text string) bool { strings.Contains(text, "DO NOT EDIT") } +// linknameDoc reports whether a doc comment contains a go:linkname directive. +func linknameDoc(doc *ast.CommentGroup) bool { + if doc == nil { + return false + } + for _, comment := range doc.List { + if strings.HasPrefix(comment.Text, "//go:linkname ") { + return true + } + } + return false +} + // eqlConsts reports whether two constant values, possibly nil, are equal. func eqlConsts(c1, c2 *ssa.Const) bool { if c1 == nil || c2 == nil { return c1 == c2 } - if c1.Type() != c2.Type() { + if !types.Identical(c1.Type(), c2.Type()) { return false } if c1.Value == nil || c2.Value == nil { @@ -190,6 +211,7 @@ func (c *Checker) Check() ([]Issue, error) { c.callByPos = make(map[token.Pos]*ast.CallExpr) c.funcBodyByPos = make(map[token.Pos]*ast.BlockStmt) c.typesImplementing = make(map[*types.Named][]string) + c.linknamed = make(map[token.Pos]bool) wantPkg := make(map[*types.Package]*packages.Package) genFiles := make(map[string]bool) @@ -221,6 +243,9 @@ func (c *Checker) Check() ([]Issue, error) { // FuncDecl.Name. case *ast.FuncDecl: c.funcBodyByPos[node.Name.Pos()] = node.Body + if linknameDoc(node.Doc) { + c.linknamed[node.Name.Pos()] = true + } case *ast.FuncLit: c.funcBodyByPos[node.Pos()] = node.Body } @@ -230,6 +255,30 @@ func (c *Checker) Check() ([]Issue, error) { } allFuncs := ssautil.AllFunctions(c.prog) + // ssautil.AllFunctions skips methods of unexported types unless they + // are reachable via an interface or an exported type, so we could miss + // call sites or entire functions to check. Add all the source-level + // funcs and methods from the loaded packages ourselves. + // We still want ssautil.AllFunctions for the synthetic wrappers it + // finds, such as those for promoted methods called via an interface, + // as their bodies record call sites too. + var addSrcFunc func(fn *ssa.Function) + addSrcFunc = func(fn *ssa.Function) { + allFuncs[fn] = true + for _, anon := range fn.AnonFuncs { + addSrcFunc(anon) + } + } + for _, pkg := range c.pkgs { + for _, def := range pkg.TypesInfo.Defs { + if def, ok := def.(*types.Func); ok { + if fn := c.prog.FuncValue(def); fn != nil { + addSrcFunc(fn) + } + } + } + } + // map from *ssa.FreeVar to *ssa.Function, to find function literals // behind closure vars in the simpler scenarios. freeVars := map[*ssa.FreeVar]*ssa.Function{} @@ -283,15 +332,14 @@ func (c *Checker) Check() ([]Issue, error) { // fn(someFunc()) fixes params c.paramsRequiredBy[fn] = "forwarded call" } - } - switch instr := instr.(type) { - case *ssa.Call: - for _, arg := range instr.Call.Args { + for _, arg := range instr.Common().Args { if fn := findFunction(freeVars, arg); fn != nil { - // someFunc(fn) + // someFunc(fn), also via go or defer c.signRequiredBy[fn] = "call" } } + } + switch instr := instr.(type) { case *ssa.Phi: for _, val := range instr.Edges { if fn := findFunction(freeVars, val); fn != nil { @@ -300,13 +348,14 @@ func (c *Checker) Check() ([]Issue, error) { } } case *ssa.Return: - for _, val := range instr.Results { + results := returnValues(instr) + for _, val := range results { if fn := findFunction(freeVars, val); fn != nil { // return fn c.signRequiredBy[fn] = "result" } } - if call := callExtract(instr, instr.Results); call != nil { + if call := callExtract(instr, results); call != nil { if fn := findFunction(freeVars, call.Call.Value); fn != nil { // return fn() c.resultsRequiredBy[fn] = "return" @@ -330,6 +379,26 @@ func (c *Checker) Check() ([]Issue, error) { if fn := findFunction(freeVars, instr.Val); fn != nil { c.signRequiredBy[fn] = as } + case *ssa.MapUpdate: + if fn := findFunction(freeVars, instr.Value); fn != nil { + // someMap[someKey] = fn + c.signRequiredBy[fn] = "map value" + } + case *ssa.Send: + if fn := findFunction(freeVars, instr.X); fn != nil { + // someChan <- fn + c.signRequiredBy[fn] = "channel send" + } + case *ssa.Select: + for _, state := range instr.States { + if state.Dir != types.SendOnly { + continue + } + if fn := findFunction(freeVars, state.Send); fn != nil { + // select { case someChan <- fn: } + c.signRequiredBy[fn] = "channel send" + } + } case *ssa.MakeInterface: // someIface(named) iface := instr.Type().Underlying().(*types.Interface) @@ -407,7 +476,9 @@ func findNamed(typ types.Type) *types.Named { case *types.Pointer: return findNamed(typ.Elem()) case *types.Named: - return typ + // Use the generic origin, so that an instantiation like G[int] + // and the receiver type of G's methods map to the same key. + return typ.Origin() } return nil } @@ -475,6 +546,10 @@ func (c *Checker) checkFunc(fn *ssa.Function, pkg *packages.Package) { c.debug(" skip - func signature required by %s\n", by) return } + if c.linknamed[fn.Pos()] { + c.debug(" skip - go:linkname directive\n") + return + } if recv := fn.Signature.Recv(); recv != nil { named := findNamed(recv.Type()) if slices.Contains(c.typesImplementing[named], fn.Name()) { @@ -503,6 +578,8 @@ func (c *Checker) checkFunc(fn *ssa.Function, pkg *packages.Package) { if !ok { continue } + // Note that we don't use returnValues here, as resolving loads + // could add reports rather than suppress them; see its doc. for i, val := range ret.Results { if _, ok := val.(*ssa.Extract); !ok { allRetsExtracting = false @@ -540,7 +617,7 @@ resLoop: continue } res := results.At(i) - if res.Type() == errorType { + if types.Unalias(res.Type()) == errorType { // "error is never used" is less useful, and it's up to // tools like errcheck anyway. continue @@ -610,7 +687,7 @@ resLoop: } func containsTypeParam(t types.Type) bool { - switch t := t.(type) { + switch t := types.Unalias(t).(type) { case *types.TypeParam, *types.Union: return true case *types.Struct: @@ -962,6 +1039,49 @@ func receivesExtractedArgs(freeVars map[*ssa.FreeVar]*ssa.Function, call ssa.Cal return nil } +// returnValues returns the values of a return instruction. In a function with +// deferred calls, go/ssa stores the results in local variables and loads them +// again after the deferred calls run; see through those stores and loads so +// that patterns like "return fn()" are still recognized. +// +// Note that a deferred call may modify the stored results, so the resolved +// values are only good enough to suppress reports, never to add them. +func returnValues(ret *ssa.Return) []ssa.Value { + var results []ssa.Value // lazily cloned from ret.Results + for i, val := range ret.Results { + if stored := storedValue(ret.Block(), val); stored != nil { + if results == nil { + results = slices.Clone(ret.Results) + } + results[i] = stored + } + } + if results == nil { + return ret.Results + } + return results +} + +// storedValue returns the value most recently stored within a block into the +// local variable that val loads, if any. +func storedValue(block *ssa.BasicBlock, val ssa.Value) ssa.Value { + load, ok := val.(*ssa.UnOp) + if !ok || load.Op != token.MUL { + return nil + } + alloc, ok := load.X.(*ssa.Alloc) + if !ok { + return nil + } + var stored ssa.Value + for _, instr := range block.Instrs { + if store, ok := instr.(*ssa.Store); ok && store.Addr == alloc { + stored = store.Val + } + } + return stored +} + // callExtract returns the call instruction fn(...) if it is used directly as // arguments to the parent instruction, such as fn2(fn(...)) or return fn(...). func callExtract(parent ssa.Instruction, values []ssa.Value) *ssa.Call {