]> Cypherpunks repositories - gostls13.git/commitdiff
all: update vendored dependencies [generated]
authorDmitri Shuralyov <dmitshur@golang.org>
Tue, 11 Feb 2025 22:59:59 +0000 (17:59 -0500)
committerGopher Robot <gobot@golang.org>
Wed, 12 Feb 2025 17:31:18 +0000 (09:31 -0800)
The tree has opened for Go 1.25 development. This is a time to update
all golang.org/x/... module versions that contribute packages to the
std and cmd modules in the standard library to latest master versions.

For #36905.

[git-generate]
go install golang.org/x/build/cmd/updatestd@latest
go install golang.org/x/tools/cmd/bundle@latest
updatestd -goroot=$(pwd) -branch=master

# Update a cmd/vet test case.
cat <<EOF | patch
diff --git a/src/cmd/vet/testdata/print/print.go b/src/cmd/vet/testdata/print/print.go
index a2ad0f1298..fffe571163 100644
--- a/src/cmd/vet/testdata/print/print.go
+++ b/src/cmd/vet/testdata/print/print.go
@@ -200,8 +200,8 @@ func PrintfTests() {
  // Bad argument reorderings.
  Printf("%[xd", 3)                      // ERROR "Printf format %\[xd is missing closing \]"
  Printf("%[x]d x", 3)                   // ERROR "Printf format has invalid argument index \[x\]"
- Printf("%[3]*s x", "hi", 2)            // ERROR "Printf format has invalid argument index \[3\]"
- _ = fmt.Sprintf("%[3]d x", 2)          // ERROR "Sprintf format has invalid argument index \[3\]"
+ Printf("%[3]*s x", "hi", 2)            // ERROR "Printf format %\[3\]\*s reads arg #3, but call has 2 args"
+ _ = fmt.Sprintf("%[3]d x", 2)          // ERROR "Sprintf format %\[3\]d reads arg #3, but call has 1 arg"
  Printf("%[2]*.[1]*[3]d x", 2, "hi", 4) // ERROR "Printf format %\[2]\*\.\[1\]\*\[3\]d uses non-int \x22hi\x22 as argument of \*"
  Printf("%[0]s x", "arg1")              // ERROR "Printf format has invalid argument index \[0\]"
  Printf("%[0]d x", 1)                   // ERROR "Printf format has invalid argument index \[0\]"
EOF

# Temporarily hold x/net back to leave out CL 643780 because it's
# causing an import cycle in net/http's generated h2_bundle.go.
cd src
sed -i '' 's|"golang.org/x/net/internal/httpcommon"||' net/http/h2_bundle.go
go get golang.org/x/net@v0.34.1-0.20250123000230-c72e89d6a9e4  # version before CL 643780
go mod tidy
go mod vendor
go generate net/http

Change-Id: I91967ceb797bbc741af024cd2d2dba29dc558384
Reviewed-on: https://go-review.googlesource.com/c/go/+/648735
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>

105 files changed:
src/cmd/go.mod
src/cmd/go.sum
src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go
src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
src/cmd/vendor/golang.org/x/build/relnote/links.go
src/cmd/vendor/golang.org/x/build/relnote/relnote.go
src/cmd/vendor/golang.org/x/mod/modfile/read.go
src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
src/cmd/vendor/golang.org/x/sys/unix/auxv.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
src/cmd/vendor/golang.org/x/sys/windows/dll_windows.go
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go
src/cmd/vendor/golang.org/x/tools/cmd/bisect/main.go
src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go
src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go
src/cmd/vendor/golang.org/x/tools/internal/typeparams/coretype.go
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/recv.go
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
src/cmd/vendor/modules.txt
src/cmd/vet/testdata/print/print.go
src/go.mod
src/go.sum
src/net/http/h2_bundle.go
src/vendor/golang.org/x/sys/cpu/cpu.go
src/vendor/golang.org/x/sys/cpu/cpu_x86.go
src/vendor/modules.txt

index 9c29c3ac74d197e991578cbef9d14f033978345a..5f4e4186160dd13670113b6ab2ba2035d7165e7b 100644 (file)
@@ -1,21 +1,21 @@
 module cmd
 
-go 1.24
+go 1.25
 
 require (
        github.com/google/pprof v0.0.0-20241101162523-b92577c0c142
-       golang.org/x/arch v0.12.0
-       golang.org/x/build v0.0.0-20241205234318-b850320af2a4
-       golang.org/x/mod v0.22.0
-       golang.org/x/sync v0.10.0
-       golang.org/x/sys v0.28.0
-       golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3
-       golang.org/x/term v0.27.0
-       golang.org/x/tools v0.28.1-0.20250131145412-98746475647e
+       golang.org/x/arch v0.14.0
+       golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63
+       golang.org/x/mod v0.23.0
+       golang.org/x/sync v0.11.0
+       golang.org/x/sys v0.30.0
+       golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a
+       golang.org/x/term v0.29.0
+       golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f
 )
 
 require (
        github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd // indirect
-       golang.org/x/text v0.21.0 // indirect
+       golang.org/x/text v0.22.0 // indirect
        rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef // indirect
 )
index 593063a9daa35156d0863cef93c02beb8b7dfe9d..75299131f6a996e5f2f2c2362515bde7b31bd57f 100644 (file)
@@ -6,23 +6,23 @@ github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd h1:EVX1s+X
 github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
 github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
 github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
-golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/build v0.0.0-20241205234318-b850320af2a4 h1:ri5CIHQTJCd3jd0Jez97HiPE+VMT0hFNKqLHn2EjrXk=
-golang.org/x/build v0.0.0-20241205234318-b850320af2a4/go.mod h1:9O1P9bdbWH7KXtcbo+6amI/59H5mNq7+CTE1eKqNsjg=
-golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
-golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
-golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
-golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3 h1:rCLsPBq7l0E9Z451UgkWFkaWYhgt7dGmAlpD6hLjK5I=
-golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3/go.mod h1:8h4Hgq+jcTvCDv2+i7NrfWwpYHcESleo2nGHxLbFLJ4=
-golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
-golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/tools v0.28.1-0.20250131145412-98746475647e h1:6Kzwg7JxW2HRWToKpIKqlpF8l8XMasoALX3OcAMdgL8=
-golang.org/x/tools v0.28.1-0.20250131145412-98746475647e/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
+golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
+golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63 h1:QZ8/V1B4oK7N5t6w0zX5dAxFIHt0WaTX+r1z29cWXjY=
+golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63/go.mod h1:JhINjMoWj8G2oLkaBLNDBIr/GLqJNOkCr4XzFWWYCf4=
+golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
+golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a h1:3fgycqG+90xOafOruMBVZXa8DUeOt5qbGLjQoNvZ8Ew=
+golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a/go.mod h1:Ng+6E7PnWNge4EifZkPKeQUnm5iyAoH8qQgw3pLCiF4=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f h1:wN7/h1uT0B8rVpI6iWEPBC6qO1tdoMaNR6cOwdqqy/s=
+golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
 rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8=
 rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ=
index d6b3dc040e8bcc1bd49cbcb76b476ea8e3abb0c5..3ee0449640aa5a6ba9b2d040edd301bc4802a638 100644 (file)
@@ -42,6 +42,11 @@ func GNUSyntax(inst Inst) string {
                        }
                }
 
+               if inst.Op == ANDI && inst.Args[2].(Simm).Imm == 255 {
+                       op = "zext.b"
+                       args = args[:len(args)-1]
+               }
+
                if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 {
                        op = "sext.w"
                        args = args[:len(args)-1]
index 6f57c70bf1529acc3e66dcb133fefaeb28bdb247..9710bbd8bd0c5bc37473fcebf204f7a32583aad8 100644 (file)
@@ -1,4 +1,4 @@
-// Code generated by x86map -fmt=decoder x86.csv DO NOT EDIT.
+// Code generated by x86map -fmt=decoder ../x86.csv DO NOT EDIT.
 
 package x86asm
 
index b8e3a0f4b08f16201d7c68cb5c1b5a0d540ec0b4..ff62cdabfa3c5f475e9a69a0f0865e13a76d2a27 100644 (file)
@@ -158,7 +158,7 @@ func symbolLinkText(i int, ins []md.Inline) string {
        if plainText(i) != "[" {
                return ""
        }
-       // The open bracket must be preceeded by a link-adjacent rune (or by nothing).
+       // The open bracket must be preceded by a link-adjacent rune (or by nothing).
        if t := plainText(i - 1); t != "" {
                r, _ := utf8.DecodeLastRuneInString(t)
                if !isLinkAdjacentRune(r) {
index ba48e6f576fc2afaf120cf66312a9c41e3d66ee7..eeb12ce9e3ea287bb068eea3c8a67ca884951ffc 100644 (file)
@@ -462,5 +462,8 @@ func checkFragmentFile(fsys fs.FS, filename string) error {
        }
        defer f.Close()
        data, err := io.ReadAll(f)
+       if err != nil {
+               return err
+       }
        return CheckFragment(string(data))
 }
index de1b98211a1907acfdf5aae42579d0ef3919ec83..2d7486804f50608e58f50b61c95a9460e8b93ba5 100644 (file)
@@ -877,6 +877,11 @@ func (in *input) parseLineBlock(start Position, token []string, lparen token) *L
                        in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune))
                case ')':
                        rparen := in.lex()
+                       // Don't preserve blank lines (denoted by a single empty comment, added above)
+                       // at the end of the block.
+                       if len(comments) == 1 && comments[0] == (Comment{}) {
+                               comments = nil
+                       }
                        x.RParen.Before = comments
                        x.RParen.Pos = rparen.pos
                        if !in.peek().isEOL() {
index 948a3ee63d4ffe370a795e2233634309646d69b9..b8322598ae3ea0a6614de7692b051241fc586709 100644 (file)
@@ -118,6 +118,7 @@ func (g *Group) TryGo(f func() error) bool {
 
 // SetLimit limits the number of active goroutines in this group to at most n.
 // A negative value indicates no limit.
+// A limit of zero will prevent any new goroutines from being added.
 //
 // Any subsequent call to the Go method will block until it can add an active
 // goroutine without exceeding the configured limit.
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/auxv.go b/src/cmd/vendor/golang.org/x/sys/unix/auxv.go
new file mode 100644 (file)
index 0000000..37a8252
--- /dev/null
@@ -0,0 +1,36 @@
+// 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.
+
+//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
+
+package unix
+
+import (
+       "syscall"
+       "unsafe"
+)
+
+//go:linkname runtime_getAuxv runtime.getAuxv
+func runtime_getAuxv() []uintptr
+
+// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs.
+// The returned slice is always a fresh copy, owned by the caller.
+// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed,
+// which happens in some locked-down environments and build modes.
+func Auxv() ([][2]uintptr, error) {
+       vec := runtime_getAuxv()
+       vecLen := len(vec)
+
+       if vecLen == 0 {
+               return nil, syscall.ENOENT
+       }
+
+       if vecLen%2 != 0 {
+               return nil, syscall.EINVAL
+       }
+
+       result := make([]uintptr, vecLen)
+       copy(result, vec)
+       return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil
+}
diff --git a/src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go b/src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go
new file mode 100644 (file)
index 0000000..1200487
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+//go:build !go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
+
+package unix
+
+import "syscall"
+
+func Auxv() ([][2]uintptr, error) {
+       return nil, syscall.ENOTSUP
+}
index 97cb916f2c90ef178ea7d14f319ff73360ef2210..be8c0020701ee4ccbc415fb16e00108033093c5b 100644 (file)
@@ -246,6 +246,18 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
        return sendfile(outfd, infd, offset, count)
 }
 
+func Dup3(oldfd, newfd, flags int) error {
+       if oldfd == newfd || flags&^O_CLOEXEC != 0 {
+               return EINVAL
+       }
+       how := F_DUP2FD
+       if flags&O_CLOEXEC != 0 {
+               how = F_DUP2FD_CLOEXEC
+       }
+       _, err := fcntl(oldfd, how, newfd)
+       return err
+}
+
 /*
  * Exposed directly
  */
index 21974af064ddc38e765f3543cda0a9ca29aa44aa..abc3955477c7d38a774bc46bdd8ed0fd736a7bb8 100644 (file)
@@ -1102,3 +1102,90 @@ func (s *Strioctl) SetInt(i int) {
 func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {
        return ioctlPtrRet(fd, req, unsafe.Pointer(s))
 }
+
+// Ucred Helpers
+// See ucred(3c) and getpeerucred(3c)
+
+//sys  getpeerucred(fd uintptr, ucred *uintptr) (err error)
+//sys  ucredFree(ucred uintptr) = ucred_free
+//sys  ucredGet(pid int) (ucred uintptr, err error) = ucred_get
+//sys  ucredGeteuid(ucred uintptr) (uid int) = ucred_geteuid
+//sys  ucredGetegid(ucred uintptr) (gid int) = ucred_getegid
+//sys  ucredGetruid(ucred uintptr) (uid int) = ucred_getruid
+//sys  ucredGetrgid(ucred uintptr) (gid int) = ucred_getrgid
+//sys  ucredGetsuid(ucred uintptr) (uid int) = ucred_getsuid
+//sys  ucredGetsgid(ucred uintptr) (gid int) = ucred_getsgid
+//sys  ucredGetpid(ucred uintptr) (pid int) = ucred_getpid
+
+// Ucred is an opaque struct that holds user credentials.
+type Ucred struct {
+       ucred uintptr
+}
+
+// We need to ensure that ucredFree is called on the underlying ucred
+// when the Ucred is garbage collected.
+func ucredFinalizer(u *Ucred) {
+       ucredFree(u.ucred)
+}
+
+func GetPeerUcred(fd uintptr) (*Ucred, error) {
+       var ucred uintptr
+       err := getpeerucred(fd, &ucred)
+       if err != nil {
+               return nil, err
+       }
+       result := &Ucred{
+               ucred: ucred,
+       }
+       // set the finalizer on the result so that the ucred will be freed
+       runtime.SetFinalizer(result, ucredFinalizer)
+       return result, nil
+}
+
+func UcredGet(pid int) (*Ucred, error) {
+       ucred, err := ucredGet(pid)
+       if err != nil {
+               return nil, err
+       }
+       result := &Ucred{
+               ucred: ucred,
+       }
+       // set the finalizer on the result so that the ucred will be freed
+       runtime.SetFinalizer(result, ucredFinalizer)
+       return result, nil
+}
+
+func (u *Ucred) Geteuid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGeteuid(u.ucred)
+}
+
+func (u *Ucred) Getruid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetruid(u.ucred)
+}
+
+func (u *Ucred) Getsuid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetsuid(u.ucred)
+}
+
+func (u *Ucred) Getegid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetegid(u.ucred)
+}
+
+func (u *Ucred) Getrgid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetrgid(u.ucred)
+}
+
+func (u *Ucred) Getsgid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetsgid(u.ucred)
+}
+
+func (u *Ucred) Getpid() int {
+       defer runtime.KeepAlive(u)
+       return ucredGetpid(u.ucred)
+}
index 6ebc48b3fecd71f891b0aeff1f2f9c8110b9e88d..4f432bfe8feeee77862ace1bbfbed983d72f6e76 100644 (file)
@@ -1245,6 +1245,7 @@ const (
        FAN_REPORT_DFID_NAME                        = 0xc00
        FAN_REPORT_DFID_NAME_TARGET                 = 0x1e00
        FAN_REPORT_DIR_FID                          = 0x400
+       FAN_REPORT_FD_ERROR                         = 0x2000
        FAN_REPORT_FID                              = 0x200
        FAN_REPORT_NAME                             = 0x800
        FAN_REPORT_PIDFD                            = 0x80
@@ -1330,8 +1331,10 @@ const (
        FUSE_SUPER_MAGIC                            = 0x65735546
        FUTEXFS_SUPER_MAGIC                         = 0xbad1dea
        F_ADD_SEALS                                 = 0x409
+       F_CREATED_QUERY                             = 0x404
        F_DUPFD                                     = 0x0
        F_DUPFD_CLOEXEC                             = 0x406
+       F_DUPFD_QUERY                               = 0x403
        F_EXLCK                                     = 0x4
        F_GETFD                                     = 0x1
        F_GETFL                                     = 0x3
@@ -1551,6 +1554,7 @@ const (
        IPPROTO_ROUTING                             = 0x2b
        IPPROTO_RSVP                                = 0x2e
        IPPROTO_SCTP                                = 0x84
+       IPPROTO_SMC                                 = 0x100
        IPPROTO_TCP                                 = 0x6
        IPPROTO_TP                                  = 0x1d
        IPPROTO_UDP                                 = 0x11
@@ -1623,6 +1627,8 @@ const (
        IPV6_UNICAST_IF                             = 0x4c
        IPV6_USER_FLOW                              = 0xe
        IPV6_V6ONLY                                 = 0x1a
+       IPV6_VERSION                                = 0x60
+       IPV6_VERSION_MASK                           = 0xf0
        IPV6_XFRM_POLICY                            = 0x23
        IP_ADD_MEMBERSHIP                           = 0x23
        IP_ADD_SOURCE_MEMBERSHIP                    = 0x27
@@ -1867,6 +1873,7 @@ const (
        MADV_UNMERGEABLE                            = 0xd
        MADV_WILLNEED                               = 0x3
        MADV_WIPEONFORK                             = 0x12
+       MAP_DROPPABLE                               = 0x8
        MAP_FILE                                    = 0x0
        MAP_FIXED                                   = 0x10
        MAP_FIXED_NOREPLACE                         = 0x100000
@@ -1967,6 +1974,7 @@ const (
        MSG_PEEK                                    = 0x2
        MSG_PROXY                                   = 0x10
        MSG_RST                                     = 0x1000
+       MSG_SOCK_DEVMEM                             = 0x2000000
        MSG_SYN                                     = 0x400
        MSG_TRUNC                                   = 0x20
        MSG_TRYHARD                                 = 0x4
@@ -2083,6 +2091,7 @@ const (
        NFC_ATR_REQ_MAXSIZE                         = 0x40
        NFC_ATR_RES_GB_MAXSIZE                      = 0x2f
        NFC_ATR_RES_MAXSIZE                         = 0x40
+       NFC_ATS_MAXSIZE                             = 0x14
        NFC_COMM_ACTIVE                             = 0x0
        NFC_COMM_PASSIVE                            = 0x1
        NFC_DEVICE_NAME_MAXSIZE                     = 0x8
@@ -2163,6 +2172,7 @@ const (
        NFNL_SUBSYS_QUEUE                           = 0x3
        NFNL_SUBSYS_ULOG                            = 0x4
        NFS_SUPER_MAGIC                             = 0x6969
+       NFT_BITWISE_BOOL                            = 0x0
        NFT_CHAIN_FLAGS                             = 0x7
        NFT_CHAIN_MAXNAMELEN                        = 0x100
        NFT_CT_MAX                                  = 0x17
@@ -2491,6 +2501,7 @@ const (
        PR_GET_PDEATHSIG                            = 0x2
        PR_GET_SECCOMP                              = 0x15
        PR_GET_SECUREBITS                           = 0x1b
+       PR_GET_SHADOW_STACK_STATUS                  = 0x4a
        PR_GET_SPECULATION_CTRL                     = 0x34
        PR_GET_TAGGED_ADDR_CTRL                     = 0x38
        PR_GET_THP_DISABLE                          = 0x2a
@@ -2499,6 +2510,7 @@ const (
        PR_GET_TIMING                               = 0xd
        PR_GET_TSC                                  = 0x19
        PR_GET_UNALIGN                              = 0x5
+       PR_LOCK_SHADOW_STACK_STATUS                 = 0x4c
        PR_MCE_KILL                                 = 0x21
        PR_MCE_KILL_CLEAR                           = 0x0
        PR_MCE_KILL_DEFAULT                         = 0x2
@@ -2525,6 +2537,8 @@ const (
        PR_PAC_GET_ENABLED_KEYS                     = 0x3d
        PR_PAC_RESET_KEYS                           = 0x36
        PR_PAC_SET_ENABLED_KEYS                     = 0x3c
+       PR_PMLEN_MASK                               = 0x7f000000
+       PR_PMLEN_SHIFT                              = 0x18
        PR_PPC_DEXCR_CTRL_CLEAR                     = 0x4
        PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC              = 0x10
        PR_PPC_DEXCR_CTRL_EDITABLE                  = 0x1
@@ -2592,6 +2606,7 @@ const (
        PR_SET_PTRACER                              = 0x59616d61
        PR_SET_SECCOMP                              = 0x16
        PR_SET_SECUREBITS                           = 0x1c
+       PR_SET_SHADOW_STACK_STATUS                  = 0x4b
        PR_SET_SPECULATION_CTRL                     = 0x35
        PR_SET_SYSCALL_USER_DISPATCH                = 0x3b
        PR_SET_TAGGED_ADDR_CTRL                     = 0x37
@@ -2602,6 +2617,9 @@ const (
        PR_SET_UNALIGN                              = 0x6
        PR_SET_VMA                                  = 0x53564d41
        PR_SET_VMA_ANON_NAME                        = 0x0
+       PR_SHADOW_STACK_ENABLE                      = 0x1
+       PR_SHADOW_STACK_PUSH                        = 0x4
+       PR_SHADOW_STACK_WRITE                       = 0x2
        PR_SME_GET_VL                               = 0x40
        PR_SME_SET_VL                               = 0x3f
        PR_SME_SET_VL_ONEXEC                        = 0x40000
@@ -2911,7 +2929,6 @@ const (
        RTM_NEWNEXTHOP                              = 0x68
        RTM_NEWNEXTHOPBUCKET                        = 0x74
        RTM_NEWNSID                                 = 0x58
-       RTM_NEWNVLAN                                = 0x70
        RTM_NEWPREFIX                               = 0x34
        RTM_NEWQDISC                                = 0x24
        RTM_NEWROUTE                                = 0x18
@@ -2920,6 +2937,7 @@ const (
        RTM_NEWTCLASS                               = 0x28
        RTM_NEWTFILTER                              = 0x2c
        RTM_NEWTUNNEL                               = 0x78
+       RTM_NEWVLAN                                 = 0x70
        RTM_NR_FAMILIES                             = 0x1b
        RTM_NR_MSGTYPES                             = 0x6c
        RTM_SETDCB                                  = 0x4f
index c0d45e320505ff6424711bbec395223c8d4ec450..75207613c785dbe3fb5e9afd152330e4ff342de3 100644 (file)
@@ -116,6 +116,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -304,6 +306,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index c731d24f02529136a59cf292fcfc27673e1c1396..c68acda53522d124fc1ef7c7dc889394ca4103ab 100644 (file)
@@ -116,6 +116,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -305,6 +307,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index 680018a4a7c9f0f67be48f7ebd0a31a7b6438d38..a8c607ab86b51b1e69629a7131b674a533c1a05f 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -310,6 +312,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index a63909f308d6d7d45db1b23ba71826ef51bd4c72..18563dd8d33a0f8e7a343377cd529ddf3eeb47fc 100644 (file)
@@ -109,6 +109,7 @@ const (
        F_SETOWN                         = 0x8
        F_UNLCK                          = 0x2
        F_WRLCK                          = 0x1
+       GCS_MAGIC                        = 0x47435300
        HIDIOCGRAWINFO                   = 0x80084803
        HIDIOCGRDESC                     = 0x90044802
        HIDIOCGRDESCSIZE                 = 0x80044801
@@ -119,6 +120,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -302,6 +305,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index 9b0a2573fe3fb37337d0c4b87cf268bf95deeb87..22912cdaa94483d6a5a2759d4d05b72663fce96b 100644 (file)
@@ -116,6 +116,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -297,6 +299,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index 958e6e0645acddc8287e1bdae4f672a49a3fb06b..29344eb37ab55a5982a044ccd388638be2ce0f23 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x80
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -303,6 +305,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index 50c7f25bd16c6b4bb48ba4f594c2c8064796075a..20d51fb96a897f5c675d91b1107efa1b0956c3b0 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x80
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -303,6 +305,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index ced21d66d955aa1471413648b780ac6a79c29dda..321b60902ae5cd5686f44b8dcf9d742a6df9d30c 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x80
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -303,6 +305,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index 226c0441902358d4fe95110e043721360edb84f8..9bacdf1e27910f1e8f2cb8c582b37f7c54467224 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x80
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -303,6 +305,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index 3122737cd464f0b9033911d2e928a48994c7b8fd..c2242726156a94e77d1b3a6b5c8f5e0f61b643f7 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x80
        IUCLC                            = 0x1000
        IXOFF                            = 0x400
@@ -358,6 +360,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index eb5d3467edf0c1a6fcda2fd26ca8685a89207a1f..6270c8ee13e3f5ac37b6954b36ca972696ad092c 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x80
        IUCLC                            = 0x1000
        IXOFF                            = 0x400
@@ -362,6 +364,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index e921ebc60b7142bf22eb748914eaf6557ce644b9..9966c1941f8301450c052e12184340b465ad204e 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x80
        IUCLC                            = 0x1000
        IXOFF                            = 0x400
@@ -362,6 +364,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index 38ba81c55c1fd3f8fee36578e2a5b67e1a5b1eb1..848e5fcc42e6f2f5dcc59d5a5d79199e57a856cb 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xffffff0f
+       IPV6_FLOWLABEL_MASK              = 0xffff0f00
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -294,6 +296,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index 71f0400977b3672a79401900b85701a23d8b0f99..669b2adb80b778d9daf8400dd00cbab41c0ea5d1 100644 (file)
@@ -115,6 +115,8 @@ const (
        IN_CLOEXEC                       = 0x80000
        IN_NONBLOCK                      = 0x800
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x7b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -366,6 +368,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x36
        SCM_TIMESTAMPING_PKTINFO         = 0x3a
        SCM_TIMESTAMPNS                  = 0x23
+       SCM_TS_OPT_ID                    = 0x51
        SCM_TXTIME                       = 0x3d
        SCM_WIFI_STATUS                  = 0x29
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x40182103
index c44a313322c54c61e7b1952290d2cc5f214331c3..4834e57514e44a7f8ca60a6a29e241ac1dba1c77 100644 (file)
@@ -119,6 +119,8 @@ const (
        IN_CLOEXEC                       = 0x400000
        IN_NONBLOCK                      = 0x4000
        IOCTL_VM_SOCKETS_GET_LOCAL_CID   = 0x200007b9
+       IPV6_FLOWINFO_MASK               = 0xfffffff
+       IPV6_FLOWLABEL_MASK              = 0xfffff
        ISIG                             = 0x1
        IUCLC                            = 0x200
        IXOFF                            = 0x1000
@@ -357,6 +359,7 @@ const (
        SCM_TIMESTAMPING_OPT_STATS       = 0x38
        SCM_TIMESTAMPING_PKTINFO         = 0x3c
        SCM_TIMESTAMPNS                  = 0x21
+       SCM_TS_OPT_ID                    = 0x5a
        SCM_TXTIME                       = 0x3f
        SCM_WIFI_STATUS                  = 0x25
        SECCOMP_IOCTL_NOTIF_ADDFD        = 0x80182103
index 829b87feb8da62f255f3b0662ed64cde8c2d01f7..c6545413c45b44cfa7876eb1ce27a1848c79b192 100644 (file)
@@ -141,6 +141,16 @@ import (
 //go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
 //go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
 //go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
+//go:cgo_import_dynamic libc_getpeerucred getpeerucred "libc.so"
+//go:cgo_import_dynamic libc_ucred_get ucred_get "libc.so"
+//go:cgo_import_dynamic libc_ucred_geteuid ucred_geteuid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getegid ucred_getegid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getruid ucred_getruid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getrgid ucred_getrgid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getsuid ucred_getsuid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getsgid ucred_getsgid "libc.so"
+//go:cgo_import_dynamic libc_ucred_getpid ucred_getpid "libc.so"
+//go:cgo_import_dynamic libc_ucred_free ucred_free "libc.so"
 //go:cgo_import_dynamic libc_port_create port_create "libc.so"
 //go:cgo_import_dynamic libc_port_associate port_associate "libc.so"
 //go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so"
@@ -280,6 +290,16 @@ import (
 //go:linkname procgetpeername libc_getpeername
 //go:linkname procsetsockopt libc_setsockopt
 //go:linkname procrecvfrom libc_recvfrom
+//go:linkname procgetpeerucred libc_getpeerucred
+//go:linkname procucred_get libc_ucred_get
+//go:linkname procucred_geteuid libc_ucred_geteuid
+//go:linkname procucred_getegid libc_ucred_getegid
+//go:linkname procucred_getruid libc_ucred_getruid
+//go:linkname procucred_getrgid libc_ucred_getrgid
+//go:linkname procucred_getsuid libc_ucred_getsuid
+//go:linkname procucred_getsgid libc_ucred_getsgid
+//go:linkname procucred_getpid libc_ucred_getpid
+//go:linkname procucred_free libc_ucred_free
 //go:linkname procport_create libc_port_create
 //go:linkname procport_associate libc_port_associate
 //go:linkname procport_dissociate libc_port_dissociate
@@ -420,6 +440,16 @@ var (
        procgetpeername,
        procsetsockopt,
        procrecvfrom,
+       procgetpeerucred,
+       procucred_get,
+       procucred_geteuid,
+       procucred_getegid,
+       procucred_getruid,
+       procucred_getrgid,
+       procucred_getsuid,
+       procucred_getsgid,
+       procucred_getpid,
+       procucred_free,
        procport_create,
        procport_associate,
        procport_dissociate,
@@ -2029,6 +2059,90 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func getpeerucred(fd uintptr, ucred *uintptr) (err error) {
+       _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procgetpeerucred)), 2, uintptr(fd), uintptr(unsafe.Pointer(ucred)), 0, 0, 0, 0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGet(pid int) (ucred uintptr, err error) {
+       r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procucred_get)), 1, uintptr(pid), 0, 0, 0, 0, 0)
+       ucred = uintptr(r0)
+       if e1 != 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGeteuid(ucred uintptr) (uid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_geteuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       uid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetegid(ucred uintptr) (gid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getegid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       gid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetruid(ucred uintptr) (uid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getruid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       uid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetrgid(ucred uintptr) (gid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getrgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       gid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetsuid(ucred uintptr) (uid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       uid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetsgid(ucred uintptr) (gid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       gid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredGetpid(ucred uintptr) (pid int) {
+       r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getpid)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       pid = int(r0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ucredFree(ucred uintptr) {
+       sysvicall6(uintptr(unsafe.Pointer(&procucred_free)), 1, uintptr(ucred), 0, 0, 0, 0, 0)
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func port_create() (n int, err error) {
        r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_create)), 0, 0, 0, 0, 0, 0, 0)
        n = int(r0)
index 524b0820cbc2ee32a4598fa64ebbe64cec2a9dda..c79aaff306ae3eebf5d338ac84c4d478f566c485 100644 (file)
@@ -458,4 +458,8 @@ const (
        SYS_LSM_SET_SELF_ATTR            = 460
        SYS_LSM_LIST_MODULES             = 461
        SYS_MSEAL                        = 462
+       SYS_SETXATTRAT                   = 463
+       SYS_GETXATTRAT                   = 464
+       SYS_LISTXATTRAT                  = 465
+       SYS_REMOVEXATTRAT                = 466
 )
index f485dbf4565671fd01bc685d7de256cbbac0dee2..5eb450695e95a819f1756ff2241adda0588cf628 100644 (file)
@@ -381,4 +381,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 70b35bf3b09f68cb6bd6c4065b4248ed02657766..05e5029744586103a94d9482fe3dac1bb9ca607f 100644 (file)
@@ -422,4 +422,8 @@ const (
        SYS_LSM_SET_SELF_ATTR            = 460
        SYS_LSM_LIST_MODULES             = 461
        SYS_MSEAL                        = 462
+       SYS_SETXATTRAT                   = 463
+       SYS_GETXATTRAT                   = 464
+       SYS_LISTXATTRAT                  = 465
+       SYS_REMOVEXATTRAT                = 466
 )
index 1893e2fe884044dc9724126bf8565ca9fca04748..38c53ec51bb3e6b6fff2b168f1351758d99b6b05 100644 (file)
@@ -325,4 +325,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 16a4017da0ab2fbb8868a34cf7e90df9b052577e..31d2e71a18e17f4cd6fdd3a16f8ecffa1c2cdc91 100644 (file)
@@ -321,4 +321,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 7e567f1efff21dabc0bbb99d82ac79568fa0c71e..f4184a336b0e02d1ff0a976a4d47d01667072ff7 100644 (file)
@@ -442,4 +442,8 @@ const (
        SYS_LSM_SET_SELF_ATTR            = 4460
        SYS_LSM_LIST_MODULES             = 4461
        SYS_MSEAL                        = 4462
+       SYS_SETXATTRAT                   = 4463
+       SYS_GETXATTRAT                   = 4464
+       SYS_LISTXATTRAT                  = 4465
+       SYS_REMOVEXATTRAT                = 4466
 )
index 38ae55e5ef8564b859a937192e6e7ff9ff75404d..05b9962278f2760f8134c2396859cb9c142fa0a2 100644 (file)
@@ -372,4 +372,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 5460
        SYS_LSM_LIST_MODULES        = 5461
        SYS_MSEAL                   = 5462
+       SYS_SETXATTRAT              = 5463
+       SYS_GETXATTRAT              = 5464
+       SYS_LISTXATTRAT             = 5465
+       SYS_REMOVEXATTRAT           = 5466
 )
index 55e92e60a82abed887cc2e86929cf413ccc1f0e7..43a256e9e6758502f2f5883e3c43c29bb05f2bff 100644 (file)
@@ -372,4 +372,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 5460
        SYS_LSM_LIST_MODULES        = 5461
        SYS_MSEAL                   = 5462
+       SYS_SETXATTRAT              = 5463
+       SYS_GETXATTRAT              = 5464
+       SYS_LISTXATTRAT             = 5465
+       SYS_REMOVEXATTRAT           = 5466
 )
index 60658d6a021f66f19d23ed38f6eae448f0fa1b21..eea5ddfc220774443034d5ad1b052c17347d626e 100644 (file)
@@ -442,4 +442,8 @@ const (
        SYS_LSM_SET_SELF_ATTR            = 4460
        SYS_LSM_LIST_MODULES             = 4461
        SYS_MSEAL                        = 4462
+       SYS_SETXATTRAT                   = 4463
+       SYS_GETXATTRAT                   = 4464
+       SYS_LISTXATTRAT                  = 4465
+       SYS_REMOVEXATTRAT                = 4466
 )
index e203e8a7ed4b2c76d1a08ccda193c17f82fc7e93..0d777bfbb1408e2c32b03fdc2b5652157b3872a8 100644 (file)
@@ -449,4 +449,8 @@ const (
        SYS_LSM_SET_SELF_ATTR            = 460
        SYS_LSM_LIST_MODULES             = 461
        SYS_MSEAL                        = 462
+       SYS_SETXATTRAT                   = 463
+       SYS_GETXATTRAT                   = 464
+       SYS_LISTXATTRAT                  = 465
+       SYS_REMOVEXATTRAT                = 466
 )
index 5944b97d54604ea41a1dea195b26f3bd1f387343..b44636502561e6953318bb9cc942be9616340bc9 100644 (file)
@@ -421,4 +421,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index c66d416dad1ccb56f1196d99545460f9d658f092..0c7d21c18816539b4d6856dbcf44f56b4217c421 100644 (file)
@@ -421,4 +421,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index a5459e766f59dbfbd2751e1ecc5f7f1c4561bfb4..8405391698787a00552d807260232ad8680fd332 100644 (file)
@@ -326,4 +326,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 01d86825bb926417fbc8c9e69c5ecb5bb599d683..fcf1b790d6cfd31996ab2f95beb8f965657e70be 100644 (file)
@@ -387,4 +387,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 7b703e77cda8450621f3892f1a03d7e698f12cee..52d15b5f9d4597c74ff988c7893a0f2710963e3f 100644 (file)
@@ -400,4 +400,8 @@ const (
        SYS_LSM_SET_SELF_ATTR       = 460
        SYS_LSM_LIST_MODULES        = 461
        SYS_MSEAL                   = 462
+       SYS_SETXATTRAT              = 463
+       SYS_GETXATTRAT              = 464
+       SYS_LISTXATTRAT             = 465
+       SYS_REMOVEXATTRAT           = 466
 )
index 5537148dcbb3dee0a8d5c8c85f5566895decc8db..a46abe64720547a72a90330c2aa29113b4ef0552 100644 (file)
@@ -4747,7 +4747,7 @@ const (
        NL80211_ATTR_MAC_HINT                                   = 0xc8
        NL80211_ATTR_MAC_MASK                                   = 0xd7
        NL80211_ATTR_MAX_AP_ASSOC_STA                           = 0xca
-       NL80211_ATTR_MAX                                        = 0x14c
+       NL80211_ATTR_MAX                                        = 0x14d
        NL80211_ATTR_MAX_CRIT_PROT_DURATION                     = 0xb4
        NL80211_ATTR_MAX_CSA_COUNTERS                           = 0xce
        NL80211_ATTR_MAX_MATCH_SETS                             = 0x85
@@ -5519,7 +5519,7 @@ const (
        NL80211_MNTR_FLAG_CONTROL                               = 0x3
        NL80211_MNTR_FLAG_COOK_FRAMES                           = 0x5
        NL80211_MNTR_FLAG_FCSFAIL                               = 0x1
-       NL80211_MNTR_FLAG_MAX                                   = 0x6
+       NL80211_MNTR_FLAG_MAX                                   = 0x7
        NL80211_MNTR_FLAG_OTHER_BSS                             = 0x4
        NL80211_MNTR_FLAG_PLCPFAIL                              = 0x2
        NL80211_MPATH_FLAG_ACTIVE                               = 0x1
@@ -6174,3 +6174,5 @@ type SockDiagReq struct {
        Family   uint8
        Protocol uint8
 }
+
+const RTM_NEWNVLAN = 0x70
index 4e613cf6335ceaaaf3075e177938ef11688461a4..3ca814f54d44eb100e254cebd949d31f0fe22b59 100644 (file)
@@ -43,8 +43,8 @@ type DLL struct {
 // LoadDLL loads DLL file into memory.
 //
 // Warning: using LoadDLL without an absolute path name is subject to
-// DLL preloading attacks. To safely load a system DLL, use LazyDLL
-// with System set to true, or use LoadLibraryEx directly.
+// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL],
+// or use [LoadLibraryEx] directly.
 func LoadDLL(name string) (dll *DLL, err error) {
        namep, err := UTF16PtrFromString(name)
        if err != nil {
@@ -271,6 +271,9 @@ func (d *LazyDLL) NewProc(name string) *LazyProc {
 }
 
 // NewLazyDLL creates new LazyDLL associated with DLL file.
+//
+// Warning: using NewLazyDLL without an absolute path name is subject to
+// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL].
 func NewLazyDLL(name string) *LazyDLL {
        return &LazyDLL{Name: name}
 }
@@ -410,7 +413,3 @@ func loadLibraryEx(name string, system bool) (*DLL, error) {
        }
        return &DLL{Name: name, Handle: h}, nil
 }
-
-type errString string
-
-func (s errString) Error() string { return string(s) }
index 612f7563a74c9f05b6e6cb3cb6203879018507e2..f43d2cd455b638dbd86d3d4a44e1d7612bda93d4 100644 (file)
@@ -170,6 +170,35 @@ func telemetryCounterName(crash []byte) (string, error) {
 // there is no possibility of strings from the crash report (which may
 // contain PII) leaking into the telemetry system.
 func parseStackPCs(crash string) ([]uintptr, error) {
+       // getSymbol parses the symbol name out of a line of the form:
+       // SYMBOL(ARGS)
+       //
+       // Note: SYMBOL may contain parens "pkg.(*T).method". However, type
+       // parameters are always replaced with ..., so they cannot introduce
+       // more parens. e.g., "pkg.(*T[...]).method".
+       //
+       // ARGS can contain parens. We want the first paren that is not
+       // immediately preceded by a ".".
+       //
+       // TODO(prattmic): This is mildly complicated and is only used to find
+       // runtime.sigpanic, so perhaps simplify this by checking explicitly
+       // for sigpanic.
+       getSymbol := func(line string) (string, error) {
+               var prev rune
+               for i, c := range line {
+                       if line[i] != '(' {
+                               prev = c
+                               continue
+                       }
+                       if prev == '.' {
+                               prev = c
+                               continue
+                       }
+                       return line[:i], nil
+               }
+               return "", fmt.Errorf("no symbol for stack frame: %s", line)
+       }
+
        // getPC parses the PC out of a line of the form:
        //     \tFILE:LINE +0xRELPC sp=... fp=... pc=...
        getPC := func(line string) (uint64, error) {
@@ -186,6 +215,9 @@ func parseStackPCs(crash string) ([]uintptr, error) {
                childSentinel  = sentinel()
                on             = false // are we in the first running goroutine?
                lines          = strings.Split(crash, "\n")
+               symLine        = true // within a goroutine, every other line is a symbol or file/line/pc location, starting with symbol.
+               currSymbol     string
+               prevSymbol     string // symbol of the most recent previous frame with a PC.
        )
        for i := 0; i < len(lines); i++ {
                line := lines[i]
@@ -228,21 +260,76 @@ func parseStackPCs(crash string) ([]uintptr, error) {
                // Note: SYMBOL may contain parens "pkg.(*T).method"
                // The RELPC is sometimes missing.
 
-               // Skip the symbol(args) line.
-               i++
-               if i == len(lines) {
-                       break
-               }
-               line = lines[i]
+               if symLine {
+                       var err error
+                       currSymbol, err = getSymbol(line)
+                       if err != nil {
+                               return nil, fmt.Errorf("error extracting symbol: %v", err)
+                       }
 
-               // Parse the PC, and correct for the parent and child's
-               // different mappings of the text section.
-               pc, err := getPC(line)
-               if err != nil {
-                       // Inlined frame, perhaps; skip it.
-                       continue
+                       symLine = false // Next line is FILE:LINE.
+               } else {
+                       // Parse the PC, and correct for the parent and child's
+                       // different mappings of the text section.
+                       pc, err := getPC(line)
+                       if err != nil {
+                               // Inlined frame, perhaps; skip it.
+
+                               // Done with this frame. Next line is a new frame.
+                               //
+                               // Don't update prevSymbol; we only want to
+                               // track frames with a PC.
+                               currSymbol = ""
+                               symLine = true
+                               continue
+                       }
+
+                       pc = pc-parentSentinel+childSentinel
+
+                       // If the previous frame was sigpanic, then this frame
+                       // was a trap (e.g., SIGSEGV).
+                       //
+                       // Typically all middle frames are calls, and report
+                       // the "return PC". That is, the instruction following
+                       // the CALL where the callee will eventually return to.
+                       //
+                       // runtime.CallersFrames is aware of this property and
+                       // will decrement each PC by 1 to "back up" to the
+                       // location of the CALL, which is the actual line
+                       // number the user expects.
+                       //
+                       // This does not work for traps, as a trap is not a
+                       // call, so the reported PC is not the return PC, but
+                       // the actual PC of the trap.
+                       //
+                       // runtime.Callers is aware of this and will
+                       // intentionally increment trap PCs in order to correct
+                       // for the decrement performed by
+                       // runtime.CallersFrames. See runtime.tracebackPCs and
+                       // runtume.(*unwinder).symPC.
+                       //
+                       // We must emulate the same behavior, otherwise we will
+                       // report the location of the instruction immediately
+                       // prior to the trap, which may be on a different line,
+                       // or even a different inlined functions.
+                       //
+                       // TODO(prattmic): The runtime applies the same trap
+                       // behavior for other "injected calls", see injectCall
+                       // in runtime.(*unwinder).next. Do we want to handle
+                       // those as well? I don't believe we'd ever see
+                       // runtime.asyncPreempt or runtime.debugCallV2 in a
+                       // typical crash.
+                       if prevSymbol == "runtime.sigpanic" {
+                               pc++
+                       }
+
+                       pcs = append(pcs, uintptr(pc))
+
+                       // Done with this frame. Next line is a new frame.
+                       prevSymbol = currSymbol
+                       currSymbol = ""
+                       symLine = true
                }
-               pcs = append(pcs, uintptr(pc-parentSentinel+childSentinel))
        }
        return pcs, nil
 }
index 6a3745c0582ae2388f61ef099f4ecc027427e5da..a152fbd37c7ef58753afe41f72830a06e3f33fb9 100644 (file)
@@ -262,7 +262,7 @@ type Bisect struct {
        // each pattern starts with a !.
        Disable bool
 
-       // SkipDigits is the number of hex digits to use in skip messages.
+       // SkipHexDigits is the number of hex digits to use in skip messages.
        // If the set of available changes is the same in each run, as it should be,
        // then this doesn't matter: we'll only exclude suffixes that uniquely identify
        // a given change. But for some programs, especially bisecting runtime
index d384aa89b8ebde1e5fdd21b6587b16de6785c76f..3a73084a53c2e6746f593439e60b4a7963854aeb 100644 (file)
@@ -156,10 +156,17 @@ type Pass struct {
 
        // AllPackageFacts returns a new slice containing all package
        // facts of the analysis's FactTypes in unspecified order.
+       // See comments for AllObjectFacts.
        AllPackageFacts func() []PackageFact
 
        // AllObjectFacts returns a new slice containing all object
        // facts of the analysis's FactTypes in unspecified order.
+       //
+       // The result includes all facts exported by packages
+       // whose symbols are referenced by the current package
+       // (by qualified identifiers or field/method selections).
+       // And it includes all facts exported from the current
+       // package by the current analysis pass.
        AllObjectFacts func() []ObjectFact
 
        /* Further fields may be added in future. */
index ee083a2d686723b887413e3bab1f17c28365562b..f6118bec647620e982ad064e30637a92ebcda330 100644 (file)
@@ -65,7 +65,9 @@ type RelatedInformation struct {
 // user can choose to apply to their code. Usually the SuggestedFix is
 // meant to fix the issue flagged by the diagnostic.
 //
-// The TextEdits must not overlap, nor contain edits for other packages.
+// The TextEdits must not overlap, nor contain edits for other
+// packages. Edits need not be totally ordered, but the order
+// determines how insertions at the same point will be applied.
 type SuggestedFix struct {
        // A verb phrase describing the fix, to be shown to
        // a user trying to decide whether to accept it.
index 1282e70d41f7030250e0e019b4523c5d74b444fd..c2445575cff8cf3a0f7e703d226b6e4f8022c789 100644 (file)
@@ -250,21 +250,12 @@ const (
        setFalse
 )
 
-func triStateFlag(name string, value triState, usage string) *triState {
-       flag.Var(&value, name, usage)
-       return &value
-}
-
 // triState implements flag.Value, flag.Getter, and flag.boolFlag.
 // They work like boolean flags: we can say vet -printf as well as vet -printf=true
 func (ts *triState) Get() interface{} {
        return *ts == setTrue
 }
 
-func (ts triState) isTrue() bool {
-       return ts == setTrue
-}
-
 func (ts *triState) Set(value string) error {
        b, err := strconv.ParseBool(value)
        if err != nil {
index b622dfdf3a06aa9a39c75cf73b46b1cbfdcbd345..a47ecbae731a510b5cab41f42ca60daba01bdbf7 100644 (file)
@@ -542,8 +542,8 @@ func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suff
                elem := tu.Elem()
                // Calculate offset of each element array.
                fields := []*types.Var{
-                       types.NewVar(token.NoPos, nil, "fake0", elem),
-                       types.NewVar(token.NoPos, nil, "fake1", elem),
+                       types.NewField(token.NoPos, nil, "fake0", elem, false),
+                       types.NewField(token.NoPos, nil, "fake1", elem, false),
                }
                offsets := arch.sizes.Offsetsof(fields)
                elemoff := int(offsets[1])
index 0d95fefcb5a2869b2021bb6f205b144fb70dc078..1413ee13d293e02a12984468d621ab2b589c6756 100644 (file)
@@ -19,6 +19,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -32,7 +33,7 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
 
        nodeFilter := []ast.Node{
@@ -57,15 +58,17 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
                                continue // short-circuit the heavy-weight gofmt check
                        }
-                       le := analysisutil.Format(pass.Fset, lhs)
-                       re := analysisutil.Format(pass.Fset, rhs)
+                       le := analysisinternal.Format(pass.Fset, lhs)
+                       re := analysisinternal.Format(pass.Fset, rhs)
                        if le == re {
                                pass.Report(analysis.Diagnostic{
                                        Pos: stmt.Pos(), Message: fmt.Sprintf("self-assignment of %s to %s", re, le),
-                                       SuggestedFixes: []analysis.SuggestedFix{
-                                               {Message: "Remove", TextEdits: []analysis.TextEdit{
-                                                       {Pos: stmt.Pos(), End: stmt.End(), NewText: []byte{}},
-                                               }},
+                                       SuggestedFixes: []analysis.SuggestedFix{{
+                                               Message: "Remove self-assignment",
+                                               TextEdits: []analysis.TextEdit{{
+                                                       Pos: stmt.Pos(),
+                                                       End: stmt.End(),
+                                               }}},
                                        },
                                })
                        }
index 931f9ca7540f65b0cd66c80b1e3daa1a3bef5b36..82d5439ce571e9eeedd783c58fb3f89356a80b14 100644 (file)
@@ -14,6 +14,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -28,8 +29,8 @@ var Analyzer = &analysis.Analyzer{
        Run:              run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
-       if !analysisutil.Imports(pass.Pkg, "sync/atomic") {
+func run(pass *analysis.Pass) (any, error) {
+       if !analysisinternal.Imports(pass.Pkg, "sync/atomic") {
                return nil, nil // doesn't directly import sync/atomic
        }
 
@@ -52,8 +53,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        if !ok {
                                continue
                        }
-                       fn := typeutil.StaticCallee(pass.TypesInfo, call)
-                       if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
+                       obj := typeutil.Callee(pass.TypesInfo, call)
+                       if analysisinternal.IsFunctionNamed(obj, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
                                checkAtomicAddAssignment(pass, n.Lhs[i], call)
                        }
                }
@@ -71,7 +72,7 @@ func checkAtomicAddAssignment(pass *analysis.Pass, left ast.Expr, call *ast.Call
        arg := call.Args[0]
        broken := false
 
-       gofmt := func(e ast.Expr) string { return analysisutil.Format(pass.Fset, e) }
+       gofmt := func(e ast.Expr) string { return analysisinternal.Format(pass.Fset, e) }
 
        if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
                broken = gofmt(left) == gofmt(uarg.X)
index 8cec6e8224a5dc0a04a724456a926f70fa101a78..e1cf9f9b7ade101bd66f2ccb2e8114e657893428 100644 (file)
@@ -15,6 +15,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 const Doc = "check for common mistakes involving boolean operators"
@@ -27,7 +28,7 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
 
        nodeFilter := []ast.Node{
@@ -103,7 +104,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[*
 func (op boolOp) checkRedundant(pass *analysis.Pass, exprs []ast.Expr) {
        seen := make(map[string]bool)
        for _, e := range exprs {
-               efmt := analysisutil.Format(pass.Fset, e)
+               efmt := analysisinternal.Format(pass.Fset, e)
                if seen[efmt] {
                        pass.ReportRangef(e, "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
                } else {
@@ -149,8 +150,8 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) {
                }
 
                // e is of the form 'x != c' or 'x == c'.
-               xfmt := analysisutil.Format(pass.Fset, x)
-               efmt := analysisutil.Format(pass.Fset, e)
+               xfmt := analysisinternal.Format(pass.Fset, x)
+               efmt := analysisinternal.Format(pass.Fset, e)
                if prev, found := seen[xfmt]; found {
                        // checkRedundant handles the case in which efmt == prev.
                        if efmt != prev {
index 613583a1a64909c40b39950431a8b7f72c2f617f..4f3bb035d65783e05346c760bece1b92e80dc8f8 100644 (file)
@@ -18,7 +18,7 @@ import (
        "strconv"
 
        "golang.org/x/tools/go/analysis"
-       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 const debug = false
@@ -40,8 +40,8 @@ var Analyzer = &analysis.Analyzer{
        Run:              run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
-       if !analysisutil.Imports(pass.Pkg, "runtime/cgo") {
+func run(pass *analysis.Pass) (any, error) {
+       if !analysisinternal.Imports(pass.Pkg, "runtime/cgo") {
                return nil, nil // doesn't use cgo
        }
 
index 03496cb3037d14258af3f3ff03d919624dd8a497..a9f02ac62e640589b1cea90a0117a87f290bb14c 100644 (file)
@@ -15,8 +15,8 @@ import (
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
-       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
        "golang.org/x/tools/internal/typeparams"
        "golang.org/x/tools/internal/versions"
 )
@@ -86,7 +86,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion
        lhs := assign.Lhs
        for i, x := range assign.Rhs {
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, assign.Lhs[i]), path)
+                       pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisinternal.Format(pass.Fset, assign.Lhs[i]), path)
                        lhs = nil // An lhs has been reported. We prefer the assignment warning and do not report twice.
                }
        }
@@ -100,7 +100,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion
                                if id, ok := l.(*ast.Ident); ok && id.Name != "_" {
                                        if obj := pass.TypesInfo.Defs[id]; obj != nil && obj.Type() != nil {
                                                if path := lockPath(pass.Pkg, obj.Type(), nil); path != nil {
-                                                       pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisutil.Format(pass.Fset, l), path)
+                                                       pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisinternal.Format(pass.Fset, l), path)
                                                }
                                        }
                                }
@@ -132,7 +132,7 @@ func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) {
                        x = node.Value
                }
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path)
+                       pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisinternal.Format(pass.Fset, x), path)
                }
        }
 }
@@ -163,7 +163,7 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) {
        }
        for _, x := range ce.Args {
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.ReportRangef(x, "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path)
+                       pass.ReportRangef(x, "call of %s copies lock value: %v", analysisinternal.Format(pass.Fset, ce.Fun), path)
                }
        }
 }
@@ -230,7 +230,7 @@ func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) {
                return
        }
        if path := lockPath(pass.Pkg, typ, nil); path != nil {
-               pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisutil.Format(pass.Fset, e), path)
+               pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisinternal.Format(pass.Fset, e), path)
        }
 }
 
@@ -350,7 +350,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
        // In go1.10, sync.noCopy did not implement Locker.
        // (The Unlock method was added only in CL 121876.)
        // TODO(adonovan): remove workaround when we drop go1.10.
-       if analysisutil.IsNamedType(typ, "sync", "noCopy") {
+       if analysisinternal.IsTypeNamed(typ, "sync", "noCopy") {
                return []string{typ.String()}
        }
 
index 5e8e80a6a77cd210f7caa081c4bdf177a895f4a5..e11957f2d099d113078e560a3152e112c5efec80 100644 (file)
@@ -13,6 +13,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -27,15 +28,15 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
-       if !analysisutil.Imports(pass.Pkg, "time") {
+func run(pass *analysis.Pass) (any, error) {
+       if !analysisinternal.Imports(pass.Pkg, "time") {
                return nil, nil
        }
 
        checkDeferCall := func(node ast.Node) bool {
                switch v := node.(type) {
                case *ast.CallExpr:
-                       if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") {
+                       if analysisinternal.IsFunctionNamed(typeutil.Callee(pass.TypesInfo, v), "time", "Since") {
                                pass.Reportf(v.Pos(), "call to time.Since is not deferred")
                        }
                case *ast.FuncLit:
index 7f62ad4c825d6af80269c3d093518c6fb07e0e0d..b8d29d019db0b0d7dcd6b79994d2a851dfc1a8d5 100644 (file)
@@ -13,9 +13,9 @@ import (
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
-       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 const Doc = `report passing non-pointer or non-error values to errors.As
@@ -31,7 +31,7 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        switch pass.Pkg.Path() {
        case "errors", "errors_test":
                // These packages know how to use their own APIs.
@@ -39,7 +39,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                return nil, nil
        }
 
-       if !analysisutil.Imports(pass.Pkg, "errors") {
+       if !analysisinternal.Imports(pass.Pkg, "errors") {
                return nil, nil // doesn't directly import errors
        }
 
@@ -50,8 +50,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
        }
        inspect.Preorder(nodeFilter, func(n ast.Node) {
                call := n.(*ast.CallExpr)
-               fn := typeutil.StaticCallee(pass.TypesInfo, call)
-               if !analysisutil.IsFunctionNamed(fn, "errors", "As") {
+               obj := typeutil.Callee(pass.TypesInfo, call)
+               if !analysisinternal.IsFunctionNamed(obj, "errors", "As") {
                        return
                }
                if len(call.Args) < 2 {
index 6eff3a20feae11090a1781200f3c9b9918a751b7..8012de99daaedb2a87ee0bbbab05699064494020 100644 (file)
@@ -10,6 +10,7 @@ import (
        "go/build"
        "regexp"
        "strings"
+       "unicode"
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
@@ -24,15 +25,97 @@ var Analyzer = &analysis.Analyzer{
        Run:  run,
 }
 
-var (
-       re             = regexp.MustCompile
-       asmWriteBP     = re(`,\s*BP$`) // TODO: can have false positive, e.g. for TESTQ BP,BP. Seems unlikely.
-       asmMentionBP   = re(`\bBP\b`)
-       asmControlFlow = re(`^(J|RET)`)
-)
+// Per-architecture checks for instructions.
+// Assume comments, leading and trailing spaces are removed.
+type arch struct {
+       isFPWrite func(string) bool
+       isFPRead  func(string) bool
+       isBranch  func(string) bool
+}
+
+var re = regexp.MustCompile
+
+func hasAnyPrefix(s string, prefixes ...string) bool {
+       for _, p := range prefixes {
+               if strings.HasPrefix(s, p) {
+                       return true
+               }
+       }
+       return false
+}
+
+var arches = map[string]arch{
+       "amd64": {
+               isFPWrite: re(`,\s*BP$`).MatchString, // TODO: can have false positive, e.g. for TESTQ BP,BP. Seems unlikely.
+               isFPRead:  re(`\bBP\b`).MatchString,
+               isBranch: func(s string) bool {
+                       return hasAnyPrefix(s, "J", "RET")
+               },
+       },
+       "arm64": {
+               isFPWrite: func(s string) bool {
+                       if i := strings.LastIndex(s, ","); i > 0 && strings.HasSuffix(s[i:], "R29") {
+                               return true
+                       }
+                       if hasAnyPrefix(s, "LDP", "LDAXP", "LDXP", "CASP") {
+                               // Instructions which write to a pair of registers, e.g.
+                               //      LDP 8(R0), (R26, R29)
+                               //      CASPD (R2, R3), (R2), (R26, R29)
+                               lp := strings.LastIndex(s, "(")
+                               rp := strings.LastIndex(s, ")")
+                               if lp > -1 && lp < rp {
+                                       return strings.Contains(s[lp:rp], ",") && strings.Contains(s[lp:rp], "R29")
+                               }
+                       }
+                       return false
+               },
+               isFPRead: re(`\bR29\b`).MatchString,
+               isBranch: func(s string) bool {
+                       // Get just the instruction
+                       if i := strings.IndexFunc(s, unicode.IsSpace); i > 0 {
+                               s = s[:i]
+                       }
+                       return arm64Branch[s]
+               },
+       },
+}
+
+// arm64 has many control flow instructions.
+// ^(B|RET) isn't sufficient or correct (e.g. BIC, BFI aren't control flow.)
+// It's easier to explicitly enumerate them in a map than to write a regex.
+// Borrowed from Go tree, cmd/asm/internal/arch/arm64.go
+var arm64Branch = map[string]bool{
+       "B":     true,
+       "BL":    true,
+       "BEQ":   true,
+       "BNE":   true,
+       "BCS":   true,
+       "BHS":   true,
+       "BCC":   true,
+       "BLO":   true,
+       "BMI":   true,
+       "BPL":   true,
+       "BVS":   true,
+       "BVC":   true,
+       "BHI":   true,
+       "BLS":   true,
+       "BGE":   true,
+       "BLT":   true,
+       "BGT":   true,
+       "BLE":   true,
+       "CBZ":   true,
+       "CBZW":  true,
+       "CBNZ":  true,
+       "CBNZW": true,
+       "JMP":   true,
+       "TBNZ":  true,
+       "TBZ":   true,
+       "RET":   true,
+}
 
 func run(pass *analysis.Pass) (interface{}, error) {
-       if build.Default.GOARCH != "amd64" { // TODO: arm64 also?
+       arch, ok := arches[build.Default.GOARCH]
+       if !ok {
                return nil, nil
        }
        if build.Default.GOOS != "linux" && build.Default.GOOS != "darwin" {
@@ -63,6 +146,9 @@ func run(pass *analysis.Pass) (interface{}, error) {
                                line = line[:i]
                        }
                        line = strings.TrimSpace(line)
+                       if line == "" {
+                               continue
+                       }
 
                        // We start checking code at a TEXT line for a frameless function.
                        if strings.HasPrefix(line, "TEXT") && strings.Contains(line, "(SB)") && strings.Contains(line, "$0") {
@@ -73,16 +159,12 @@ func run(pass *analysis.Pass) (interface{}, error) {
                                continue
                        }
 
-                       if asmWriteBP.MatchString(line) { // clobber of BP, function is not OK
+                       if arch.isFPWrite(line) {
                                pass.Reportf(analysisutil.LineStart(tf, lineno), "frame pointer is clobbered before saving")
                                active = false
                                continue
                        }
-                       if asmMentionBP.MatchString(line) { // any other use of BP might be a read, so function is OK
-                               active = false
-                               continue
-                       }
-                       if asmControlFlow.MatchString(line) { // give up after any branch instruction
+                       if arch.isFPRead(line) || arch.isBranch(line) {
                                active = false
                                continue
                        }
index 91ebe29de117a34b36518fe7707078b441ca8e66..e9acd96547e1a786255029b66f118326757e17f4 100644 (file)
@@ -12,8 +12,8 @@ import (
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
-       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
        "golang.org/x/tools/internal/typesinternal"
 )
 
@@ -41,12 +41,12 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
 
        // Fast path: if the package doesn't import net/http,
        // skip the traversal.
-       if !analysisutil.Imports(pass.Pkg, "net/http") {
+       if !analysisinternal.Imports(pass.Pkg, "net/http") {
                return nil, nil
        }
 
@@ -118,7 +118,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
                return false // the function called does not return two values.
        }
        isPtr, named := typesinternal.ReceiverNamed(res.At(0))
-       if !isPtr || named == nil || !analysisutil.IsNamedType(named, "net/http", "Response") {
+       if !isPtr || named == nil || !analysisinternal.IsTypeNamed(named, "net/http", "Response") {
                return false // the first return type is not *http.Response.
        }
 
@@ -133,11 +133,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
                return ok && id.Name == "http" // function in net/http package.
        }
 
-       if analysisutil.IsNamedType(typ, "net/http", "Client") {
+       if analysisinternal.IsTypeNamed(typ, "net/http", "Client") {
                return true // method on http.Client.
        }
        ptr, ok := types.Unalias(typ).(*types.Pointer)
-       return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
+       return ok && analysisinternal.IsTypeNamed(ptr.Elem(), "net/http", "Client") // method on *http.Client.
 }
 
 // restOfBlock, given a traversal stack, finds the innermost containing
index a4fa8d31c4ed5bbc7e50a4079e04b20037436238..d3df898d3011cdeded3d5ca41c7d8ccdff06b40c 100644 (file)
@@ -7,9 +7,7 @@
 package analysisutil
 
 import (
-       "bytes"
        "go/ast"
-       "go/printer"
        "go/token"
        "go/types"
        "os"
@@ -18,13 +16,6 @@ import (
        "golang.org/x/tools/internal/analysisinternal"
 )
 
-// Format returns a string representation of the expression.
-func Format(fset *token.FileSet, x ast.Expr) string {
-       var b bytes.Buffer
-       printer.Fprint(&b, fset, x)
-       return b.String()
-}
-
 // HasSideEffects reports whether evaluation of e has side effects.
 func HasSideEffects(info *types.Info, e ast.Expr) bool {
        safe := true
@@ -105,57 +96,4 @@ func LineStart(f *token.File, line int) token.Pos {
        }
 }
 
-// Imports returns true if 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
-}
-
-// IsNamedType reports whether t is the named type with the given package path
-// and one of the given names.
-// This function avoids allocating the concatenation of "pkg.Name",
-// which is important for the performance of syntax matching.
-func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
-       n, ok := types.Unalias(t).(*types.Named)
-       if !ok {
-               return false
-       }
-       obj := n.Obj()
-       if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath {
-               return false
-       }
-       name := obj.Name()
-       for _, n := range names {
-               if name == n {
-                       return true
-               }
-       }
-       return false
-}
-
-// IsFunctionNamed reports whether f is a top-level function defined in the
-// given package and has one of the given names.
-// It returns false if f is nil or a method.
-func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool {
-       if f == nil {
-               return false
-       }
-       if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
-               return false
-       }
-       if f.Type().(*types.Signature).Recv() != nil {
-               return false
-       }
-       for _, n := range names {
-               if f.Name() == n {
-                       return true
-               }
-       }
-       return false
-}
-
 var MustExtractDoc = analysisinternal.MustExtractDoc
index fe05eda44e49d32e061a9b6199b5c45973edbe18..d3181242153764fb9a182b833b718f6b37a9ba21 100644 (file)
@@ -14,6 +14,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
        "golang.org/x/tools/internal/typesinternal"
        "golang.org/x/tools/internal/versions"
 )
@@ -368,5 +369,5 @@ func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method str
        // Check that the receiver is a <pkgPath>.<typeName> or
        // *<pkgPath>.<typeName>.
        _, named := typesinternal.ReceiverNamed(recv)
-       return analysisutil.IsNamedType(named, pkgPath, typeName)
+       return analysisinternal.IsTypeNamed(named, pkgPath, typeName)
 }
index 26fdc1206f805542426b73e1daca06e519e3dbfa..f8a661aa5db0593bd7291a89191fe21a550266c9 100644 (file)
@@ -16,6 +16,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/cfg"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -48,7 +49,7 @@ var contextPackage = "context"
 // checkLostCancel analyzes a single named or literal function.
 func run(pass *analysis.Pass) (interface{}, error) {
        // Fast path: bypass check if file doesn't use context.WithCancel.
-       if !analysisutil.Imports(pass.Pkg, contextPackage) {
+       if !analysisinternal.Imports(pass.Pkg, contextPackage) {
                return nil, nil
        }
 
index 011ea8bef629256a21f87a6ead7ad394962653bb..81600a283aa21cb950a1fed2811c76df5e38b9e4 100644 (file)
@@ -5,7 +5,6 @@
 package printf
 
 import (
-       "bytes"
        _ "embed"
        "fmt"
        "go/ast"
@@ -15,15 +14,15 @@ import (
        "reflect"
        "regexp"
        "sort"
-       "strconv"
        "strings"
-       "unicode/utf8"
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
+       "golang.org/x/tools/internal/fmtstr"
        "golang.org/x/tools/internal/typeparams"
        "golang.org/x/tools/internal/versions"
 )
@@ -429,9 +428,9 @@ func checkCalls(pass *analysis.Pass) {
                        fn, kind := printfNameAndKind(pass, n)
                        switch kind {
                        case KindPrintf, KindErrorf:
-                               checkPrintf(pass, fileVersion, kind, n, fn)
+                               checkPrintf(pass, fileVersion, kind, n, fn.FullName())
                        case KindPrint:
-                               checkPrint(pass, n, fn)
+                               checkPrint(pass, n, fn.FullName())
                        }
                }
        })
@@ -490,30 +489,12 @@ func isFormatter(typ types.Type) bool {
        sig := fn.Type().(*types.Signature)
        return sig.Params().Len() == 2 &&
                sig.Results().Len() == 0 &&
-               analysisutil.IsNamedType(sig.Params().At(0).Type(), "fmt", "State") &&
+               analysisinternal.IsTypeNamed(sig.Params().At(0).Type(), "fmt", "State") &&
                types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune])
 }
 
-// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
-// It is constructed by parsePrintfVerb.
-type formatState struct {
-       verb     rune   // the format verb: 'd' for "%d"
-       format   string // the full format directive from % through verb, "%.3d".
-       name     string // Printf, Sprintf etc.
-       flags    []byte // the list of # + etc.
-       argNums  []int  // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
-       firstArg int    // Index of first argument after the format in the Printf call.
-       // Used only during parse.
-       pass         *analysis.Pass
-       call         *ast.CallExpr
-       argNum       int  // Which argument we're expecting to format now.
-       hasIndex     bool // Whether the argument is indexed.
-       indexPending bool // Whether we have an indexed argument that has not resolved.
-       nbytes       int  // number of bytes of the format string consumed.
-}
-
 // checkPrintf checks a call to a formatted print routine such as Printf.
-func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, fn *types.Func) {
+func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, name string) {
        idx := formatStringIndex(pass, call)
        if idx < 0 || idx >= len(call.Args) {
                return
@@ -542,7 +523,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
                                Pos: formatArg.Pos(),
                                End: formatArg.End(),
                                Message: fmt.Sprintf("non-constant format string in call to %s",
-                                       fn.FullName()),
+                                       name),
                                SuggestedFixes: []analysis.SuggestedFix{{
                                        Message: `Insert "%s" format string`,
                                        TextEdits: []analysis.TextEdit{{
@@ -559,49 +540,46 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
        firstArg := idx + 1 // Arguments are immediately after format string.
        if !strings.Contains(format, "%") {
                if len(call.Args) > firstArg {
-                       pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName())
+                       pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", name)
                }
                return
        }
-       // Hard part: check formats against args.
-       argNum := firstArg
-       maxArgNum := firstArg
+
+       // Pass the string constant value so
+       // fmt.Sprintf("%"+("s"), "hi", 3) can be reported as
+       // "fmt.Sprintf call needs 1 arg but has 2 args".
+       operations, err := fmtstr.Parse(format, idx)
+       if err != nil {
+               // All error messages are in predicate form ("call has a problem")
+               // so that they may be affixed into a subject ("log.Printf ").
+               pass.ReportRangef(call.Args[idx], "%s %s", name, err)
+               return
+       }
+
+       // index of the highest used index.
+       maxArgIndex := firstArg - 1
        anyIndex := false
-       for i, w := 0, 0; i < len(format); i += w {
-               w = 1
-               if format[i] != '%' {
-                       continue
-               }
-               state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum)
-               if state == nil {
-                       return
+       // Check formats against args.
+       for _, operation := range operations {
+               if operation.Prec.Index != -1 ||
+                       operation.Width.Index != -1 ||
+                       operation.Verb.Index != -1 {
+                       anyIndex = true
                }
-               w = len(state.format)
-               if !okPrintfArg(pass, call, state) { // One error per format is enough.
+               if !okPrintfArg(pass, call, &maxArgIndex, firstArg, name, operation) {
+                       // One error per format is enough.
                        return
                }
-               if state.hasIndex {
-                       anyIndex = true
-               }
-               if state.verb == 'w' {
+               if operation.Verb.Verb == 'w' {
                        switch kind {
                        case KindNone, KindPrint, KindPrintf:
-                               pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name)
+                               pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", name)
                                return
                        }
                }
-               if len(state.argNums) > 0 {
-                       // Continue with the next sequential argument.
-                       argNum = state.argNums[len(state.argNums)-1] + 1
-               }
-               for _, n := range state.argNums {
-                       if n >= maxArgNum {
-                               maxArgNum = n + 1
-                       }
-               }
        }
        // Dotdotdot is hard.
-       if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
+       if call.Ellipsis.IsValid() && maxArgIndex >= len(call.Args)-2 {
                return
        }
        // If any formats are indexed, extra arguments are ignored.
@@ -609,147 +587,13 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
                return
        }
        // There should be no leftover arguments.
-       if maxArgNum != len(call.Args) {
-               expect := maxArgNum - firstArg
+       if maxArgIndex+1 < len(call.Args) {
+               expect := maxArgIndex + 1 - firstArg
                numArgs := len(call.Args) - firstArg
-               pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg"))
-       }
-}
-
-// parseFlags accepts any printf flags.
-func (s *formatState) parseFlags() {
-       for s.nbytes < len(s.format) {
-               switch c := s.format[s.nbytes]; c {
-               case '#', '0', '+', '-', ' ':
-                       s.flags = append(s.flags, c)
-                       s.nbytes++
-               default:
-                       return
-               }
+               pass.ReportRangef(call, "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg"))
        }
 }
 
-// scanNum advances through a decimal number if present.
-func (s *formatState) scanNum() {
-       for ; s.nbytes < len(s.format); s.nbytes++ {
-               c := s.format[s.nbytes]
-               if c < '0' || '9' < c {
-                       return
-               }
-       }
-}
-
-// parseIndex scans an index expression. It returns false if there is a syntax error.
-func (s *formatState) parseIndex() bool {
-       if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
-               return true
-       }
-       // Argument index present.
-       s.nbytes++ // skip '['
-       start := s.nbytes
-       s.scanNum()
-       ok := true
-       if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
-               ok = false // syntax error is either missing "]" or invalid index.
-               s.nbytes = strings.Index(s.format[start:], "]")
-               if s.nbytes < 0 {
-                       s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format)
-                       return false
-               }
-               s.nbytes = s.nbytes + start
-       }
-       arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
-       if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) {
-               s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
-               return false
-       }
-       s.nbytes++ // skip ']'
-       arg := int(arg32)
-       arg += s.firstArg - 1 // We want to zero-index the actual arguments.
-       s.argNum = arg
-       s.hasIndex = true
-       s.indexPending = true
-       return true
-}
-
-// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
-func (s *formatState) parseNum() bool {
-       if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
-               if s.indexPending { // Absorb it.
-                       s.indexPending = false
-               }
-               s.nbytes++
-               s.argNums = append(s.argNums, s.argNum)
-               s.argNum++
-       } else {
-               s.scanNum()
-       }
-       return true
-}
-
-// parsePrecision scans for a precision. It returns false if there's a bad index expression.
-func (s *formatState) parsePrecision() bool {
-       // If there's a period, there may be a precision.
-       if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
-               s.flags = append(s.flags, '.') // Treat precision as a flag.
-               s.nbytes++
-               if !s.parseIndex() {
-                       return false
-               }
-               if !s.parseNum() {
-                       return false
-               }
-       }
-       return true
-}
-
-// parsePrintfVerb looks the formatting directive that begins the format string
-// and returns a formatState that encodes what the directive wants, without looking
-// at the actual arguments present in the call. The result is nil if there is an error.
-func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
-       state := &formatState{
-               format:   format,
-               name:     name,
-               flags:    make([]byte, 0, 5),
-               argNum:   argNum,
-               argNums:  make([]int, 0, 1),
-               nbytes:   1, // There's guaranteed to be a percent sign.
-               firstArg: firstArg,
-               pass:     pass,
-               call:     call,
-       }
-       // There may be flags.
-       state.parseFlags()
-       // There may be an index.
-       if !state.parseIndex() {
-               return nil
-       }
-       // There may be a width.
-       if !state.parseNum() {
-               return nil
-       }
-       // There may be a precision.
-       if !state.parsePrecision() {
-               return nil
-       }
-       // Now a verb, possibly prefixed by an index (which we may already have).
-       if !state.indexPending && !state.parseIndex() {
-               return nil
-       }
-       if state.nbytes == len(state.format) {
-               pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format)
-               return nil
-       }
-       verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
-       state.verb = verb
-       state.nbytes += w
-       if verb != '%' {
-               state.argNums = append(state.argNums, state.argNum)
-       }
-       state.format = state.format[:state.nbytes]
-       return state
-}
-
 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
 type printfArgType int
 
@@ -810,79 +654,96 @@ var printVerbs = []printVerb{
        {'X', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex},
 }
 
-// okPrintfArg compares the formatState to the arguments actually present,
-// reporting any discrepancies it can discern. If the final argument is ellipsissed,
-// there's little it can do for that.
-func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) {
+// okPrintfArg compares the operation to the arguments actually present,
+// reporting any discrepancies it can discern, maxArgIndex was the index of the highest used index.
+// If the final argument is ellipsissed, there's little it can do for that.
+func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) {
+       verb := operation.Verb.Verb
        var v printVerb
        found := false
        // Linear scan is fast enough for a small list.
        for _, v = range printVerbs {
-               if v.verb == state.verb {
+               if v.verb == verb {
                        found = true
                        break
                }
        }
 
-       // Could current arg implement fmt.Formatter?
+       // Could verb's arg implement fmt.Formatter?
        // Skip check for the %w verb, which requires an error.
        formatter := false
-       if v.typ != argError && state.argNum < len(call.Args) {
-               if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
+       if v.typ != argError && operation.Verb.ArgIndex < len(call.Args) {
+               if tv, ok := pass.TypesInfo.Types[call.Args[operation.Verb.ArgIndex]]; ok {
                        formatter = isFormatter(tv.Type)
                }
        }
 
        if !formatter {
                if !found {
-                       pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb)
+                       pass.ReportRangef(call, "%s format %s has unknown verb %c", name, operation.Text, verb)
                        return false
                }
-               for _, flag := range state.flags {
+               for _, flag := range operation.Flags {
                        // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
                        // See issues 23598 and 23605.
                        if flag == '0' {
                                continue
                        }
                        if !strings.ContainsRune(v.flags, rune(flag)) {
-                               pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag)
+                               pass.ReportRangef(call, "%s format %s has unrecognized flag %c", name, operation.Text, flag)
                                return false
                        }
                }
        }
-       // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
-       // but the final arg must be an integer.
-       trueArgs := 1
-       if state.verb == '%' {
-               trueArgs = 0
+
+       var argIndexes []int
+       // First check for *.
+       if operation.Width.Dynamic != -1 {
+               argIndexes = append(argIndexes, operation.Width.Dynamic)
+       }
+       if operation.Prec.Dynamic != -1 {
+               argIndexes = append(argIndexes, operation.Prec.Dynamic)
        }
-       nargs := len(state.argNums)
-       for i := 0; i < nargs-trueArgs; i++ {
-               argNum := state.argNums[i]
-               if !argCanBeChecked(pass, call, i, state) {
+       // If len(argIndexes)>0, we have something like %.*s and all
+       // indexes in argIndexes must be an integer.
+       for _, argIndex := range argIndexes {
+               if !argCanBeChecked(pass, call, argIndex, firstArg, operation, name) {
                        return
                }
-               arg := call.Args[argNum]
+               arg := call.Args[argIndex]
                if reason, ok := matchArgType(pass, argInt, arg); !ok {
                        details := ""
                        if reason != "" {
                                details = " (" + reason + ")"
                        }
-                       pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg), details)
+                       pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", name, operation.Text, analysisinternal.Format(pass.Fset, arg), details)
                        return false
                }
        }
 
-       if state.verb == '%' || formatter {
+       // Collect to update maxArgNum in one loop.
+       if operation.Verb.ArgIndex != -1 && verb != '%' {
+               argIndexes = append(argIndexes, operation.Verb.ArgIndex)
+       }
+       for _, index := range argIndexes {
+               *maxArgIndex = max(*maxArgIndex, index)
+       }
+
+       // Special case for '%', go will print "fmt.Printf("%10.2%%dhello", 4)"
+       // as "%4hello", discard any runes between the two '%'s, and treat the verb '%'
+       // as an ordinary rune, so early return to skip the type check.
+       if verb == '%' || formatter {
                return true
        }
-       argNum := state.argNums[len(state.argNums)-1]
-       if !argCanBeChecked(pass, call, len(state.argNums)-1, state) {
+
+       // Now check verb's type.
+       verbArgIndex := operation.Verb.ArgIndex
+       if !argCanBeChecked(pass, call, verbArgIndex, firstArg, operation, name) {
                return false
        }
-       arg := call.Args[argNum]
-       if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' {
-               pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg))
+       arg := call.Args[verbArgIndex]
+       if isFunctionValue(pass, arg) && verb != 'p' && verb != 'T' {
+               pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", name, operation.Text, analysisinternal.Format(pass.Fset, arg))
                return false
        }
        if reason, ok := matchArgType(pass, v.typ, arg); !ok {
@@ -894,12 +755,12 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
                if reason != "" {
                        details = " (" + reason + ")"
                }
-               pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
+               pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", name, operation.Text, analysisinternal.Format(pass.Fset, arg), typeString, details)
                return false
        }
-       if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) {
+       if v.typ&argString != 0 && v.verb != 'T' && !strings.Contains(operation.Flags, "#") {
                if methodName, ok := recursiveStringer(pass, arg); ok {
-                       pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName)
+                       pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", name, operation.Text, analysisinternal.Format(pass.Fset, arg), methodName)
                        return false
                }
        }
@@ -983,25 +844,24 @@ func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
 // argCanBeChecked reports whether the specified argument is statically present;
 // it may be beyond the list of arguments or in a terminal slice... argument, which
 // means we can't see it.
-func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool {
-       argNum := state.argNums[formatArg]
-       if argNum <= 0 {
+func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, argIndex, firstArg int, operation *fmtstr.Operation, name string) bool {
+       if argIndex <= 0 {
                // Shouldn't happen, so catch it with prejudice.
-               panic("negative arg num")
+               panic("negative argIndex")
        }
-       if argNum < len(call.Args)-1 {
+       if argIndex < len(call.Args)-1 {
                return true // Always OK.
        }
        if call.Ellipsis.IsValid() {
                return false // We just can't tell; there could be many more arguments.
        }
-       if argNum < len(call.Args) {
+       if argIndex < len(call.Args) {
                return true
        }
        // There are bad indexes in the format or there are fewer arguments than the format needs.
        // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
-       arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
-       pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
+       arg := argIndex - firstArg + 1 // People think of arguments as 1-indexed.
+       pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", name, operation.Text, arg, count(len(call.Args)-firstArg, "arg"))
        return false
 }
 
@@ -1018,7 +878,7 @@ const (
 )
 
 // checkPrint checks a call to an unformatted print routine such as Println.
-func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
+func checkPrint(pass *analysis.Pass, call *ast.CallExpr, name string) {
        firstArg := 0
        typ := pass.TypesInfo.Types[call.Fun].Type
        if typ == nil {
@@ -1052,7 +912,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
                if sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
                        if x, ok := sel.X.(*ast.Ident); ok {
                                if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
-                                       pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0]))
+                                       pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", name, analysisinternal.Format(pass.Fset, call.Args[0]))
                                }
                        }
                }
@@ -1066,25 +926,25 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
                if strings.Contains(s, "%") {
                        m := printFormatRE.FindStringSubmatch(s)
                        if m != nil {
-                               pass.ReportRangef(call, "%s call has possible Printf formatting directive %s", fn.FullName(), m[0])
+                               pass.ReportRangef(call, "%s call has possible Printf formatting directive %s", name, m[0])
                        }
                }
        }
-       if strings.HasSuffix(fn.Name(), "ln") {
+       if strings.HasSuffix(name, "ln") {
                // The last item, if a string, should not have a newline.
                arg = args[len(args)-1]
                if s, ok := stringConstantExpr(pass, arg); ok {
                        if strings.HasSuffix(s, "\n") {
-                               pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName())
+                               pass.ReportRangef(call, "%s arg list ends with redundant newline", name)
                        }
                }
        }
        for _, arg := range args {
                if isFunctionValue(pass, arg) {
-                       pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg))
+                       pass.ReportRangef(call, "%s arg %s is a func value, not called", name, analysisinternal.Format(pass.Fset, arg))
                }
                if methodName, ok := recursiveStringer(pass, arg); ok {
-                       pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName)
+                       pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", name, analysisinternal.Format(pass.Fset, arg), methodName)
                }
        }
 }
index 759ed0043ff17cd531cd813885d3bcdedf5f6b0e..46b5f6d68c612a095ba8c21fd07aea8747c493ec 100644 (file)
@@ -19,8 +19,8 @@ import (
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
-       "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
        "golang.org/x/tools/internal/typeparams"
 )
 
@@ -123,7 +123,7 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
                }
        }
        if amt >= minSize {
-               ident := analysisutil.Format(pass.Fset, x)
+               ident := analysisinternal.Format(pass.Fset, x)
                qualifier := ""
                if len(sizes) > 1 {
                        qualifier = "may be "
index 5f121f720d8315dcefe6fa365f3a6d37dca27edb..78a2fa5ea3bd346396f476e06387b5a85e51b74f 100644 (file)
@@ -8,6 +8,8 @@ package sigchanyzer
 
 import (
        "bytes"
+       "slices"
+
        _ "embed"
        "go/ast"
        "go/format"
@@ -18,6 +20,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -32,8 +35,8 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
-       if !analysisutil.Imports(pass.Pkg, "os/signal") {
+func run(pass *analysis.Pass) (any, error) {
+       if !analysisinternal.Imports(pass.Pkg, "os/signal") {
                return nil, nil // doesn't directly import signal
        }
 
@@ -69,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                // mutating the AST. See https://golang.org/issue/46129.
                chanDeclCopy := &ast.CallExpr{}
                *chanDeclCopy = *chanDecl
-               chanDeclCopy.Args = append([]ast.Expr(nil), chanDecl.Args...)
+               chanDeclCopy.Args = slices.Clone(chanDecl.Args)
                chanDeclCopy.Args = append(chanDeclCopy.Args, &ast.BasicLit{
                        Kind:  token.INT,
                        Value: "1",
index 0129102a33695b6b13b7646f2d62fe80090e6de9..c1ac960435d41fe79323d79e5a523e621e556431 100644 (file)
@@ -20,6 +20,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
        "golang.org/x/tools/internal/typesinternal"
 )
 
@@ -114,10 +115,10 @@ func run(pass *analysis.Pass) (any, error) {
                                default:
                                        if unknownArg == nil {
                                                pass.ReportRangef(arg, "%s arg %q should be a string or a slog.Attr (possible missing key or value)",
-                                                       shortName(fn), analysisutil.Format(pass.Fset, arg))
+                                                       shortName(fn), analysisinternal.Format(pass.Fset, arg))
                                        } else {
                                                pass.ReportRangef(arg, "%s arg %q should probably be a string or a slog.Attr (previous arg %q cannot be a key)",
-                                                       shortName(fn), analysisutil.Format(pass.Fset, arg), analysisutil.Format(pass.Fset, unknownArg))
+                                                       shortName(fn), analysisinternal.Format(pass.Fset, arg), analysisinternal.Format(pass.Fset, unknownArg))
                                        }
                                        // Stop here so we report at most one missing key per call.
                                        return
@@ -157,7 +158,7 @@ func run(pass *analysis.Pass) (any, error) {
 }
 
 func isAttr(t types.Type) bool {
-       return analysisutil.IsNamedType(t, "log/slog", "Attr")
+       return analysisinternal.IsTypeNamed(t, "log/slog", "Attr")
 }
 
 // shortName returns a name for the function that is shorter than FullName.
index 75d8697759eb62892b84e33c1612a6ac76ebfe5b..429125a8b7d42898d024125813e2610692dcc0a2 100644 (file)
@@ -11,6 +11,7 @@ import (
        "go/build"
        "go/types"
        "regexp"
+       "slices"
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/inspect"
@@ -46,16 +47,14 @@ func run(pass *analysis.Pass) (any, error) {
        // Prior to go1.22, versions.FileVersion returns only the
        // toolchain version, which is of no use to us, so
        // disable this analyzer on earlier versions.
-       if !slicesContains(build.Default.ReleaseTags, "go1.22") {
+       if !slices.Contains(build.Default.ReleaseTags, "go1.22") {
                return nil, nil
        }
 
        // Don't report diagnostics for modules marked before go1.21,
        // since at that time the go directive wasn't clearly
        // specified as a toolchain requirement.
-       //
-       // TODO(adonovan): after go1.21, call GoVersion directly.
-       pkgVersion := any(pass.Pkg).(interface{ GoVersion() string }).GoVersion()
+       pkgVersion := pass.Pkg.GoVersion()
        if !versions.AtLeast(pkgVersion, "go1.21") {
                return nil, nil
        }
@@ -88,7 +87,7 @@ func run(pass *analysis.Pass) (any, error) {
        inspect.Preorder(nodeFilter, func(n ast.Node) {
                switch n := n.(type) {
                case *ast.File:
-                       if isGenerated(n) {
+                       if ast.IsGenerated(n) {
                                // Suppress diagnostics in generated files (such as cgo).
                                fileVersion = ""
                        } else {
@@ -115,19 +114,6 @@ func run(pass *analysis.Pass) (any, error) {
        return nil, nil
 }
 
-// Reduced from x/tools/gopls/internal/golang/util.go. Good enough for now.
-// TODO(adonovan): use ast.IsGenerated in go1.21.
-func isGenerated(f *ast.File) bool {
-       for _, group := range f.Comments {
-               for _, comment := range group.List {
-                       if matched := generatedRx.MatchString(comment.Text); matched {
-                               return true
-                       }
-               }
-       }
-       return false
-}
-
 // Matches cgo generated comment as well as the proposed standard:
 //
 //     https://golang.org/s/generatedcode
@@ -147,13 +133,3 @@ func origin(obj types.Object) types.Object {
        }
        return obj
 }
-
-// TODO(adonovan): use go1.21 slices.Contains.
-func slicesContains[S ~[]E, E comparable](slice S, x E) bool {
-       for _, elem := range slice {
-               if elem == x {
-                       return true
-               }
-       }
-       return false
-}
index 108600a2baf1a86be3893b4cdcc3cd63de58927c..f56e6ecaa299b630b514929742c4f4dc936e1879 100644 (file)
@@ -198,14 +198,14 @@ func run(pass *analysis.Pass) (interface{}, error) {
                // the type has methods, as some {String,GoString,Format}
                // may change the behavior of fmt.Sprint.
                if len(ttypes) == 1 && len(vtypes) == 1 && types.NewMethodSet(V0).Len() == 0 {
-                       fmtName, importEdits := analysisinternal.AddImport(pass.TypesInfo, file, arg.Pos(), "fmt", "fmt")
+                       _, prefix, importEdits := analysisinternal.AddImport(pass.TypesInfo, file, "fmt", "fmt", "Sprint", arg.Pos())
                        if types.Identical(T0, types.Typ[types.String]) {
                                // string(x) -> fmt.Sprint(x)
                                addFix("Format the number as a decimal", append(importEdits,
                                        analysis.TextEdit{
                                                Pos:     call.Fun.Pos(),
                                                End:     call.Fun.End(),
-                                               NewText: []byte(fmtName + ".Sprint"),
+                                               NewText: []byte(prefix + "Sprint"),
                                        }),
                                )
                        } else {
@@ -214,7 +214,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                                        analysis.TextEdit{
                                                Pos:     call.Lparen + 1,
                                                End:     call.Lparen + 1,
-                                               NewText: []byte(fmtName + ".Sprint("),
+                                               NewText: []byte(prefix + "Sprint("),
                                        },
                                        analysis.TextEdit{
                                                Pos:     call.Rparen,
index a0beb46bd143b66e26ea8f1fa44a2908cfe95403..4115ef769430b218b02ad56013f5948901f4bcd5 100644 (file)
@@ -89,7 +89,7 @@ var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
 // checkCanonicalFieldTag checks a single struct field tag.
 func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *namesSeen) {
        switch pass.Pkg.Path() {
-       case "encoding/json", "encoding/xml":
+       case "encoding/json", "encoding/json/v2", "encoding/xml":
                // These packages know how to use their own APIs.
                // Sometimes they are testing what happens to incorrect programs.
                return
index effcdc5700b16d3309d5aa85d7304646ad7ee6ab..fef5a6014c41dbd12a7b7e731a191af2b22d6066 100644 (file)
@@ -16,6 +16,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -38,7 +39,7 @@ var Analyzer = &analysis.Analyzer{
 func run(pass *analysis.Pass) (interface{}, error) {
        inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
 
-       if !analysisutil.Imports(pass.Pkg, "testing") {
+       if !analysisinternal.Imports(pass.Pkg, "testing") {
                return nil, nil
        }
 
index 8c7a51ca525dda1b6bfdd2f2313830e888077273..027c99e6b0f9316733f8c6e1361d6fc3758ddd2b 100644 (file)
@@ -36,6 +36,8 @@ func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *
 
 // isMethodNamed returns true if f is a method defined
 // in package with the path pkgPath with a name in names.
+//
+// (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.)
 func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
        if f == nil {
                return false
index 36f2c43eb64d3029e26fb982378411ddcb67ff27..285b34218c3f16891226179fde67592d486b8769 100644 (file)
@@ -16,6 +16,7 @@ import (
 
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -257,7 +258,7 @@ func isTestingType(typ types.Type, testingType string) bool {
        if !ok {
                return false
        }
-       return analysisutil.IsNamedType(ptr.Elem(), "testing", testingType)
+       return analysisinternal.IsTypeNamed(ptr.Elem(), "testing", testingType)
 }
 
 // Validate that fuzz target function's arguments are of accepted types.
index 4a6c6b8bc6cc5c9e0c3826b561c2d820acb408ac..4fdbb2b5415eff7da5c12692f9ad92e4dd650328 100644 (file)
@@ -19,6 +19,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
        "golang.org/x/tools/go/types/typeutil"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 const badFormat = "2006-02-01"
@@ -35,7 +36,7 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        // Note: (time.Time).Format is a method and can be a typeutil.Callee
        // without directly importing "time". So we cannot just skip this package
        // when !analysisutil.Imports(pass.Pkg, "time").
@@ -48,11 +49,9 @@ func run(pass *analysis.Pass) (interface{}, error) {
        }
        inspect.Preorder(nodeFilter, func(n ast.Node) {
                call := n.(*ast.CallExpr)
-               fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
-               if !ok {
-                       return
-               }
-               if !isTimeDotFormat(fn) && !isTimeDotParse(fn) {
+               obj := typeutil.Callee(pass.TypesInfo, call)
+               if !analysisinternal.IsMethodNamed(obj, "time", "Time", "Format") &&
+                       !analysisinternal.IsFunctionNamed(obj, "time", "Parse") {
                        return
                }
                if len(call.Args) > 0 {
@@ -87,19 +86,6 @@ func run(pass *analysis.Pass) (interface{}, error) {
        return nil, nil
 }
 
-func isTimeDotFormat(f *types.Func) bool {
-       if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" {
-               return false
-       }
-       // Verify that the receiver is time.Time.
-       recv := f.Type().(*types.Signature).Recv()
-       return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time")
-}
-
-func isTimeDotParse(f *types.Func) bool {
-       return analysisutil.IsFunctionNamed(f, "time", "Parse")
-}
-
 // badFormatAt return the start of a bad format in e or -1 if no bad format is found.
 func badFormatAt(info *types.Info, e ast.Expr) int {
        tv, ok := info.Types[e]
index a7889fa45908378cab6728b5ce69ffbecc90f6db..26e894bd4000eb9e92a9a6c6b01092d9c6f1d8df 100644 (file)
@@ -28,7 +28,7 @@ var Analyzer = &analysis.Analyzer{
        Run:      run,
 }
 
-func run(pass *analysis.Pass) (interface{}, error) {
+func run(pass *analysis.Pass) (any, error) {
        switch pass.Pkg.Path() {
        case "encoding/gob", "encoding/json", "encoding/xml", "encoding/asn1":
                // These packages know how to use their own APIs.
index d17d0d9444e1f41d82b8c3a272940f30ad087860..325a15358d5939c1b2d0d6dc77e5faa12b8aeb57 100644 (file)
@@ -9,6 +9,6 @@
 // unreachable: check for unreachable code
 //
 // The unreachable analyzer finds statements that execution can never reach
-// because they are preceded by an return statement, a call to panic, an
+// because they are preceded by a return statement, a call to panic, an
 // infinite loop, or similar constructs.
 package unreachable
index 272ae7fe045e3e2f9a4955a55ec14afa163e2acb..fb5b944faad08d06e7204d5de2da8300035c10b4 100644 (file)
@@ -16,6 +16,7 @@ import (
        "golang.org/x/tools/go/analysis/passes/inspect"
        "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
        "golang.org/x/tools/go/ast/inspector"
+       "golang.org/x/tools/internal/analysisinternal"
 )
 
 //go:embed doc.go
@@ -104,7 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
                }
                switch sel.Sel.Name {
                case "Pointer", "UnsafeAddr":
-                       if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "Value") {
+                       if analysisinternal.IsTypeNamed(info.Types[sel.X].Type, "reflect", "Value") {
                                return true
                        }
                }
@@ -152,5 +153,5 @@ func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool {
 
 // isReflectHeader reports whether t is reflect.SliceHeader or reflect.StringHeader.
 func isReflectHeader(t types.Type) bool {
-       return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader")
+       return analysisinternal.IsTypeNamed(t, "reflect", "SliceHeader", "StringHeader")
 }
index c27d26dd6ec010cb06c3dcb4094a54aee3f9f4e8..d7cc1e6ae2c7cfce3d32b22e890d163287a43564 100644 (file)
@@ -131,7 +131,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
 
 // func() string
 var sigNoArgsStringResult = types.NewSignature(nil, nil,
-       types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
+       types.NewTuple(types.NewParam(token.NoPos, nil, "", types.Typ[types.String])),
        false)
 
 type stringSetFlag map[string]bool
index 1a9b3094e5e5779c5b3b1a016b2f82221a823c99..82c3db6a39db748c58b18d8f73e2908de9fdc347 100644 (file)
@@ -367,17 +367,26 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
                        }
 
                        pass := &analysis.Pass{
-                               Analyzer:          a,
-                               Fset:              fset,
-                               Files:             files,
-                               OtherFiles:        cfg.NonGoFiles,
-                               IgnoredFiles:      cfg.IgnoredFiles,
-                               Pkg:               pkg,
-                               TypesInfo:         info,
-                               TypesSizes:        tc.Sizes,
-                               TypeErrors:        nil, // unitchecker doesn't RunDespiteErrors
-                               ResultOf:          inputs,
-                               Report:            func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
+                               Analyzer:     a,
+                               Fset:         fset,
+                               Files:        files,
+                               OtherFiles:   cfg.NonGoFiles,
+                               IgnoredFiles: cfg.IgnoredFiles,
+                               Pkg:          pkg,
+                               TypesInfo:    info,
+                               TypesSizes:   tc.Sizes,
+                               TypeErrors:   nil, // unitchecker doesn't RunDespiteErrors
+                               ResultOf:     inputs,
+                               Report: func(d analysis.Diagnostic) {
+                                       // Unitchecker doesn't apply fixes, but it does report them in the JSON output.
+                                       if err := analysisinternal.ValidateFixes(fset, a, d.SuggestedFixes); err != nil {
+                                               // Since we have diagnostics, the exit code will be nonzero,
+                                               // so logging these errors is sufficient.
+                                               log.Println(err)
+                                               d.SuggestedFixes = nil
+                                       }
+                                       act.diagnostics = append(act.diagnostics, d)
+                               },
                                ImportObjectFact:  facts.ImportObjectFact,
                                ExportObjectFact:  facts.ExportObjectFact,
                                AllObjectFacts:    func() []analysis.ObjectFact { return facts.AllObjectFacts(factFilter) },
@@ -386,7 +395,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
                                AllPackageFacts:   func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) },
                                Module:            module,
                        }
-                       pass.ReadFile = analysisinternal.MakeReadFile(pass)
+                       pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile)
 
                        t0 := time.Now()
                        act.result, act.err = a.Run(pass)
index 958cf38deb00a4c85d5659cad7f3efe34d6efc79..0d5050fe40510f7ca0023c145b4a46e59b1a5aef 100644 (file)
@@ -36,6 +36,9 @@ package inspector
 
 import (
        "go/ast"
+       _ "unsafe"
+
+       "golang.org/x/tools/internal/astutil/edge"
 )
 
 // An Inspector provides methods for inspecting
@@ -44,6 +47,24 @@ type Inspector struct {
        events []event
 }
 
+//go:linkname events
+func events(in *Inspector) []event { return in.events }
+
+func packEdgeKindAndIndex(ek edge.Kind, index int) int32 {
+       return int32(uint32(index+1)<<7 | uint32(ek))
+}
+
+// unpackEdgeKindAndIndex unpacks the edge kind and edge index (within
+// an []ast.Node slice) from the parent field of a pop event.
+//
+//go:linkname unpackEdgeKindAndIndex
+func unpackEdgeKindAndIndex(x int32) (edge.Kind, int) {
+       // The "parent" field of a pop node holds the
+       // edge Kind in the lower 7 bits and the index+1
+       // in the upper 25.
+       return edge.Kind(x & 0x7f), int(x>>7) - 1
+}
+
 // New returns an Inspector for the specified syntax trees.
 func New(files []*ast.File) *Inspector {
        return &Inspector{traverse(files)}
@@ -52,9 +73,10 @@ func New(files []*ast.File) *Inspector {
 // An event represents a push or a pop
 // of an ast.Node during a traversal.
 type event struct {
-       node  ast.Node
-       typ   uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events
-       index int    // index of corresponding push or pop event
+       node   ast.Node
+       typ    uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events
+       index  int32  // index of corresponding push or pop event
+       parent int32  // index of parent's push node (push nodes only), or packed edge kind/index (pop nodes only)
 }
 
 // TODO: Experiment with storing only the second word of event.node (unsafe.Pointer).
@@ -83,7 +105,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) {
        // })
 
        mask := maskOf(types)
-       for i := 0; i < len(in.events); {
+       for i := int32(0); i < int32(len(in.events)); {
                ev := in.events[i]
                if ev.index > i {
                        // push
@@ -113,7 +135,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) {
 // matches an element of the types slice.
 func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) {
        mask := maskOf(types)
-       for i := 0; i < len(in.events); {
+       for i := int32(0); i < int32(len(in.events)); {
                ev := in.events[i]
                if ev.index > i {
                        // push
@@ -147,7 +169,7 @@ func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proc
 func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) {
        mask := maskOf(types)
        var stack []ast.Node
-       for i := 0; i < len(in.events); {
+       for i := int32(0); i < int32(len(in.events)); {
                ev := in.events[i]
                if ev.index > i {
                        // push
@@ -189,43 +211,74 @@ func traverse(files []*ast.File) []event {
                extent += int(f.End() - f.Pos())
        }
        // This estimate is based on the net/http package.
-       capacity := extent * 33 / 100
-       if capacity > 1e6 {
-               capacity = 1e6 // impose some reasonable maximum
+       capacity := min(extent*33/100, 1e6) // impose some reasonable maximum (1M)
+
+       v := &visitor{
+               events: make([]event, 0, capacity),
+               stack:  []item{{index: -1}}, // include an extra event so file nodes have a parent
+       }
+       for _, file := range files {
+               walk(v, edge.Invalid, -1, file)
        }
-       events := make([]event, 0, capacity)
+       return v.events
+}
 
-       var stack []event
-       stack = append(stack, event{}) // include an extra event so file nodes have a parent
-       for _, f := range files {
-               ast.Inspect(f, func(n ast.Node) bool {
-                       if n != nil {
-                               // push
-                               ev := event{
-                                       node:  n,
-                                       typ:   0,           // temporarily used to accumulate type bits of subtree
-                                       index: len(events), // push event temporarily holds own index
-                               }
-                               stack = append(stack, ev)
-                               events = append(events, ev)
-                       } else {
-                               // pop
-                               top := len(stack) - 1
-                               ev := stack[top]
-                               typ := typeOf(ev.node)
-                               push := ev.index
-                               parent := top - 1
-
-                               events[push].typ = typ            // set type of push
-                               stack[parent].typ |= typ | ev.typ // parent's typ contains push and pop's typs.
-                               events[push].index = len(events)  // make push refer to pop
-
-                               stack = stack[:top]
-                               events = append(events, ev)
-                       }
-                       return true
-               })
+type visitor struct {
+       events []event
+       stack  []item
+}
+
+type item struct {
+       index            int32  // index of current node's push event
+       parentIndex      int32  // index of parent node's push event
+       typAccum         uint64 // accumulated type bits of current node's descendents
+       edgeKindAndIndex int32  // edge.Kind and index, bit packed
+}
+
+func (v *visitor) push(ek edge.Kind, eindex int, node ast.Node) {
+       var (
+               index       = int32(len(v.events))
+               parentIndex = v.stack[len(v.stack)-1].index
+       )
+       v.events = append(v.events, event{
+               node:   node,
+               parent: parentIndex,
+               typ:    typeOf(node),
+               index:  0, // (pop index is set later by visitor.pop)
+       })
+       v.stack = append(v.stack, item{
+               index:            index,
+               parentIndex:      parentIndex,
+               edgeKindAndIndex: packEdgeKindAndIndex(ek, eindex),
+       })
+
+       // 2B nodes ought to be enough for anyone!
+       if int32(len(v.events)) < 0 {
+               panic("event index exceeded int32")
        }
 
-       return events
+       // 32M elements in an []ast.Node ought to be enough for anyone!
+       if ek2, eindex2 := unpackEdgeKindAndIndex(packEdgeKindAndIndex(ek, eindex)); ek2 != ek || eindex2 != eindex {
+               panic("Node slice index exceeded uint25")
+       }
+}
+
+func (v *visitor) pop(node ast.Node) {
+       top := len(v.stack) - 1
+       current := v.stack[top]
+
+       push := &v.events[current.index]
+       parent := &v.stack[top-1]
+
+       push.index = int32(len(v.events))              // make push event refer to pop
+       parent.typAccum |= current.typAccum | push.typ // accumulate type bits into parent
+
+       v.stack = v.stack[:top]
+
+       v.events = append(v.events, event{
+               node:   node,
+               typ:    current.typAccum,
+               index:  current.index,
+               parent: current.edgeKindAndIndex, // see [unpackEdgeKindAndIndex]
+       })
 }
index b7e959114cb0b48927b5cae2382f8db9e73bcf42..c576dc70ac7093b262c1e92beb2479be7218e274 100644 (file)
@@ -26,7 +26,7 @@ func (in *Inspector) PreorderSeq(types ...ast.Node) iter.Seq[ast.Node] {
 
        return func(yield func(ast.Node) bool) {
                mask := maskOf(types)
-               for i := 0; i < len(in.events); {
+               for i := int32(0); i < int32(len(in.events)); {
                        ev := in.events[i]
                        if ev.index > i {
                                // push
@@ -63,7 +63,7 @@ func All[N interface {
 
        mask := typeOf((N)(nil))
        return func(yield func(N) bool) {
-               for i := 0; i < len(in.events); {
+               for i := int32(0); i < int32(len(in.events)); {
                        ev := in.events[i]
                        if ev.index > i {
                                // push
index 2a872f89d47d236ee0afa773661504ebd2addd64..97784484578d5047fe555c1be0595fc0ac507f72 100644 (file)
@@ -12,6 +12,8 @@ package inspector
 import (
        "go/ast"
        "math"
+
+       _ "unsafe"
 )
 
 const (
@@ -215,8 +217,9 @@ func typeOf(n ast.Node) uint64 {
        return 0
 }
 
+//go:linkname maskOf
 func maskOf(nodes []ast.Node) uint64 {
-       if nodes == nil {
+       if len(nodes) == 0 {
                return math.MaxUint64 // match all node types
        }
        var mask uint64
diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go
new file mode 100644 (file)
index 0000000..5a42174
--- /dev/null
@@ -0,0 +1,341 @@
+// 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 inspector
+
+// This file is a fork of ast.Inspect to reduce unnecessary dynamic
+// calls and to gather edge information.
+//
+// Consistency with the original is ensured by TestInspectAllNodes.
+
+import (
+       "fmt"
+       "go/ast"
+
+       "golang.org/x/tools/internal/astutil/edge"
+)
+
+func walkList[N ast.Node](v *visitor, ek edge.Kind, list []N) {
+       for i, node := range list {
+               walk(v, ek, i, node)
+       }
+}
+
+func walk(v *visitor, ek edge.Kind, index int, node ast.Node) {
+       v.push(ek, index, node)
+
+       // walk children
+       // (the order of the cases matches the order
+       // of the corresponding node types in ast.go)
+       switch n := node.(type) {
+       // Comments and fields
+       case *ast.Comment:
+               // nothing to do
+
+       case *ast.CommentGroup:
+               walkList(v, edge.CommentGroup_List, n.List)
+
+       case *ast.Field:
+               if n.Doc != nil {
+                       walk(v, edge.Field_Doc, -1, n.Doc)
+               }
+               walkList(v, edge.Field_Names, n.Names)
+               if n.Type != nil {
+                       walk(v, edge.Field_Type, -1, n.Type)
+               }
+               if n.Tag != nil {
+                       walk(v, edge.Field_Tag, -1, n.Tag)
+               }
+               if n.Comment != nil {
+                       walk(v, edge.Field_Comment, -1, n.Comment)
+               }
+
+       case *ast.FieldList:
+               walkList(v, edge.FieldList_List, n.List)
+
+       // Expressions
+       case *ast.BadExpr, *ast.Ident, *ast.BasicLit:
+               // nothing to do
+
+       case *ast.Ellipsis:
+               if n.Elt != nil {
+                       walk(v, edge.Ellipsis_Elt, -1, n.Elt)
+               }
+
+       case *ast.FuncLit:
+               walk(v, edge.FuncLit_Type, -1, n.Type)
+               walk(v, edge.FuncLit_Body, -1, n.Body)
+
+       case *ast.CompositeLit:
+               if n.Type != nil {
+                       walk(v, edge.CompositeLit_Type, -1, n.Type)
+               }
+               walkList(v, edge.CompositeLit_Elts, n.Elts)
+
+       case *ast.ParenExpr:
+               walk(v, edge.ParenExpr_X, -1, n.X)
+
+       case *ast.SelectorExpr:
+               walk(v, edge.SelectorExpr_X, -1, n.X)
+               walk(v, edge.SelectorExpr_Sel, -1, n.Sel)
+
+       case *ast.IndexExpr:
+               walk(v, edge.IndexExpr_X, -1, n.X)
+               walk(v, edge.IndexExpr_Index, -1, n.Index)
+
+       case *ast.IndexListExpr:
+               walk(v, edge.IndexListExpr_X, -1, n.X)
+               walkList(v, edge.IndexListExpr_Indices, n.Indices)
+
+       case *ast.SliceExpr:
+               walk(v, edge.SliceExpr_X, -1, n.X)
+               if n.Low != nil {
+                       walk(v, edge.SliceExpr_Low, -1, n.Low)
+               }
+               if n.High != nil {
+                       walk(v, edge.SliceExpr_High, -1, n.High)
+               }
+               if n.Max != nil {
+                       walk(v, edge.SliceExpr_Max, -1, n.Max)
+               }
+
+       case *ast.TypeAssertExpr:
+               walk(v, edge.TypeAssertExpr_X, -1, n.X)
+               if n.Type != nil {
+                       walk(v, edge.TypeAssertExpr_Type, -1, n.Type)
+               }
+
+       case *ast.CallExpr:
+               walk(v, edge.CallExpr_Fun, -1, n.Fun)
+               walkList(v, edge.CallExpr_Args, n.Args)
+
+       case *ast.StarExpr:
+               walk(v, edge.StarExpr_X, -1, n.X)
+
+       case *ast.UnaryExpr:
+               walk(v, edge.UnaryExpr_X, -1, n.X)
+
+       case *ast.BinaryExpr:
+               walk(v, edge.BinaryExpr_X, -1, n.X)
+               walk(v, edge.BinaryExpr_Y, -1, n.Y)
+
+       case *ast.KeyValueExpr:
+               walk(v, edge.KeyValueExpr_Key, -1, n.Key)
+               walk(v, edge.KeyValueExpr_Value, -1, n.Value)
+
+       // Types
+       case *ast.ArrayType:
+               if n.Len != nil {
+                       walk(v, edge.ArrayType_Len, -1, n.Len)
+               }
+               walk(v, edge.ArrayType_Elt, -1, n.Elt)
+
+       case *ast.StructType:
+               walk(v, edge.StructType_Fields, -1, n.Fields)
+
+       case *ast.FuncType:
+               if n.TypeParams != nil {
+                       walk(v, edge.FuncType_TypeParams, -1, n.TypeParams)
+               }
+               if n.Params != nil {
+                       walk(v, edge.FuncType_Params, -1, n.Params)
+               }
+               if n.Results != nil {
+                       walk(v, edge.FuncType_Results, -1, n.Results)
+               }
+
+       case *ast.InterfaceType:
+               walk(v, edge.InterfaceType_Methods, -1, n.Methods)
+
+       case *ast.MapType:
+               walk(v, edge.MapType_Key, -1, n.Key)
+               walk(v, edge.MapType_Value, -1, n.Value)
+
+       case *ast.ChanType:
+               walk(v, edge.ChanType_Value, -1, n.Value)
+
+       // Statements
+       case *ast.BadStmt:
+               // nothing to do
+
+       case *ast.DeclStmt:
+               walk(v, edge.DeclStmt_Decl, -1, n.Decl)
+
+       case *ast.EmptyStmt:
+               // nothing to do
+
+       case *ast.LabeledStmt:
+               walk(v, edge.LabeledStmt_Label, -1, n.Label)
+               walk(v, edge.LabeledStmt_Stmt, -1, n.Stmt)
+
+       case *ast.ExprStmt:
+               walk(v, edge.ExprStmt_X, -1, n.X)
+
+       case *ast.SendStmt:
+               walk(v, edge.SendStmt_Chan, -1, n.Chan)
+               walk(v, edge.SendStmt_Value, -1, n.Value)
+
+       case *ast.IncDecStmt:
+               walk(v, edge.IncDecStmt_X, -1, n.X)
+
+       case *ast.AssignStmt:
+               walkList(v, edge.AssignStmt_Lhs, n.Lhs)
+               walkList(v, edge.AssignStmt_Rhs, n.Rhs)
+
+       case *ast.GoStmt:
+               walk(v, edge.GoStmt_Call, -1, n.Call)
+
+       case *ast.DeferStmt:
+               walk(v, edge.DeferStmt_Call, -1, n.Call)
+
+       case *ast.ReturnStmt:
+               walkList(v, edge.ReturnStmt_Results, n.Results)
+
+       case *ast.BranchStmt:
+               if n.Label != nil {
+                       walk(v, edge.BranchStmt_Label, -1, n.Label)
+               }
+
+       case *ast.BlockStmt:
+               walkList(v, edge.BlockStmt_List, n.List)
+
+       case *ast.IfStmt:
+               if n.Init != nil {
+                       walk(v, edge.IfStmt_Init, -1, n.Init)
+               }
+               walk(v, edge.IfStmt_Cond, -1, n.Cond)
+               walk(v, edge.IfStmt_Body, -1, n.Body)
+               if n.Else != nil {
+                       walk(v, edge.IfStmt_Else, -1, n.Else)
+               }
+
+       case *ast.CaseClause:
+               walkList(v, edge.CaseClause_List, n.List)
+               walkList(v, edge.CaseClause_Body, n.Body)
+
+       case *ast.SwitchStmt:
+               if n.Init != nil {
+                       walk(v, edge.SwitchStmt_Init, -1, n.Init)
+               }
+               if n.Tag != nil {
+                       walk(v, edge.SwitchStmt_Tag, -1, n.Tag)
+               }
+               walk(v, edge.SwitchStmt_Body, -1, n.Body)
+
+       case *ast.TypeSwitchStmt:
+               if n.Init != nil {
+                       walk(v, edge.TypeSwitchStmt_Init, -1, n.Init)
+               }
+               walk(v, edge.TypeSwitchStmt_Assign, -1, n.Assign)
+               walk(v, edge.TypeSwitchStmt_Body, -1, n.Body)
+
+       case *ast.CommClause:
+               if n.Comm != nil {
+                       walk(v, edge.CommClause_Comm, -1, n.Comm)
+               }
+               walkList(v, edge.CommClause_Body, n.Body)
+
+       case *ast.SelectStmt:
+               walk(v, edge.SelectStmt_Body, -1, n.Body)
+
+       case *ast.ForStmt:
+               if n.Init != nil {
+                       walk(v, edge.ForStmt_Init, -1, n.Init)
+               }
+               if n.Cond != nil {
+                       walk(v, edge.ForStmt_Cond, -1, n.Cond)
+               }
+               if n.Post != nil {
+                       walk(v, edge.ForStmt_Post, -1, n.Post)
+               }
+               walk(v, edge.ForStmt_Body, -1, n.Body)
+
+       case *ast.RangeStmt:
+               if n.Key != nil {
+                       walk(v, edge.RangeStmt_Key, -1, n.Key)
+               }
+               if n.Value != nil {
+                       walk(v, edge.RangeStmt_Value, -1, n.Value)
+               }
+               walk(v, edge.RangeStmt_X, -1, n.X)
+               walk(v, edge.RangeStmt_Body, -1, n.Body)
+
+       // Declarations
+       case *ast.ImportSpec:
+               if n.Doc != nil {
+                       walk(v, edge.ImportSpec_Doc, -1, n.Doc)
+               }
+               if n.Name != nil {
+                       walk(v, edge.ImportSpec_Name, -1, n.Name)
+               }
+               walk(v, edge.ImportSpec_Path, -1, n.Path)
+               if n.Comment != nil {
+                       walk(v, edge.ImportSpec_Comment, -1, n.Comment)
+               }
+
+       case *ast.ValueSpec:
+               if n.Doc != nil {
+                       walk(v, edge.ValueSpec_Doc, -1, n.Doc)
+               }
+               walkList(v, edge.ValueSpec_Names, n.Names)
+               if n.Type != nil {
+                       walk(v, edge.ValueSpec_Type, -1, n.Type)
+               }
+               walkList(v, edge.ValueSpec_Values, n.Values)
+               if n.Comment != nil {
+                       walk(v, edge.ValueSpec_Comment, -1, n.Comment)
+               }
+
+       case *ast.TypeSpec:
+               if n.Doc != nil {
+                       walk(v, edge.TypeSpec_Doc, -1, n.Doc)
+               }
+               walk(v, edge.TypeSpec_Name, -1, n.Name)
+               if n.TypeParams != nil {
+                       walk(v, edge.TypeSpec_TypeParams, -1, n.TypeParams)
+               }
+               walk(v, edge.TypeSpec_Type, -1, n.Type)
+               if n.Comment != nil {
+                       walk(v, edge.TypeSpec_Comment, -1, n.Comment)
+               }
+
+       case *ast.BadDecl:
+               // nothing to do
+
+       case *ast.GenDecl:
+               if n.Doc != nil {
+                       walk(v, edge.GenDecl_Doc, -1, n.Doc)
+               }
+               walkList(v, edge.GenDecl_Specs, n.Specs)
+
+       case *ast.FuncDecl:
+               if n.Doc != nil {
+                       walk(v, edge.FuncDecl_Doc, -1, n.Doc)
+               }
+               if n.Recv != nil {
+                       walk(v, edge.FuncDecl_Recv, -1, n.Recv)
+               }
+               walk(v, edge.FuncDecl_Name, -1, n.Name)
+               walk(v, edge.FuncDecl_Type, -1, n.Type)
+               if n.Body != nil {
+                       walk(v, edge.FuncDecl_Body, -1, n.Body)
+               }
+
+       case *ast.File:
+               if n.Doc != nil {
+                       walk(v, edge.File_Doc, -1, n.Doc)
+               }
+               walk(v, edge.File_Name, -1, n.Name)
+               walkList(v, edge.File_Decls, n.Decls)
+               // don't walk n.Comments - they have been
+               // visited already through the individual
+               // nodes
+
+       default:
+               // (includes *ast.Package)
+               panic(fmt.Sprintf("Walk: unexpected node type %T", n))
+       }
+
+       v.pop(node)
+}
index 8d824f7140f456ac27e5ad6affa2deb7f2f460e5..b6d542c64ee64a5ee7c19702449a5c84de6aa4d1 100644 (file)
@@ -2,30 +2,35 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package typeutil defines various utilities for types, such as Map,
-// a mapping from types.Type to any values.
-package typeutil // import "golang.org/x/tools/go/types/typeutil"
+// Package typeutil defines various utilities for types, such as [Map],
+// a hash table that maps [types.Type] to any value.
+package typeutil
 
 import (
        "bytes"
        "fmt"
        "go/types"
-       "reflect"
+       "hash/maphash"
+       "unsafe"
 
        "golang.org/x/tools/internal/typeparams"
 )
 
 // Map is a hash-table-based mapping from types (types.Type) to
-// arbitrary any values.  The concrete types that implement
+// arbitrary values.  The concrete types that implement
 // the Type interface are pointers.  Since they are not canonicalized,
 // == cannot be used to check for equivalence, and thus we cannot
 // simply use a Go map.
 //
 // Just as with map[K]V, a nil *Map is a valid empty map.
 //
-// Not thread-safe.
+// Read-only map operations ([Map.At], [Map.Len], and so on) may
+// safely be called concurrently.
+//
+// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420
+// and 69559, if the latter proposals for a generic hash-map type and
+// a types.Hash function are accepted.
 type Map struct {
-       hasher Hasher             // shared by many Maps
        table  map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
        length int                // number of map entries
 }
@@ -36,35 +41,17 @@ type entry struct {
        value any
 }
 
-// SetHasher sets the hasher used by Map.
-//
-// All Hashers are functionally equivalent but contain internal state
-// used to cache the results of hashing previously seen types.
-//
-// A single Hasher created by MakeHasher() may be shared among many
-// Maps.  This is recommended if the instances have many keys in
-// common, as it will amortize the cost of hash computation.
-//
-// A Hasher may grow without bound as new types are seen.  Even when a
-// type is deleted from the map, the Hasher never shrinks, since other
-// types in the map may reference the deleted type indirectly.
+// SetHasher has no effect.
 //
-// Hashers are not thread-safe, and read-only operations such as
-// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
-// read-lock) is require around all Map operations if a shared
-// hasher is accessed from multiple threads.
-//
-// If SetHasher is not called, the Map will create a private hasher at
-// the first call to Insert.
-func (m *Map) SetHasher(hasher Hasher) {
-       m.hasher = hasher
-}
+// It is a relic of an optimization that is no longer profitable. Do
+// not use [Hasher], [MakeHasher], or [SetHasher] in new code.
+func (m *Map) SetHasher(Hasher) {}
 
 // Delete removes the entry with the given key, if any.
 // It returns true if the entry was found.
 func (m *Map) Delete(key types.Type) bool {
        if m != nil && m.table != nil {
-               hash := m.hasher.Hash(key)
+               hash := hash(key)
                bucket := m.table[hash]
                for i, e := range bucket {
                        if e.key != nil && types.Identical(key, e.key) {
@@ -83,7 +70,7 @@ func (m *Map) Delete(key types.Type) bool {
 // The result is nil if the entry is not present.
 func (m *Map) At(key types.Type) any {
        if m != nil && m.table != nil {
-               for _, e := range m.table[m.hasher.Hash(key)] {
+               for _, e := range m.table[hash(key)] {
                        if e.key != nil && types.Identical(key, e.key) {
                                return e.value
                        }
@@ -96,7 +83,7 @@ func (m *Map) At(key types.Type) any {
 // and returns the previous entry, if any.
 func (m *Map) Set(key types.Type, value any) (prev any) {
        if m.table != nil {
-               hash := m.hasher.Hash(key)
+               hash := hash(key)
                bucket := m.table[hash]
                var hole *entry
                for i, e := range bucket {
@@ -115,10 +102,7 @@ func (m *Map) Set(key types.Type, value any) (prev any) {
                        m.table[hash] = append(bucket, entry{key, value})
                }
        } else {
-               if m.hasher.memo == nil {
-                       m.hasher = MakeHasher()
-               }
-               hash := m.hasher.Hash(key)
+               hash := hash(key)
                m.table = map[uint32][]entry{hash: {entry{key, value}}}
        }
 
@@ -195,53 +179,35 @@ func (m *Map) KeysString() string {
        return m.toString(false)
 }
 
-////////////////////////////////////////////////////////////////////////
-// Hasher
-
-// A Hasher maps each type to its hash value.
-// For efficiency, a hasher uses memoization; thus its memory
-// footprint grows monotonically over time.
-// Hashers are not thread-safe.
-// Hashers have reference semantics.
-// Call MakeHasher to create a Hasher.
-type Hasher struct {
-       memo map[types.Type]uint32
-
-       // ptrMap records pointer identity.
-       ptrMap map[any]uint32
-
-       // sigTParams holds type parameters from the signature being hashed.
-       // Signatures are considered identical modulo renaming of type parameters, so
-       // within the scope of a signature type the identity of the signature's type
-       // parameters is just their index.
-       //
-       // Since the language does not currently support referring to uninstantiated
-       // generic types or functions, and instantiated signatures do not have type
-       // parameter lists, we should never encounter a second non-empty type
-       // parameter list when hashing a generic signature.
-       sigTParams *types.TypeParamList
-}
+// -- Hasher --
 
-// MakeHasher returns a new Hasher instance.
-func MakeHasher() Hasher {
-       return Hasher{
-               memo:       make(map[types.Type]uint32),
-               ptrMap:     make(map[any]uint32),
-               sigTParams: nil,
-       }
+// hash returns the hash of type t.
+// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted.
+func hash(t types.Type) uint32 {
+       return theHasher.Hash(t)
 }
 
+// A Hasher provides a [Hasher.Hash] method to map a type to its hash value.
+// Hashers are stateless, and all are equivalent.
+type Hasher struct{}
+
+var theHasher Hasher
+
+// MakeHasher returns Hasher{}.
+// Hashers are stateless; all are equivalent.
+func MakeHasher() Hasher { return theHasher }
+
 // Hash computes a hash value for the given type t such that
 // Identical(t, t') => Hash(t) == Hash(t').
 func (h Hasher) Hash(t types.Type) uint32 {
-       hash, ok := h.memo[t]
-       if !ok {
-               hash = h.hashFor(t)
-               h.memo[t] = hash
-       }
-       return hash
+       return hasher{inGenericSig: false}.hash(t)
 }
 
+// hasher holds the state of a single Hash traversal: whether we are
+// inside the signature of a generic function; this is used to
+// optimize [hasher.hashTypeParam].
+type hasher struct{ inGenericSig bool }
+
 // hashString computes the Fowler–Noll–Vo hash of s.
 func hashString(s string) uint32 {
        var h uint32
@@ -252,21 +218,21 @@ func hashString(s string) uint32 {
        return h
 }
 
-// hashFor computes the hash of t.
-func (h Hasher) hashFor(t types.Type) uint32 {
+// hash computes the hash of t.
+func (h hasher) hash(t types.Type) uint32 {
        // See Identical for rationale.
        switch t := t.(type) {
        case *types.Basic:
                return uint32(t.Kind())
 
        case *types.Alias:
-               return h.Hash(types.Unalias(t))
+               return h.hash(types.Unalias(t))
 
        case *types.Array:
-               return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
+               return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem())
 
        case *types.Slice:
-               return 9049 + 2*h.Hash(t.Elem())
+               return 9049 + 2*h.hash(t.Elem())
 
        case *types.Struct:
                var hash uint32 = 9059
@@ -277,12 +243,12 @@ func (h Hasher) hashFor(t types.Type) uint32 {
                        }
                        hash += hashString(t.Tag(i))
                        hash += hashString(f.Name()) // (ignore f.Pkg)
-                       hash += h.Hash(f.Type())
+                       hash += h.hash(f.Type())
                }
                return hash
 
        case *types.Pointer:
-               return 9067 + 2*h.Hash(t.Elem())
+               return 9067 + 2*h.hash(t.Elem())
 
        case *types.Signature:
                var hash uint32 = 9091
@@ -290,33 +256,14 @@ func (h Hasher) hashFor(t types.Type) uint32 {
                        hash *= 8863
                }
 
-               // Use a separate hasher for types inside of the signature, where type
-               // parameter identity is modified to be (index, constraint). We must use a
-               // new memo for this hasher as type identity may be affected by this
-               // masking. For example, in func[T any](*T), the identity of *T depends on
-               // whether we are mapping the argument in isolation, or recursively as part
-               // of hashing the signature.
-               //
-               // We should never encounter a generic signature while hashing another
-               // generic signature, but defensively set sigTParams only if h.mask is
-               // unset.
                tparams := t.TypeParams()
-               if h.sigTParams == nil && tparams.Len() != 0 {
-                       h = Hasher{
-                               // There may be something more efficient than discarding the existing
-                               // memo, but it would require detecting whether types are 'tainted' by
-                               // references to type parameters.
-                               memo: make(map[types.Type]uint32),
-                               // Re-using ptrMap ensures that pointer identity is preserved in this
-                               // hasher.
-                               ptrMap:     h.ptrMap,
-                               sigTParams: tparams,
-                       }
-               }
+               if n := tparams.Len(); n > 0 {
+                       h.inGenericSig = true // affects constraints, params, and results
 
-               for i := 0; i < tparams.Len(); i++ {
-                       tparam := tparams.At(i)
-                       hash += 7 * h.Hash(tparam.Constraint())
+                       for i := range n {
+                               tparam := tparams.At(i)
+                               hash += 7 * h.hash(tparam.Constraint())
+                       }
                }
 
                return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
@@ -350,17 +297,17 @@ func (h Hasher) hashFor(t types.Type) uint32 {
                return hash
 
        case *types.Map:
-               return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())
+               return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem())
 
        case *types.Chan:
-               return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())
+               return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem())
 
        case *types.Named:
-               hash := h.hashPtr(t.Obj())
+               hash := h.hashTypeName(t.Obj())
                targs := t.TypeArgs()
                for i := 0; i < targs.Len(); i++ {
                        targ := targs.At(i)
-                       hash += 2 * h.Hash(targ)
+                       hash += 2 * h.hash(targ)
                }
                return hash
 
@@ -374,17 +321,17 @@ func (h Hasher) hashFor(t types.Type) uint32 {
        panic(fmt.Sprintf("%T: %v", t, t))
 }
 
-func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
+func (h hasher) hashTuple(tuple *types.Tuple) uint32 {
        // See go/types.identicalTypes for rationale.
        n := tuple.Len()
        hash := 9137 + 2*uint32(n)
-       for i := 0; i < n; i++ {
-               hash += 3 * h.Hash(tuple.At(i).Type())
+       for i := range n {
+               hash += 3 * h.hash(tuple.At(i).Type())
        }
        return hash
 }
 
-func (h Hasher) hashUnion(t *types.Union) uint32 {
+func (h hasher) hashUnion(t *types.Union) uint32 {
        // Hash type restrictions.
        terms, err := typeparams.UnionTermSet(t)
        // if err != nil t has invalid type restrictions. Fall back on a non-zero
@@ -395,11 +342,11 @@ func (h Hasher) hashUnion(t *types.Union) uint32 {
        return h.hashTermSet(terms)
 }
 
-func (h Hasher) hashTermSet(terms []*types.Term) uint32 {
+func (h hasher) hashTermSet(terms []*types.Term) uint32 {
        hash := 9157 + 2*uint32(len(terms))
        for _, term := range terms {
                // term order is not significant.
-               termHash := h.Hash(term.Type())
+               termHash := h.hash(term.Type())
                if term.Tilde() {
                        termHash *= 9161
                }
@@ -408,36 +355,47 @@ func (h Hasher) hashTermSet(terms []*types.Term) uint32 {
        return hash
 }
 
-// hashTypeParam returns a hash of the type parameter t, with a hash value
-// depending on whether t is contained in h.sigTParams.
-//
-// If h.sigTParams is set and contains t, then we are in the process of hashing
-// a signature, and the hash value of t must depend only on t's index and
-// constraint: signatures are considered identical modulo type parameter
-// renaming. To avoid infinite recursion, we only hash the type parameter
-// index, and rely on types.Identical to handle signatures where constraints
-// are not identical.
-//
-// Otherwise the hash of t depends only on t's pointer identity.
-func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 {
-       if h.sigTParams != nil {
-               i := t.Index()
-               if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
-                       return 9173 + 3*uint32(i)
-               }
+// hashTypeParam returns the hash of a type parameter.
+func (h hasher) hashTypeParam(t *types.TypeParam) uint32 {
+       // Within the signature of a generic function, TypeParams are
+       // identical if they have the same index and constraint, so we
+       // hash them based on index.
+       //
+       // When we are outside a generic function, free TypeParams are
+       // identical iff they are the same object, so we can use a
+       // more discriminating hash consistent with object identity.
+       // This optimization saves [Map] about 4% when hashing all the
+       // types.Info.Types in the forward closure of net/http.
+       if !h.inGenericSig {
+               // Optimization: outside a generic function signature,
+               // use a more discrimating hash consistent with object identity.
+               return h.hashTypeName(t.Obj())
        }
-       return h.hashPtr(t.Obj())
+       return 9173 + 3*uint32(t.Index())
 }
 
-// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that
-// pointers values are not dependent on the GC.
-func (h Hasher) hashPtr(ptr any) uint32 {
-       if hash, ok := h.ptrMap[ptr]; ok {
-               return hash
+var theSeed = maphash.MakeSeed()
+
+// hashTypeName hashes the pointer of tname.
+func (hasher) hashTypeName(tname *types.TypeName) uint32 {
+       // Since types.Identical uses == to compare TypeNames,
+       // the Hash function uses maphash.Comparable.
+       // TODO(adonovan): or will, when it becomes available in go1.24.
+       // In the meantime we use the pointer's numeric value.
+       //
+       //   hash := maphash.Comparable(theSeed, tname)
+       //
+       // (Another approach would be to hash the name and package
+       // path, and whether or not it is a package-level typename. It
+       // is rare for a package to define multiple local types with
+       // the same name.)
+       ptr := uintptr(unsafe.Pointer(tname))
+       if unsafe.Sizeof(ptr) == 8 {
+               hash := uint64(ptr)
+               return uint32(hash ^ (hash >> 32))
+       } else {
+               return uint32(ptr)
        }
-       hash := uint32(reflect.ValueOf(ptr).Pointer())
-       h.ptrMap[ptr] = hash
-       return hash
 }
 
 // shallowHash computes a hash of t without looking at any of its
@@ -454,7 +412,7 @@ func (h Hasher) hashPtr(ptr any) uint32 {
 // include m itself; there is no mention of the named type X that
 // might help us break the cycle.
 // (See comment in go/types.identical, case *Interface, for more.)
-func (h Hasher) shallowHash(t types.Type) uint32 {
+func (h hasher) shallowHash(t types.Type) uint32 {
        // t is the type of an interface method (Signature),
        // its params or results (Tuples), or their immediate
        // elements (mostly Slice, Pointer, Basic, Named),
@@ -475,7 +433,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 {
        case *types.Tuple:
                n := t.Len()
                hash := 9137 + 2*uint32(n)
-               for i := 0; i < n; i++ {
+               for i := range n {
                        hash += 53471161 * h.shallowHash(t.At(i).Type())
                }
                return hash
@@ -508,10 +466,10 @@ func (h Hasher) shallowHash(t types.Type) uint32 {
                return 9127
 
        case *types.Named:
-               return h.hashPtr(t.Obj())
+               return h.hashTypeName(t.Obj())
 
        case *types.TypeParam:
-               return h.hashPtr(t.Obj())
+               return h.hashTypeParam(t)
        }
        panic(fmt.Sprintf("shallowHash: %T: %v", t, t))
 }
index fe67b0fa27a69f17eb2e211c58d32ecf9d320460..d96d22982c5a7235dd0f78ead7ef1d70bb8a8ee9 100644 (file)
@@ -8,15 +8,19 @@ package analysisinternal
 
 import (
        "bytes"
+       "cmp"
        "fmt"
        "go/ast"
+       "go/printer"
        "go/scanner"
        "go/token"
        "go/types"
-       "os"
        pathpkg "path"
+       "slices"
+       "strings"
 
        "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/internal/typesinternal"
 )
 
 func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
@@ -65,90 +69,6 @@ func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos
        return end
 }
 
-// StmtToInsertVarBefore returns the ast.Stmt before which we can
-// safely insert a new var declaration, or nil if the path denotes a
-// node outside any statement.
-//
-// Basic Example:
-//
-//     z := 1
-//     y := z + x
-//
-// If x is undeclared, then this function would return `y := z + x`, so that we
-// can insert `x := ` on the line before `y := z + x`.
-//
-// If stmt example:
-//
-//     if z == 1 {
-//     } else if z == y {}
-//
-// If y is undeclared, then this function would return `if z == 1 {`, because we cannot
-// insert a statement between an if and an else if statement. As a result, we need to find
-// the top of the if chain to insert `y := ` before.
-func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
-       enclosingIndex := -1
-       for i, p := range path {
-               if _, ok := p.(ast.Stmt); ok {
-                       enclosingIndex = i
-                       break
-               }
-       }
-       if enclosingIndex == -1 {
-               return nil // no enclosing statement: outside function
-       }
-       enclosingStmt := path[enclosingIndex]
-       switch enclosingStmt.(type) {
-       case *ast.IfStmt:
-               // The enclosingStmt is inside of the if declaration,
-               // We need to check if we are in an else-if stmt and
-               // get the base if statement.
-               // TODO(adonovan): for non-constants, it may be preferable
-               // to add the decl as the Init field of the innermost
-               // enclosing ast.IfStmt.
-               return baseIfStmt(path, enclosingIndex)
-       case *ast.CaseClause:
-               // Get the enclosing switch stmt if the enclosingStmt is
-               // inside of the case statement.
-               for i := enclosingIndex + 1; i < len(path); i++ {
-                       if node, ok := path[i].(*ast.SwitchStmt); ok {
-                               return node
-                       } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
-                               return node
-                       }
-               }
-       }
-       if len(path) <= enclosingIndex+1 {
-               return enclosingStmt.(ast.Stmt)
-       }
-       // Check if the enclosing statement is inside another node.
-       switch expr := path[enclosingIndex+1].(type) {
-       case *ast.IfStmt:
-               // Get the base if statement.
-               return baseIfStmt(path, enclosingIndex+1)
-       case *ast.ForStmt:
-               if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
-                       return expr
-               }
-       case *ast.SwitchStmt, *ast.TypeSwitchStmt:
-               return expr.(ast.Stmt)
-       }
-       return enclosingStmt.(ast.Stmt)
-}
-
-// baseIfStmt walks up the if/else-if chain until we get to
-// the top of the current if chain.
-func baseIfStmt(path []ast.Node, index int) ast.Stmt {
-       stmt := path[index]
-       for i := index + 1; i < len(path); i++ {
-               if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
-                       stmt = node
-                       continue
-               }
-               break
-       }
-       return stmt.(ast.Stmt)
-}
-
 // WalkASTWithParent walks the AST rooted at n. The semantics are
 // similar to ast.Inspect except it does not call f(nil).
 func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
@@ -258,20 +178,25 @@ func equivalentTypes(want, got types.Type) bool {
        return types.AssignableTo(want, got)
 }
 
-// MakeReadFile returns a simple implementation of the Pass.ReadFile function.
-func MakeReadFile(pass *analysis.Pass) func(filename string) ([]byte, error) {
+// A ReadFileFunc is a function that returns the
+// contents of a file, such as [os.ReadFile].
+type ReadFileFunc = func(filename string) ([]byte, error)
+
+// CheckedReadFile returns a wrapper around a Pass.ReadFile
+// function that performs the appropriate checks.
+func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc {
        return func(filename string) ([]byte, error) {
                if err := CheckReadable(pass, filename); err != nil {
                        return nil, err
                }
-               return os.ReadFile(filename)
+               return readFile(filename)
        }
 }
 
 // CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass].
 func CheckReadable(pass *analysis.Pass, filename string) error {
-       if slicesContains(pass.OtherFiles, filename) ||
-               slicesContains(pass.IgnoredFiles, filename) {
+       if slices.Contains(pass.OtherFiles, filename) ||
+               slices.Contains(pass.IgnoredFiles, filename) {
                return nil
        }
        for _, f := range pass.Files {
@@ -282,24 +207,21 @@ func CheckReadable(pass *analysis.Pass, filename string) error {
        return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
 }
 
-// TODO(adonovan): use go1.21 slices.Contains.
-func slicesContains[S ~[]E, E comparable](slice S, x E) bool {
-       for _, elem := range slice {
-               if elem == x {
-                       return true
-               }
-       }
-       return false
-}
-
 // AddImport checks whether this file already imports pkgpath and
 // that import is in scope at pos. If so, it returns the name under
 // which it was imported and a zero edit. Otherwise, it adds a new
 // import of pkgpath, using a name derived from the preferred name,
-// and returns the chosen name along with the edit for the new import.
+// and returns the chosen name, a prefix to be concatenated with member
+// to form a qualified name, and the edit for the new import.
+//
+// In the special case that pkgpath is dot-imported then member, the
+// identifer for which the import is being added, is consulted. If
+// member is not shadowed at pos, AddImport returns (".", "", nil).
+// (AddImport accepts the caller's implicit claim that the imported
+// package declares member.)
 //
 // It does not mutate its arguments.
-func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferredName string) (name string, newImport []analysis.TextEdit) {
+func AddImport(info *types.Info, file *ast.File, preferredName, pkgpath, member string, pos token.Pos) (name, prefix string, newImport []analysis.TextEdit) {
        // Find innermost enclosing lexical block.
        scope := info.Scopes[file].Innermost(pos)
        if scope == nil {
@@ -309,10 +231,16 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr
        // Is there an existing import of this package?
        // If so, are we in its scope? (not shadowed)
        for _, spec := range file.Imports {
-               pkgname, ok := importedPkgName(info, spec)
-               if ok && pkgname.Imported().Path() == pkgpath {
-                       if _, obj := scope.LookupParent(pkgname.Name(), pos); obj == pkgname {
-                               return pkgname.Name(), nil
+               pkgname := info.PkgNameOf(spec)
+               if pkgname != nil && pkgname.Imported().Path() == pkgpath {
+                       name = pkgname.Name()
+                       if name == "." {
+                               // The scope of ident must be the file scope.
+                               if s, _ := scope.LookupParent(member, pos); s == info.Scopes[file] {
+                                       return name, "", nil
+                               }
+                       } else if _, obj := scope.LookupParent(name, pos); obj == pkgname {
+                               return name, name + ".", nil
                        }
                }
        }
@@ -327,16 +255,16 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr
                newName = fmt.Sprintf("%s%d", preferredName, i)
        }
 
-       // For now, keep it real simple: create a new import
-       // declaration before the first existing declaration (which
-       // must exist), including its comments, and let goimports tidy it up.
+       // Create a new import declaration either before the first existing
+       // declaration (which must exist), including its comments; or
+       // inside the declaration, if it is an import group.
        //
        // Use a renaming import whenever the preferred name is not
        // available, or the chosen name does not match the last
        // segment of its path.
-       newText := fmt.Sprintf("import %q\n\n", pkgpath)
+       newText := fmt.Sprintf("%q", pkgpath)
        if newName != preferredName || newName != pathpkg.Base(pkgpath) {
-               newText = fmt.Sprintf("import %s %q\n\n", newName, pkgpath)
+               newText = fmt.Sprintf("%s %q", newName, pkgpath)
        }
        decl0 := file.Decls[0]
        var before ast.Node = decl0
@@ -350,22 +278,209 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr
                        before = decl0.Doc
                }
        }
-       return newName, []analysis.TextEdit{{
-               Pos:     before.Pos(),
-               End:     before.Pos(),
+       // If the first decl is an import group, add this new import at the end.
+       if gd, ok := before.(*ast.GenDecl); ok && gd.Tok == token.IMPORT && gd.Rparen.IsValid() {
+               pos = gd.Rparen
+               newText = "\t" + newText + "\n"
+       } else {
+               pos = before.Pos()
+               newText = "import " + newText + "\n\n"
+       }
+       return newName, newName + ".", []analysis.TextEdit{{
+               Pos:     pos,
+               End:     pos,
                NewText: []byte(newText),
        }}
 }
 
-// importedPkgName returns the PkgName object declared by an ImportSpec.
-// TODO(adonovan): use go1.22's Info.PkgNameOf.
-func importedPkgName(info *types.Info, imp *ast.ImportSpec) (*types.PkgName, bool) {
-       var obj types.Object
-       if imp.Name != nil {
-               obj = info.Defs[imp.Name]
-       } else {
-               obj = info.Implicits[imp]
+// Format returns a string representation of the expression e.
+func Format(fset *token.FileSet, e ast.Expr) string {
+       var buf strings.Builder
+       printer.Fprint(&buf, fset, e) // ignore errors
+       return buf.String()
+}
+
+// Imports returns true if 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
+}
+
+// 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 &&
+                       typesinternal.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 := typesinternal.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 &&
+               typesinternal.IsPackageLevel(obj) &&
+               f.Pkg().Path() == pkgPath &&
+               f.Type().(*types.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.Type().(*types.Signature).Recv(); recv != nil {
+                       _, T := typesinternal.ReceiverNamed(recv)
+                       return T != nil &&
+                               IsTypeNamed(T, pkgPath, typeName) &&
+                               slices.Contains(names, fn.Name())
+               }
+       }
+       return false
+}
+
+// ValidateFixes validates the set of fixes for a single diagnostic.
+// Any error indicates a bug in the originating analyzer.
+//
+// It updates fixes so that fixes[*].End.IsValid().
+//
+// It may be used as part of an analysis driver implementation.
+func ValidateFixes(fset *token.FileSet, a *analysis.Analyzer, fixes []analysis.SuggestedFix) error {
+       fixMessages := make(map[string]bool)
+       for i := range fixes {
+               fix := &fixes[i]
+               if fixMessages[fix.Message] {
+                       return fmt.Errorf("analyzer %q suggests two fixes with same Message (%s)", a.Name, fix.Message)
+               }
+               fixMessages[fix.Message] = true
+               if err := validateFix(fset, fix); err != nil {
+                       return fmt.Errorf("analyzer %q suggests invalid fix (%s): %v", a.Name, fix.Message, err)
+               }
+       }
+       return nil
+}
+
+// validateFix validates a single fix.
+// Any error indicates a bug in the originating analyzer.
+//
+// It updates fix so that fix.End.IsValid().
+func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error {
+
+       // Stably sort edits by Pos. This ordering puts insertions
+       // (end = start) before deletions (end > start) at the same
+       // point, but uses a stable sort to preserve the order of
+       // multiple insertions at the same point.
+       slices.SortStableFunc(fix.TextEdits, func(x, y analysis.TextEdit) int {
+               if sign := cmp.Compare(x.Pos, y.Pos); sign != 0 {
+                       return sign
+               }
+               return cmp.Compare(x.End, y.End)
+       })
+
+       var prev *analysis.TextEdit
+       for i := range fix.TextEdits {
+               edit := &fix.TextEdits[i]
+
+               // Validate edit individually.
+               start := edit.Pos
+               file := fset.File(start)
+               if file == nil {
+                       return fmt.Errorf("missing file info for pos (%v)", edit.Pos)
+               }
+               if end := edit.End; end.IsValid() {
+                       if end < start {
+                               return fmt.Errorf("pos (%v) > end (%v)", edit.Pos, edit.End)
+                       }
+                       endFile := fset.File(end)
+                       if endFile == nil {
+                               return fmt.Errorf("malformed end position %v", end)
+                       }
+                       if endFile != file {
+                               return fmt.Errorf("edit spans files %v and %v", file.Name(), endFile.Name())
+                       }
+               } else {
+                       edit.End = start // update the SuggestedFix
+               }
+               if eof := token.Pos(file.Base() + file.Size()); edit.End > eof {
+                       return fmt.Errorf("end is (%v) beyond end of file (%v)", edit.End, eof)
+               }
+
+               // Validate the sequence of edits:
+               // properly ordered, no overlapping deletions
+               if prev != nil && edit.Pos < prev.End {
+                       xpos := fset.Position(prev.Pos)
+                       xend := fset.Position(prev.End)
+                       ypos := fset.Position(edit.Pos)
+                       yend := fset.Position(edit.End)
+                       return fmt.Errorf("overlapping edits to %s (%d:%d-%d:%d and %d:%d-%d:%d)",
+                               xpos.Filename,
+                               xpos.Line, xpos.Column,
+                               xend.Line, xend.Column,
+                               ypos.Line, ypos.Column,
+                               yend.Line, yend.Column,
+                       )
+               }
+               prev = edit
+       }
+
+       return nil
+}
+
+// CanImport reports whether one package is allowed to import another.
+//
+// TODO(adonovan): allow customization of the accessibility relation
+// (e.g. for Bazel).
+func CanImport(from, to string) bool {
+       // TODO(adonovan): better segment hygiene.
+       if to == "internal" || strings.HasPrefix(to, "internal/") {
+               // Special case: only std packages may import internal/...
+               // We can't reliably know whether we're in std, so we
+               // use a heuristic on the first segment.
+               first, _, _ := strings.Cut(from, "/")
+               if strings.Contains(first, ".") {
+                       return false // example.com/foo âˆ‰ std
+               }
+               if first == "testdata" {
+                       return false // testdata/foo âˆ‰ std
+               }
+       }
+       if strings.HasSuffix(to, "/internal") {
+               return strings.HasPrefix(from, to[:len(to)-len("/internal")])
+       }
+       if i := strings.LastIndex(to, "/internal/"); i >= 0 {
+               return strings.HasPrefix(from, to[:i])
        }
-       pkgname, ok := obj.(*types.PkgName)
-       return pkgname, ok
+       return true
 }
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go
new file mode 100644 (file)
index 0000000..4f6ccfd
--- /dev/null
@@ -0,0 +1,295 @@
+// 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 edge defines identifiers for each field of an ast.Node
+// struct type that refers to another Node.
+package edge
+
+import (
+       "fmt"
+       "go/ast"
+       "reflect"
+)
+
+// A Kind describes a field of an ast.Node struct.
+type Kind uint8
+
+// String returns a description of the edge kind.
+func (k Kind) String() string {
+       if k == Invalid {
+               return "<invalid>"
+       }
+       info := fieldInfos[k]
+       return fmt.Sprintf("%v.%s", info.nodeType.Elem().Name(), info.name)
+}
+
+// NodeType returns the pointer-to-struct type of the ast.Node implementation.
+func (k Kind) NodeType() reflect.Type { return fieldInfos[k].nodeType }
+
+// FieldName returns the name of the field.
+func (k Kind) FieldName() string { return fieldInfos[k].name }
+
+// FieldType returns the declared type of the field.
+func (k Kind) FieldType() reflect.Type { return fieldInfos[k].fieldType }
+
+// Get returns the direct child of n identified by (k, idx).
+// n's type must match k.NodeType().
+// idx must be a valid slice index, or -1 for a non-slice.
+func (k Kind) Get(n ast.Node, idx int) ast.Node {
+       if k.NodeType() != reflect.TypeOf(n) {
+               panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n))
+       }
+       v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index)
+       if idx != -1 {
+               v = v.Index(idx) // asserts valid index
+       } else {
+               // (The type assertion below asserts that v is not a slice.)
+       }
+       return v.Interface().(ast.Node) // may be nil
+}
+
+const (
+       Invalid Kind = iota // for nodes at the root of the traversal
+
+       // Kinds are sorted alphabetically.
+       // Numbering is not stable.
+       // Each is named Type_Field, where Type is the
+       // ast.Node struct type and Field is the name of the field
+
+       ArrayType_Elt
+       ArrayType_Len
+       AssignStmt_Lhs
+       AssignStmt_Rhs
+       BinaryExpr_X
+       BinaryExpr_Y
+       BlockStmt_List
+       BranchStmt_Label
+       CallExpr_Args
+       CallExpr_Fun
+       CaseClause_Body
+       CaseClause_List
+       ChanType_Value
+       CommClause_Body
+       CommClause_Comm
+       CommentGroup_List
+       CompositeLit_Elts
+       CompositeLit_Type
+       DeclStmt_Decl
+       DeferStmt_Call
+       Ellipsis_Elt
+       ExprStmt_X
+       FieldList_List
+       Field_Comment
+       Field_Doc
+       Field_Names
+       Field_Tag
+       Field_Type
+       File_Decls
+       File_Doc
+       File_Name
+       ForStmt_Body
+       ForStmt_Cond
+       ForStmt_Init
+       ForStmt_Post
+       FuncDecl_Body
+       FuncDecl_Doc
+       FuncDecl_Name
+       FuncDecl_Recv
+       FuncDecl_Type
+       FuncLit_Body
+       FuncLit_Type
+       FuncType_Params
+       FuncType_Results
+       FuncType_TypeParams
+       GenDecl_Doc
+       GenDecl_Specs
+       GoStmt_Call
+       IfStmt_Body
+       IfStmt_Cond
+       IfStmt_Else
+       IfStmt_Init
+       ImportSpec_Comment
+       ImportSpec_Doc
+       ImportSpec_Name
+       ImportSpec_Path
+       IncDecStmt_X
+       IndexExpr_Index
+       IndexExpr_X
+       IndexListExpr_Indices
+       IndexListExpr_X
+       InterfaceType_Methods
+       KeyValueExpr_Key
+       KeyValueExpr_Value
+       LabeledStmt_Label
+       LabeledStmt_Stmt
+       MapType_Key
+       MapType_Value
+       ParenExpr_X
+       RangeStmt_Body
+       RangeStmt_Key
+       RangeStmt_Value
+       RangeStmt_X
+       ReturnStmt_Results
+       SelectStmt_Body
+       SelectorExpr_Sel
+       SelectorExpr_X
+       SendStmt_Chan
+       SendStmt_Value
+       SliceExpr_High
+       SliceExpr_Low
+       SliceExpr_Max
+       SliceExpr_X
+       StarExpr_X
+       StructType_Fields
+       SwitchStmt_Body
+       SwitchStmt_Init
+       SwitchStmt_Tag
+       TypeAssertExpr_Type
+       TypeAssertExpr_X
+       TypeSpec_Comment
+       TypeSpec_Doc
+       TypeSpec_Name
+       TypeSpec_Type
+       TypeSpec_TypeParams
+       TypeSwitchStmt_Assign
+       TypeSwitchStmt_Body
+       TypeSwitchStmt_Init
+       UnaryExpr_X
+       ValueSpec_Comment
+       ValueSpec_Doc
+       ValueSpec_Names
+       ValueSpec_Type
+       ValueSpec_Values
+
+       maxKind
+)
+
+// Assert that the encoding fits in 7 bits,
+// as the inspector relies on this.
+// (We are currently at 104.)
+var _ = [1 << 7]struct{}{}[maxKind]
+
+type fieldInfo struct {
+       nodeType  reflect.Type // pointer-to-struct type of ast.Node implementation
+       name      string
+       index     int
+       fieldType reflect.Type
+}
+
+func info[N ast.Node](fieldName string) fieldInfo {
+       nodePtrType := reflect.TypeFor[N]()
+       f, ok := nodePtrType.Elem().FieldByName(fieldName)
+       if !ok {
+               panic(fieldName)
+       }
+       return fieldInfo{nodePtrType, fieldName, f.Index[0], f.Type}
+}
+
+var fieldInfos = [...]fieldInfo{
+       Invalid:               {},
+       ArrayType_Elt:         info[*ast.ArrayType]("Elt"),
+       ArrayType_Len:         info[*ast.ArrayType]("Len"),
+       AssignStmt_Lhs:        info[*ast.AssignStmt]("Lhs"),
+       AssignStmt_Rhs:        info[*ast.AssignStmt]("Rhs"),
+       BinaryExpr_X:          info[*ast.BinaryExpr]("X"),
+       BinaryExpr_Y:          info[*ast.BinaryExpr]("Y"),
+       BlockStmt_List:        info[*ast.BlockStmt]("List"),
+       BranchStmt_Label:      info[*ast.BranchStmt]("Label"),
+       CallExpr_Args:         info[*ast.CallExpr]("Args"),
+       CallExpr_Fun:          info[*ast.CallExpr]("Fun"),
+       CaseClause_Body:       info[*ast.CaseClause]("Body"),
+       CaseClause_List:       info[*ast.CaseClause]("List"),
+       ChanType_Value:        info[*ast.ChanType]("Value"),
+       CommClause_Body:       info[*ast.CommClause]("Body"),
+       CommClause_Comm:       info[*ast.CommClause]("Comm"),
+       CommentGroup_List:     info[*ast.CommentGroup]("List"),
+       CompositeLit_Elts:     info[*ast.CompositeLit]("Elts"),
+       CompositeLit_Type:     info[*ast.CompositeLit]("Type"),
+       DeclStmt_Decl:         info[*ast.DeclStmt]("Decl"),
+       DeferStmt_Call:        info[*ast.DeferStmt]("Call"),
+       Ellipsis_Elt:          info[*ast.Ellipsis]("Elt"),
+       ExprStmt_X:            info[*ast.ExprStmt]("X"),
+       FieldList_List:        info[*ast.FieldList]("List"),
+       Field_Comment:         info[*ast.Field]("Comment"),
+       Field_Doc:             info[*ast.Field]("Doc"),
+       Field_Names:           info[*ast.Field]("Names"),
+       Field_Tag:             info[*ast.Field]("Tag"),
+       Field_Type:            info[*ast.Field]("Type"),
+       File_Decls:            info[*ast.File]("Decls"),
+       File_Doc:              info[*ast.File]("Doc"),
+       File_Name:             info[*ast.File]("Name"),
+       ForStmt_Body:          info[*ast.ForStmt]("Body"),
+       ForStmt_Cond:          info[*ast.ForStmt]("Cond"),
+       ForStmt_Init:          info[*ast.ForStmt]("Init"),
+       ForStmt_Post:          info[*ast.ForStmt]("Post"),
+       FuncDecl_Body:         info[*ast.FuncDecl]("Body"),
+       FuncDecl_Doc:          info[*ast.FuncDecl]("Doc"),
+       FuncDecl_Name:         info[*ast.FuncDecl]("Name"),
+       FuncDecl_Recv:         info[*ast.FuncDecl]("Recv"),
+       FuncDecl_Type:         info[*ast.FuncDecl]("Type"),
+       FuncLit_Body:          info[*ast.FuncLit]("Body"),
+       FuncLit_Type:          info[*ast.FuncLit]("Type"),
+       FuncType_Params:       info[*ast.FuncType]("Params"),
+       FuncType_Results:      info[*ast.FuncType]("Results"),
+       FuncType_TypeParams:   info[*ast.FuncType]("TypeParams"),
+       GenDecl_Doc:           info[*ast.GenDecl]("Doc"),
+       GenDecl_Specs:         info[*ast.GenDecl]("Specs"),
+       GoStmt_Call:           info[*ast.GoStmt]("Call"),
+       IfStmt_Body:           info[*ast.IfStmt]("Body"),
+       IfStmt_Cond:           info[*ast.IfStmt]("Cond"),
+       IfStmt_Else:           info[*ast.IfStmt]("Else"),
+       IfStmt_Init:           info[*ast.IfStmt]("Init"),
+       ImportSpec_Comment:    info[*ast.ImportSpec]("Comment"),
+       ImportSpec_Doc:        info[*ast.ImportSpec]("Doc"),
+       ImportSpec_Name:       info[*ast.ImportSpec]("Name"),
+       ImportSpec_Path:       info[*ast.ImportSpec]("Path"),
+       IncDecStmt_X:          info[*ast.IncDecStmt]("X"),
+       IndexExpr_Index:       info[*ast.IndexExpr]("Index"),
+       IndexExpr_X:           info[*ast.IndexExpr]("X"),
+       IndexListExpr_Indices: info[*ast.IndexListExpr]("Indices"),
+       IndexListExpr_X:       info[*ast.IndexListExpr]("X"),
+       InterfaceType_Methods: info[*ast.InterfaceType]("Methods"),
+       KeyValueExpr_Key:      info[*ast.KeyValueExpr]("Key"),
+       KeyValueExpr_Value:    info[*ast.KeyValueExpr]("Value"),
+       LabeledStmt_Label:     info[*ast.LabeledStmt]("Label"),
+       LabeledStmt_Stmt:      info[*ast.LabeledStmt]("Stmt"),
+       MapType_Key:           info[*ast.MapType]("Key"),
+       MapType_Value:         info[*ast.MapType]("Value"),
+       ParenExpr_X:           info[*ast.ParenExpr]("X"),
+       RangeStmt_Body:        info[*ast.RangeStmt]("Body"),
+       RangeStmt_Key:         info[*ast.RangeStmt]("Key"),
+       RangeStmt_Value:       info[*ast.RangeStmt]("Value"),
+       RangeStmt_X:           info[*ast.RangeStmt]("X"),
+       ReturnStmt_Results:    info[*ast.ReturnStmt]("Results"),
+       SelectStmt_Body:       info[*ast.SelectStmt]("Body"),
+       SelectorExpr_Sel:      info[*ast.SelectorExpr]("Sel"),
+       SelectorExpr_X:        info[*ast.SelectorExpr]("X"),
+       SendStmt_Chan:         info[*ast.SendStmt]("Chan"),
+       SendStmt_Value:        info[*ast.SendStmt]("Value"),
+       SliceExpr_High:        info[*ast.SliceExpr]("High"),
+       SliceExpr_Low:         info[*ast.SliceExpr]("Low"),
+       SliceExpr_Max:         info[*ast.SliceExpr]("Max"),
+       SliceExpr_X:           info[*ast.SliceExpr]("X"),
+       StarExpr_X:            info[*ast.StarExpr]("X"),
+       StructType_Fields:     info[*ast.StructType]("Fields"),
+       SwitchStmt_Body:       info[*ast.SwitchStmt]("Body"),
+       SwitchStmt_Init:       info[*ast.SwitchStmt]("Init"),
+       SwitchStmt_Tag:        info[*ast.SwitchStmt]("Tag"),
+       TypeAssertExpr_Type:   info[*ast.TypeAssertExpr]("Type"),
+       TypeAssertExpr_X:      info[*ast.TypeAssertExpr]("X"),
+       TypeSpec_Comment:      info[*ast.TypeSpec]("Comment"),
+       TypeSpec_Doc:          info[*ast.TypeSpec]("Doc"),
+       TypeSpec_Name:         info[*ast.TypeSpec]("Name"),
+       TypeSpec_Type:         info[*ast.TypeSpec]("Type"),
+       TypeSpec_TypeParams:   info[*ast.TypeSpec]("TypeParams"),
+       TypeSwitchStmt_Assign: info[*ast.TypeSwitchStmt]("Assign"),
+       TypeSwitchStmt_Body:   info[*ast.TypeSwitchStmt]("Body"),
+       TypeSwitchStmt_Init:   info[*ast.TypeSwitchStmt]("Init"),
+       UnaryExpr_X:           info[*ast.UnaryExpr]("X"),
+       ValueSpec_Comment:     info[*ast.ValueSpec]("Comment"),
+       ValueSpec_Doc:         info[*ast.ValueSpec]("Doc"),
+       ValueSpec_Names:       info[*ast.ValueSpec]("Names"),
+       ValueSpec_Type:        info[*ast.ValueSpec]("Type"),
+       ValueSpec_Values:      info[*ast.ValueSpec]("Values"),
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go b/src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go
new file mode 100644 (file)
index 0000000..9ab264f
--- /dev/null
@@ -0,0 +1,370 @@
+// 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 fmtstr defines a parser for format strings as used by [fmt.Printf].
+package fmtstr
+
+import (
+       "fmt"
+       "strconv"
+       "strings"
+       "unicode/utf8"
+)
+
+// Operation holds the parsed representation of a printf operation such as "%3.*[4]d".
+// It is constructed by [Parse].
+type Operation struct {
+       Text  string // full text of the operation, e.g. "%[2]*.3d"
+       Verb  Verb   // verb specifier, guaranteed to exist, e.g., 'd' in '%[1]d'
+       Range Range  // the range of Text within the overall format string
+       Flags string // formatting flags, e.g. "-0"
+       Width Size   // width specifier, e.g., '3' in '%3d'
+       Prec  Size   // precision specifier, e.g., '.4' in '%.4f'
+}
+
+// Size describes an optional width or precision in a format operation.
+// It may represent no value, a literal number, an asterisk, or an indexed asterisk.
+type Size struct {
+       // At most one of these two fields is non-negative.
+       Fixed   int // e.g. 4 from "%4d", otherwise -1
+       Dynamic int // index of argument providing dynamic size (e.g. %*d or %[3]*d), otherwise -1
+
+       Index int   // If the width or precision uses an indexed argument (e.g. 2 in %[2]*d), this is the index, otherwise -1
+       Range Range // position of the size specifier within the operation
+}
+
+// Verb represents the verb character of a format operation (e.g., 'd', 's', 'f').
+// It also includes positional information and any explicit argument indexing.
+type Verb struct {
+       Verb     rune
+       Range    Range // positional range of the verb in the format string
+       Index    int   // index of an indexed argument, (e.g. 2 in %[2]d), otherwise -1
+       ArgIndex int   // argument index (0-based) associated with this verb, relative to CallExpr
+}
+
+// byte offsets of format string
+type Range struct {
+       Start, End int
+}
+
+// Parse takes a format string and its index in the printf-like call,
+// parses out all format operations, returns a slice of parsed
+// [Operation] which describes flags, width, precision, verb, and argument indexing,
+// or an error if parsing fails.
+//
+// All error messages are in predicate form ("call has a problem")
+// so that they may be affixed into a subject ("log.Printf ").
+//
+// The flags will only be a subset of ['#', '0', '+', '-', ' '].
+// It does not perform any validation of verbs, nor the
+// existence of corresponding arguments (obviously it can't). The provided format string may differ
+// from the one in CallExpr, such as a concatenated string or a string
+// referred to by the argument in the CallExpr.
+func Parse(format string, idx int) ([]*Operation, error) {
+       if !strings.Contains(format, "%") {
+               return nil, fmt.Errorf("call has arguments but no formatting directives")
+       }
+
+       firstArg := idx + 1 // Arguments are immediately after format string.
+       argNum := firstArg
+       var operations []*Operation
+       for i, w := 0, 0; i < len(format); i += w {
+               w = 1
+               if format[i] != '%' {
+                       continue
+               }
+               state, err := parseOperation(format[i:], firstArg, argNum)
+               if err != nil {
+                       return nil, err
+               }
+
+               state.operation.addOffset(i)
+               operations = append(operations, state.operation)
+
+               w = len(state.operation.Text)
+               // Do not waste an argument for '%'.
+               if state.operation.Verb.Verb != '%' {
+                       argNum = state.argNum + 1
+               }
+       }
+       return operations, nil
+}
+
+// Internal parsing state to operation.
+type state struct {
+       operation    *Operation
+       firstArg     int  // index of the first argument after the format string
+       argNum       int  // which argument we're expecting to format now
+       hasIndex     bool // whether the argument is indexed
+       index        int  // the encountered index
+       indexPos     int  // the encountered index's offset
+       indexPending bool // whether we have an indexed argument that has not resolved
+       nbytes       int  // number of bytes of the format string consumed
+}
+
+// parseOperation parses one format operation starting at the given substring `format`,
+// which should begin with '%'. It returns a fully populated state or an error
+// if the operation is malformed. The firstArg and argNum parameters help determine how
+// arguments map to this operation.
+//
+// Parse sequence: '%' -> flags -> {[N]* or width} -> .{[N]* or precision} -> [N] -> verb.
+func parseOperation(format string, firstArg, argNum int) (*state, error) {
+       state := &state{
+               operation: &Operation{
+                       Text: format,
+                       Width: Size{
+                               Fixed:   -1,
+                               Dynamic: -1,
+                               Index:   -1,
+                       },
+                       Prec: Size{
+                               Fixed:   -1,
+                               Dynamic: -1,
+                               Index:   -1,
+                       },
+               },
+               firstArg:     firstArg,
+               argNum:       argNum,
+               hasIndex:     false,
+               index:        0,
+               indexPos:     0,
+               indexPending: false,
+               nbytes:       len("%"), // There's guaranteed to be a percent sign.
+       }
+       // There may be flags.
+       state.parseFlags()
+       // There may be an index.
+       if err := state.parseIndex(); err != nil {
+               return nil, err
+       }
+       // There may be a width.
+       state.parseSize(Width)
+       // There may be a precision.
+       if err := state.parsePrecision(); err != nil {
+               return nil, err
+       }
+       // Now a verb, possibly prefixed by an index (which we may already have).
+       if !state.indexPending {
+               if err := state.parseIndex(); err != nil {
+                       return nil, err
+               }
+       }
+       if state.nbytes == len(state.operation.Text) {
+               return nil, fmt.Errorf("format %s is missing verb at end of string", state.operation.Text)
+       }
+       verb, w := utf8.DecodeRuneInString(state.operation.Text[state.nbytes:])
+
+       // Ensure there must be a verb.
+       if state.indexPending {
+               state.operation.Verb = Verb{
+                       Verb: verb,
+                       Range: Range{
+                               Start: state.indexPos,
+                               End:   state.nbytes + w,
+                       },
+                       Index:    state.index,
+                       ArgIndex: state.argNum,
+               }
+       } else {
+               state.operation.Verb = Verb{
+                       Verb: verb,
+                       Range: Range{
+                               Start: state.nbytes,
+                               End:   state.nbytes + w,
+                       },
+                       Index:    -1,
+                       ArgIndex: state.argNum,
+               }
+       }
+
+       state.nbytes += w
+       state.operation.Text = state.operation.Text[:state.nbytes]
+       return state, nil
+}
+
+// addOffset adjusts the recorded positions in Verb, Width, Prec, and the
+// operation's overall Range to be relative to the position in the full format string.
+func (s *Operation) addOffset(parsedLen int) {
+       s.Verb.Range.Start += parsedLen
+       s.Verb.Range.End += parsedLen
+
+       s.Range.Start = parsedLen
+       s.Range.End = s.Verb.Range.End
+
+       // one of Fixed or Dynamic is non-negative means existence.
+       if s.Prec.Fixed != -1 || s.Prec.Dynamic != -1 {
+               s.Prec.Range.Start += parsedLen
+               s.Prec.Range.End += parsedLen
+       }
+       if s.Width.Fixed != -1 || s.Width.Dynamic != -1 {
+               s.Width.Range.Start += parsedLen
+               s.Width.Range.End += parsedLen
+       }
+}
+
+// parseFlags accepts any printf flags.
+func (s *state) parseFlags() {
+       s.operation.Flags = prefixOf(s.operation.Text[s.nbytes:], "#0+- ")
+       s.nbytes += len(s.operation.Flags)
+}
+
+// prefixOf returns the prefix of s composed only of runes from the specified set.
+func prefixOf(s, set string) string {
+       rest := strings.TrimLeft(s, set)
+       return s[:len(s)-len(rest)]
+}
+
+// parseIndex parses an argument index of the form "[n]" that can appear
+// in a printf operation (e.g., "%[2]d"). Returns an error if syntax is
+// malformed or index is invalid.
+func (s *state) parseIndex() error {
+       if s.nbytes == len(s.operation.Text) || s.operation.Text[s.nbytes] != '[' {
+               return nil
+       }
+       // Argument index present.
+       s.nbytes++ // skip '['
+       start := s.nbytes
+       if num, ok := s.scanNum(); ok {
+               // Later consumed/stored by a '*' or verb.
+               s.index = num
+               s.indexPos = start - 1
+       }
+
+       ok := true
+       if s.nbytes == len(s.operation.Text) || s.nbytes == start || s.operation.Text[s.nbytes] != ']' {
+               ok = false // syntax error is either missing "]" or invalid index.
+               s.nbytes = strings.Index(s.operation.Text[start:], "]")
+               if s.nbytes < 0 {
+                       return fmt.Errorf("format %s is missing closing ]", s.operation.Text)
+               }
+               s.nbytes = s.nbytes + start
+       }
+       arg32, err := strconv.ParseInt(s.operation.Text[start:s.nbytes], 10, 32)
+       if err != nil || !ok || arg32 <= 0 {
+               return fmt.Errorf("format has invalid argument index [%s]", s.operation.Text[start:s.nbytes])
+       }
+
+       s.nbytes++ // skip ']'
+       arg := int(arg32)
+       arg += s.firstArg - 1 // We want to zero-index the actual arguments.
+       s.argNum = arg
+       s.hasIndex = true
+       s.indexPending = true
+       return nil
+}
+
+// scanNum advances through a decimal number if present, which represents a [Size] or [Index].
+func (s *state) scanNum() (int, bool) {
+       start := s.nbytes
+       for ; s.nbytes < len(s.operation.Text); s.nbytes++ {
+               c := s.operation.Text[s.nbytes]
+               if c < '0' || '9' < c {
+                       if start < s.nbytes {
+                               num, _ := strconv.ParseInt(s.operation.Text[start:s.nbytes], 10, 32)
+                               return int(num), true
+                       } else {
+                               return 0, false
+                       }
+               }
+       }
+       return 0, false
+}
+
+type sizeType int
+
+const (
+       Width sizeType = iota
+       Precision
+)
+
+// parseSize parses a width or precision specifier. It handles literal numeric
+// values (e.g., "%3d"), asterisk values (e.g., "%*d"), or indexed asterisk values (e.g., "%[2]*d").
+func (s *state) parseSize(kind sizeType) {
+       if s.nbytes < len(s.operation.Text) && s.operation.Text[s.nbytes] == '*' {
+               s.nbytes++
+               if s.indexPending {
+                       // Absorb it.
+                       s.indexPending = false
+                       size := Size{
+                               Fixed:   -1,
+                               Dynamic: s.argNum,
+                               Index:   s.index,
+                               Range: Range{
+                                       Start: s.indexPos,
+                                       End:   s.nbytes,
+                               },
+                       }
+                       switch kind {
+                       case Width:
+                               s.operation.Width = size
+                       case Precision:
+                               // Include the leading '.'.
+                               size.Range.Start -= len(".")
+                               s.operation.Prec = size
+                       default:
+                               panic(kind)
+                       }
+               } else {
+                       // Non-indexed asterisk: "%*d".
+                       size := Size{
+                               Dynamic: s.argNum,
+                               Index:   -1,
+                               Fixed:   -1,
+                               Range: Range{
+                                       Start: s.nbytes - 1,
+                                       End:   s.nbytes,
+                               },
+                       }
+                       switch kind {
+                       case Width:
+                               s.operation.Width = size
+                       case Precision:
+                               // For precision, include the '.' in the range.
+                               size.Range.Start -= 1
+                               s.operation.Prec = size
+                       default:
+                               panic(kind)
+                       }
+               }
+               s.argNum++
+       } else { // Literal number, e.g. "%10d"
+               start := s.nbytes
+               if num, ok := s.scanNum(); ok {
+                       size := Size{
+                               Fixed:   num,
+                               Index:   -1,
+                               Dynamic: -1,
+                               Range: Range{
+                                       Start: start,
+                                       End:   s.nbytes,
+                               },
+                       }
+                       switch kind {
+                       case Width:
+                               s.operation.Width = size
+                       case Precision:
+                               // Include the leading '.'.
+                               size.Range.Start -= 1
+                               s.operation.Prec = size
+                       default:
+                               panic(kind)
+                       }
+               }
+       }
+}
+
+// parsePrecision checks if there's a precision specified after a '.' character.
+// If found, it may also parse an index or an asterisk. Returns an error if any index
+// parsing fails.
+func (s *state) parsePrecision() error {
+       // If there's a period, there may be a precision.
+       if s.nbytes < len(s.operation.Text) && s.operation.Text[s.nbytes] == '.' {
+               s.nbytes++
+               if err := s.parseIndex(); err != nil {
+                       return err
+               }
+               s.parseSize(Precision)
+       }
+       return nil
+}
index cdaac9ab34df2632265636d5a5f9ad03b260d018..e7d0aee218648c689ca5eb7fa2cb73e7a2672970 100644 (file)
@@ -268,6 +268,8 @@ var PackageSymbols = map[string][]Symbol{
                {"ErrTooLarge", Var, 0},
                {"Fields", Func, 0},
                {"FieldsFunc", Func, 0},
+               {"FieldsFuncSeq", Func, 24},
+               {"FieldsSeq", Func, 24},
                {"HasPrefix", Func, 0},
                {"HasSuffix", Func, 0},
                {"Index", Func, 0},
@@ -280,6 +282,7 @@ var PackageSymbols = map[string][]Symbol{
                {"LastIndexAny", Func, 0},
                {"LastIndexByte", Func, 5},
                {"LastIndexFunc", Func, 0},
+               {"Lines", Func, 24},
                {"Map", Func, 0},
                {"MinRead", Const, 0},
                {"NewBuffer", Func, 0},
@@ -293,7 +296,9 @@ var PackageSymbols = map[string][]Symbol{
                {"Split", Func, 0},
                {"SplitAfter", Func, 0},
                {"SplitAfterN", Func, 0},
+               {"SplitAfterSeq", Func, 24},
                {"SplitN", Func, 0},
+               {"SplitSeq", Func, 24},
                {"Title", Func, 0},
                {"ToLower", Func, 0},
                {"ToLowerSpecial", Func, 0},
@@ -535,6 +540,7 @@ var PackageSymbols = map[string][]Symbol{
                {"NewCTR", Func, 0},
                {"NewGCM", Func, 2},
                {"NewGCMWithNonceSize", Func, 5},
+               {"NewGCMWithRandomNonce", Func, 24},
                {"NewGCMWithTagSize", Func, 11},
                {"NewOFB", Func, 0},
                {"Stream", Type, 0},
@@ -673,6 +679,14 @@ var PackageSymbols = map[string][]Symbol{
                {"Unmarshal", Func, 0},
                {"UnmarshalCompressed", Func, 15},
        },
+       "crypto/fips140": {
+               {"Enabled", Func, 24},
+       },
+       "crypto/hkdf": {
+               {"Expand", Func, 24},
+               {"Extract", Func, 24},
+               {"Key", Func, 24},
+       },
        "crypto/hmac": {
                {"Equal", Func, 1},
                {"New", Func, 0},
@@ -683,11 +697,43 @@ var PackageSymbols = map[string][]Symbol{
                {"Size", Const, 0},
                {"Sum", Func, 2},
        },
+       "crypto/mlkem": {
+               {"(*DecapsulationKey1024).Bytes", Method, 24},
+               {"(*DecapsulationKey1024).Decapsulate", Method, 24},
+               {"(*DecapsulationKey1024).EncapsulationKey", Method, 24},
+               {"(*DecapsulationKey768).Bytes", Method, 24},
+               {"(*DecapsulationKey768).Decapsulate", Method, 24},
+               {"(*DecapsulationKey768).EncapsulationKey", Method, 24},
+               {"(*EncapsulationKey1024).Bytes", Method, 24},
+               {"(*EncapsulationKey1024).Encapsulate", Method, 24},
+               {"(*EncapsulationKey768).Bytes", Method, 24},
+               {"(*EncapsulationKey768).Encapsulate", Method, 24},
+               {"CiphertextSize1024", Const, 24},
+               {"CiphertextSize768", Const, 24},
+               {"DecapsulationKey1024", Type, 24},
+               {"DecapsulationKey768", Type, 24},
+               {"EncapsulationKey1024", Type, 24},
+               {"EncapsulationKey768", Type, 24},
+               {"EncapsulationKeySize1024", Const, 24},
+               {"EncapsulationKeySize768", Const, 24},
+               {"GenerateKey1024", Func, 24},
+               {"GenerateKey768", Func, 24},
+               {"NewDecapsulationKey1024", Func, 24},
+               {"NewDecapsulationKey768", Func, 24},
+               {"NewEncapsulationKey1024", Func, 24},
+               {"NewEncapsulationKey768", Func, 24},
+               {"SeedSize", Const, 24},
+               {"SharedKeySize", Const, 24},
+       },
+       "crypto/pbkdf2": {
+               {"Key", Func, 24},
+       },
        "crypto/rand": {
                {"Int", Func, 0},
                {"Prime", Func, 0},
                {"Read", Func, 0},
                {"Reader", Var, 0},
+               {"Text", Func, 24},
        },
        "crypto/rc4": {
                {"(*Cipher).Reset", Method, 0},
@@ -766,6 +812,39 @@ var PackageSymbols = map[string][]Symbol{
                {"Sum224", Func, 2},
                {"Sum256", Func, 2},
        },
+       "crypto/sha3": {
+               {"(*SHA3).AppendBinary", Method, 24},
+               {"(*SHA3).BlockSize", Method, 24},
+               {"(*SHA3).MarshalBinary", Method, 24},
+               {"(*SHA3).Reset", Method, 24},
+               {"(*SHA3).Size", Method, 24},
+               {"(*SHA3).Sum", Method, 24},
+               {"(*SHA3).UnmarshalBinary", Method, 24},
+               {"(*SHA3).Write", Method, 24},
+               {"(*SHAKE).AppendBinary", Method, 24},
+               {"(*SHAKE).BlockSize", Method, 24},
+               {"(*SHAKE).MarshalBinary", Method, 24},
+               {"(*SHAKE).Read", Method, 24},
+               {"(*SHAKE).Reset", Method, 24},
+               {"(*SHAKE).UnmarshalBinary", Method, 24},
+               {"(*SHAKE).Write", Method, 24},
+               {"New224", Func, 24},
+               {"New256", Func, 24},
+               {"New384", Func, 24},
+               {"New512", Func, 24},
+               {"NewCSHAKE128", Func, 24},
+               {"NewCSHAKE256", Func, 24},
+               {"NewSHAKE128", Func, 24},
+               {"NewSHAKE256", Func, 24},
+               {"SHA3", Type, 24},
+               {"SHAKE", Type, 24},
+               {"Sum224", Func, 24},
+               {"Sum256", Func, 24},
+               {"Sum384", Func, 24},
+               {"Sum512", Func, 24},
+               {"SumSHAKE128", Func, 24},
+               {"SumSHAKE256", Func, 24},
+       },
        "crypto/sha512": {
                {"BlockSize", Const, 0},
                {"New", Func, 0},
@@ -788,6 +867,7 @@ var PackageSymbols = map[string][]Symbol{
                {"ConstantTimeEq", Func, 0},
                {"ConstantTimeLessOrEq", Func, 2},
                {"ConstantTimeSelect", Func, 0},
+               {"WithDataIndependentTiming", Func, 24},
                {"XORBytes", Func, 20},
        },
        "crypto/tls": {
@@ -864,6 +944,7 @@ var PackageSymbols = map[string][]Symbol{
                {"ClientHelloInfo", Type, 4},
                {"ClientHelloInfo.CipherSuites", Field, 4},
                {"ClientHelloInfo.Conn", Field, 8},
+               {"ClientHelloInfo.Extensions", Field, 24},
                {"ClientHelloInfo.ServerName", Field, 4},
                {"ClientHelloInfo.SignatureSchemes", Field, 8},
                {"ClientHelloInfo.SupportedCurves", Field, 4},
@@ -881,6 +962,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Config.CurvePreferences", Field, 3},
                {"Config.DynamicRecordSizingDisabled", Field, 7},
                {"Config.EncryptedClientHelloConfigList", Field, 23},
+               {"Config.EncryptedClientHelloKeys", Field, 24},
                {"Config.EncryptedClientHelloRejectionVerify", Field, 23},
                {"Config.GetCertificate", Field, 4},
                {"Config.GetClientCertificate", Field, 8},
@@ -934,6 +1016,10 @@ var PackageSymbols = map[string][]Symbol{
                {"ECHRejectionError", Type, 23},
                {"ECHRejectionError.RetryConfigList", Field, 23},
                {"Ed25519", Const, 13},
+               {"EncryptedClientHelloKey", Type, 24},
+               {"EncryptedClientHelloKey.Config", Field, 24},
+               {"EncryptedClientHelloKey.PrivateKey", Field, 24},
+               {"EncryptedClientHelloKey.SendAsRetry", Field, 24},
                {"InsecureCipherSuites", Func, 14},
                {"Listen", Func, 0},
                {"LoadX509KeyPair", Func, 0},
@@ -1032,6 +1118,7 @@ var PackageSymbols = map[string][]Symbol{
                {"VersionTLS12", Const, 2},
                {"VersionTLS13", Const, 12},
                {"X25519", Const, 8},
+               {"X25519MLKEM768", Const, 24},
                {"X509KeyPair", Func, 0},
        },
        "crypto/x509": {
@@ -1056,6 +1143,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(ConstraintViolationError).Error", Method, 0},
                {"(HostnameError).Error", Method, 0},
                {"(InsecureAlgorithmError).Error", Method, 6},
+               {"(OID).AppendBinary", Method, 24},
+               {"(OID).AppendText", Method, 24},
                {"(OID).Equal", Method, 22},
                {"(OID).EqualASN1OID", Method, 22},
                {"(OID).MarshalBinary", Method, 23},
@@ -1084,6 +1173,10 @@ var PackageSymbols = map[string][]Symbol{
                {"Certificate.Extensions", Field, 2},
                {"Certificate.ExtraExtensions", Field, 2},
                {"Certificate.IPAddresses", Field, 1},
+               {"Certificate.InhibitAnyPolicy", Field, 24},
+               {"Certificate.InhibitAnyPolicyZero", Field, 24},
+               {"Certificate.InhibitPolicyMapping", Field, 24},
+               {"Certificate.InhibitPolicyMappingZero", Field, 24},
                {"Certificate.IsCA", Field, 0},
                {"Certificate.Issuer", Field, 0},
                {"Certificate.IssuingCertificateURL", Field, 2},
@@ -1100,6 +1193,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Certificate.PermittedURIDomains", Field, 10},
                {"Certificate.Policies", Field, 22},
                {"Certificate.PolicyIdentifiers", Field, 0},
+               {"Certificate.PolicyMappings", Field, 24},
                {"Certificate.PublicKey", Field, 0},
                {"Certificate.PublicKeyAlgorithm", Field, 0},
                {"Certificate.Raw", Field, 0},
@@ -1107,6 +1201,8 @@ var PackageSymbols = map[string][]Symbol{
                {"Certificate.RawSubject", Field, 0},
                {"Certificate.RawSubjectPublicKeyInfo", Field, 0},
                {"Certificate.RawTBSCertificate", Field, 0},
+               {"Certificate.RequireExplicitPolicy", Field, 24},
+               {"Certificate.RequireExplicitPolicyZero", Field, 24},
                {"Certificate.SerialNumber", Field, 0},
                {"Certificate.Signature", Field, 0},
                {"Certificate.SignatureAlgorithm", Field, 0},
@@ -1198,6 +1294,7 @@ var PackageSymbols = map[string][]Symbol{
                {"NameConstraintsWithoutSANs", Const, 10},
                {"NameMismatch", Const, 8},
                {"NewCertPool", Func, 0},
+               {"NoValidChains", Const, 24},
                {"NotAuthorizedToSign", Const, 0},
                {"OID", Type, 22},
                {"OIDFromInts", Func, 22},
@@ -1219,6 +1316,9 @@ var PackageSymbols = map[string][]Symbol{
                {"ParsePKCS8PrivateKey", Func, 0},
                {"ParsePKIXPublicKey", Func, 0},
                {"ParseRevocationList", Func, 19},
+               {"PolicyMapping", Type, 24},
+               {"PolicyMapping.IssuerDomainPolicy", Field, 24},
+               {"PolicyMapping.SubjectDomainPolicy", Field, 24},
                {"PublicKeyAlgorithm", Type, 0},
                {"PureEd25519", Const, 13},
                {"RSA", Const, 0},
@@ -1265,6 +1365,7 @@ var PackageSymbols = map[string][]Symbol{
                {"UnknownPublicKeyAlgorithm", Const, 0},
                {"UnknownSignatureAlgorithm", Const, 0},
                {"VerifyOptions", Type, 0},
+               {"VerifyOptions.CertificatePolicies", Field, 24},
                {"VerifyOptions.CurrentTime", Field, 0},
                {"VerifyOptions.DNSName", Field, 0},
                {"VerifyOptions.Intermediates", Field, 0},
@@ -1975,6 +2076,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(*File).DynString", Method, 1},
                {"(*File).DynValue", Method, 21},
                {"(*File).DynamicSymbols", Method, 4},
+               {"(*File).DynamicVersionNeeds", Method, 24},
+               {"(*File).DynamicVersions", Method, 24},
                {"(*File).ImportedLibraries", Method, 0},
                {"(*File).ImportedSymbols", Method, 0},
                {"(*File).Section", Method, 0},
@@ -2048,6 +2151,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(Type).String", Method, 0},
                {"(Version).GoString", Method, 0},
                {"(Version).String", Method, 0},
+               {"(VersionIndex).Index", Method, 24},
+               {"(VersionIndex).IsHidden", Method, 24},
                {"ARM_MAGIC_TRAMP_NUMBER", Const, 0},
                {"COMPRESS_HIOS", Const, 6},
                {"COMPRESS_HIPROC", Const, 6},
@@ -2240,6 +2345,19 @@ var PackageSymbols = map[string][]Symbol{
                {"DynFlag", Type, 0},
                {"DynFlag1", Type, 21},
                {"DynTag", Type, 0},
+               {"DynamicVersion", Type, 24},
+               {"DynamicVersion.Deps", Field, 24},
+               {"DynamicVersion.Flags", Field, 24},
+               {"DynamicVersion.Index", Field, 24},
+               {"DynamicVersion.Name", Field, 24},
+               {"DynamicVersionDep", Type, 24},
+               {"DynamicVersionDep.Dep", Field, 24},
+               {"DynamicVersionDep.Flags", Field, 24},
+               {"DynamicVersionDep.Index", Field, 24},
+               {"DynamicVersionFlag", Type, 24},
+               {"DynamicVersionNeed", Type, 24},
+               {"DynamicVersionNeed.Name", Field, 24},
+               {"DynamicVersionNeed.Needs", Field, 24},
                {"EI_ABIVERSION", Const, 0},
                {"EI_CLASS", Const, 0},
                {"EI_DATA", Const, 0},
@@ -3718,6 +3836,7 @@ var PackageSymbols = map[string][]Symbol{
                {"SymType", Type, 0},
                {"SymVis", Type, 0},
                {"Symbol", Type, 0},
+               {"Symbol.HasVersion", Field, 24},
                {"Symbol.Info", Field, 0},
                {"Symbol.Library", Field, 13},
                {"Symbol.Name", Field, 0},
@@ -3726,8 +3845,13 @@ var PackageSymbols = map[string][]Symbol{
                {"Symbol.Size", Field, 0},
                {"Symbol.Value", Field, 0},
                {"Symbol.Version", Field, 13},
+               {"Symbol.VersionIndex", Field, 24},
                {"Type", Type, 0},
+               {"VER_FLG_BASE", Const, 24},
+               {"VER_FLG_INFO", Const, 24},
+               {"VER_FLG_WEAK", Const, 24},
                {"Version", Type, 0},
+               {"VersionIndex", Type, 24},
        },
        "debug/gosym": {
                {"(*DecodingError).Error", Method, 0},
@@ -4453,8 +4577,10 @@ var PackageSymbols = map[string][]Symbol{
                {"FS", Type, 16},
        },
        "encoding": {
+               {"BinaryAppender", Type, 24},
                {"BinaryMarshaler", Type, 2},
                {"BinaryUnmarshaler", Type, 2},
+               {"TextAppender", Type, 24},
                {"TextMarshaler", Type, 2},
                {"TextUnmarshaler", Type, 2},
        },
@@ -5984,13 +6110,16 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Interface).Complete", Method, 5},
                {"(*Interface).Embedded", Method, 5},
                {"(*Interface).EmbeddedType", Method, 11},
+               {"(*Interface).EmbeddedTypes", Method, 24},
                {"(*Interface).Empty", Method, 5},
                {"(*Interface).ExplicitMethod", Method, 5},
+               {"(*Interface).ExplicitMethods", Method, 24},
                {"(*Interface).IsComparable", Method, 18},
                {"(*Interface).IsImplicit", Method, 18},
                {"(*Interface).IsMethodSet", Method, 18},
                {"(*Interface).MarkImplicit", Method, 18},
                {"(*Interface).Method", Method, 5},
+               {"(*Interface).Methods", Method, 24},
                {"(*Interface).NumEmbeddeds", Method, 5},
                {"(*Interface).NumExplicitMethods", Method, 5},
                {"(*Interface).NumMethods", Method, 5},
@@ -6011,9 +6140,11 @@ var PackageSymbols = map[string][]Symbol{
                {"(*MethodSet).At", Method, 5},
                {"(*MethodSet).Len", Method, 5},
                {"(*MethodSet).Lookup", Method, 5},
+               {"(*MethodSet).Methods", Method, 24},
                {"(*MethodSet).String", Method, 5},
                {"(*Named).AddMethod", Method, 5},
                {"(*Named).Method", Method, 5},
+               {"(*Named).Methods", Method, 24},
                {"(*Named).NumMethods", Method, 5},
                {"(*Named).Obj", Method, 5},
                {"(*Named).Origin", Method, 18},
@@ -6054,6 +6185,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Pointer).String", Method, 5},
                {"(*Pointer).Underlying", Method, 5},
                {"(*Scope).Child", Method, 5},
+               {"(*Scope).Children", Method, 24},
                {"(*Scope).Contains", Method, 5},
                {"(*Scope).End", Method, 5},
                {"(*Scope).Innermost", Method, 5},
@@ -6089,6 +6221,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*StdSizes).Offsetsof", Method, 5},
                {"(*StdSizes).Sizeof", Method, 5},
                {"(*Struct).Field", Method, 5},
+               {"(*Struct).Fields", Method, 24},
                {"(*Struct).NumFields", Method, 5},
                {"(*Struct).String", Method, 5},
                {"(*Struct).Tag", Method, 5},
@@ -6100,8 +6233,10 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Tuple).Len", Method, 5},
                {"(*Tuple).String", Method, 5},
                {"(*Tuple).Underlying", Method, 5},
+               {"(*Tuple).Variables", Method, 24},
                {"(*TypeList).At", Method, 18},
                {"(*TypeList).Len", Method, 18},
+               {"(*TypeList).Types", Method, 24},
                {"(*TypeName).Exported", Method, 5},
                {"(*TypeName).Id", Method, 5},
                {"(*TypeName).IsAlias", Method, 9},
@@ -6119,9 +6254,11 @@ var PackageSymbols = map[string][]Symbol{
                {"(*TypeParam).Underlying", Method, 18},
                {"(*TypeParamList).At", Method, 18},
                {"(*TypeParamList).Len", Method, 18},
+               {"(*TypeParamList).TypeParams", Method, 24},
                {"(*Union).Len", Method, 18},
                {"(*Union).String", Method, 18},
                {"(*Union).Term", Method, 18},
+               {"(*Union).Terms", Method, 24},
                {"(*Union).Underlying", Method, 18},
                {"(*Var).Anonymous", Method, 5},
                {"(*Var).Embedded", Method, 11},
@@ -6392,10 +6529,12 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Hash).WriteByte", Method, 14},
                {"(*Hash).WriteString", Method, 14},
                {"Bytes", Func, 19},
+               {"Comparable", Func, 24},
                {"Hash", Type, 14},
                {"MakeSeed", Func, 14},
                {"Seed", Type, 14},
                {"String", Func, 19},
+               {"WriteComparable", Func, 24},
        },
        "html": {
                {"EscapeString", Func, 0},
@@ -7082,6 +7221,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*JSONHandler).WithGroup", Method, 21},
                {"(*Level).UnmarshalJSON", Method, 21},
                {"(*Level).UnmarshalText", Method, 21},
+               {"(*LevelVar).AppendText", Method, 24},
                {"(*LevelVar).Level", Method, 21},
                {"(*LevelVar).MarshalText", Method, 21},
                {"(*LevelVar).Set", Method, 21},
@@ -7110,6 +7250,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(Attr).Equal", Method, 21},
                {"(Attr).String", Method, 21},
                {"(Kind).String", Method, 21},
+               {"(Level).AppendText", Method, 24},
                {"(Level).Level", Method, 21},
                {"(Level).MarshalJSON", Method, 21},
                {"(Level).MarshalText", Method, 21},
@@ -7140,6 +7281,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Debug", Func, 21},
                {"DebugContext", Func, 21},
                {"Default", Func, 21},
+               {"DiscardHandler", Var, 24},
                {"Duration", Func, 21},
                {"DurationValue", Func, 21},
                {"Error", Func, 21},
@@ -7375,6 +7517,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Float).Acc", Method, 5},
                {"(*Float).Add", Method, 5},
                {"(*Float).Append", Method, 5},
+               {"(*Float).AppendText", Method, 24},
                {"(*Float).Cmp", Method, 5},
                {"(*Float).Copy", Method, 5},
                {"(*Float).Float32", Method, 5},
@@ -7421,6 +7564,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Int).And", Method, 0},
                {"(*Int).AndNot", Method, 0},
                {"(*Int).Append", Method, 6},
+               {"(*Int).AppendText", Method, 24},
                {"(*Int).Binomial", Method, 0},
                {"(*Int).Bit", Method, 0},
                {"(*Int).BitLen", Method, 0},
@@ -7477,6 +7621,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Int).Xor", Method, 0},
                {"(*Rat).Abs", Method, 0},
                {"(*Rat).Add", Method, 0},
+               {"(*Rat).AppendText", Method, 24},
                {"(*Rat).Cmp", Method, 0},
                {"(*Rat).Denom", Method, 0},
                {"(*Rat).Float32", Method, 4},
@@ -7659,11 +7804,13 @@ var PackageSymbols = map[string][]Symbol{
                {"Zipf", Type, 0},
        },
        "math/rand/v2": {
+               {"(*ChaCha8).AppendBinary", Method, 24},
                {"(*ChaCha8).MarshalBinary", Method, 22},
                {"(*ChaCha8).Read", Method, 23},
                {"(*ChaCha8).Seed", Method, 22},
                {"(*ChaCha8).Uint64", Method, 22},
                {"(*ChaCha8).UnmarshalBinary", Method, 22},
+               {"(*PCG).AppendBinary", Method, 24},
                {"(*PCG).MarshalBinary", Method, 22},
                {"(*PCG).Seed", Method, 22},
                {"(*PCG).Uint64", Method, 22},
@@ -7931,6 +8078,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*UnixListener).SyscallConn", Method, 10},
                {"(Flags).String", Method, 0},
                {"(HardwareAddr).String", Method, 0},
+               {"(IP).AppendText", Method, 24},
                {"(IP).DefaultMask", Method, 0},
                {"(IP).Equal", Method, 0},
                {"(IP).IsGlobalUnicast", Method, 0},
@@ -8131,6 +8279,9 @@ var PackageSymbols = map[string][]Symbol{
                {"(*MaxBytesError).Error", Method, 19},
                {"(*ProtocolError).Error", Method, 0},
                {"(*ProtocolError).Is", Method, 21},
+               {"(*Protocols).SetHTTP1", Method, 24},
+               {"(*Protocols).SetHTTP2", Method, 24},
+               {"(*Protocols).SetUnencryptedHTTP2", Method, 24},
                {"(*Request).AddCookie", Method, 0},
                {"(*Request).BasicAuth", Method, 4},
                {"(*Request).Clone", Method, 13},
@@ -8190,6 +8341,10 @@ var PackageSymbols = map[string][]Symbol{
                {"(Header).Values", Method, 14},
                {"(Header).Write", Method, 0},
                {"(Header).WriteSubset", Method, 0},
+               {"(Protocols).HTTP1", Method, 24},
+               {"(Protocols).HTTP2", Method, 24},
+               {"(Protocols).String", Method, 24},
+               {"(Protocols).UnencryptedHTTP2", Method, 24},
                {"AllowQuerySemicolons", Func, 17},
                {"CanonicalHeaderKey", Func, 0},
                {"Client", Type, 0},
@@ -8252,6 +8407,18 @@ var PackageSymbols = map[string][]Symbol{
                {"FileSystem", Type, 0},
                {"Flusher", Type, 0},
                {"Get", Func, 0},
+               {"HTTP2Config", Type, 24},
+               {"HTTP2Config.CountError", Field, 24},
+               {"HTTP2Config.MaxConcurrentStreams", Field, 24},
+               {"HTTP2Config.MaxDecoderHeaderTableSize", Field, 24},
+               {"HTTP2Config.MaxEncoderHeaderTableSize", Field, 24},
+               {"HTTP2Config.MaxReadFrameSize", Field, 24},
+               {"HTTP2Config.MaxReceiveBufferPerConnection", Field, 24},
+               {"HTTP2Config.MaxReceiveBufferPerStream", Field, 24},
+               {"HTTP2Config.PermitProhibitedCipherSuites", Field, 24},
+               {"HTTP2Config.PingTimeout", Field, 24},
+               {"HTTP2Config.SendPingTimeout", Field, 24},
+               {"HTTP2Config.WriteByteTimeout", Field, 24},
                {"Handle", Func, 0},
                {"HandleFunc", Func, 0},
                {"Handler", Type, 0},
@@ -8292,6 +8459,7 @@ var PackageSymbols = map[string][]Symbol{
                {"PostForm", Func, 0},
                {"ProtocolError", Type, 0},
                {"ProtocolError.ErrorString", Field, 0},
+               {"Protocols", Type, 24},
                {"ProxyFromEnvironment", Func, 0},
                {"ProxyURL", Func, 0},
                {"PushOptions", Type, 8},
@@ -8361,9 +8529,11 @@ var PackageSymbols = map[string][]Symbol{
                {"Server.ConnState", Field, 3},
                {"Server.DisableGeneralOptionsHandler", Field, 20},
                {"Server.ErrorLog", Field, 3},
+               {"Server.HTTP2", Field, 24},
                {"Server.Handler", Field, 0},
                {"Server.IdleTimeout", Field, 8},
                {"Server.MaxHeaderBytes", Field, 0},
+               {"Server.Protocols", Field, 24},
                {"Server.ReadHeaderTimeout", Field, 8},
                {"Server.ReadTimeout", Field, 0},
                {"Server.TLSConfig", Field, 0},
@@ -8453,12 +8623,14 @@ var PackageSymbols = map[string][]Symbol{
                {"Transport.ExpectContinueTimeout", Field, 6},
                {"Transport.ForceAttemptHTTP2", Field, 13},
                {"Transport.GetProxyConnectHeader", Field, 16},
+               {"Transport.HTTP2", Field, 24},
                {"Transport.IdleConnTimeout", Field, 7},
                {"Transport.MaxConnsPerHost", Field, 11},
                {"Transport.MaxIdleConns", Field, 7},
                {"Transport.MaxIdleConnsPerHost", Field, 0},
                {"Transport.MaxResponseHeaderBytes", Field, 7},
                {"Transport.OnProxyConnectResponse", Field, 20},
+               {"Transport.Protocols", Field, 24},
                {"Transport.Proxy", Field, 0},
                {"Transport.ProxyConnectHeader", Field, 8},
                {"Transport.ReadBufferSize", Field, 13},
@@ -8646,6 +8818,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(*AddrPort).UnmarshalText", Method, 18},
                {"(*Prefix).UnmarshalBinary", Method, 18},
                {"(*Prefix).UnmarshalText", Method, 18},
+               {"(Addr).AppendBinary", Method, 24},
+               {"(Addr).AppendText", Method, 24},
                {"(Addr).AppendTo", Method, 18},
                {"(Addr).As16", Method, 18},
                {"(Addr).As4", Method, 18},
@@ -8676,6 +8850,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(Addr).WithZone", Method, 18},
                {"(Addr).Zone", Method, 18},
                {"(AddrPort).Addr", Method, 18},
+               {"(AddrPort).AppendBinary", Method, 24},
+               {"(AddrPort).AppendText", Method, 24},
                {"(AddrPort).AppendTo", Method, 18},
                {"(AddrPort).Compare", Method, 22},
                {"(AddrPort).IsValid", Method, 18},
@@ -8684,6 +8860,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(AddrPort).Port", Method, 18},
                {"(AddrPort).String", Method, 18},
                {"(Prefix).Addr", Method, 18},
+               {"(Prefix).AppendBinary", Method, 24},
+               {"(Prefix).AppendText", Method, 24},
                {"(Prefix).AppendTo", Method, 18},
                {"(Prefix).Bits", Method, 18},
                {"(Prefix).Contains", Method, 18},
@@ -8868,6 +9046,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*Error).Temporary", Method, 6},
                {"(*Error).Timeout", Method, 6},
                {"(*Error).Unwrap", Method, 13},
+               {"(*URL).AppendBinary", Method, 24},
                {"(*URL).EscapedFragment", Method, 15},
                {"(*URL).EscapedPath", Method, 5},
                {"(*URL).Hostname", Method, 8},
@@ -8967,6 +9146,17 @@ var PackageSymbols = map[string][]Symbol{
                {"(*ProcessState).SysUsage", Method, 0},
                {"(*ProcessState).SystemTime", Method, 0},
                {"(*ProcessState).UserTime", Method, 0},
+               {"(*Root).Close", Method, 24},
+               {"(*Root).Create", Method, 24},
+               {"(*Root).FS", Method, 24},
+               {"(*Root).Lstat", Method, 24},
+               {"(*Root).Mkdir", Method, 24},
+               {"(*Root).Name", Method, 24},
+               {"(*Root).Open", Method, 24},
+               {"(*Root).OpenFile", Method, 24},
+               {"(*Root).OpenRoot", Method, 24},
+               {"(*Root).Remove", Method, 24},
+               {"(*Root).Stat", Method, 24},
                {"(*SyscallError).Error", Method, 0},
                {"(*SyscallError).Timeout", Method, 10},
                {"(*SyscallError).Unwrap", Method, 13},
@@ -9060,6 +9250,8 @@ var PackageSymbols = map[string][]Symbol{
                {"O_WRONLY", Const, 0},
                {"Open", Func, 0},
                {"OpenFile", Func, 0},
+               {"OpenInRoot", Func, 24},
+               {"OpenRoot", Func, 24},
                {"PathError", Type, 0},
                {"PathError.Err", Field, 0},
                {"PathError.Op", Field, 0},
@@ -9081,6 +9273,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Remove", Func, 0},
                {"RemoveAll", Func, 0},
                {"Rename", Func, 0},
+               {"Root", Type, 24},
                {"SEEK_CUR", Const, 0},
                {"SEEK_END", Const, 0},
                {"SEEK_SET", Const, 0},
@@ -9422,6 +9615,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Zero", Func, 0},
        },
        "regexp": {
+               {"(*Regexp).AppendText", Method, 24},
                {"(*Regexp).Copy", Method, 6},
                {"(*Regexp).Expand", Method, 0},
                {"(*Regexp).ExpandString", Method, 0},
@@ -9602,6 +9796,8 @@ var PackageSymbols = map[string][]Symbol{
                {"(*StackRecord).Stack", Method, 0},
                {"(*TypeAssertionError).Error", Method, 0},
                {"(*TypeAssertionError).RuntimeError", Method, 0},
+               {"(Cleanup).Stop", Method, 24},
+               {"AddCleanup", Func, 24},
                {"BlockProfile", Func, 1},
                {"BlockProfileRecord", Type, 1},
                {"BlockProfileRecord.Count", Field, 1},
@@ -9612,6 +9808,7 @@ var PackageSymbols = map[string][]Symbol{
                {"Caller", Func, 0},
                {"Callers", Func, 0},
                {"CallersFrames", Func, 7},
+               {"Cleanup", Type, 24},
                {"Compiler", Const, 0},
                {"Error", Type, 0},
                {"Frame", Type, 7},
@@ -9974,6 +10171,8 @@ var PackageSymbols = map[string][]Symbol{
                {"EqualFold", Func, 0},
                {"Fields", Func, 0},
                {"FieldsFunc", Func, 0},
+               {"FieldsFuncSeq", Func, 24},
+               {"FieldsSeq", Func, 24},
                {"HasPrefix", Func, 0},
                {"HasSuffix", Func, 0},
                {"Index", Func, 0},
@@ -9986,6 +10185,7 @@ var PackageSymbols = map[string][]Symbol{
                {"LastIndexAny", Func, 0},
                {"LastIndexByte", Func, 5},
                {"LastIndexFunc", Func, 0},
+               {"Lines", Func, 24},
                {"Map", Func, 0},
                {"NewReader", Func, 0},
                {"NewReplacer", Func, 0},
@@ -9997,7 +10197,9 @@ var PackageSymbols = map[string][]Symbol{
                {"Split", Func, 0},
                {"SplitAfter", Func, 0},
                {"SplitAfterN", Func, 0},
+               {"SplitAfterSeq", Func, 24},
                {"SplitN", Func, 0},
+               {"SplitSeq", Func, 24},
                {"Title", Func, 0},
                {"ToLower", Func, 0},
                {"ToLowerSpecial", Func, 0},
@@ -16413,7 +16615,9 @@ var PackageSymbols = map[string][]Symbol{
                {"ValueOf", Func, 0},
        },
        "testing": {
+               {"(*B).Chdir", Method, 24},
                {"(*B).Cleanup", Method, 14},
+               {"(*B).Context", Method, 24},
                {"(*B).Elapsed", Method, 20},
                {"(*B).Error", Method, 0},
                {"(*B).Errorf", Method, 0},
@@ -16425,6 +16629,7 @@ var PackageSymbols = map[string][]Symbol{
                {"(*B).Helper", Method, 9},
                {"(*B).Log", Method, 0},
                {"(*B).Logf", Method, 0},
+               {"(*B).Loop", Method, 24},
                {"(*B).Name", Method, 8},
                {"(*B).ReportAllocs", Method, 1},
                {"(*B).ReportMetric", Method, 13},
@@ -16442,7 +16647,9 @@ var PackageSymbols = map[string][]Symbol{
                {"(*B).StopTimer", Method, 0},
                {"(*B).TempDir", Method, 15},
                {"(*F).Add", Method, 18},
+               {"(*F).Chdir", Method, 24},
                {"(*F).Cleanup", Method, 18},
+               {"(*F).Context", Method, 24},
                {"(*F).Error", Method, 18},
                {"(*F).Errorf", Method, 18},
                {"(*F).Fail", Method, 18},
@@ -16463,7 +16670,9 @@ var PackageSymbols = map[string][]Symbol{
                {"(*F).TempDir", Method, 18},
                {"(*M).Run", Method, 4},
                {"(*PB).Next", Method, 3},
+               {"(*T).Chdir", Method, 24},
                {"(*T).Cleanup", Method, 14},
+               {"(*T).Context", Method, 24},
                {"(*T).Deadline", Method, 15},
                {"(*T).Error", Method, 0},
                {"(*T).Errorf", Method, 0},
@@ -16954,7 +17163,9 @@ var PackageSymbols = map[string][]Symbol{
                {"(Time).Add", Method, 0},
                {"(Time).AddDate", Method, 0},
                {"(Time).After", Method, 0},
+               {"(Time).AppendBinary", Method, 24},
                {"(Time).AppendFormat", Method, 5},
+               {"(Time).AppendText", Method, 24},
                {"(Time).Before", Method, 0},
                {"(Time).Clock", Method, 0},
                {"(Time).Compare", Method, 20},
@@ -17428,4 +17639,9 @@ var PackageSymbols = map[string][]Symbol{
                {"String", Func, 0},
                {"StringData", Func, 0},
        },
+       "weak": {
+               {"(Pointer).Value", Method, 24},
+               {"Make", Func, 24},
+               {"Pointer", Type, 24},
+       },
 }
index 0b84acc5c7fa43e3d2e9199916194fb9e0d268e1..cdae2b8e818485cefe6177924a2687a856c849ad 100644 (file)
@@ -66,75 +66,3 @@ func IsTypeParam(t types.Type) bool {
        _, ok := types.Unalias(t).(*types.TypeParam)
        return ok
 }
-
-// GenericAssignableTo is a generalization of types.AssignableTo that
-// implements the following rule for uninstantiated generic types:
-//
-// If V and T are generic named types, then V is considered assignable to T if,
-// for every possible instantiation of V[A_1, ..., A_N], the instantiation
-// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N].
-//
-// If T has structural constraints, they must be satisfied by V.
-//
-// For example, consider the following type declarations:
-//
-//     type Interface[T any] interface {
-//             Accept(T)
-//     }
-//
-//     type Container[T any] struct {
-//             Element T
-//     }
-//
-//     func (c Container[T]) Accept(t T) { c.Element = t }
-//
-// In this case, GenericAssignableTo reports that instantiations of Container
-// are assignable to the corresponding instantiation of Interface.
-func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool {
-       V = types.Unalias(V)
-       T = types.Unalias(T)
-
-       // If V and T are not both named, or do not have matching non-empty type
-       // parameter lists, fall back on types.AssignableTo.
-
-       VN, Vnamed := V.(*types.Named)
-       TN, Tnamed := T.(*types.Named)
-       if !Vnamed || !Tnamed {
-               return types.AssignableTo(V, T)
-       }
-
-       vtparams := VN.TypeParams()
-       ttparams := TN.TypeParams()
-       if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 {
-               return types.AssignableTo(V, T)
-       }
-
-       // V and T have the same (non-zero) number of type params. Instantiate both
-       // with the type parameters of V. This must always succeed for V, and will
-       // succeed for T if and only if the type set of each type parameter of V is a
-       // subset of the type set of the corresponding type parameter of T, meaning
-       // that every instantiation of V corresponds to a valid instantiation of T.
-
-       // Minor optimization: ensure we share a context across the two
-       // instantiations below.
-       if ctxt == nil {
-               ctxt = types.NewContext()
-       }
-
-       var targs []types.Type
-       for i := 0; i < vtparams.Len(); i++ {
-               targs = append(targs, vtparams.At(i))
-       }
-
-       vinst, err := types.Instantiate(ctxt, V, targs, true)
-       if err != nil {
-               panic("type parameters should satisfy their own constraints")
-       }
-
-       tinst, err := types.Instantiate(ctxt, T, targs, true)
-       if err != nil {
-               return false
-       }
-
-       return types.AssignableTo(vinst, tinst)
-}
index 6e83c6fb1a2b0860cfc1e4dcf446ff1f7c858dd7..27a2b1792996812ba09b25f19f077b107d06d765 100644 (file)
@@ -109,8 +109,13 @@ func CoreType(T types.Type) types.Type {
 //
 // NormalTerms makes no guarantees about the order of terms, except that it
 // is deterministic.
-func NormalTerms(typ types.Type) ([]*types.Term, error) {
-       switch typ := typ.Underlying().(type) {
+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:
@@ -118,7 +123,7 @@ func NormalTerms(typ types.Type) ([]*types.Term, error) {
        case *types.Interface:
                return InterfaceTermSet(typ)
        default:
-               return []*types.Term{types.NewTerm(false, typ)}, nil
+               return []*types.Term{types.NewTerm(false, T)}, nil
        }
 }
 
index 131caab2847ecf86997e05a3c059f0dea9dd34a2..235a6defc4c73364ad59ba7d4f135e6b4031bdbc 100644 (file)
@@ -966,7 +966,7 @@ const (
        //  var _ = string(x)
        InvalidConversion
 
-       // InvalidUntypedConversion occurs when an there is no valid implicit
+       // 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.
        //
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go
new file mode 100644 (file)
index 0000000..b64f714
--- /dev/null
@@ -0,0 +1,46 @@
+// 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.
+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()
+       }
+}
index ba6f4f4ebd522f42c7f440838f9099479cd5d3db..8352ea761736a400522045722efe79e88ab4b783 100644 (file)
@@ -11,6 +11,9 @@ import (
 // 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 {
index df3ea52125439c929827ed7ffc553d89d22e5eb5..34534879630c33063b40f2829c39e6da29d0ef04 100644 (file)
@@ -82,6 +82,7 @@ func NameRelativeTo(pkg *types.Package) types.Qualifier {
 type NamedOrAlias interface {
        types.Type
        Obj() *types.TypeName
+       // TODO(hxjiang): add method TypeArgs() *types.TypeList after stop supporting go1.22.
 }
 
 // TypeParams is a light shim around t.TypeParams().
@@ -119,3 +120,8 @@ func Origin(t NamedOrAlias) NamedOrAlias {
        }
        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()
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go
new file mode 100644 (file)
index 0000000..e5da049
--- /dev/null
@@ -0,0 +1,40 @@
+// 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
+
+// TODO(adonovan): when CL 645115 lands, define the go1.25 version of
+// this API that actually does something.
+
+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) {}
index 1066980649e09124c34fbc7aaf9e0bf89d5c8675..d272949c17718996d7c09589b45284636181dd86 100644 (file)
@@ -9,62 +9,97 @@ import (
        "go/ast"
        "go/token"
        "go/types"
-       "strconv"
        "strings"
 )
 
-// ZeroString returns the string representation of the "zero" value of the type t.
+// 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.
-// When assigning to a wider type (such as 'any'), it's the caller's
-// responsibility to handle any necessary type conversions.
+//
 // See [ZeroExpr] for a variant that returns an [ast.Expr].
-func ZeroString(t types.Type, qf types.Qualifier) string {
+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"
+                       return "false", true
                case t.Info()&types.IsNumeric != 0:
-                       return "0"
+                       return "0", true
                case t.Info()&types.IsString != 0:
-                       return `""`
+                       return `""`, true
                case t.Kind() == types.UnsafePointer:
                        fallthrough
                case t.Kind() == types.UntypedNil:
-                       return "nil"
+                       return "nil", true
+               case t.Kind() == types.Invalid:
+                       return "invalid", false
                default:
-                       panic(fmt.Sprint("ZeroString for unexpected type:", t))
+                       panic(fmt.Sprintf("ZeroString for unexpected type %v", t))
                }
 
-       case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
-               return "nil"
+       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, *types.Alias:
+       case *types.Named:
                switch under := t.Underlying().(type) {
                case *types.Struct, *types.Array:
-                       return types.TypeString(t, qf) + "{}"
+                       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:
-                       return ZeroString(under, qf)
+                       // 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, qf) + "{}"
+               return types.TypeString(t, qual) + "{}", true
 
        case *types.TypeParam:
                // Assumes func new is not shadowed.
-               return "*new(" + types.TypeString(t, qf) + ")"
+               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++ {
-                       components[i] = ZeroString(t.At(i).Type(), qf)
+                       comp, ok := ZeroString(t.At(i).Type(), qual)
+
+                       components[i] = comp
+                       isValid = isValid && ok
                }
-               return "(" + strings.Join(components, ", ") + ")"
+               return "(" + strings.Join(components, ", ") + ")", isValid
 
        case *types.Union:
                // Variables of these types cannot be created, so it makes
@@ -76,45 +111,72 @@ func ZeroString(t types.Type, qf types.Qualifier) string {
        }
 }
 
-// ZeroExpr returns the ast.Expr representation of the "zero" value of the type t.
-// ZeroExpr is defined for types that are suitable for variables.
-// It may panic for other types such as Tuple or Union.
+// 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(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
-       switch t := typ.(type) {
+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"}
+                       return &ast.Ident{Name: "false"}, true
                case t.Info()&types.IsNumeric != 0:
-                       return &ast.BasicLit{Kind: token.INT, Value: "0"}
+                       return &ast.BasicLit{Kind: token.INT, Value: "0"}, true
                case t.Info()&types.IsString != 0:
-                       return &ast.BasicLit{Kind: token.STRING, Value: `""`}
+                       return &ast.BasicLit{Kind: token.STRING, Value: `""`}, true
                case t.Kind() == types.UnsafePointer:
                        fallthrough
                case t.Kind() == types.UntypedNil:
-                       return ast.NewIdent("nil")
+                       return ast.NewIdent("nil"), true
+               case t.Kind() == types.Invalid:
+                       return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false
                default:
-                       panic(fmt.Sprint("ZeroExpr for unexpected type:", t))
+                       panic(fmt.Sprintf("ZeroExpr for unexpected type %v", t))
                }
 
-       case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
-               return ast.NewIdent("nil")
+       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, *types.Alias:
+       case *types.Named:
                switch under := t.Underlying().(type) {
                case *types.Struct, *types.Array:
                        return &ast.CompositeLit{
-                               Type: TypeExpr(f, pkg, typ),
-                       }
+                               Type: TypeExpr(t, qual),
+                       }, true
                default:
-                       return ZeroExpr(f, pkg, under)
+                       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(f, pkg, typ),
-               }
+                       Type: TypeExpr(t, qual),
+               }, true
 
        case *types.TypeParam:
                return &ast.StarExpr{ // *new(T)
@@ -125,7 +187,7 @@ func ZeroExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                                        ast.NewIdent(t.Obj().Name()),
                                },
                        },
-               }
+               }, true
 
        case *types.Tuple:
                // Unlike ZeroString, there is no ast.Expr can express tuple by
@@ -157,16 +219,14 @@ func IsZeroExpr(expr ast.Expr) bool {
 }
 
 // TypeExpr returns syntax for the specified type. References to named types
-// from packages other than pkg are qualified by an appropriate package name, as
-// defined by the import environment of file.
+// are qualified by an appropriate (optional) qualifier function.
 // It may panic for types such as Tuple or Union.
-func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
-       switch t := typ.(type) {
+func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
+       switch t := t.(type) {
        case *types.Basic:
                switch t.Kind() {
                case types.UnsafePointer:
-                       // TODO(hxjiang): replace the implementation with types.Qualifier.
-                       return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
+                       return &ast.SelectorExpr{X: ast.NewIdent(qual(types.NewPackage("unsafe", "unsafe"))), Sel: ast.NewIdent("Pointer")}
                default:
                        return ast.NewIdent(t.Name())
                }
@@ -174,7 +234,7 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
        case *types.Pointer:
                return &ast.UnaryExpr{
                        Op: token.MUL,
-                       X:  TypeExpr(f, pkg, t.Elem()),
+                       X:  TypeExpr(t.Elem(), qual),
                }
 
        case *types.Array:
@@ -183,18 +243,18 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                                Kind:  token.INT,
                                Value: fmt.Sprintf("%d", t.Len()),
                        },
-                       Elt: TypeExpr(f, pkg, t.Elem()),
+                       Elt: TypeExpr(t.Elem(), qual),
                }
 
        case *types.Slice:
                return &ast.ArrayType{
-                       Elt: TypeExpr(f, pkg, t.Elem()),
+                       Elt: TypeExpr(t.Elem(), qual),
                }
 
        case *types.Map:
                return &ast.MapType{
-                       Key:   TypeExpr(f, pkg, t.Key()),
-                       Value: TypeExpr(f, pkg, t.Elem()),
+                       Key:   TypeExpr(t.Key(), qual),
+                       Value: TypeExpr(t.Elem(), qual),
                }
 
        case *types.Chan:
@@ -204,14 +264,14 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                }
                return &ast.ChanType{
                        Dir:   dir,
-                       Value: TypeExpr(f, pkg, t.Elem()),
+                       Value: TypeExpr(t.Elem(), qual),
                }
 
        case *types.Signature:
                var params []*ast.Field
                for i := 0; i < t.Params().Len(); i++ {
                        params = append(params, &ast.Field{
-                               Type: TypeExpr(f, pkg, t.Params().At(i).Type()),
+                               Type: TypeExpr(t.Params().At(i).Type(), qual),
                                Names: []*ast.Ident{
                                        {
                                                Name: t.Params().At(i).Name(),
@@ -226,7 +286,7 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                var returns []*ast.Field
                for i := 0; i < t.Results().Len(); i++ {
                        returns = append(returns, &ast.Field{
-                               Type: TypeExpr(f, pkg, t.Results().At(i).Type()),
+                               Type: TypeExpr(t.Results().At(i).Type(), qual),
                        })
                }
                return &ast.FuncType{
@@ -238,23 +298,9 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                        },
                }
 
-       case interface{ Obj() *types.TypeName }: // *types.{Alias,Named,TypeParam}
-               switch t.Obj().Pkg() {
-               case pkg, nil:
-                       return ast.NewIdent(t.Obj().Name())
-               }
-               pkgName := t.Obj().Pkg().Name()
-
-               // TODO(hxjiang): replace the implementation with types.Qualifier.
-               // If the file already imports the package under another name, use that.
-               for _, cand := range f.Imports {
-                       if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() {
-                               if cand.Name != nil && cand.Name.Name != "" {
-                                       pkgName = cand.Name.Name
-                               }
-                       }
-               }
-               if pkgName == "." {
+       case *types.TypeParam:
+               pkgName := qual(t.Obj().Pkg())
+               if pkgName == "" || t.Obj().Pkg() == nil {
                        return ast.NewIdent(t.Obj().Name())
                }
                return &ast.SelectorExpr{
@@ -262,6 +308,36 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                        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 i := range typeArgs.Len() {
+                                       indices = append(indices, TypeExpr(typeArgs.At(i), qual))
+                               }
+                               expr = &ast.IndexListExpr{
+                                       X:       expr,
+                                       Indices: indices,
+                               }
+                       }
+               }
+
+               return expr
+
        case *types.Struct:
                return ast.NewIdent(t.String())
 
@@ -269,9 +345,43 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
                return ast.NewIdent(t.String())
 
        case *types.Union:
-               // TODO(hxjiang): handle the union through syntax (~A | ... | ~Z).
-               // Remove nil check when calling typesinternal.TypeExpr.
-               return nil
+               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")
index 118646d75c4ccbe6ea3ac4f2771bb55cfb48daab..703d9364eac99fa9482e506d99e2d2f2ccfd57ac 100644 (file)
@@ -16,7 +16,7 @@ github.com/google/pprof/third_party/svgpan
 # github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd
 ## explicit; go 1.13
 github.com/ianlancetaylor/demangle
-# golang.org/x/arch v0.12.0
+# golang.org/x/arch v0.14.0
 ## explicit; go 1.18
 golang.org/x/arch/arm/armasm
 golang.org/x/arch/arm64/arm64asm
@@ -25,10 +25,10 @@ golang.org/x/arch/ppc64/ppc64asm
 golang.org/x/arch/riscv64/riscv64asm
 golang.org/x/arch/s390x/s390xasm
 golang.org/x/arch/x86/x86asm
-# golang.org/x/build v0.0.0-20241205234318-b850320af2a4
+# golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63
 ## explicit; go 1.22.0
 golang.org/x/build/relnote
-# golang.org/x/mod v0.22.0
+# golang.org/x/mod v0.23.0
 ## explicit; go 1.22.0
 golang.org/x/mod/internal/lazyregexp
 golang.org/x/mod/modfile
@@ -39,16 +39,16 @@ golang.org/x/mod/sumdb/dirhash
 golang.org/x/mod/sumdb/note
 golang.org/x/mod/sumdb/tlog
 golang.org/x/mod/zip
-# golang.org/x/sync v0.10.0
+# golang.org/x/sync v0.11.0
 ## explicit; go 1.18
 golang.org/x/sync/errgroup
 golang.org/x/sync/semaphore
-# golang.org/x/sys v0.28.0
+# golang.org/x/sys v0.30.0
 ## explicit; go 1.18
 golang.org/x/sys/plan9
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3
+# golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a
 ## explicit; go 1.22.0
 golang.org/x/telemetry
 golang.org/x/telemetry/counter
@@ -60,10 +60,10 @@ golang.org/x/telemetry/internal/crashmonitor
 golang.org/x/telemetry/internal/mmap
 golang.org/x/telemetry/internal/telemetry
 golang.org/x/telemetry/internal/upload
-# golang.org/x/term v0.27.0
+# golang.org/x/term v0.29.0
 ## explicit; go 1.18
 golang.org/x/term
-# golang.org/x/text v0.21.0
+# golang.org/x/text v0.22.0
 ## explicit; go 1.18
 golang.org/x/text/cases
 golang.org/x/text/internal
@@ -73,7 +73,7 @@ golang.org/x/text/internal/tag
 golang.org/x/text/language
 golang.org/x/text/transform
 golang.org/x/text/unicode/norm
-# golang.org/x/tools v0.28.1-0.20250131145412-98746475647e
+# golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f
 ## explicit; go 1.22.0
 golang.org/x/tools/cmd/bisect
 golang.org/x/tools/cover
@@ -122,8 +122,10 @@ golang.org/x/tools/go/types/objectpath
 golang.org/x/tools/go/types/typeutil
 golang.org/x/tools/internal/aliases
 golang.org/x/tools/internal/analysisinternal
+golang.org/x/tools/internal/astutil/edge
 golang.org/x/tools/internal/bisect
 golang.org/x/tools/internal/facts
+golang.org/x/tools/internal/fmtstr
 golang.org/x/tools/internal/stdlib
 golang.org/x/tools/internal/typeparams
 golang.org/x/tools/internal/typesinternal
index a2ad0f1298aa797b61439b76b323881484604136..fffe571163889f584bd340a3655bd40aa90ce9d3 100644 (file)
@@ -200,8 +200,8 @@ func PrintfTests() {
        // Bad argument reorderings.
        Printf("%[xd", 3)                      // ERROR "Printf format %\[xd is missing closing \]"
        Printf("%[x]d x", 3)                   // ERROR "Printf format has invalid argument index \[x\]"
-       Printf("%[3]*s x", "hi", 2)            // ERROR "Printf format has invalid argument index \[3\]"
-       _ = fmt.Sprintf("%[3]d x", 2)          // ERROR "Sprintf format has invalid argument index \[3\]"
+       Printf("%[3]*s x", "hi", 2)            // ERROR "Printf format %\[3\]\*s reads arg #3, but call has 2 args"
+       _ = fmt.Sprintf("%[3]d x", 2)          // ERROR "Sprintf format %\[3\]d reads arg #3, but call has 1 arg"
        Printf("%[2]*.[1]*[3]d x", 2, "hi", 4) // ERROR "Printf format %\[2]\*\.\[1\]\*\[3\]d uses non-int \x22hi\x22 as argument of \*"
        Printf("%[0]s x", "arg1")              // ERROR "Printf format has invalid argument index \[0\]"
        Printf("%[0]d x", 1)                   // ERROR "Printf format has invalid argument index \[0\]"
index ccfdbd8ea22d77344a1af775c66c3cd354f9d222..4ccf4ff79eed2f0578ef8c70eeac3cd7bc00b77d 100644 (file)
@@ -1,13 +1,13 @@
 module std
 
-go 1.24
+go 1.25
 
 require (
-       golang.org/x/crypto v0.30.0
-       golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98
+       golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108
+       golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4
 )
 
 require (
-       golang.org/x/sys v0.28.0 // indirect
-       golang.org/x/text v0.21.0 // indirect
+       golang.org/x/sys v0.30.0 // indirect
+       golang.org/x/text v0.22.0 // indirect
 )
index 4d6a33e34a4e6344d6541962dd8befdf3eba3774..50dec70ed6e6f228d706d8d49173c985a9fadac6 100644 (file)
@@ -1,8 +1,8 @@
-golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
-golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 h1:36bTiCRO7f/J3t+LumnLTJDXqxsp1x6Q7754SsRD9u4=
-golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 h1:FwaGHNRX5GDt6vHr+Ly+yRTs0ADe4xTlGOzwaga4ZOs=
+golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 h1:guLo+MhruvDNVBe2ssFzu5BGn4pc0G1xx6TqTHK+MnE=
+golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
index 22f013f1d48407cf3ffc6478f5522dcec4783283..81a8c4bc4dedbfce6aa935b69ec50ce4c78a6d02 100644 (file)
@@ -1085,7 +1085,7 @@ func http2configFromServer(h1 *Server, h2 *http2Server) http2http2Config {
        return conf
 }
 
-// configFromServer merges configuration settings from h2 and h2.t1.HTTP2
+// configFromTransport merges configuration settings from h2 and h2.t1.HTTP2
 // (the net/http Transport).
 func http2configFromTransport(h2 *http2Transport) http2http2Config {
        conf := http2http2Config{
@@ -1151,7 +1151,7 @@ func http2fillNetHTTPServerConfig(conf *http2http2Config, srv *Server) {
        http2fillNetHTTPConfig(conf, srv.HTTP2)
 }
 
-// fillNetHTTPServerConfig sets fields in conf from tr.HTTP2.
+// fillNetHTTPTransportConfig sets fields in conf from tr.HTTP2.
 func http2fillNetHTTPTransportConfig(conf *http2http2Config, tr *Transport) {
        http2fillNetHTTPConfig(conf, tr.HTTP2)
 }
@@ -7797,6 +7797,7 @@ type http2ClientConn struct {
        doNotReuse       bool         // whether conn is marked to not be reused for any future requests
        closing          bool
        closed           bool
+       closedOnIdle     bool                          // true if conn was closed for idleness
        seenSettings     bool                          // true if we've seen a settings frame, false otherwise
        seenSettingsChan chan struct{}                 // closed when seenSettings is true or frame reading fails
        wantSettingsAck  bool                          // we sent a SETTINGS frame and haven't heard back
@@ -8512,10 +8513,12 @@ func (cc *http2ClientConn) idleStateLocked() (st http2clientConnIdleState) {
 
        // If this connection has never been used for a request and is closed,
        // then let it take a request (which will fail).
+       // If the conn was closed for idleness, we're racing the idle timer;
+       // don't try to use the conn. (Issue #70515.)
        //
        // This avoids a situation where an error early in a connection's lifetime
        // goes unreported.
-       if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed {
+       if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle {
                st.canTakeNewRequest = true
        }
 
@@ -8578,6 +8581,7 @@ func (cc *http2ClientConn) closeIfIdle() {
                return
        }
        cc.closed = true
+       cc.closedOnIdle = true
        nextID := cc.nextStreamID
        // TODO: do clients send GOAWAY too? maybe? Just Close:
        cc.mu.Unlock()
@@ -9869,9 +9873,12 @@ func (rl *http2clientConnReadLoop) cleanup() {
        // This avoids a situation where new connections are constantly created,
        // added to the pool, fail, and are removed from the pool, without any error
        // being surfaced to the user.
-       const unusedWaitTime = 5 * time.Second
+       unusedWaitTime := 5 * time.Second
+       if cc.idleTimeout > 0 && unusedWaitTime > cc.idleTimeout {
+               unusedWaitTime = cc.idleTimeout
+       }
        idleTime := cc.t.now().Sub(cc.lastActive)
-       if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime {
+       if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime && !cc.closedOnIdle {
                cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() {
                        cc.t.connPool().MarkDead(cc)
                })
index 02609d5b21d56a5b82ce169a3bd1f933f9d091f3..9c105f23afcdc411cd3b0368f1077943e91bff45 100644 (file)
@@ -72,6 +72,9 @@ var X86 struct {
        HasSSSE3            bool // Supplemental streaming SIMD extension 3
        HasSSE41            bool // Streaming SIMD extension 4 and 4.1
        HasSSE42            bool // Streaming SIMD extension 4 and 4.2
+       HasAVXIFMA          bool // Advanced vector extension Integer Fused Multiply Add
+       HasAVXVNNI          bool // Advanced vector extension Vector Neural Network Instructions
+       HasAVXVNNIInt8      bool // Advanced vector extension Vector Neural Network Int8 instructions
        _                   CacheLinePad
 }
 
index 600a6807861e7fd225b672283e2bc5c984eb13d6..1e642f3304fa87b95c67d47454e2eb62825fccf2 100644 (file)
@@ -53,6 +53,9 @@ func initOptions() {
                {Name: "sse41", Feature: &X86.HasSSE41},
                {Name: "sse42", Feature: &X86.HasSSE42},
                {Name: "ssse3", Feature: &X86.HasSSSE3},
+               {Name: "avxifma", Feature: &X86.HasAVXIFMA},
+               {Name: "avxvnni", Feature: &X86.HasAVXVNNI},
+               {Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8},
 
                // These capabilities should always be enabled on amd64:
                {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"},
@@ -106,7 +109,7 @@ func archInit() {
                return
        }
 
-       _, ebx7, ecx7, edx7 := cpuid(7, 0)
+       eax7, ebx7, ecx7, edx7 := cpuid(7, 0)
        X86.HasBMI1 = isSet(3, ebx7)
        X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
        X86.HasBMI2 = isSet(8, ebx7)
@@ -134,14 +137,24 @@ func archInit() {
                X86.HasAVX512VAES = isSet(9, ecx7)
                X86.HasAVX512VBMI2 = isSet(6, ecx7)
                X86.HasAVX512BITALG = isSet(12, ecx7)
-
-               eax71, _, _, _ := cpuid(7, 1)
-               X86.HasAVX512BF16 = isSet(5, eax71)
        }
 
        X86.HasAMXTile = isSet(24, edx7)
        X86.HasAMXInt8 = isSet(25, edx7)
        X86.HasAMXBF16 = isSet(22, edx7)
+
+       // These features depend on the second level of extended features.
+       if eax7 >= 1 {
+               eax71, _, _, edx71 := cpuid(7, 1)
+               if X86.HasAVX512 {
+                       X86.HasAVX512BF16 = isSet(5, eax71)
+               }
+               if X86.HasAVX {
+                       X86.HasAVXIFMA = isSet(23, eax71)
+                       X86.HasAVXVNNI = isSet(4, eax71)
+                       X86.HasAVXVNNIInt8 = isSet(4, edx71)
+               }
+       }
 }
 
 func isSet(bitpos uint, value uint32) bool {
index 45bf5af236cad63db4e00b10b52707972092fb7d..5ffa43e85ef3eae8f3294248fabeb23d09883e6d 100644 (file)
@@ -1,4 +1,4 @@
-# golang.org/x/crypto v0.30.0
+# golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108
 ## explicit; go 1.20
 golang.org/x/crypto/chacha20
 golang.org/x/crypto/chacha20poly1305
@@ -6,7 +6,7 @@ golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
 golang.org/x/crypto/internal/alias
 golang.org/x/crypto/internal/poly1305
-# golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98
+# golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4
 ## explicit; go 1.18
 golang.org/x/net/dns/dnsmessage
 golang.org/x/net/http/httpguts
@@ -15,10 +15,10 @@ golang.org/x/net/http2/hpack
 golang.org/x/net/idna
 golang.org/x/net/lif
 golang.org/x/net/nettest
-# golang.org/x/sys v0.28.0
+# golang.org/x/sys v0.30.0
 ## explicit; go 1.18
 golang.org/x/sys/cpu
-# golang.org/x/text v0.21.0
+# golang.org/x/text v0.22.0
 ## explicit; go 1.18
 golang.org/x/text/secure/bidirule
 golang.org/x/text/transform