mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd: update to x/tools@7d9453cc
go get golang.org/x/tools@master go mod tidy go mod vendor in both cmd and src, for (enforced) consistency. Also: GOWORK=off go generate -run=bundle std This will enable use of modernize and inline. Change-Id: I6348dd97ec2c41437b3ca899ed91f10815f2fe26 Reviewed-on: https://go-review.googlesource.com/c/go/+/707135 Reviewed-by: Michael Matloob <matloob@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Alan Donovan <adonovan@google.com> Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
45eee553e2
commit
6cbe0920c4
70 changed files with 1600 additions and 1070 deletions
|
|
@ -6,16 +6,16 @@ require (
|
|||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
|
||||
golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58
|
||||
golang.org/x/build v0.0.0-20250806225920-b7c66c047964
|
||||
golang.org/x/mod v0.28.0
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.36.0
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053
|
||||
golang.org/x/sys v0.37.0
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8
|
||||
golang.org/x/term v0.34.0
|
||||
golang.org/x/tools v0.37.1-0.20250924232827-4df13e317ce4
|
||||
golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58 h1:uxPa6+/WsUfzikIAPMqpT
|
|||
golang.org/x/arch v0.20.1-0.20250808194827-46ba08e3ae58/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/build v0.0.0-20250806225920-b7c66c047964 h1:yRs1K51GKq7hsIO+YHJ8LsslrvwFceNPIv0tYjpcBd0=
|
||||
golang.org/x/build v0.0.0-20250806225920-b7c66c047964/go.mod h1:i9Vx7+aOQUpYJRxSO+OpRStVBCVL/9ccI51xblWm5WY=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/tools v0.37.1-0.20250924232827-4df13e317ce4 h1:IcXDtHggZZo+GzNzvVRPyNFLnOc2/Z1gg3ZVIWF2uCU=
|
||||
golang.org/x/tools v0.37.1-0.20250924232827-4df13e317ce4/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5 h1:cz7f45KGWAtyIrz6bm45Gc+lw8beIxBSW3EQh4Bwbg4=
|
||||
golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8=
|
||||
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ=
|
||||
|
|
|
|||
9
src/cmd/vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
9
src/cmd/vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
|
|
@ -41,6 +41,15 @@ func (s *CPUSet) Zero() {
|
|||
clear(s[:])
|
||||
}
|
||||
|
||||
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity]
|
||||
// will silently ignore any invalid CPU bits in [CPUSet] so this is an
|
||||
// efficient way of resetting the CPU affinity of a process.
|
||||
func (s *CPUSet) Fill() {
|
||||
for i := range s {
|
||||
s[i] = ^cpuMask(0)
|
||||
}
|
||||
}
|
||||
|
||||
func cpuBitsIndex(cpu int) int {
|
||||
return cpu / _NCPUBITS
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/sys/unix/fdset.go
generated
vendored
4
src/cmd/vendor/golang.org/x/sys/unix/fdset.go
generated
vendored
|
|
@ -23,7 +23,5 @@ func (fds *FdSet) IsSet(fd int) bool {
|
|||
|
||||
// Zero clears the set fds.
|
||||
func (fds *FdSet) Zero() {
|
||||
for i := range fds.Bits {
|
||||
fds.Bits[i] = 0
|
||||
}
|
||||
clear(fds.Bits[:])
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
4
src/cmd/vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
|
|
@ -111,9 +111,7 @@ func (ifr *Ifreq) SetUint32(v uint32) {
|
|||
// clear zeroes the ifreq's union field to prevent trailing garbage data from
|
||||
// being sent to the kernel if an ifreq is reused.
|
||||
func (ifr *Ifreq) clear() {
|
||||
for i := range ifr.raw.Ifru {
|
||||
ifr.raw.Ifru[i] = 0
|
||||
}
|
||||
clear(ifr.raw.Ifru[:])
|
||||
}
|
||||
|
||||
// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
|
||||
|
|
|
|||
1
src/cmd/vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
1
src/cmd/vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
|
|
@ -49,6 +49,7 @@ esac
|
|||
if [[ "$GOOS" = "linux" ]]; then
|
||||
# Use the Docker-based build system
|
||||
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
|
||||
set -e
|
||||
$cmd docker build --tag generate:$GOOS $GOOS
|
||||
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
|
||||
exit
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
4
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
|
|
@ -801,9 +801,7 @@ func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|||
// one. The kernel expects SID to be in network byte order.
|
||||
binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID)
|
||||
copy(sa.raw[8:14], sa.Remote)
|
||||
for i := 14; i < 14+IFNAMSIZ; i++ {
|
||||
sa.raw[i] = 0
|
||||
}
|
||||
clear(sa.raw[14 : 14+IFNAMSIZ])
|
||||
copy(sa.raw[14:], sa.Dev)
|
||||
return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil
|
||||
}
|
||||
|
|
|
|||
17
src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go
generated
vendored
17
src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go
generated
vendored
|
|
@ -248,6 +248,23 @@ func Statvfs(path string, buf *Statvfs_t) (err error) {
|
|||
return Statvfs1(path, buf, ST_WAIT)
|
||||
}
|
||||
|
||||
func Getvfsstat(buf []Statvfs_t, flags int) (n int, err error) {
|
||||
var (
|
||||
_p0 unsafe.Pointer
|
||||
bufsize uintptr
|
||||
)
|
||||
if len(buf) > 0 {
|
||||
_p0 = unsafe.Pointer(&buf[0])
|
||||
bufsize = unsafe.Sizeof(Statvfs_t{}) * uintptr(len(buf))
|
||||
}
|
||||
r0, _, e1 := Syscall(SYS_GETVFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Exposed directly
|
||||
*/
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
2
src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
|
|
@ -321,6 +321,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
|||
//sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP
|
||||
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
|
||||
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
|
||||
//sys GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) = kernel32.GetNumberOfConsoleInputEvents
|
||||
//sys FlushConsoleInputBuffer(console Handle) (err error) = kernel32.FlushConsoleInputBuffer
|
||||
//sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole
|
||||
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
|
||||
//sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW
|
||||
|
|
|
|||
16
src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
16
src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
|
|
@ -65,6 +65,22 @@ var signals = [...]string{
|
|||
15: "terminated",
|
||||
}
|
||||
|
||||
// File flags for [os.OpenFile]. The O_ prefix is used to indicate
|
||||
// that these flags are specific to the OpenFile function.
|
||||
const (
|
||||
O_FILE_FLAG_OPEN_NO_RECALL = FILE_FLAG_OPEN_NO_RECALL
|
||||
O_FILE_FLAG_OPEN_REPARSE_POINT = FILE_FLAG_OPEN_REPARSE_POINT
|
||||
O_FILE_FLAG_SESSION_AWARE = FILE_FLAG_SESSION_AWARE
|
||||
O_FILE_FLAG_POSIX_SEMANTICS = FILE_FLAG_POSIX_SEMANTICS
|
||||
O_FILE_FLAG_BACKUP_SEMANTICS = FILE_FLAG_BACKUP_SEMANTICS
|
||||
O_FILE_FLAG_DELETE_ON_CLOSE = FILE_FLAG_DELETE_ON_CLOSE
|
||||
O_FILE_FLAG_SEQUENTIAL_SCAN = FILE_FLAG_SEQUENTIAL_SCAN
|
||||
O_FILE_FLAG_RANDOM_ACCESS = FILE_FLAG_RANDOM_ACCESS
|
||||
O_FILE_FLAG_NO_BUFFERING = FILE_FLAG_NO_BUFFERING
|
||||
O_FILE_FLAG_OVERLAPPED = FILE_FLAG_OVERLAPPED
|
||||
O_FILE_FLAG_WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
|
||||
)
|
||||
|
||||
const (
|
||||
FILE_READ_DATA = 0x00000001
|
||||
FILE_READ_ATTRIBUTES = 0x00000080
|
||||
|
|
|
|||
18
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
18
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
|
|
@ -238,6 +238,7 @@ var (
|
|||
procFindResourceW = modkernel32.NewProc("FindResourceW")
|
||||
procFindVolumeClose = modkernel32.NewProc("FindVolumeClose")
|
||||
procFindVolumeMountPointClose = modkernel32.NewProc("FindVolumeMountPointClose")
|
||||
procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer")
|
||||
procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
|
||||
procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
|
||||
procFormatMessageW = modkernel32.NewProc("FormatMessageW")
|
||||
|
|
@ -284,6 +285,7 @@ var (
|
|||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId")
|
||||
procGetNumberOfConsoleInputEvents = modkernel32.NewProc("GetNumberOfConsoleInputEvents")
|
||||
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
|
||||
procGetPriorityClass = modkernel32.NewProc("GetPriorityClass")
|
||||
procGetProcAddress = modkernel32.NewProc("GetProcAddress")
|
||||
|
|
@ -2111,6 +2113,14 @@ func FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func FlushConsoleInputBuffer(console Handle) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procFlushConsoleInputBuffer.Addr(), uintptr(console))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FlushFileBuffers(handle Handle) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procFlushFileBuffers.Addr(), uintptr(handle))
|
||||
if r1 == 0 {
|
||||
|
|
@ -2481,6 +2491,14 @@ func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err erro
|
|||
return
|
||||
}
|
||||
|
||||
func GetNumberOfConsoleInputEvents(console Handle, numevents *uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetNumberOfConsoleInputEvents.Addr(), uintptr(console), uintptr(unsafe.Pointer(numevents)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go
generated
vendored
8
src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go
generated
vendored
|
|
@ -326,11 +326,3 @@ func parseStackPCs(crash string) ([]uintptr, error) {
|
|||
}
|
||||
return pcs, nil
|
||||
}
|
||||
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
} else {
|
||||
return y
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
generated
vendored
26
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
generated
vendored
|
|
@ -17,10 +17,26 @@ import (
|
|||
|
||||
const help = `PROGNAME is a tool for static analysis of Go programs.
|
||||
|
||||
PROGNAME examines Go source code and reports suspicious constructs,
|
||||
such as Printf calls whose arguments do not align with the format
|
||||
string. It uses heuristics that do not guarantee all reports are
|
||||
genuine problems, but it can find errors not caught by the compilers.
|
||||
PROGNAME examines Go source code and reports diagnostics for
|
||||
suspicious constructs or opportunities for improvement.
|
||||
Diagnostics may include suggested fixes.
|
||||
|
||||
An example of a suspicious construct is a Printf call whose arguments
|
||||
do not align with the format string. Analyzers may use heuristics that
|
||||
do not guarantee all reports are genuine problems, but can find
|
||||
mistakes not caught by the compiler.
|
||||
|
||||
An example of an opportunity for improvement is a loop over
|
||||
strings.Split(doc, "\n"), which may be replaced by a loop over the
|
||||
strings.SplitSeq iterator, avoiding an array allocation.
|
||||
Diagnostics in such cases may report non-problems,
|
||||
but should carry fixes that may be safely applied.
|
||||
|
||||
For analyzers of the first kind, use "go vet -vettool=PROGRAM"
|
||||
to run the tool and report diagnostics.
|
||||
|
||||
For analyzers of the second kind, use "go fix -fixtool=PROGRAM"
|
||||
to run the tool and apply the fixes it suggests.
|
||||
`
|
||||
|
||||
// Help implements the help subcommand for a multichecker or unitchecker
|
||||
|
|
@ -29,7 +45,7 @@ genuine problems, but it can find errors not caught by the compilers.
|
|||
func Help(progname string, analyzers []*analysis.Analyzer, args []string) {
|
||||
// No args: show summary of all analyzers.
|
||||
if len(args) == 0 {
|
||||
fmt.Println(strings.Replace(help, "PROGNAME", progname, -1))
|
||||
fmt.Println(strings.ReplaceAll(help, "PROGNAME", progname))
|
||||
fmt.Println("Registered analyzers:")
|
||||
fmt.Println()
|
||||
sort.Slice(analyzers, func(i, j int) bool {
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
generated
vendored
|
|
@ -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"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -23,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "appends",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "appends"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "appends"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/appends",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
generated
vendored
|
|
@ -19,7 +19,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
const Doc = "report mismatches between assembly files and Go declarations"
|
||||
|
|
@ -175,7 +175,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
|
||||
Files:
|
||||
for _, fname := range sfiles {
|
||||
content, tf, err := analysisutil.ReadFile(pass, fname)
|
||||
content, tf, err := analysisinternal.ReadFile(pass, fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ Files:
|
|||
resultStr = "result register"
|
||||
}
|
||||
for _, line := range retLine {
|
||||
pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %s", arch, fnName, resultStr)
|
||||
pass.Reportf(tf.LineStart(line), "[%s] %s: RET without writing to %s", arch, fnName, resultStr)
|
||||
}
|
||||
}
|
||||
retLine = nil
|
||||
|
|
@ -227,7 +227,7 @@ Files:
|
|||
lineno++
|
||||
|
||||
badf := func(format string, args ...any) {
|
||||
pass.Reportf(analysisutil.LineStart(tf, lineno), "[%s] %s: %s", arch, fnName, fmt.Sprintf(format, args...))
|
||||
pass.Reportf(tf.LineStart(lineno), "[%s] %s: %s", arch, fnName, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
if arch == "" {
|
||||
|
|
|
|||
39
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
generated
vendored
39
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
generated
vendored
|
|
@ -17,9 +17,11 @@ 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/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -27,26 +29,26 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "assign",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "assign"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "assign"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
info = pass.TypesInfo
|
||||
)
|
||||
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.AssignStmt)(nil),
|
||||
}
|
||||
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||
stmt := n.(*ast.AssignStmt)
|
||||
for curAssign := range inspect.Root().Preorder((*ast.AssignStmt)(nil)) {
|
||||
stmt := curAssign.Node().(*ast.AssignStmt)
|
||||
if stmt.Tok != token.ASSIGN {
|
||||
return // ignore :=
|
||||
continue // ignore :=
|
||||
}
|
||||
if len(stmt.Lhs) != len(stmt.Rhs) {
|
||||
// If LHS and RHS have different cardinality, they can't be the same.
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
// Delete redundant LHS, RHS pairs, taking care
|
||||
|
|
@ -61,13 +63,13 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
isSelfAssign := false
|
||||
var le string
|
||||
|
||||
if !analysisutil.HasSideEffects(pass.TypesInfo, lhs) &&
|
||||
!analysisutil.HasSideEffects(pass.TypesInfo, rhs) &&
|
||||
!isMapIndex(pass.TypesInfo, lhs) &&
|
||||
if typesinternal.NoEffects(info, lhs) &&
|
||||
typesinternal.NoEffects(info, rhs) &&
|
||||
!isMapIndex(info, lhs) &&
|
||||
reflect.TypeOf(lhs) == reflect.TypeOf(rhs) { // short-circuit the heavy-weight gofmt check
|
||||
|
||||
le = analysisinternal.Format(pass.Fset, lhs)
|
||||
re := analysisinternal.Format(pass.Fset, rhs)
|
||||
le = astutil.Format(pass.Fset, lhs)
|
||||
re := astutil.Format(pass.Fset, rhs)
|
||||
if le == re {
|
||||
isSelfAssign = true
|
||||
}
|
||||
|
|
@ -109,13 +111,14 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
if len(exprs) == 0 {
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
if len(exprs) == len(stmt.Lhs) {
|
||||
// If every part of the statement is a self-assignment,
|
||||
// remove the whole statement.
|
||||
edits = []analysis.TextEdit{{Pos: stmt.Pos(), End: stmt.End()}}
|
||||
tokFile := pass.Fset.File(stmt.Pos())
|
||||
edits = refactor.DeleteStmt(tokFile, curAssign)
|
||||
}
|
||||
|
||||
pass.Report(analysis.Diagnostic{
|
||||
|
|
@ -126,7 +129,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
TextEdits: edits,
|
||||
}},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
11
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
generated
vendored
11
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
generated
vendored
|
|
@ -11,10 +11,11 @@ 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"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -22,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "atomic",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "atomic"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "atomic"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
RunDespiteErrors: true,
|
||||
|
|
@ -30,7 +31,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
if !analysisinternal.Imports(pass.Pkg, "sync/atomic") {
|
||||
if !typesinternal.Imports(pass.Pkg, "sync/atomic") {
|
||||
return nil, nil // doesn't directly import sync/atomic
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
continue
|
||||
}
|
||||
obj := typeutil.Callee(pass.TypesInfo, call)
|
||||
if analysisinternal.IsFunctionNamed(obj, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
|
||||
if typesinternal.IsFunctionNamed(obj, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
|
||||
checkAtomicAddAssignment(pass, n.Lhs[i], call)
|
||||
}
|
||||
}
|
||||
|
|
@ -72,7 +73,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 analysisinternal.Format(pass.Fset, e) }
|
||||
gofmt := func(e ast.Expr) string { return astutil.Format(pass.Fset, e) }
|
||||
|
||||
if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
|
||||
broken = gofmt(left) == gofmt(uarg.X)
|
||||
|
|
|
|||
12
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
generated
vendored
12
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
generated
vendored
|
|
@ -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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
const Doc = "check for common mistakes involving boolean operators"
|
||||
|
|
@ -84,7 +84,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[*
|
|||
i := 0
|
||||
var sets [][]ast.Expr
|
||||
for j := 0; j <= len(exprs); j++ {
|
||||
if j == len(exprs) || analysisutil.HasSideEffects(info, exprs[j]) {
|
||||
if j == len(exprs) || !typesinternal.NoEffects(info, exprs[j]) {
|
||||
if i < j {
|
||||
sets = append(sets, exprs[i:j])
|
||||
}
|
||||
|
|
@ -104,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 := analysisinternal.Format(pass.Fset, e)
|
||||
efmt := astutil.Format(pass.Fset, e)
|
||||
if seen[efmt] {
|
||||
pass.ReportRangef(e, "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
|
||||
} else {
|
||||
|
|
@ -150,8 +150,8 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) {
|
|||
}
|
||||
|
||||
// e is of the form 'x != c' or 'x == c'.
|
||||
xfmt := analysisinternal.Format(pass.Fset, x)
|
||||
efmt := analysisinternal.Format(pass.Fset, e)
|
||||
xfmt := astutil.Format(pass.Fset, x)
|
||||
efmt := astutil.Format(pass.Fset, e)
|
||||
if prev, found := seen[xfmt]; found {
|
||||
// checkRedundant handles the case in which efmt == prev.
|
||||
if efmt != prev {
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
generated
vendored
|
|
@ -14,7 +14,7 @@ import (
|
|||
"unicode"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
const Doc = "check //go:build and // +build directives"
|
||||
|
|
@ -86,7 +86,7 @@ func checkOtherFile(pass *analysis.Pass, filename string) error {
|
|||
|
||||
// We cannot use the Go parser, since this may not be a Go source file.
|
||||
// Read the raw bytes instead.
|
||||
content, tf, err := analysisutil.ReadFile(pass, filename)
|
||||
content, tf, err := analysisinternal.ReadFile(pass, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
generated
vendored
|
|
@ -18,7 +18,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
|
|
@ -41,7 +41,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
if !analysisinternal.Imports(pass.Pkg, "runtime/cgo") {
|
||||
if !typesinternal.Imports(pass.Pkg, "runtime/cgo") {
|
||||
return nil, nil // doesn't use cgo
|
||||
}
|
||||
|
||||
|
|
|
|||
15
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
generated
vendored
15
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
generated
vendored
|
|
@ -16,8 +16,9 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
|
|
@ -86,7 +87,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", analysisinternal.Format(pass.Fset, assign.Lhs[i]), path)
|
||||
pass.ReportRangef(x, "assignment copies lock value to %v: %v", astutil.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 +101,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", analysisinternal.Format(pass.Fset, l), path)
|
||||
pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", astutil.Format(pass.Fset, l), path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +133,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", analysisinternal.Format(pass.Fset, x), path)
|
||||
pass.ReportRangef(x, "literal copies lock value from %v: %v", astutil.Format(pass.Fset, x), path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +167,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", analysisinternal.Format(pass.Fset, ce.Fun), path)
|
||||
pass.ReportRangef(x, "call of %s copies lock value: %v", astutil.Format(pass.Fset, ce.Fun), path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -233,7 +234,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", analysisinternal.Format(pass.Fset, e), path)
|
||||
pass.Reportf(e.Pos(), "range var %s copies lock: %v", astutil.Format(pass.Fset, e), path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +354,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 analysisinternal.IsTypeNamed(typ, "sync", "noCopy") {
|
||||
if typesinternal.IsTypeNamed(typ, "sync", "noCopy") {
|
||||
return []string{typ.String()}
|
||||
}
|
||||
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
generated
vendored
|
|
@ -10,10 +10,10 @@ 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"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -23,20 +23,20 @@ var doc string
|
|||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "defers",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "defers"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "defers"),
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
if !analysisinternal.Imports(pass.Pkg, "time") {
|
||||
if !typesinternal.Imports(pass.Pkg, "time") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
checkDeferCall := func(node ast.Node) bool {
|
||||
switch v := node.(type) {
|
||||
case *ast.CallExpr:
|
||||
if analysisinternal.IsFunctionNamed(typeutil.Callee(pass.TypesInfo, v), "time", "Since") {
|
||||
if typesinternal.IsFunctionNamed(typeutil.Callee(pass.TypesInfo, v), "time", "Since") {
|
||||
pass.Reportf(v.Pos(), "call to time.Since is not deferred")
|
||||
}
|
||||
case *ast.FuncLit:
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/directive/directive.go
generated
vendored
|
|
@ -14,7 +14,7 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
const Doc = `check Go toolchain directives such as //go:debug
|
||||
|
|
@ -86,7 +86,7 @@ func checkGoFile(pass *analysis.Pass, f *ast.File) {
|
|||
func checkOtherFile(pass *analysis.Pass, filename string) error {
|
||||
// We cannot use the Go parser, since is not a Go source file.
|
||||
// Read the raw bytes instead.
|
||||
content, tf, err := analysisutil.ReadFile(pass, filename)
|
||||
content, tf, err := analysisinternal.ReadFile(pass, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
63
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
63
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
|
|
@ -12,22 +12,20 @@ import (
|
|||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
)
|
||||
|
||||
const Doc = `report passing non-pointer or non-error values to errors.As
|
||||
|
||||
The errorsas analysis reports calls to errors.As where the type
|
||||
The errorsas analyzer reports calls to errors.As where the type
|
||||
of the second argument is not a pointer to a type implementing error.`
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "errorsas",
|
||||
Doc: Doc,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Requires: []*analysis.Analyzer{typeindexanalyzer.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
|
|
@ -39,38 +37,31 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
if !analysisinternal.Imports(pass.Pkg, "errors") {
|
||||
return nil, nil // doesn't directly import errors
|
||||
}
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
)
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.CallExpr)(nil),
|
||||
}
|
||||
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||
call := n.(*ast.CallExpr)
|
||||
obj := typeutil.Callee(pass.TypesInfo, call)
|
||||
if !analysisinternal.IsFunctionNamed(obj, "errors", "As") {
|
||||
return
|
||||
}
|
||||
for curCall := range index.Calls(index.Object("errors", "As")) {
|
||||
call := curCall.Node().(*ast.CallExpr)
|
||||
if len(call.Args) < 2 {
|
||||
return // not enough arguments, e.g. called with return values of another function
|
||||
continue // spread call: errors.As(pair())
|
||||
}
|
||||
if err := checkAsTarget(pass, call.Args[1]); err != nil {
|
||||
|
||||
// Check for incorrect arguments.
|
||||
if err := checkAsTarget(info, call.Args[1]); err != nil {
|
||||
pass.ReportRangef(call, "%v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var errorType = types.Universe.Lookup("error").Type()
|
||||
|
||||
// checkAsTarget reports an error if the second argument to errors.As is invalid.
|
||||
func checkAsTarget(pass *analysis.Pass, e ast.Expr) error {
|
||||
t := pass.TypesInfo.Types[e].Type
|
||||
if it, ok := t.Underlying().(*types.Interface); ok && it.NumMethods() == 0 {
|
||||
// A target of interface{} is always allowed, since it often indicates
|
||||
func checkAsTarget(info *types.Info, e ast.Expr) error {
|
||||
t := info.Types[e].Type
|
||||
if types.Identical(t.Underlying(), anyType) {
|
||||
// A target of any is always allowed, since it often indicates
|
||||
// a value forwarded from another source.
|
||||
return nil
|
||||
}
|
||||
|
|
@ -78,12 +69,16 @@ func checkAsTarget(pass *analysis.Pass, e ast.Expr) error {
|
|||
if !ok {
|
||||
return errors.New("second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type")
|
||||
}
|
||||
if pt.Elem() == errorType {
|
||||
if types.Identical(pt.Elem(), errorType) {
|
||||
return errors.New("second argument to errors.As should not be *error")
|
||||
}
|
||||
_, ok = pt.Elem().Underlying().(*types.Interface)
|
||||
if ok || types.Implements(pt.Elem(), errorType.Underlying().(*types.Interface)) {
|
||||
return nil
|
||||
}
|
||||
if !types.IsInterface(pt.Elem()) && !types.AssignableTo(pt.Elem(), errorType) {
|
||||
return errors.New("second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
anyType = types.Universe.Lookup("any").Type()
|
||||
errorType = types.Universe.Lookup("error").Type()
|
||||
)
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
"unicode"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
const Doc = "report assembly that clobbers the frame pointer before saving it"
|
||||
|
|
@ -98,7 +98,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
for _, fname := range sfiles {
|
||||
content, tf, err := analysisutil.ReadFile(pass, fname)
|
||||
content, tf, err := analysisinternal.ReadFile(pass, fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
if arch.isFPWrite(line) {
|
||||
pass.Reportf(analysisutil.LineStart(tf, lineno), "frame pointer is clobbered before saving")
|
||||
pass.Reportf(tf.LineStart(lineno), "frame pointer is clobbered before saving")
|
||||
active = false
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
9
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
generated
vendored
9
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
generated
vendored
|
|
@ -13,7 +13,6 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -46,7 +45,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
|
||||
// Fast path: if the package doesn't import net/http,
|
||||
// skip the traversal.
|
||||
if !analysisinternal.Imports(pass.Pkg, "net/http") {
|
||||
if !typesinternal.Imports(pass.Pkg, "net/http") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +117,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 || !analysisinternal.IsTypeNamed(named, "net/http", "Response") {
|
||||
if !isPtr || named == nil || !typesinternal.IsTypeNamed(named, "net/http", "Response") {
|
||||
return false // the first return type is not *http.Response.
|
||||
}
|
||||
|
||||
|
|
@ -133,11 +132,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
|
|||
return ok && id.Name == "http" // function in net/http package.
|
||||
}
|
||||
|
||||
if analysisinternal.IsTypeNamed(typ, "net/http", "Client") {
|
||||
if typesinternal.IsTypeNamed(typ, "net/http", "Client") {
|
||||
return true // method on http.Client.
|
||||
}
|
||||
ptr, ok := types.Unalias(typ).(*types.Pointer)
|
||||
return ok && analysisinternal.IsTypeNamed(ptr.Elem(), "net/http", "Client") // method on *http.Client.
|
||||
return ok && typesinternal.IsTypeNamed(ptr.Elem(), "net/http", "Client") // method on *http.Client.
|
||||
}
|
||||
|
||||
// restOfBlock, given a traversal stack, finds the innermost containing
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go
generated
vendored
|
|
@ -11,8 +11,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"
|
||||
)
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "ifaceassert",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "ifaceassert"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "ifaceassert"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
99
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
generated
vendored
99
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
generated
vendored
|
|
@ -1,99 +0,0 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package analysisutil defines various helper functions
|
||||
// used by two or more packages beneath go/analysis.
|
||||
package analysisutil
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
)
|
||||
|
||||
// HasSideEffects reports whether evaluation of e has side effects.
|
||||
func HasSideEffects(info *types.Info, e ast.Expr) bool {
|
||||
safe := true
|
||||
ast.Inspect(e, func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.CallExpr:
|
||||
typVal := info.Types[n.Fun]
|
||||
switch {
|
||||
case typVal.IsType():
|
||||
// Type conversion, which is safe.
|
||||
case typVal.IsBuiltin():
|
||||
// Builtin func, conservatively assumed to not
|
||||
// be safe for now.
|
||||
safe = false
|
||||
return false
|
||||
default:
|
||||
// A non-builtin func or method call.
|
||||
// Conservatively assume that all of them have
|
||||
// side effects for now.
|
||||
safe = false
|
||||
return false
|
||||
}
|
||||
case *ast.UnaryExpr:
|
||||
if n.Op == token.ARROW {
|
||||
safe = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return !safe
|
||||
}
|
||||
|
||||
// ReadFile reads a file and adds it to the FileSet
|
||||
// so that we can report errors against it using lineStart.
|
||||
func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
|
||||
readFile := pass.ReadFile
|
||||
if readFile == nil {
|
||||
readFile = os.ReadFile
|
||||
}
|
||||
content, err := readFile(filename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
tf := pass.Fset.AddFile(filename, -1, len(content))
|
||||
tf.SetLinesForContent(content)
|
||||
return content, tf, nil
|
||||
}
|
||||
|
||||
// LineStart returns the position of the start of the specified line
|
||||
// within file f, or NoPos if there is no line of that number.
|
||||
func LineStart(f *token.File, line int) token.Pos {
|
||||
// Use binary search to find the start offset of this line.
|
||||
//
|
||||
// TODO(adonovan): eventually replace this function with the
|
||||
// simpler and more efficient (*go/token.File).LineStart, added
|
||||
// in go1.12.
|
||||
|
||||
min := 0 // inclusive
|
||||
max := f.Size() // exclusive
|
||||
for {
|
||||
offset := (min + max) / 2
|
||||
pos := f.Pos(offset)
|
||||
posn := f.Position(pos)
|
||||
if posn.Line == line {
|
||||
return pos - (token.Pos(posn.Column) - 1)
|
||||
}
|
||||
|
||||
if min+1 >= max {
|
||||
return token.NoPos
|
||||
}
|
||||
|
||||
if posn.Line < line {
|
||||
min = offset
|
||||
} else {
|
||||
max = offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var MustExtractDoc = analysisinternal.MustExtractDoc
|
||||
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
|
|
@ -11,7 +11,6 @@ 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"
|
||||
|
|
@ -24,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "loopclosure",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "loopclosure"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "loopclosure"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -369,5 +368,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 analysisinternal.IsTypeNamed(named, pkgPath, typeName)
|
||||
return typesinternal.IsTypeNamed(named, pkgPath, typeName)
|
||||
}
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
generated
vendored
|
|
@ -13,11 +13,11 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/ctrlflow"
|
||||
"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/cfg"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -25,7 +25,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "lostcancel",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "lostcancel"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "lostcancel"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
|
||||
Run: run,
|
||||
Requires: []*analysis.Analyzer{
|
||||
|
|
@ -50,7 +50,7 @@ var contextPackage = "context"
|
|||
// checkLostCancel analyzes a single named or literal function.
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
// Fast path: bypass check if file doesn't use context.WithCancel.
|
||||
if !analysisinternal.Imports(pass.Pkg, contextPackage) {
|
||||
if !typesinternal.Imports(pass.Pkg, contextPackage) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
generated
vendored
|
|
@ -14,8 +14,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"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "nilfunc",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "nilfunc"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "nilfunc"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go
generated
vendored
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go
generated
vendored
|
|
@ -82,6 +82,16 @@
|
|||
// ...
|
||||
// }
|
||||
//
|
||||
// A local function may also be inferred as a printf wrapper. If it
|
||||
// is assigned to a variable, each call made through that variable will
|
||||
// be checked just like a call to a function:
|
||||
//
|
||||
// logf := func(format string, args ...any) {
|
||||
// message := fmt.Sprintf(format, args...)
|
||||
// log.Printf("%s: %s", prefix, message)
|
||||
// }
|
||||
// logf("%s", 123) // logf format %s has arg 123 of wrong type int
|
||||
//
|
||||
// # Specifying printf wrappers by flag
|
||||
//
|
||||
// The -funcs flag specifies a comma-separated list of names of
|
||||
|
|
|
|||
379
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
379
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
|
|
@ -18,13 +18,14 @@ 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/edge"
|
||||
"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/astutil"
|
||||
"golang.org/x/tools/internal/fmtstr"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
|
|
@ -37,11 +38,11 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "printf",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "printf"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "printf"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
ResultType: reflect.TypeOf((*Result)(nil)),
|
||||
ResultType: reflect.TypeFor[*Result](),
|
||||
FactTypes: []analysis.Fact{new(isWrapper)},
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ func (kind Kind) String() string {
|
|||
// Result is the printf analyzer's result type. Clients may query the result
|
||||
// to learn whether a function behaves like fmt.Print or fmt.Printf.
|
||||
type Result struct {
|
||||
funcs map[*types.Func]Kind
|
||||
funcs map[types.Object]Kind
|
||||
}
|
||||
|
||||
// Kind reports whether fn behaves like fmt.Print or fmt.Printf.
|
||||
|
|
@ -111,149 +112,210 @@ func (f *isWrapper) String() string {
|
|||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
res := &Result{
|
||||
funcs: make(map[*types.Func]Kind),
|
||||
funcs: make(map[types.Object]Kind),
|
||||
}
|
||||
findPrintfLike(pass, res)
|
||||
checkCalls(pass)
|
||||
findPrintLike(pass, res)
|
||||
checkCalls(pass, res)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type printfWrapper struct {
|
||||
obj *types.Func
|
||||
fdecl *ast.FuncDecl
|
||||
format *types.Var
|
||||
args *types.Var
|
||||
// A wrapper is a candidate print/printf wrapper function.
|
||||
//
|
||||
// We represent functions generally as types.Object, not *Func, so
|
||||
// that we can analyze anonymous functions such as
|
||||
//
|
||||
// printf := func(format string, args ...any) {...},
|
||||
//
|
||||
// representing them by the *types.Var symbol for the local variable
|
||||
// 'printf'.
|
||||
type wrapper struct {
|
||||
obj types.Object // *Func or *Var
|
||||
curBody inspector.Cursor // for *ast.BlockStmt
|
||||
format *types.Var // optional "format string" parameter in the Func{Decl,Lit}
|
||||
args *types.Var // "args ...any" parameter in the Func{Decl,Lit}
|
||||
callers []printfCaller
|
||||
failed bool // if true, not a printf wrapper
|
||||
}
|
||||
|
||||
type printfCaller struct {
|
||||
w *printfWrapper
|
||||
w *wrapper
|
||||
call *ast.CallExpr
|
||||
}
|
||||
|
||||
// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper
|
||||
// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper
|
||||
// function describing the declaration. Later processing will analyze the
|
||||
// graph of potential printf wrappers to pick out the ones that are true wrappers.
|
||||
// A function may be a Printf or Print wrapper if its last argument is ...interface{}.
|
||||
// If the next-to-last argument is a string, then this may be a Printf wrapper.
|
||||
// Otherwise it may be a Print wrapper.
|
||||
func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper {
|
||||
// Look for functions with final argument type ...interface{}.
|
||||
fdecl, ok := decl.(*ast.FuncDecl)
|
||||
if !ok || fdecl.Body == nil {
|
||||
return nil
|
||||
}
|
||||
fn, ok := info.Defs[fdecl.Name].(*types.Func)
|
||||
// Type information may be incomplete.
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
sig := fn.Type().(*types.Signature)
|
||||
// formatArgsParams returns the "format string" and "args ...any"
|
||||
// parameters of a potential print or printf wrapper function.
|
||||
// (The format is nil in the print-like case.)
|
||||
func formatArgsParams(sig *types.Signature) (format, args *types.Var) {
|
||||
if !sig.Variadic() {
|
||||
return nil // not variadic
|
||||
return nil, nil // not variadic
|
||||
}
|
||||
|
||||
params := sig.Params()
|
||||
nparams := params.Len() // variadic => nonzero
|
||||
|
||||
// Check final parameter is "args ...interface{}".
|
||||
args := params.At(nparams - 1)
|
||||
iface, ok := types.Unalias(args.Type().(*types.Slice).Elem()).(*types.Interface)
|
||||
if !ok || !iface.Empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Is second last param 'format string'?
|
||||
var format *types.Var
|
||||
if nparams >= 2 {
|
||||
if p := params.At(nparams - 2); p.Type() == types.Typ[types.String] {
|
||||
format = p
|
||||
}
|
||||
}
|
||||
|
||||
return &printfWrapper{
|
||||
obj: fn,
|
||||
fdecl: fdecl,
|
||||
format: format,
|
||||
args: args,
|
||||
// Check final parameter is "args ...any".
|
||||
// (variadic => slice)
|
||||
args = params.At(nparams - 1)
|
||||
iface, ok := types.Unalias(args.Type().(*types.Slice).Elem()).(*types.Interface)
|
||||
if !ok || !iface.Empty() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return format, args
|
||||
}
|
||||
|
||||
// findPrintfLike scans the entire package to find printf-like functions.
|
||||
func findPrintfLike(pass *analysis.Pass, res *Result) (any, error) {
|
||||
// Gather potential wrappers and call graph between them.
|
||||
byObj := make(map[*types.Func]*printfWrapper)
|
||||
var wrappers []*printfWrapper
|
||||
for _, file := range pass.Files {
|
||||
for _, decl := range file.Decls {
|
||||
w := maybePrintfWrapper(pass.TypesInfo, decl)
|
||||
if w == nil {
|
||||
continue
|
||||
// findPrintLike scans the entire package to find print or printf-like functions.
|
||||
// When it returns, all such functions have been identified.
|
||||
func findPrintLike(pass *analysis.Pass, res *Result) {
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
info = pass.TypesInfo
|
||||
)
|
||||
|
||||
// Pass 1: gather candidate wrapper functions (and populate wrappers).
|
||||
var (
|
||||
wrappers []*wrapper
|
||||
byObj = make(map[types.Object]*wrapper)
|
||||
)
|
||||
for cur := range inspect.Root().Preorder((*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) {
|
||||
var (
|
||||
curBody inspector.Cursor // for *ast.BlockStmt
|
||||
sig *types.Signature
|
||||
obj types.Object
|
||||
)
|
||||
switch f := cur.Node().(type) {
|
||||
case *ast.FuncDecl:
|
||||
// named function or method:
|
||||
//
|
||||
// func wrapf(format string, args ...any) {...}
|
||||
if f.Body != nil {
|
||||
curBody = cur.ChildAt(edge.FuncDecl_Body, -1)
|
||||
obj = info.Defs[f.Name]
|
||||
sig = obj.Type().(*types.Signature)
|
||||
}
|
||||
|
||||
case *ast.FuncLit:
|
||||
// anonymous function directly assigned to a variable:
|
||||
//
|
||||
// var wrapf = func(format string, args ...any) {...}
|
||||
// wrapf := func(format string, args ...any) {...}
|
||||
// wrapf = func(format string, args ...any) {...}
|
||||
//
|
||||
// The LHS may also be a struct field x.wrapf or
|
||||
// an imported var pkg.Wrapf.
|
||||
//
|
||||
sig = info.TypeOf(f).(*types.Signature)
|
||||
curBody = cur.ChildAt(edge.FuncLit_Body, -1)
|
||||
var lhs ast.Expr
|
||||
switch ek, idx := cur.ParentEdge(); ek {
|
||||
case edge.ValueSpec_Values:
|
||||
curName := cur.Parent().ChildAt(edge.ValueSpec_Names, idx)
|
||||
lhs = curName.Node().(*ast.Ident)
|
||||
case edge.AssignStmt_Rhs:
|
||||
curLhs := cur.Parent().ChildAt(edge.AssignStmt_Lhs, idx)
|
||||
lhs = curLhs.Node().(ast.Expr)
|
||||
}
|
||||
|
||||
switch lhs := lhs.(type) {
|
||||
case *ast.Ident:
|
||||
// variable: wrapf = func(...)
|
||||
obj = info.ObjectOf(lhs).(*types.Var)
|
||||
case *ast.SelectorExpr:
|
||||
if sel, ok := info.Selections[lhs]; ok {
|
||||
// struct field: x.wrapf = func(...)
|
||||
obj = sel.Obj().(*types.Var)
|
||||
} else {
|
||||
// imported var: pkg.Wrapf = func(...)
|
||||
obj = info.Uses[lhs.Sel].(*types.Var)
|
||||
}
|
||||
}
|
||||
}
|
||||
if obj != nil {
|
||||
format, args := formatArgsParams(sig)
|
||||
if args != nil {
|
||||
// obj (the symbol for a function/method, or variable
|
||||
// assigned to an anonymous function) is a potential
|
||||
// print or printf wrapper.
|
||||
//
|
||||
// Later processing will analyze the graph of potential
|
||||
// wrappers and their function bodies to pick out the
|
||||
// ones that are true wrappers.
|
||||
w := &wrapper{
|
||||
obj: obj,
|
||||
curBody: curBody,
|
||||
format: format, // non-nil => printf
|
||||
args: args,
|
||||
}
|
||||
byObj[w.obj] = w
|
||||
wrappers = append(wrappers, w)
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the graph to figure out which are really printf wrappers.
|
||||
for _, w := range wrappers {
|
||||
// Scan function for calls that could be to other printf-like functions.
|
||||
ast.Inspect(w.fdecl.Body, func(n ast.Node) bool {
|
||||
if w.failed {
|
||||
return false
|
||||
}
|
||||
|
||||
// Pass 2: scan the body of each wrapper function
|
||||
// for calls to other printf-like functions.
|
||||
//
|
||||
// Also, reject tricky cases where the parameters
|
||||
// are potentially mutated by AssignStmt or UnaryExpr.
|
||||
// TODO: Relax these checks; issue 26555.
|
||||
if assign, ok := n.(*ast.AssignStmt); ok {
|
||||
for _, lhs := range assign.Lhs {
|
||||
if match(pass.TypesInfo, lhs, w.format) ||
|
||||
match(pass.TypesInfo, lhs, w.args) {
|
||||
// Modifies the format
|
||||
// string or args in
|
||||
// some way, so not a
|
||||
// simple wrapper.
|
||||
w.failed = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND {
|
||||
if match(pass.TypesInfo, un.X, w.format) ||
|
||||
match(pass.TypesInfo, un.X, w.args) {
|
||||
// Taking the address of the
|
||||
// format string or args,
|
||||
// so not a simple wrapper.
|
||||
w.failed = true
|
||||
return false
|
||||
for _, w := range wrappers {
|
||||
scan:
|
||||
for cur := range w.curBody.Preorder(
|
||||
(*ast.AssignStmt)(nil),
|
||||
(*ast.UnaryExpr)(nil),
|
||||
(*ast.CallExpr)(nil),
|
||||
) {
|
||||
switch n := cur.Node().(type) {
|
||||
case *ast.AssignStmt:
|
||||
// If the wrapper updates format or args
|
||||
// it is not a simple wrapper.
|
||||
for _, lhs := range n.Lhs {
|
||||
if w.format != nil && match(info, lhs, w.format) ||
|
||||
match(info, lhs, w.args) {
|
||||
break scan
|
||||
}
|
||||
}
|
||||
|
||||
call, ok := n.(*ast.CallExpr)
|
||||
if !ok || len(call.Args) == 0 || !match(pass.TypesInfo, call.Args[len(call.Args)-1], w.args) {
|
||||
return true
|
||||
case *ast.UnaryExpr:
|
||||
// If the wrapper computes &format or &args,
|
||||
// it is not a simple wrapper.
|
||||
if n.Op == token.AND &&
|
||||
(w.format != nil && match(info, n.X, w.format) ||
|
||||
match(info, n.X, w.args)) {
|
||||
break scan
|
||||
}
|
||||
|
||||
fn, kind := printfNameAndKind(pass, call)
|
||||
if kind != 0 {
|
||||
checkPrintfFwd(pass, w, call, kind, res)
|
||||
return true
|
||||
case *ast.CallExpr:
|
||||
if len(n.Args) > 0 && match(info, n.Args[len(n.Args)-1], w.args) {
|
||||
if callee := typeutil.Callee(pass.TypesInfo, n); callee != nil {
|
||||
|
||||
// Call from one wrapper candidate to another?
|
||||
// Record the edge so that if callee is found to be
|
||||
// a true wrapper, w will be too.
|
||||
if w2, ok := byObj[callee]; ok {
|
||||
w2.callers = append(w2.callers, printfCaller{w, n})
|
||||
}
|
||||
|
||||
// If the call is to another function in this package,
|
||||
// maybe we will find out it is printf-like later.
|
||||
// Remember this call for later checking.
|
||||
if fn != nil && fn.Pkg() == pass.Pkg && byObj[fn] != nil {
|
||||
callee := byObj[fn]
|
||||
callee.callers = append(callee.callers, printfCaller{w, call})
|
||||
// Is the candidate a true wrapper, because it calls
|
||||
// a known print{,f}-like function from the allowlist
|
||||
// or an imported fact, or another wrapper found
|
||||
// to be a true wrapper?
|
||||
// If so, convert all w's callers to kind.
|
||||
kind := callKind(pass, callee, res)
|
||||
if kind != KindNone {
|
||||
checkForward(pass, w, n, kind, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func match(info *types.Info, arg ast.Expr, param *types.Var) bool {
|
||||
|
|
@ -261,9 +323,9 @@ func match(info *types.Info, arg ast.Expr, param *types.Var) bool {
|
|||
return ok && info.ObjectOf(id) == param
|
||||
}
|
||||
|
||||
// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
|
||||
// checkForward checks that a forwarding wrapper is forwarding correctly.
|
||||
// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
|
||||
func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind Kind, res *Result) {
|
||||
func checkForward(pass *analysis.Pass, w *wrapper, call *ast.CallExpr, kind Kind, res *Result) {
|
||||
matched := kind == KindPrint ||
|
||||
kind != KindNone && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format)
|
||||
if !matched {
|
||||
|
|
@ -292,18 +354,39 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k
|
|||
pass.ReportRangef(call, "missing ... in args forwarded to %s-like function", desc)
|
||||
return
|
||||
}
|
||||
fn := w.obj
|
||||
var fact isWrapper
|
||||
if !pass.ImportObjectFact(fn, &fact) {
|
||||
fact.Kind = kind
|
||||
pass.ExportObjectFact(fn, &fact)
|
||||
res.funcs[fn] = kind
|
||||
|
||||
// If the candidate's print{,f} status becomes known,
|
||||
// propagate it back to all its so-far known callers.
|
||||
if res.funcs[w.obj] != kind {
|
||||
res.funcs[w.obj] = kind
|
||||
|
||||
// Export a fact.
|
||||
// (This is a no-op for local symbols.)
|
||||
// We can't export facts on a symbol of another package,
|
||||
// but we can treat the symbol as a wrapper within
|
||||
// the current analysis unit.
|
||||
if w.obj.Pkg() == pass.Pkg {
|
||||
// Facts are associated with origins.
|
||||
pass.ExportObjectFact(origin(w.obj), &isWrapper{Kind: kind})
|
||||
}
|
||||
|
||||
// Propagate kind back to known callers.
|
||||
for _, caller := range w.callers {
|
||||
checkPrintfFwd(pass, caller.w, caller.call, kind, res)
|
||||
checkForward(pass, caller.w, caller.call, kind, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func origin(obj types.Object) types.Object {
|
||||
switch obj := obj.(type) {
|
||||
case *types.Func:
|
||||
return obj.Origin()
|
||||
case *types.Var:
|
||||
return obj.Origin()
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// isPrint records the print functions.
|
||||
// If a key ends in 'f' then it is assumed to be a formatted print.
|
||||
//
|
||||
|
|
@ -412,7 +495,7 @@ func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) {
|
|||
|
||||
// checkCalls triggers the print-specific checks for calls that invoke a print
|
||||
// function.
|
||||
func checkCalls(pass *analysis.Pass) {
|
||||
func checkCalls(pass *analysis.Pass, res *Result) {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.File)(nil),
|
||||
|
|
@ -426,48 +509,60 @@ func checkCalls(pass *analysis.Pass) {
|
|||
fileVersion = versions.Lang(versions.FileVersion(pass.TypesInfo, n))
|
||||
|
||||
case *ast.CallExpr:
|
||||
fn, kind := printfNameAndKind(pass, n)
|
||||
if callee := typeutil.Callee(pass.TypesInfo, n); callee != nil {
|
||||
kind := callKind(pass, callee, res)
|
||||
switch kind {
|
||||
case KindPrintf, KindErrorf:
|
||||
checkPrintf(pass, fileVersion, kind, n, fn.FullName())
|
||||
checkPrintf(pass, fileVersion, kind, n, fullname(callee))
|
||||
case KindPrint:
|
||||
checkPrint(pass, n, fn.FullName())
|
||||
checkPrint(pass, n, fullname(callee))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) {
|
||||
fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func)
|
||||
if fn == nil {
|
||||
return nil, 0
|
||||
func fullname(obj types.Object) string {
|
||||
if fn, ok := obj.(*types.Func); ok {
|
||||
return fn.FullName()
|
||||
}
|
||||
return obj.Name()
|
||||
}
|
||||
|
||||
// Facts are associated with generic declarations, not instantiations.
|
||||
fn = fn.Origin()
|
||||
|
||||
_, ok := isPrint[fn.FullName()]
|
||||
// callKind returns the symbol of the called function
|
||||
// and its print/printf kind, if any.
|
||||
// (The symbol may be a var for an anonymous function.)
|
||||
// The result is memoized in res.funcs.
|
||||
func callKind(pass *analysis.Pass, obj types.Object, res *Result) Kind {
|
||||
kind, ok := res.funcs[obj]
|
||||
if !ok {
|
||||
// cache miss
|
||||
_, ok := isPrint[fullname(obj)]
|
||||
if !ok {
|
||||
// Next look up just "printf", for use with -printf.funcs.
|
||||
_, ok = isPrint[strings.ToLower(fn.Name())]
|
||||
_, ok = isPrint[strings.ToLower(obj.Name())]
|
||||
}
|
||||
if ok {
|
||||
if fn.FullName() == "fmt.Errorf" {
|
||||
// well-known printf functions
|
||||
if fullname(obj) == "fmt.Errorf" {
|
||||
kind = KindErrorf
|
||||
} else if strings.HasSuffix(fn.Name(), "f") {
|
||||
} else if strings.HasSuffix(obj.Name(), "f") {
|
||||
kind = KindPrintf
|
||||
} else {
|
||||
kind = KindPrint
|
||||
}
|
||||
return fn, kind
|
||||
}
|
||||
|
||||
} else {
|
||||
// imported wrappers
|
||||
// Facts are associated with generic declarations, not instantiations.
|
||||
obj = origin(obj)
|
||||
var fact isWrapper
|
||||
if pass.ImportObjectFact(fn, &fact) {
|
||||
return fn, fact.Kind
|
||||
if pass.ImportObjectFact(obj, &fact) {
|
||||
kind = fact.Kind
|
||||
}
|
||||
|
||||
return fn, KindNone
|
||||
}
|
||||
res.funcs[obj] = kind // cache
|
||||
}
|
||||
return kind
|
||||
}
|
||||
|
||||
// isFormatter reports whether t could satisfy fmt.Formatter.
|
||||
|
|
@ -490,7 +585,7 @@ func isFormatter(typ types.Type) bool {
|
|||
sig := fn.Type().(*types.Signature)
|
||||
return sig.Params().Len() == 2 &&
|
||||
sig.Results().Len() == 0 &&
|
||||
analysisinternal.IsTypeNamed(sig.Params().At(0).Type(), "fmt", "State") &&
|
||||
typesinternal.IsTypeNamed(sig.Params().At(0).Type(), "fmt", "State") &&
|
||||
types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune])
|
||||
}
|
||||
|
||||
|
|
@ -729,7 +824,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, ma
|
|||
if reason != "" {
|
||||
details = " (" + reason + ")"
|
||||
}
|
||||
pass.ReportRangef(rng, "%s format %s uses non-int %s%s as argument of *", name, operation.Text, analysisinternal.Format(pass.Fset, arg), details)
|
||||
pass.ReportRangef(rng, "%s format %s uses non-int %s%s as argument of *", name, operation.Text, astutil.Format(pass.Fset, arg), details)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -756,7 +851,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, ma
|
|||
}
|
||||
arg := call.Args[verbArgIndex]
|
||||
if isFunctionValue(pass, arg) && verb != 'p' && verb != 'T' {
|
||||
pass.ReportRangef(rng, "%s format %s arg %s is a func value, not called", name, operation.Text, analysisinternal.Format(pass.Fset, arg))
|
||||
pass.ReportRangef(rng, "%s format %s arg %s is a func value, not called", name, operation.Text, astutil.Format(pass.Fset, arg))
|
||||
return false
|
||||
}
|
||||
if reason, ok := matchArgType(pass, v.typ, arg); !ok {
|
||||
|
|
@ -768,14 +863,14 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, ma
|
|||
if reason != "" {
|
||||
details = " (" + reason + ")"
|
||||
}
|
||||
pass.ReportRangef(rng, "%s format %s has arg %s of wrong type %s%s", name, operation.Text, analysisinternal.Format(pass.Fset, arg), typeString, details)
|
||||
pass.ReportRangef(rng, "%s format %s has arg %s of wrong type %s%s", name, operation.Text, astutil.Format(pass.Fset, arg), typeString, details)
|
||||
return false
|
||||
}
|
||||
// Detect recursive formatting via value's String/Error methods.
|
||||
// The '#' flag suppresses the methods, except with %x, %X, and %q.
|
||||
if v.typ&argString != 0 && v.verb != 'T' && (!strings.Contains(operation.Flags, "#") || strings.ContainsRune("qxX", v.verb)) {
|
||||
if methodName, ok := recursiveStringer(pass, arg); ok {
|
||||
pass.ReportRangef(rng, "%s format %s with arg %s causes recursive %s method call", name, operation.Text, analysisinternal.Format(pass.Fset, arg), methodName)
|
||||
pass.ReportRangef(rng, "%s format %s with arg %s causes recursive %s method call", name, operation.Text, astutil.Format(pass.Fset, arg), methodName)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -927,7 +1022,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, name string) {
|
|||
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", name, analysisinternal.Format(pass.Fset, call.Args[0]))
|
||||
pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", name, astutil.Format(pass.Fset, call.Args[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -961,10 +1056,10 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, name string) {
|
|||
}
|
||||
for _, arg := range args {
|
||||
if isFunctionValue(pass, arg) {
|
||||
pass.ReportRangef(call, "%s arg %s is a func value, not called", name, analysisinternal.Format(pass.Fset, arg))
|
||||
pass.ReportRangef(call, "%s arg %s is a func value, not called", name, astutil.Format(pass.Fset, arg))
|
||||
}
|
||||
if methodName, ok := recursiveStringer(pass, arg); ok {
|
||||
pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", name, analysisinternal.Format(pass.Fset, arg), methodName)
|
||||
pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", name, astutil.Format(pass.Fset, arg), methodName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
generated
vendored
|
|
@ -20,7 +20,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"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 := analysisinternal.Format(pass.Fset, x)
|
||||
ident := astutil.Format(pass.Fset, x)
|
||||
qualifier := ""
|
||||
if len(sizes) > 1 {
|
||||
qualifier = "may be "
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
generated
vendored
|
|
@ -18,9 +18,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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -29,14 +29,14 @@ var doc string
|
|||
// Analyzer describes sigchanyzer analysis function detector.
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "sigchanyzer",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "sigchanyzer"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "sigchanyzer"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sigchanyzer",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
if !analysisinternal.Imports(pass.Pkg, "os/signal") {
|
||||
if !typesinternal.Imports(pass.Pkg, "os/signal") {
|
||||
return nil, nil // doesn't directly import signal
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
generated
vendored
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
generated
vendored
|
|
@ -17,10 +17,10 @@ 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"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "slog",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "slog"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "slog"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/slog",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -115,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), analysisinternal.Format(pass.Fset, arg))
|
||||
shortName(fn), astutil.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), analysisinternal.Format(pass.Fset, arg), analysisinternal.Format(pass.Fset, unknownArg))
|
||||
shortName(fn), astutil.Format(pass.Fset, arg), astutil.Format(pass.Fset, unknownArg))
|
||||
}
|
||||
// Stop here so we report at most one missing key per call.
|
||||
return
|
||||
|
|
@ -158,7 +158,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
func isAttr(t types.Type) bool {
|
||||
return analysisinternal.IsTypeNamed(t, "log/slog", "Attr")
|
||||
return typesinternal.IsTypeNamed(t, "log/slog", "Attr")
|
||||
}
|
||||
|
||||
// shortName returns a name for the function that is shorter than FullName.
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
generated
vendored
|
|
@ -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"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -21,7 +21,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "stdmethods",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "stdmethods"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stdmethods"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
|
|
@ -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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
|
@ -25,7 +25,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "stringintconv",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "stringintconv"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stringintconv"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -198,7 +198,7 @@ func run(pass *analysis.Pass) (any, 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 {
|
||||
_, prefix, importEdits := analysisinternal.AddImport(pass.TypesInfo, file, "fmt", "fmt", "Sprint", arg.Pos())
|
||||
prefix, importEdits := refactor.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,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ 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"
|
||||
|
|
@ -31,7 +30,7 @@ func init() {
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "testinggoroutine",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "testinggoroutine"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "testinggoroutine"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -40,7 +39,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
func run(pass *analysis.Pass) (any, error) {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
||||
if !analysisinternal.Imports(pass.Pkg, "testing") {
|
||||
if !typesinternal.Imports(pass.Pkg, "testing") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
generated
vendored
|
|
@ -15,8 +15,8 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "tests",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "tests"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "tests"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
|
||||
Run: run,
|
||||
}
|
||||
|
|
@ -258,7 +258,7 @@ func isTestingType(typ types.Type, testingType string) bool {
|
|||
if !ok {
|
||||
return false
|
||||
}
|
||||
return analysisinternal.IsTypeNamed(ptr.Elem(), "testing", testingType)
|
||||
return typesinternal.IsTypeNamed(ptr.Elem(), "testing", testingType)
|
||||
}
|
||||
|
||||
// Validate that fuzz target function's arguments are of accepted types.
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
generated
vendored
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
generated
vendored
|
|
@ -16,10 +16,10 @@ 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"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
const badFormat = "2006-02-01"
|
||||
|
|
@ -30,7 +30,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "timeformat",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "timeformat"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "timeformat"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -39,7 +39,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
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").
|
||||
// when !analysisinternal.Imports(pass.Pkg, "time").
|
||||
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
|
@ -50,8 +50,8 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||
call := n.(*ast.CallExpr)
|
||||
obj := typeutil.Callee(pass.TypesInfo, call)
|
||||
if !analysisinternal.IsMethodNamed(obj, "time", "Time", "Format") &&
|
||||
!analysisinternal.IsFunctionNamed(obj, "time", "Parse") {
|
||||
if !typesinternal.IsMethodNamed(obj, "time", "Time", "Format") &&
|
||||
!typesinternal.IsFunctionNamed(obj, "time", "Parse") {
|
||||
return
|
||||
}
|
||||
if len(call.Args) > 0 {
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
generated
vendored
|
|
@ -11,9 +11,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"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unmarshal",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "unmarshal"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unmarshal"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -39,7 +39,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
// Note: (*"encoding/json".Decoder).Decode, (* "encoding/gob".Decoder).Decode
|
||||
// and (* "encoding/xml".Decoder).Decode are methods and can be a typeutil.Callee
|
||||
// without directly importing their packages. So we cannot just skip this package
|
||||
// when !analysisutil.Imports(pass.Pkg, "encoding/...").
|
||||
// when !analysisinternal.Imports(pass.Pkg, "encoding/...").
|
||||
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
|
|
|||
15
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
generated
vendored
15
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
generated
vendored
|
|
@ -14,8 +14,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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -23,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unreachable",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "unreachable"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unreachable"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
RunDespiteErrors: true,
|
||||
|
|
@ -188,6 +189,11 @@ func (d *deadState) findDead(stmt ast.Stmt) {
|
|||
case *ast.EmptyStmt:
|
||||
// do not warn about unreachable empty statements
|
||||
default:
|
||||
var (
|
||||
inspect = d.pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
curStmt, _ = inspect.Root().FindNode(stmt)
|
||||
tokFile = d.pass.Fset.File(stmt.Pos())
|
||||
)
|
||||
// (This call to pass.Report is a frequent source
|
||||
// of diagnostics beyond EOF in a truncated file;
|
||||
// see #71659.)
|
||||
|
|
@ -197,10 +203,7 @@ func (d *deadState) findDead(stmt ast.Stmt) {
|
|||
Message: "unreachable code",
|
||||
SuggestedFixes: []analysis.SuggestedFix{{
|
||||
Message: "Remove",
|
||||
TextEdits: []analysis.TextEdit{{
|
||||
Pos: stmt.Pos(),
|
||||
End: stmt.End(),
|
||||
}},
|
||||
TextEdits: refactor.DeleteStmt(tokFile, curStmt),
|
||||
}},
|
||||
})
|
||||
d.reachable = true // silence error about next statement
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
generated
vendored
|
|
@ -14,9 +14,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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unsafeptr",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "unsafeptr"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unsafeptr"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -105,7 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
|
|||
}
|
||||
switch sel.Sel.Name {
|
||||
case "Pointer", "UnsafeAddr":
|
||||
if analysisinternal.IsTypeNamed(info.Types[sel.X].Type, "reflect", "Value") {
|
||||
if typesinternal.IsTypeNamed(info.Types[sel.X].Type, "reflect", "Value") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -153,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 analysisinternal.IsTypeNamed(t, "reflect", "SliceHeader", "StringHeader")
|
||||
return typesinternal.IsTypeNamed(t, "reflect", "SliceHeader", "StringHeader")
|
||||
}
|
||||
|
|
|
|||
3
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
generated
vendored
3
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
generated
vendored
|
|
@ -23,7 +23,6 @@ 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"
|
||||
|
|
@ -34,7 +33,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unusedresult",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "unusedresult"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unusedresult"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
generated
vendored
|
|
@ -13,10 +13,10 @@ 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"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -24,14 +24,14 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "waitgroup",
|
||||
Doc: analysisutil.MustExtractDoc(doc, "waitgroup"),
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "waitgroup"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
if !analysisinternal.Imports(pass.Pkg, "sync") {
|
||||
if !typesinternal.Imports(pass.Pkg, "sync") {
|
||||
return nil, nil // doesn't directly import sync
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
if push {
|
||||
call := n.(*ast.CallExpr)
|
||||
obj := typeutil.Callee(pass.TypesInfo, call)
|
||||
if analysisinternal.IsMethodNamed(obj, "sync", "WaitGroup", "Add") &&
|
||||
if typesinternal.IsMethodNamed(obj, "sync", "WaitGroup", "Add") &&
|
||||
hasSuffix(stack, wantSuffix) &&
|
||||
backindex(stack, 1) == backindex(stack, 2).(*ast.BlockStmt).List[0] { // ExprStmt must be Block's first stmt
|
||||
|
||||
|
|
|
|||
18
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
18
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
|
|
@ -75,7 +75,6 @@ type Config struct {
|
|||
VetxOutput string // where to write file of fact information
|
||||
Stdout string // write stdout (e.g. JSON, unified diff) to this file
|
||||
SucceedOnTypecheckFailure bool // obsolete awful hack; see #18395 and below
|
||||
WarnDiagnostics bool // printing diagnostics should not cause a non-zero exit
|
||||
}
|
||||
|
||||
// Main is the main function of a vet-like analysis tool that must be
|
||||
|
|
@ -87,18 +86,9 @@ type Config struct {
|
|||
// -V=full describe executable for build caching
|
||||
// foo.cfg perform separate modular analyze on the single
|
||||
// unit described by a JSON config file foo.cfg.
|
||||
//
|
||||
// Also, subject to approval of proposal #71859:
|
||||
//
|
||||
// -fix don't print each diagnostic, apply its first fix
|
||||
// -diff don't apply a fix, print the diff (requires -fix)
|
||||
//
|
||||
// Additionally, the environment variable GOVET has the value "vet" or
|
||||
// "fix" depending on whether the command is being invoked by "go vet",
|
||||
// to report diagnostics, or "go fix", to apply fixes. This is
|
||||
// necessary so that callers of Main can select their analyzer suite
|
||||
// before flag parsing. (Vet analyzers must report real code problems,
|
||||
// whereas Fix analyzers may fix non-problems such as style issues.)
|
||||
// -json print diagnostics and fixes in JSON form
|
||||
func Main(analyzers ...*analysis.Analyzer) {
|
||||
progname := filepath.Base(os.Args[0])
|
||||
log.SetFlags(0)
|
||||
|
|
@ -163,7 +153,7 @@ func Run(configFile string, analyzers []*analysis.Analyzer) {
|
|||
|
||||
// In VetxOnly mode, the analysis is run only for facts.
|
||||
if !cfg.VetxOnly {
|
||||
code = processResults(fset, cfg.ID, results, cfg.WarnDiagnostics)
|
||||
code = processResults(fset, cfg.ID, results)
|
||||
}
|
||||
|
||||
os.Exit(code)
|
||||
|
|
@ -187,7 +177,7 @@ func readConfig(filename string) (*Config, error) {
|
|||
return cfg, nil
|
||||
}
|
||||
|
||||
func processResults(fset *token.FileSet, id string, results []result, warnDiagnostics bool) (exit int) {
|
||||
func processResults(fset *token.FileSet, id string, results []result) (exit int) {
|
||||
if analysisflags.Fix {
|
||||
// Don't print the diagnostics,
|
||||
// but apply all fixes from the root actions.
|
||||
|
|
@ -236,12 +226,10 @@ func processResults(fset *token.FileSet, id string, results []result, warnDiagno
|
|||
for _, res := range results {
|
||||
for _, diag := range res.diagnostics {
|
||||
analysisflags.PrintPlain(os.Stderr, fset, analysisflags.Context, diag)
|
||||
if !warnDiagnostics {
|
||||
exit = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
540
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
generated
vendored
540
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
generated
vendored
|
|
@ -2,166 +2,39 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package analysisinternal provides gopls' internal analyses with a
|
||||
// number of helper functions that operate on typed syntax trees.
|
||||
// Package analysisinternal provides helper functions for use in both
|
||||
// the analysis drivers in go/analysis and gopls, and in various
|
||||
// analyzers.
|
||||
//
|
||||
// TODO(adonovan): this is not ideal as it may lead to unnecessary
|
||||
// dependencies between drivers and analyzers. Split into analyzerlib
|
||||
// and driverlib?
|
||||
package analysisinternal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"iter"
|
||||
pathpkg "path"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/moreiters"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
// Deprecated: this heuristic is ill-defined.
|
||||
// TODO(adonovan): move to sole use in gopls/internal/cache.
|
||||
func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
|
||||
// Get the end position for the type error.
|
||||
file := fset.File(start)
|
||||
if file == nil {
|
||||
return start
|
||||
// ReadFile reads a file and adds it to the FileSet in pass
|
||||
// so that we can report errors against it using lineStart.
|
||||
func ReadFile(pass *analysis.Pass, filename string) ([]byte, *token.File, error) {
|
||||
readFile := pass.ReadFile
|
||||
if readFile == nil {
|
||||
readFile = os.ReadFile
|
||||
}
|
||||
if offset := file.PositionFor(start, false).Offset; offset > len(src) {
|
||||
return start
|
||||
} else {
|
||||
src = src[offset:]
|
||||
content, err := readFile(filename)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Attempt to find a reasonable end position for the type error.
|
||||
//
|
||||
// TODO(rfindley): the heuristic implemented here is unclear. It looks like
|
||||
// it seeks the end of the primary operand starting at start, but that is not
|
||||
// quite implemented (for example, given a func literal this heuristic will
|
||||
// return the range of the func keyword).
|
||||
//
|
||||
// We should formalize this heuristic, or deprecate it by finally proposing
|
||||
// to add end position to all type checker errors.
|
||||
//
|
||||
// Nevertheless, ensure that the end position at least spans the current
|
||||
// token at the cursor (this was golang/go#69505).
|
||||
end := start
|
||||
{
|
||||
var s scanner.Scanner
|
||||
fset := token.NewFileSet()
|
||||
f := fset.AddFile("", fset.Base(), len(src))
|
||||
s.Init(f, src, nil /* no error handler */, scanner.ScanComments)
|
||||
pos, tok, lit := s.Scan()
|
||||
if tok != token.SEMICOLON && token.Pos(f.Base()) <= pos && pos <= token.Pos(f.Base()+f.Size()) {
|
||||
off := file.Offset(pos) + len(lit)
|
||||
src = src[off:]
|
||||
end += token.Pos(off)
|
||||
}
|
||||
}
|
||||
|
||||
// Look for bytes that might terminate the current operand. See note above:
|
||||
// this is imprecise.
|
||||
if width := bytes.IndexAny(src, " \n,():;[]+-*/"); width > 0 {
|
||||
end += token.Pos(width)
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
// MatchingIdents finds the names of all identifiers in 'node' that match any of the given types.
|
||||
// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within
|
||||
// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that
|
||||
// is unrecognized.
|
||||
func MatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]string {
|
||||
|
||||
// Initialize matches to contain the variable types we are searching for.
|
||||
matches := make(map[types.Type][]string)
|
||||
for _, typ := range typs {
|
||||
if typ == nil {
|
||||
continue // TODO(adonovan): is this reachable?
|
||||
}
|
||||
matches[typ] = nil // create entry
|
||||
}
|
||||
|
||||
seen := map[types.Object]struct{}{}
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
if n == nil {
|
||||
return false
|
||||
}
|
||||
// Prevent circular definitions. If 'pos' is within an assignment statement, do not
|
||||
// allow any identifiers in that assignment statement to be selected. Otherwise,
|
||||
// we could do the following, where 'x' satisfies the type of 'f0':
|
||||
//
|
||||
// x := fakeStruct{f0: x}
|
||||
//
|
||||
if assign, ok := n.(*ast.AssignStmt); ok && pos > assign.Pos() && pos <= assign.End() {
|
||||
return false
|
||||
}
|
||||
if n.End() > pos {
|
||||
return n.Pos() <= pos
|
||||
}
|
||||
ident, ok := n.(*ast.Ident)
|
||||
if !ok || ident.Name == "_" {
|
||||
return true
|
||||
}
|
||||
obj := info.Defs[ident]
|
||||
if obj == nil || obj.Type() == nil {
|
||||
return true
|
||||
}
|
||||
if _, ok := obj.(*types.TypeName); ok {
|
||||
return true
|
||||
}
|
||||
// Prevent duplicates in matches' values.
|
||||
if _, ok = seen[obj]; ok {
|
||||
return true
|
||||
}
|
||||
seen[obj] = struct{}{}
|
||||
// Find the scope for the given position. Then, check whether the object
|
||||
// exists within the scope.
|
||||
innerScope := pkg.Scope().Innermost(pos)
|
||||
if innerScope == nil {
|
||||
return true
|
||||
}
|
||||
_, foundObj := innerScope.LookupParent(ident.Name, pos)
|
||||
if foundObj != obj {
|
||||
return true
|
||||
}
|
||||
// The object must match one of the types that we are searching for.
|
||||
// TODO(adonovan): opt: use typeutil.Map?
|
||||
if names, ok := matches[obj.Type()]; ok {
|
||||
matches[obj.Type()] = append(names, ident.Name)
|
||||
} else {
|
||||
// If the object type does not exactly match
|
||||
// any of the target types, greedily find the first
|
||||
// target type that the object type can satisfy.
|
||||
for typ := range matches {
|
||||
if equivalentTypes(obj.Type(), typ) {
|
||||
matches[typ] = append(matches[typ], ident.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return matches
|
||||
}
|
||||
|
||||
func equivalentTypes(want, got types.Type) bool {
|
||||
if types.Identical(want, got) {
|
||||
return true
|
||||
}
|
||||
// Code segment to help check for untyped equality from (golang/go#32146).
|
||||
if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 {
|
||||
if lhs, ok := got.Underlying().(*types.Basic); ok {
|
||||
return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType
|
||||
}
|
||||
}
|
||||
return types.AssignableTo(want, got)
|
||||
tf := pass.Fset.AddFile(filename, -1, len(content))
|
||||
tf.SetLinesForContent(content)
|
||||
return content, tf, nil
|
||||
}
|
||||
|
||||
// A ReadFileFunc is a function that returns the
|
||||
|
|
@ -193,207 +66,6 @@ func CheckReadable(pass *analysis.Pass, filename string) error {
|
|||
return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
|
||||
}
|
||||
|
||||
// AddImport checks whether this file already imports pkgpath and that
|
||||
// the import is in scope at pos. If so, it returns the name under
|
||||
// which it was imported and no edits. Otherwise, it adds a new import
|
||||
// of pkgpath, using a name derived from the preferred name, and
|
||||
// returns the chosen name, a prefix to be concatenated with member to
|
||||
// form a qualified name, and the edit for the new import.
|
||||
//
|
||||
// The member argument indicates the name of the desired symbol within
|
||||
// the imported package. This is needed in the case when the existing
|
||||
// import is a dot import, because then it is possible that the
|
||||
// desired symbol is shadowed by other declarations in the current
|
||||
// package. If member is not shadowed at pos, AddImport returns (".",
|
||||
// "", nil). (AddImport accepts the caller's implicit claim that the
|
||||
// imported package declares member.)
|
||||
//
|
||||
// Use a preferredName of "_" to request a blank import;
|
||||
// member is ignored in this case.
|
||||
//
|
||||
// It does not mutate its arguments.
|
||||
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 {
|
||||
panic("no enclosing lexical block")
|
||||
}
|
||||
|
||||
// Is there an existing import of this package?
|
||||
// If so, are we in its scope? (not shadowed)
|
||||
for _, spec := range file.Imports {
|
||||
pkgname := info.PkgNameOf(spec)
|
||||
if pkgname != nil && pkgname.Imported().Path() == pkgpath {
|
||||
name = pkgname.Name()
|
||||
if preferredName == "_" {
|
||||
// Request for blank import; any existing import will do.
|
||||
return name, "", nil
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We must add a new import.
|
||||
|
||||
// Ensure we have a fresh name.
|
||||
newName := preferredName
|
||||
if preferredName != "_" {
|
||||
newName = FreshName(scope, pos, preferredName)
|
||||
}
|
||||
|
||||
// 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("%q", pkgpath)
|
||||
if newName != preferredName || newName != pathpkg.Base(pkgpath) {
|
||||
newText = fmt.Sprintf("%s %q", newName, pkgpath)
|
||||
}
|
||||
|
||||
decl0 := file.Decls[0]
|
||||
var before ast.Node = decl0
|
||||
switch decl0 := decl0.(type) {
|
||||
case *ast.GenDecl:
|
||||
if decl0.Doc != nil {
|
||||
before = decl0.Doc
|
||||
}
|
||||
case *ast.FuncDecl:
|
||||
if decl0.Doc != nil {
|
||||
before = decl0.Doc
|
||||
}
|
||||
}
|
||||
if gd, ok := before.(*ast.GenDecl); ok && gd.Tok == token.IMPORT && gd.Rparen.IsValid() {
|
||||
// Have existing grouped import ( ... ) decl.
|
||||
if IsStdPackage(pkgpath) && len(gd.Specs) > 0 {
|
||||
// Add spec for a std package before
|
||||
// first existing spec, followed by
|
||||
// a blank line if the next one is non-std.
|
||||
first := gd.Specs[0].(*ast.ImportSpec)
|
||||
pos = first.Pos()
|
||||
if !IsStdPackage(first.Path.Value) {
|
||||
newText += "\n"
|
||||
}
|
||||
newText += "\n\t"
|
||||
} else {
|
||||
// Add spec at end of group.
|
||||
pos = gd.Rparen
|
||||
newText = "\t" + newText + "\n"
|
||||
}
|
||||
} else {
|
||||
// No import decl, or non-grouped import.
|
||||
// Add a new import decl before first decl.
|
||||
// (gofmt will merge multiple import decls.)
|
||||
pos = before.Pos()
|
||||
newText = "import " + newText + "\n\n"
|
||||
}
|
||||
return newName, newName + ".", []analysis.TextEdit{{
|
||||
Pos: pos,
|
||||
End: pos,
|
||||
NewText: []byte(newText),
|
||||
}}
|
||||
}
|
||||
|
||||
// FreshName returns the name of an identifier that is undefined
|
||||
// at the specified position, based on the preferred name.
|
||||
func FreshName(scope *types.Scope, pos token.Pos, preferred string) string {
|
||||
newName := preferred
|
||||
for i := 0; ; i++ {
|
||||
if _, obj := scope.LookupParent(newName, pos); obj == nil {
|
||||
break // fresh
|
||||
}
|
||||
newName = fmt.Sprintf("%s%d", preferred, i)
|
||||
}
|
||||
return newName
|
||||
}
|
||||
|
||||
// Format returns a string representation of the node n.
|
||||
func Format(fset *token.FileSet, n ast.Node) string {
|
||||
var buf strings.Builder
|
||||
printer.Fprint(&buf, fset, n) // ignore errors
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
|
|
@ -496,172 +168,6 @@ func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error {
|
|||
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])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// DeleteStmt returns the edits to remove the [ast.Stmt] identified by
|
||||
// curStmt, if it is contained within a BlockStmt, CaseClause,
|
||||
// CommClause, or is the STMT in switch STMT; ... {...}. It returns nil otherwise.
|
||||
func DeleteStmt(fset *token.FileSet, curStmt inspector.Cursor) []analysis.TextEdit {
|
||||
stmt := curStmt.Node().(ast.Stmt)
|
||||
// if the stmt is on a line by itself delete the whole line
|
||||
// otherwise just delete the statement.
|
||||
|
||||
// this logic would be a lot simpler with the file contents, and somewhat simpler
|
||||
// if the cursors included the comments.
|
||||
|
||||
tokFile := fset.File(stmt.Pos())
|
||||
lineOf := tokFile.Line
|
||||
stmtStartLine, stmtEndLine := lineOf(stmt.Pos()), lineOf(stmt.End())
|
||||
|
||||
var from, to token.Pos
|
||||
// bounds of adjacent syntax/comments on same line, if any
|
||||
limits := func(left, right token.Pos) {
|
||||
if lineOf(left) == stmtStartLine {
|
||||
from = left
|
||||
}
|
||||
if lineOf(right) == stmtEndLine {
|
||||
to = right
|
||||
}
|
||||
}
|
||||
// TODO(pjw): there are other places a statement might be removed:
|
||||
// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
|
||||
// (removing the blocks requires more rewriting than this routine would do)
|
||||
// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
|
||||
// (removing the stmt requires more rewriting, and it's unclear what the user means)
|
||||
switch parent := curStmt.Parent().Node().(type) {
|
||||
case *ast.SwitchStmt:
|
||||
limits(parent.Switch, parent.Body.Lbrace)
|
||||
case *ast.TypeSwitchStmt:
|
||||
limits(parent.Switch, parent.Body.Lbrace)
|
||||
if parent.Assign == stmt {
|
||||
return nil // don't let the user break the type switch
|
||||
}
|
||||
case *ast.BlockStmt:
|
||||
limits(parent.Lbrace, parent.Rbrace)
|
||||
case *ast.CommClause:
|
||||
limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
|
||||
if parent.Comm == stmt {
|
||||
return nil // maybe the user meant to remove the entire CommClause?
|
||||
}
|
||||
case *ast.CaseClause:
|
||||
limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
|
||||
case *ast.ForStmt:
|
||||
limits(parent.For, parent.Body.Lbrace)
|
||||
|
||||
default:
|
||||
return nil // not one of ours
|
||||
}
|
||||
|
||||
if prev, found := curStmt.PrevSibling(); found && lineOf(prev.Node().End()) == stmtStartLine {
|
||||
from = prev.Node().End() // preceding statement ends on same line
|
||||
}
|
||||
if next, found := curStmt.NextSibling(); found && lineOf(next.Node().Pos()) == stmtEndLine {
|
||||
to = next.Node().Pos() // following statement begins on same line
|
||||
}
|
||||
// and now for the comments
|
||||
Outer:
|
||||
for _, cg := range enclosingFile(curStmt).Comments {
|
||||
for _, co := range cg.List {
|
||||
if lineOf(co.End()) < stmtStartLine {
|
||||
continue
|
||||
} else if lineOf(co.Pos()) > stmtEndLine {
|
||||
break Outer // no more are possible
|
||||
}
|
||||
if lineOf(co.End()) == stmtStartLine && co.End() < stmt.Pos() {
|
||||
if !from.IsValid() || co.End() > from {
|
||||
from = co.End()
|
||||
continue // maybe there are more
|
||||
}
|
||||
}
|
||||
if lineOf(co.Pos()) == stmtEndLine && co.Pos() > stmt.End() {
|
||||
if !to.IsValid() || co.Pos() < to {
|
||||
to = co.Pos()
|
||||
continue // maybe there are more
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if either from or to is valid, just remove the statement
|
||||
// otherwise remove the line
|
||||
edit := analysis.TextEdit{Pos: stmt.Pos(), End: stmt.End()}
|
||||
if from.IsValid() || to.IsValid() {
|
||||
// remove just the statement.
|
||||
// we can't tell if there is a ; or whitespace right after the statement
|
||||
// ideally we'd like to remove the former and leave the latter
|
||||
// (if gofmt has run, there likely won't be a ;)
|
||||
// In type switches we know there's a semicolon somewhere after the statement,
|
||||
// but the extra work for this special case is not worth it, as gofmt will fix it.
|
||||
return []analysis.TextEdit{edit}
|
||||
}
|
||||
// remove the whole line
|
||||
for lineOf(edit.Pos) == stmtStartLine {
|
||||
edit.Pos--
|
||||
}
|
||||
edit.Pos++ // get back tostmtStartLine
|
||||
for lineOf(edit.End) == stmtEndLine {
|
||||
edit.End++
|
||||
}
|
||||
return []analysis.TextEdit{edit}
|
||||
}
|
||||
|
||||
// Comments returns an iterator over the comments overlapping the specified interval.
|
||||
func Comments(file *ast.File, start, end token.Pos) iter.Seq[*ast.Comment] {
|
||||
// TODO(adonovan): optimize use binary O(log n) instead of linear O(n) search.
|
||||
return func(yield func(*ast.Comment) bool) {
|
||||
for _, cg := range file.Comments {
|
||||
for _, co := range cg.List {
|
||||
if co.Pos() > end {
|
||||
return
|
||||
}
|
||||
if co.End() < start {
|
||||
continue
|
||||
}
|
||||
|
||||
if !yield(co) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsStdPackage reports whether the specified package path belongs to a
|
||||
// package in the standard library (including internal dependencies).
|
||||
func IsStdPackage(path string) bool {
|
||||
// A standard package has no dot in its first segment.
|
||||
// (It may yet have a dot, e.g. "vendor/golang.org/x/foo".)
|
||||
slash := strings.IndexByte(path, '/')
|
||||
if slash < 0 {
|
||||
slash = len(path)
|
||||
}
|
||||
return !strings.Contains(path[:slash], ".") && path != "testdata"
|
||||
}
|
||||
|
||||
// Range returns an [analysis.Range] for the specified start and end positions.
|
||||
func Range(pos, end token.Pos) analysis.Range {
|
||||
return tokenRange{pos, end}
|
||||
|
|
@ -672,9 +178,3 @@ type tokenRange struct{ StartPos, EndPos token.Pos }
|
|||
|
||||
func (r tokenRange) Pos() token.Pos { return r.StartPos }
|
||||
func (r tokenRange) End() token.Pos { return r.EndPos }
|
||||
|
||||
// enclosingFile returns the syntax tree for the file enclosing c.
|
||||
func enclosingFile(c inspector.Cursor) *ast.File {
|
||||
c, _ = moreiters.First(c.Enclosing((*ast.File)(nil)))
|
||||
return c.Node().(*ast.File)
|
||||
}
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go
generated
vendored
|
|
@ -35,7 +35,7 @@ import (
|
|||
//
|
||||
// var Analyzer = &analysis.Analyzer{
|
||||
// Name: "halting",
|
||||
// Doc: analysisutil.MustExtractDoc(doc, "halting"),
|
||||
// Doc: analysisinternal.MustExtractDoc(doc, "halting"),
|
||||
// ...
|
||||
// }
|
||||
func MustExtractDoc(content, name string) string {
|
||||
|
|
|
|||
22
src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
generated
vendored
22
src/cmd/vendor/golang.org/x/tools/internal/astutil/comment.go
generated
vendored
|
|
@ -7,6 +7,7 @@ package astutil
|
|||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"iter"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -111,3 +112,24 @@ func Directives(g *ast.CommentGroup) (res []*Directive) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Comments returns an iterator over the comments overlapping the specified interval.
|
||||
func Comments(file *ast.File, start, end token.Pos) iter.Seq[*ast.Comment] {
|
||||
// TODO(adonovan): optimize use binary O(log n) instead of linear O(n) search.
|
||||
return func(yield func(*ast.Comment) bool) {
|
||||
for _, cg := range file.Comments {
|
||||
for _, co := range cg.List {
|
||||
if co.Pos() > end {
|
||||
return
|
||||
}
|
||||
if co.End() < start {
|
||||
continue
|
||||
}
|
||||
|
||||
if !yield(co) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/internal/astutil/equal.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/internal/astutil/equal.go
generated
vendored
|
|
@ -26,6 +26,14 @@ func Equal(x, y ast.Node, identical func(x, y *ast.Ident) bool) bool {
|
|||
return equal(reflect.ValueOf(x), reflect.ValueOf(y), identical)
|
||||
}
|
||||
|
||||
// EqualSyntax reports whether x and y are equal.
|
||||
// Identifiers are considered equal if they are spelled the same.
|
||||
// Comments are ignored.
|
||||
func EqualSyntax(x, y ast.Expr) bool {
|
||||
sameName := func(x, y *ast.Ident) bool { return x.Name == y.Name }
|
||||
return Equal(x, y, sameName)
|
||||
}
|
||||
|
||||
func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool {
|
||||
// Ensure types are the same
|
||||
if x.Type() != y.Type() {
|
||||
|
|
|
|||
50
src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go
generated
vendored
50
src/cmd/vendor/golang.org/x/tools/internal/astutil/util.go
generated
vendored
|
|
@ -6,7 +6,13 @@ package astutil
|
|||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/moreiters"
|
||||
)
|
||||
|
||||
// PreorderStack traverses the tree rooted at root,
|
||||
|
|
@ -67,3 +73,47 @@ func NodeContains(n ast.Node, pos token.Pos) bool {
|
|||
}
|
||||
return start <= pos && pos <= end
|
||||
}
|
||||
|
||||
// IsChildOf reports whether cur.ParentEdge is ek.
|
||||
//
|
||||
// TODO(adonovan): promote to a method of Cursor.
|
||||
func IsChildOf(cur inspector.Cursor, ek edge.Kind) bool {
|
||||
got, _ := cur.ParentEdge()
|
||||
return got == ek
|
||||
}
|
||||
|
||||
// EnclosingFile returns the syntax tree for the file enclosing c.
|
||||
//
|
||||
// TODO(adonovan): promote this to a method of Cursor.
|
||||
func EnclosingFile(c inspector.Cursor) *ast.File {
|
||||
c, _ = moreiters.First(c.Enclosing((*ast.File)(nil)))
|
||||
return c.Node().(*ast.File)
|
||||
}
|
||||
|
||||
// DocComment returns the doc comment for a node, if any.
|
||||
func DocComment(n ast.Node) *ast.CommentGroup {
|
||||
switch n := n.(type) {
|
||||
case *ast.FuncDecl:
|
||||
return n.Doc
|
||||
case *ast.GenDecl:
|
||||
return n.Doc
|
||||
case *ast.ValueSpec:
|
||||
return n.Doc
|
||||
case *ast.TypeSpec:
|
||||
return n.Doc
|
||||
case *ast.File:
|
||||
return n.Doc
|
||||
case *ast.ImportSpec:
|
||||
return n.Doc
|
||||
case *ast.Field:
|
||||
return n.Doc
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Format returns a string representation of the node n.
|
||||
func Format(fset *token.FileSet, n ast.Node) string {
|
||||
var buf strings.Builder
|
||||
printer.Fprint(&buf, fset, n) // ignore errors
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
|||
5
src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/old.go
generated
vendored
|
|
@ -378,10 +378,7 @@ func (e *editGraph) twoDone(df, db int) (int, bool) {
|
|||
return 0, false // diagonals cannot overlap
|
||||
}
|
||||
kmin := max(-df, -db+e.delta)
|
||||
kmax := db + e.delta
|
||||
if df < kmax {
|
||||
kmax = df
|
||||
}
|
||||
kmax := min(df, db+e.delta)
|
||||
for k := kmin; k <= kmax; k += 2 {
|
||||
x := e.vf.get(df, k)
|
||||
u := e.vb.get(db, k-e.delta)
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/sequence.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/internal/diff/lcs/sequence.go
generated
vendored
|
|
@ -103,11 +103,3 @@ func commonSuffixLenString(a, b string) int {
|
|||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
} else {
|
||||
return y
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
src/cmd/vendor/golang.org/x/tools/internal/packagepath/packagepath.go
generated
vendored
Normal file
49
src/cmd/vendor/golang.org/x/tools/internal/packagepath/packagepath.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// 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 packagepath provides metadata operations on package path
|
||||
// strings.
|
||||
package packagepath
|
||||
|
||||
// (This package should not depend on go/ast.)
|
||||
import "strings"
|
||||
|
||||
// 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])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsStdPackage reports whether the specified package path belongs to a
|
||||
// package in the standard library (including internal dependencies).
|
||||
func IsStdPackage(path string) bool {
|
||||
// A standard package has no dot in its first segment.
|
||||
// (It may yet have a dot, e.g. "vendor/golang.org/x/foo".)
|
||||
slash := strings.IndexByte(path, '/')
|
||||
if slash < 0 {
|
||||
slash = len(path)
|
||||
}
|
||||
return !strings.Contains(path[:slash], ".") && path != "testdata"
|
||||
}
|
||||
484
src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go
generated
vendored
Normal file
484
src/cmd/vendor/golang.org/x/tools/internal/refactor/delete.go
generated
vendored
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
// 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 refactor
|
||||
|
||||
// This file defines operations for computing deletion edits.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"slices"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
)
|
||||
|
||||
// DeleteVar returns edits to delete the declaration of a variable or
|
||||
// constant whose defining identifier is curId.
|
||||
//
|
||||
// It handles variants including:
|
||||
// - GenDecl > ValueSpec versus AssignStmt;
|
||||
// - RHS expression has effects, or not;
|
||||
// - entire statement/declaration may be eliminated;
|
||||
// and removes associated comments.
|
||||
//
|
||||
// If it cannot make the necessary edits, such as for a function
|
||||
// parameter or result, it returns nil.
|
||||
func DeleteVar(tokFile *token.File, info *types.Info, curId inspector.Cursor) []analysis.TextEdit {
|
||||
switch ek, _ := curId.ParentEdge(); ek {
|
||||
case edge.ValueSpec_Names:
|
||||
return deleteVarFromValueSpec(tokFile, info, curId)
|
||||
|
||||
case edge.AssignStmt_Lhs:
|
||||
return deleteVarFromAssignStmt(tokFile, info, curId)
|
||||
}
|
||||
|
||||
// e.g. function receiver, parameter, or result,
|
||||
// or "switch v := expr.(T) {}" (which has no object).
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteVarFromValueSpec returns edits to delete the declaration of a
|
||||
// variable or constant within a ValueSpec.
|
||||
//
|
||||
// Precondition: curId is Ident beneath ValueSpec.Names beneath GenDecl.
|
||||
//
|
||||
// See also [deleteVarFromAssignStmt], which has parallel structure.
|
||||
func deleteVarFromValueSpec(tokFile *token.File, info *types.Info, curIdent inspector.Cursor) []analysis.TextEdit {
|
||||
var (
|
||||
id = curIdent.Node().(*ast.Ident)
|
||||
curSpec = curIdent.Parent()
|
||||
spec = curSpec.Node().(*ast.ValueSpec)
|
||||
)
|
||||
|
||||
declaresOtherNames := slices.ContainsFunc(spec.Names, func(name *ast.Ident) bool {
|
||||
return name != id && name.Name != "_"
|
||||
})
|
||||
noRHSEffects := !slices.ContainsFunc(spec.Values, func(rhs ast.Expr) bool {
|
||||
return !typesinternal.NoEffects(info, rhs)
|
||||
})
|
||||
if !declaresOtherNames && noRHSEffects {
|
||||
// The spec is no longer needed, either to declare
|
||||
// other variables, or for its side effects.
|
||||
return DeleteSpec(tokFile, curSpec)
|
||||
}
|
||||
|
||||
// The spec is still needed, either for
|
||||
// at least one LHS, or for effects on RHS.
|
||||
// Blank out or delete just one LHS.
|
||||
|
||||
_, index := curIdent.ParentEdge() // index of LHS within ValueSpec.Names
|
||||
|
||||
// If there is no RHS, we can delete the LHS.
|
||||
if len(spec.Values) == 0 {
|
||||
var pos, end token.Pos
|
||||
if index == len(spec.Names)-1 {
|
||||
// Delete final name.
|
||||
//
|
||||
// var _, lhs1 T
|
||||
// ------
|
||||
pos = spec.Names[index-1].End()
|
||||
end = spec.Names[index].End()
|
||||
} else {
|
||||
// Delete non-final name.
|
||||
//
|
||||
// var lhs0, _ T
|
||||
// ------
|
||||
pos = spec.Names[index].Pos()
|
||||
end = spec.Names[index+1].Pos()
|
||||
}
|
||||
return []analysis.TextEdit{{
|
||||
Pos: pos,
|
||||
End: end,
|
||||
}}
|
||||
}
|
||||
|
||||
// If the assignment is n:n and the RHS has no effects,
|
||||
// we can delete the LHS and its corresponding RHS.
|
||||
if len(spec.Names) == len(spec.Values) &&
|
||||
typesinternal.NoEffects(info, spec.Values[index]) {
|
||||
|
||||
if index == len(spec.Names)-1 {
|
||||
// Delete final items.
|
||||
//
|
||||
// var _, lhs1 = rhs0, rhs1
|
||||
// ------ ------
|
||||
return []analysis.TextEdit{
|
||||
{
|
||||
Pos: spec.Names[index-1].End(),
|
||||
End: spec.Names[index].End(),
|
||||
},
|
||||
{
|
||||
Pos: spec.Values[index-1].End(),
|
||||
End: spec.Values[index].End(),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Delete non-final items.
|
||||
//
|
||||
// var lhs0, _ = rhs0, rhs1
|
||||
// ------ ------
|
||||
return []analysis.TextEdit{
|
||||
{
|
||||
Pos: spec.Names[index].Pos(),
|
||||
End: spec.Names[index+1].Pos(),
|
||||
},
|
||||
{
|
||||
Pos: spec.Values[index].Pos(),
|
||||
End: spec.Values[index+1].Pos(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot delete the RHS.
|
||||
// Blank out the LHS.
|
||||
return []analysis.TextEdit{{
|
||||
Pos: id.Pos(),
|
||||
End: id.End(),
|
||||
NewText: []byte("_"),
|
||||
}}
|
||||
}
|
||||
|
||||
// Precondition: curId is Ident beneath AssignStmt.Lhs.
|
||||
//
|
||||
// See also [deleteVarFromValueSpec], which has parallel structure.
|
||||
func deleteVarFromAssignStmt(tokFile *token.File, info *types.Info, curIdent inspector.Cursor) []analysis.TextEdit {
|
||||
var (
|
||||
id = curIdent.Node().(*ast.Ident)
|
||||
curStmt = curIdent.Parent()
|
||||
assign = curStmt.Node().(*ast.AssignStmt)
|
||||
)
|
||||
|
||||
declaresOtherNames := slices.ContainsFunc(assign.Lhs, func(lhs ast.Expr) bool {
|
||||
lhsId, ok := lhs.(*ast.Ident)
|
||||
return ok && lhsId != id && lhsId.Name != "_"
|
||||
})
|
||||
noRHSEffects := !slices.ContainsFunc(assign.Rhs, func(rhs ast.Expr) bool {
|
||||
return !typesinternal.NoEffects(info, rhs)
|
||||
})
|
||||
if !declaresOtherNames && noRHSEffects {
|
||||
// The assignment is no longer needed, either to
|
||||
// declare other variables, or for its side effects.
|
||||
if edits := DeleteStmt(tokFile, curStmt); edits != nil {
|
||||
return edits
|
||||
}
|
||||
// Statement could not not be deleted in this context.
|
||||
// Fall back to conservative deletion.
|
||||
}
|
||||
|
||||
// The assign is still needed, either for
|
||||
// at least one LHS, or for effects on RHS,
|
||||
// or because it cannot deleted because of its context.
|
||||
// Blank out or delete just one LHS.
|
||||
|
||||
// If the assignment is 1:1 and the RHS has no effects,
|
||||
// we can delete the LHS and its corresponding RHS.
|
||||
_, index := curIdent.ParentEdge()
|
||||
if len(assign.Lhs) > 1 &&
|
||||
len(assign.Lhs) == len(assign.Rhs) &&
|
||||
typesinternal.NoEffects(info, assign.Rhs[index]) {
|
||||
|
||||
if index == len(assign.Lhs)-1 {
|
||||
// Delete final items.
|
||||
//
|
||||
// _, lhs1 := rhs0, rhs1
|
||||
// ------ ------
|
||||
return []analysis.TextEdit{
|
||||
{
|
||||
Pos: assign.Lhs[index-1].End(),
|
||||
End: assign.Lhs[index].End(),
|
||||
},
|
||||
{
|
||||
Pos: assign.Rhs[index-1].End(),
|
||||
End: assign.Rhs[index].End(),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// Delete non-final items.
|
||||
//
|
||||
// lhs0, _ := rhs0, rhs1
|
||||
// ------ ------
|
||||
return []analysis.TextEdit{
|
||||
{
|
||||
Pos: assign.Lhs[index].Pos(),
|
||||
End: assign.Lhs[index+1].Pos(),
|
||||
},
|
||||
{
|
||||
Pos: assign.Rhs[index].Pos(),
|
||||
End: assign.Rhs[index+1].Pos(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot delete the RHS.
|
||||
// Blank out the LHS.
|
||||
edits := []analysis.TextEdit{{
|
||||
Pos: id.Pos(),
|
||||
End: id.End(),
|
||||
NewText: []byte("_"),
|
||||
}}
|
||||
|
||||
// If this eliminates the final variable declared by
|
||||
// an := statement, we need to turn it into an =
|
||||
// assignment to avoid a "no new variables on left
|
||||
// side of :=" error.
|
||||
if !declaresOtherNames {
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: assign.TokPos,
|
||||
End: assign.TokPos + token.Pos(len(":=")),
|
||||
NewText: []byte("="),
|
||||
})
|
||||
}
|
||||
|
||||
return edits
|
||||
}
|
||||
|
||||
// DeleteSpec returns edits to delete the {Type,Value}Spec identified by curSpec.
|
||||
//
|
||||
// TODO(adonovan): add test suite. Test for consts as well.
|
||||
func DeleteSpec(tokFile *token.File, curSpec inspector.Cursor) []analysis.TextEdit {
|
||||
var (
|
||||
spec = curSpec.Node().(ast.Spec)
|
||||
curDecl = curSpec.Parent()
|
||||
decl = curDecl.Node().(*ast.GenDecl)
|
||||
)
|
||||
|
||||
// If it is the sole spec in the decl,
|
||||
// delete the entire decl.
|
||||
if len(decl.Specs) == 1 {
|
||||
return DeleteDecl(tokFile, curDecl)
|
||||
}
|
||||
|
||||
// Delete the spec and its comments.
|
||||
_, index := curSpec.ParentEdge() // index of ValueSpec within GenDecl.Specs
|
||||
pos, end := spec.Pos(), spec.End()
|
||||
if doc := astutil.DocComment(spec); doc != nil {
|
||||
pos = doc.Pos() // leading comment
|
||||
}
|
||||
if index == len(decl.Specs)-1 {
|
||||
// Delete final spec.
|
||||
if c := eolComment(spec); c != nil {
|
||||
// var (v int // comment \n)
|
||||
end = c.End()
|
||||
}
|
||||
} else {
|
||||
// Delete non-final spec.
|
||||
// var ( a T; b T )
|
||||
// -----
|
||||
end = decl.Specs[index+1].Pos()
|
||||
}
|
||||
return []analysis.TextEdit{{
|
||||
Pos: pos,
|
||||
End: end,
|
||||
}}
|
||||
}
|
||||
|
||||
// DeleteDecl returns edits to delete the ast.Decl identified by curDecl.
|
||||
//
|
||||
// TODO(adonovan): add test suite.
|
||||
func DeleteDecl(tokFile *token.File, curDecl inspector.Cursor) []analysis.TextEdit {
|
||||
decl := curDecl.Node().(ast.Decl)
|
||||
|
||||
ek, _ := curDecl.ParentEdge()
|
||||
switch ek {
|
||||
case edge.DeclStmt_Decl:
|
||||
return DeleteStmt(tokFile, curDecl.Parent())
|
||||
|
||||
case edge.File_Decls:
|
||||
pos, end := decl.Pos(), decl.End()
|
||||
if doc := astutil.DocComment(decl); doc != nil {
|
||||
pos = doc.Pos()
|
||||
}
|
||||
|
||||
// Delete free-floating comments on same line as rparen.
|
||||
// var (...) // comment
|
||||
var (
|
||||
file = curDecl.Parent().Node().(*ast.File)
|
||||
lineOf = tokFile.Line
|
||||
declEndLine = lineOf(decl.End())
|
||||
)
|
||||
for _, cg := range file.Comments {
|
||||
for _, c := range cg.List {
|
||||
if c.Pos() < end {
|
||||
continue // too early
|
||||
}
|
||||
commentEndLine := lineOf(c.End())
|
||||
if commentEndLine > declEndLine {
|
||||
break // too late
|
||||
} else if lineOf(c.Pos()) == declEndLine && commentEndLine == declEndLine {
|
||||
end = c.End()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return []analysis.TextEdit{{
|
||||
Pos: pos,
|
||||
End: end,
|
||||
}}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Decl parent is %v, want DeclStmt or File", ek))
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteStmt returns the edits to remove the [ast.Stmt] identified by
|
||||
// curStmt, if it is contained within a BlockStmt, CaseClause,
|
||||
// CommClause, or is the STMT in switch STMT; ... {...}. It returns nil otherwise.
|
||||
func DeleteStmt(tokFile *token.File, curStmt inspector.Cursor) []analysis.TextEdit {
|
||||
stmt := curStmt.Node().(ast.Stmt)
|
||||
// if the stmt is on a line by itself delete the whole line
|
||||
// otherwise just delete the statement.
|
||||
|
||||
// this logic would be a lot simpler with the file contents, and somewhat simpler
|
||||
// if the cursors included the comments.
|
||||
|
||||
lineOf := tokFile.Line
|
||||
stmtStartLine, stmtEndLine := lineOf(stmt.Pos()), lineOf(stmt.End())
|
||||
|
||||
var from, to token.Pos
|
||||
// bounds of adjacent syntax/comments on same line, if any
|
||||
limits := func(left, right token.Pos) {
|
||||
if lineOf(left) == stmtStartLine {
|
||||
from = left
|
||||
}
|
||||
if lineOf(right) == stmtEndLine {
|
||||
to = right
|
||||
}
|
||||
}
|
||||
// TODO(pjw): there are other places a statement might be removed:
|
||||
// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
|
||||
// (removing the blocks requires more rewriting than this routine would do)
|
||||
// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
|
||||
// (removing the stmt requires more rewriting, and it's unclear what the user means)
|
||||
switch parent := curStmt.Parent().Node().(type) {
|
||||
case *ast.SwitchStmt:
|
||||
limits(parent.Switch, parent.Body.Lbrace)
|
||||
case *ast.TypeSwitchStmt:
|
||||
limits(parent.Switch, parent.Body.Lbrace)
|
||||
if parent.Assign == stmt {
|
||||
return nil // don't let the user break the type switch
|
||||
}
|
||||
case *ast.BlockStmt:
|
||||
limits(parent.Lbrace, parent.Rbrace)
|
||||
case *ast.CommClause:
|
||||
limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
|
||||
if parent.Comm == stmt {
|
||||
return nil // maybe the user meant to remove the entire CommClause?
|
||||
}
|
||||
case *ast.CaseClause:
|
||||
limits(parent.Colon, curStmt.Parent().Parent().Node().(*ast.BlockStmt).Rbrace)
|
||||
case *ast.ForStmt:
|
||||
limits(parent.For, parent.Body.Lbrace)
|
||||
|
||||
default:
|
||||
return nil // not one of ours
|
||||
}
|
||||
|
||||
if prev, found := curStmt.PrevSibling(); found && lineOf(prev.Node().End()) == stmtStartLine {
|
||||
from = prev.Node().End() // preceding statement ends on same line
|
||||
}
|
||||
if next, found := curStmt.NextSibling(); found && lineOf(next.Node().Pos()) == stmtEndLine {
|
||||
to = next.Node().Pos() // following statement begins on same line
|
||||
}
|
||||
// and now for the comments
|
||||
Outer:
|
||||
for _, cg := range astutil.EnclosingFile(curStmt).Comments {
|
||||
for _, co := range cg.List {
|
||||
if lineOf(co.End()) < stmtStartLine {
|
||||
continue
|
||||
} else if lineOf(co.Pos()) > stmtEndLine {
|
||||
break Outer // no more are possible
|
||||
}
|
||||
if lineOf(co.End()) == stmtStartLine && co.End() < stmt.Pos() {
|
||||
if !from.IsValid() || co.End() > from {
|
||||
from = co.End()
|
||||
continue // maybe there are more
|
||||
}
|
||||
}
|
||||
if lineOf(co.Pos()) == stmtEndLine && co.Pos() > stmt.End() {
|
||||
if !to.IsValid() || co.Pos() < to {
|
||||
to = co.Pos()
|
||||
continue // maybe there are more
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if either from or to is valid, just remove the statement
|
||||
// otherwise remove the line
|
||||
edit := analysis.TextEdit{Pos: stmt.Pos(), End: stmt.End()}
|
||||
if from.IsValid() || to.IsValid() {
|
||||
// remove just the statement.
|
||||
// we can't tell if there is a ; or whitespace right after the statement
|
||||
// ideally we'd like to remove the former and leave the latter
|
||||
// (if gofmt has run, there likely won't be a ;)
|
||||
// In type switches we know there's a semicolon somewhere after the statement,
|
||||
// but the extra work for this special case is not worth it, as gofmt will fix it.
|
||||
return []analysis.TextEdit{edit}
|
||||
}
|
||||
// remove the whole line
|
||||
for lineOf(edit.Pos) == stmtStartLine {
|
||||
edit.Pos--
|
||||
}
|
||||
edit.Pos++ // get back tostmtStartLine
|
||||
for lineOf(edit.End) == stmtEndLine {
|
||||
edit.End++
|
||||
}
|
||||
return []analysis.TextEdit{edit}
|
||||
}
|
||||
|
||||
// DeleteUnusedVars computes the edits required to delete the
|
||||
// declarations of any local variables whose last uses are in the
|
||||
// curDelend subtree, which is about to be deleted.
|
||||
func DeleteUnusedVars(index *typeindex.Index, info *types.Info, tokFile *token.File, curDelend inspector.Cursor) []analysis.TextEdit {
|
||||
// TODO(adonovan): we might want to generalize this by
|
||||
// splitting the two phases below, so that we can gather
|
||||
// across a whole sequence of deletions then finally compute the
|
||||
// set of variables that are no longer wanted.
|
||||
|
||||
// Count number of deletions of each var.
|
||||
delcount := make(map[*types.Var]int)
|
||||
for curId := range curDelend.Preorder((*ast.Ident)(nil)) {
|
||||
id := curId.Node().(*ast.Ident)
|
||||
if v, ok := info.Uses[id].(*types.Var); ok &&
|
||||
typesinternal.GetVarKind(v) == typesinternal.LocalVar { // always false before go1.25
|
||||
delcount[v]++
|
||||
}
|
||||
}
|
||||
|
||||
// Delete declaration of each var that became unused.
|
||||
var edits []analysis.TextEdit
|
||||
for v, count := range delcount {
|
||||
if len(slices.Collect(index.Uses(v))) == count {
|
||||
if curDefId, ok := index.Def(v); ok {
|
||||
edits = append(edits, DeleteVar(tokFile, info, curDefId)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return edits
|
||||
}
|
||||
|
||||
func eolComment(n ast.Node) *ast.CommentGroup {
|
||||
// TODO(adonovan): support:
|
||||
// func f() {...} // comment
|
||||
switch n := n.(type) {
|
||||
case *ast.GenDecl:
|
||||
if !n.TokPos.IsValid() && len(n.Specs) == 1 {
|
||||
return eolComment(n.Specs[0])
|
||||
}
|
||||
case *ast.ValueSpec:
|
||||
return n.Comment
|
||||
case *ast.TypeSpec:
|
||||
return n.Comment
|
||||
}
|
||||
return nil
|
||||
}
|
||||
127
src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go
generated
vendored
Normal file
127
src/cmd/vendor/golang.org/x/tools/internal/refactor/imports.go
generated
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// 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 refactor
|
||||
|
||||
// This file defines operations for computing edits to imports.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
pathpkg "path"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/packagepath"
|
||||
)
|
||||
|
||||
// AddImport returns the prefix (either "pkg." or "") that should be
|
||||
// used to qualify references to the desired symbol (member) imported
|
||||
// from the specified package, plus any necessary edits to the file's
|
||||
// import declaration to add a new import.
|
||||
//
|
||||
// If the import already exists, and is accessible at pos, AddImport
|
||||
// returns the existing name and no edits. (If the existing import is
|
||||
// a dot import, the prefix is "".)
|
||||
//
|
||||
// Otherwise, it adds a new import, using a local name derived from
|
||||
// the preferred name. To request a blank import, use a preferredName
|
||||
// of "_", and discard the prefix result; member is ignored in this
|
||||
// case.
|
||||
//
|
||||
// AddImport accepts the caller's implicit claim that the imported
|
||||
// package declares member.
|
||||
//
|
||||
// AddImport does not mutate its arguments.
|
||||
func AddImport(info *types.Info, file *ast.File, preferredName, pkgpath, member string, pos token.Pos) (prefix string, edits []analysis.TextEdit) {
|
||||
// Find innermost enclosing lexical block.
|
||||
scope := info.Scopes[file].Innermost(pos)
|
||||
if scope == nil {
|
||||
panic("no enclosing lexical block")
|
||||
}
|
||||
|
||||
// Is there an existing import of this package?
|
||||
// If so, are we in its scope? (not shadowed)
|
||||
for _, spec := range file.Imports {
|
||||
pkgname := info.PkgNameOf(spec)
|
||||
if pkgname != nil && pkgname.Imported().Path() == pkgpath {
|
||||
name := pkgname.Name()
|
||||
if preferredName == "_" {
|
||||
// Request for blank import; any existing import will do.
|
||||
return "", nil
|
||||
}
|
||||
if name == "." {
|
||||
// The scope of ident must be the file scope.
|
||||
if s, _ := scope.LookupParent(member, pos); s == info.Scopes[file] {
|
||||
return "", nil
|
||||
}
|
||||
} else if _, obj := scope.LookupParent(name, pos); obj == pkgname {
|
||||
return name + ".", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We must add a new import.
|
||||
|
||||
// Ensure we have a fresh name.
|
||||
newName := preferredName
|
||||
if preferredName != "_" {
|
||||
newName = FreshName(scope, pos, preferredName)
|
||||
}
|
||||
|
||||
// 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("%q", pkgpath)
|
||||
if newName != preferredName || newName != pathpkg.Base(pkgpath) {
|
||||
newText = fmt.Sprintf("%s %q", newName, pkgpath)
|
||||
}
|
||||
|
||||
decl0 := file.Decls[0]
|
||||
var before ast.Node = decl0
|
||||
switch decl0 := decl0.(type) {
|
||||
case *ast.GenDecl:
|
||||
if decl0.Doc != nil {
|
||||
before = decl0.Doc
|
||||
}
|
||||
case *ast.FuncDecl:
|
||||
if decl0.Doc != nil {
|
||||
before = decl0.Doc
|
||||
}
|
||||
}
|
||||
if gd, ok := before.(*ast.GenDecl); ok && gd.Tok == token.IMPORT && gd.Rparen.IsValid() {
|
||||
// Have existing grouped import ( ... ) decl.
|
||||
if packagepath.IsStdPackage(pkgpath) && len(gd.Specs) > 0 {
|
||||
// Add spec for a std package before
|
||||
// first existing spec, followed by
|
||||
// a blank line if the next one is non-std.
|
||||
first := gd.Specs[0].(*ast.ImportSpec)
|
||||
pos = first.Pos()
|
||||
if !packagepath.IsStdPackage(first.Path.Value) {
|
||||
newText += "\n"
|
||||
}
|
||||
newText += "\n\t"
|
||||
} else {
|
||||
// Add spec at end of group.
|
||||
pos = gd.Rparen
|
||||
newText = "\t" + newText + "\n"
|
||||
}
|
||||
} else {
|
||||
// No import decl, or non-grouped import.
|
||||
// Add a new import decl before first decl.
|
||||
// (gofmt will merge multiple import decls.)
|
||||
pos = before.Pos()
|
||||
newText = "import " + newText + "\n\n"
|
||||
}
|
||||
return newName + ".", []analysis.TextEdit{{
|
||||
Pos: pos,
|
||||
End: pos,
|
||||
NewText: []byte(newText),
|
||||
}}
|
||||
}
|
||||
29
src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go
generated
vendored
Normal file
29
src/cmd/vendor/golang.org/x/tools/internal/refactor/refactor.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// 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 refactor provides operators to compute common textual edits
|
||||
// for refactoring tools.
|
||||
//
|
||||
// This package should not use features of the analysis API
|
||||
// other than [analysis.TextEdit].
|
||||
package refactor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// FreshName returns the name of an identifier that is undefined
|
||||
// at the specified position, based on the preferred name.
|
||||
func FreshName(scope *types.Scope, pos token.Pos, preferred string) string {
|
||||
newName := preferred
|
||||
for i := 0; ; i++ {
|
||||
if _, obj := scope.LookupParent(newName, pos); obj == nil {
|
||||
break // fresh
|
||||
}
|
||||
newName = fmt.Sprintf("%s%d", preferred, i)
|
||||
}
|
||||
return newName
|
||||
}
|
||||
88
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/fx.go
generated
vendored
Normal file
88
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/fx.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// NoEffects reports whether the expression has no side effects, i.e., it
|
||||
// does not modify the memory state. This function is conservative: it may
|
||||
// return false even when the expression has no effect.
|
||||
func NoEffects(info *types.Info, expr ast.Expr) bool {
|
||||
noEffects := true
|
||||
ast.Inspect(expr, func(n ast.Node) bool {
|
||||
switch v := n.(type) {
|
||||
case nil, *ast.Ident, *ast.BasicLit, *ast.BinaryExpr, *ast.ParenExpr,
|
||||
*ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr, *ast.TypeAssertExpr,
|
||||
*ast.StarExpr, *ast.CompositeLit,
|
||||
// non-expressions that may appear within expressions
|
||||
*ast.KeyValueExpr,
|
||||
*ast.FieldList,
|
||||
*ast.Field,
|
||||
*ast.Ellipsis,
|
||||
*ast.IndexListExpr:
|
||||
// No effect.
|
||||
|
||||
case *ast.ArrayType,
|
||||
*ast.StructType,
|
||||
*ast.ChanType,
|
||||
*ast.FuncType,
|
||||
*ast.MapType,
|
||||
*ast.InterfaceType:
|
||||
// Type syntax: no effects, recursively.
|
||||
// Prune descent.
|
||||
return false
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
// Channel send <-ch has effects.
|
||||
if v.Op == token.ARROW {
|
||||
noEffects = false
|
||||
}
|
||||
|
||||
case *ast.CallExpr:
|
||||
// Type conversion has no effects.
|
||||
if !info.Types[v.Fun].IsType() {
|
||||
if CallsPureBuiltin(info, v) {
|
||||
// A call such as len(e) has no effects of its
|
||||
// own, though the subexpression e might.
|
||||
} else {
|
||||
noEffects = false
|
||||
}
|
||||
}
|
||||
|
||||
case *ast.FuncLit:
|
||||
// A FuncLit has no effects, but do not descend into it.
|
||||
return false
|
||||
|
||||
default:
|
||||
// All other expressions have effects
|
||||
noEffects = false
|
||||
}
|
||||
|
||||
return noEffects
|
||||
})
|
||||
return noEffects
|
||||
}
|
||||
|
||||
// CallsPureBuiltin reports whether call is a call of a built-in
|
||||
// function that is a pure computation over its operands (analogous to
|
||||
// a + operator). Because it does not depend on program state, it may
|
||||
// be evaluated at any point--though not necessarily at multiple
|
||||
// points (consider new, make).
|
||||
func CallsPureBuiltin(info *types.Info, call *ast.CallExpr) bool {
|
||||
if id, ok := ast.Unparen(call.Fun).(*ast.Ident); ok {
|
||||
if b, ok := info.ObjectOf(id).(*types.Builtin); ok {
|
||||
switch b.Name() {
|
||||
case "len", "cap", "complex", "imag", "real", "make", "new", "max", "min":
|
||||
return true
|
||||
}
|
||||
// Not: append clear close copy delete panic print println recover
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
71
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go
generated
vendored
Normal file
71
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/isnamed.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// IsTypeNamed reports whether t is (or is an alias for) a
|
||||
// package-level defined type with the given package path and one of
|
||||
// the given names. It returns false if t is nil.
|
||||
//
|
||||
// This function avoids allocating the concatenation of "pkg.Name",
|
||||
// which is important for the performance of syntax matching.
|
||||
func IsTypeNamed(t types.Type, pkgPath string, names ...string) bool {
|
||||
if named, ok := types.Unalias(t).(*types.Named); ok {
|
||||
tname := named.Obj()
|
||||
return tname != nil &&
|
||||
IsPackageLevel(tname) &&
|
||||
tname.Pkg().Path() == pkgPath &&
|
||||
slices.Contains(names, tname.Name())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPointerToNamed reports whether t is (or is an alias for) a pointer to a
|
||||
// package-level defined type with the given package path and one of the given
|
||||
// names. It returns false if t is not a pointer type.
|
||||
func IsPointerToNamed(t types.Type, pkgPath string, names ...string) bool {
|
||||
r := Unpointer(t)
|
||||
if r == t {
|
||||
return false
|
||||
}
|
||||
return IsTypeNamed(r, pkgPath, names...)
|
||||
}
|
||||
|
||||
// IsFunctionNamed reports whether obj is a package-level function
|
||||
// defined in the given package and has one of the given names.
|
||||
// It returns false if obj is nil.
|
||||
//
|
||||
// This function avoids allocating the concatenation of "pkg.Name",
|
||||
// which is important for the performance of syntax matching.
|
||||
func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool {
|
||||
f, ok := obj.(*types.Func)
|
||||
return ok &&
|
||||
IsPackageLevel(obj) &&
|
||||
f.Pkg().Path() == pkgPath &&
|
||||
f.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 := ReceiverNamed(recv)
|
||||
return T != nil &&
|
||||
IsTypeNamed(T, pkgPath, typeName) &&
|
||||
slices.Contains(names, fn.Name())
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
48
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
48
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go
generated
vendored
|
|
@ -2,8 +2,20 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package typesinternal provides access to internal go/types APIs that are not
|
||||
// yet exported.
|
||||
// Package typesinternal provides helpful operators for dealing with
|
||||
// go/types:
|
||||
//
|
||||
// - operators for querying typed syntax trees (e.g. [Imports], [IsFunctionNamed]);
|
||||
// - functions for converting types to strings or syntax (e.g. [TypeExpr], FileQualifier]);
|
||||
// - helpers for working with the [go/types] API (e.g. [NewTypesInfo]);
|
||||
// - access to internal go/types APIs that are not yet
|
||||
// exported (e.g. [SetUsesCgo], [ErrorCodeStartEnd], [VarKind]); and
|
||||
// - common algorithms related to types (e.g. [TooNewStdSymbols]).
|
||||
//
|
||||
// See also:
|
||||
// - [golang.org/x/tools/internal/astutil], for operations on untyped syntax;
|
||||
// - [golang.org/x/tools/internal/analysisinernal], for helpers for analyzers;
|
||||
// - [golang.org/x/tools/internal/refactor], for operators to compute text edits.
|
||||
package typesinternal
|
||||
|
||||
import (
|
||||
|
|
@ -13,6 +25,7 @@ import (
|
|||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/aliases"
|
||||
)
|
||||
|
||||
|
|
@ -60,6 +73,9 @@ func ErrorCodeStartEnd(err types.Error) (code ErrorCode, start, end token.Pos, o
|
|||
// which is often excessive.)
|
||||
//
|
||||
// If pkg is nil, it is equivalent to [*types.Package.Name].
|
||||
//
|
||||
// TODO(adonovan): all uses of this with TypeString should be
|
||||
// eliminated when https://go.dev/issues/75604 is resolved.
|
||||
func NameRelativeTo(pkg *types.Package) types.Qualifier {
|
||||
return func(other *types.Package) string {
|
||||
if pkg != nil && pkg == other {
|
||||
|
|
@ -153,3 +169,31 @@ func NewTypesInfo() *types.Info {
|
|||
FileVersions: map[*ast.File]string{},
|
||||
}
|
||||
}
|
||||
|
||||
// EnclosingScope returns the innermost block logically enclosing the cursor.
|
||||
func EnclosingScope(info *types.Info, cur inspector.Cursor) *types.Scope {
|
||||
for cur := range cur.Enclosing() {
|
||||
n := cur.Node()
|
||||
// A function's Scope is associated with its FuncType.
|
||||
switch f := n.(type) {
|
||||
case *ast.FuncDecl:
|
||||
n = f.Type
|
||||
case *ast.FuncLit:
|
||||
n = f.Type
|
||||
}
|
||||
if b := info.Scopes[n]; b != nil {
|
||||
return b
|
||||
}
|
||||
}
|
||||
panic("no Scope for *ast.File")
|
||||
}
|
||||
|
||||
// Imports reports whether path is imported by pkg.
|
||||
func Imports(pkg *types.Package, path string) bool {
|
||||
for _, imp := range pkg.Imports() {
|
||||
if imp.Path() == path {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
39
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go
generated
vendored
39
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go
generated
vendored
|
|
@ -2,39 +2,22 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package typesinternal
|
||||
//go:build go1.25
|
||||
|
||||
// TODO(adonovan): when CL 645115 lands, define the go1.25 version of
|
||||
// this API that actually does something.
|
||||
package typesinternal
|
||||
|
||||
import "go/types"
|
||||
|
||||
type VarKind uint8
|
||||
type VarKind = types.VarKind
|
||||
|
||||
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
|
||||
PackageVar = types.PackageVar
|
||||
LocalVar = types.LocalVar
|
||||
RecvVar = types.RecvVar
|
||||
ParamVar = types.ParamVar
|
||||
ResultVar = types.ResultVar
|
||||
FieldVar = types.FieldVar
|
||||
)
|
||||
|
||||
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) {}
|
||||
func GetVarKind(v *types.Var) VarKind { return v.Kind() }
|
||||
func SetVarKind(v *types.Var, kind VarKind) { v.SetKind(kind) }
|
||||
|
|
|
|||
39
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind_go124.go
generated
vendored
Normal file
39
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind_go124.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.25
|
||||
|
||||
package typesinternal
|
||||
|
||||
import "go/types"
|
||||
|
||||
type VarKind uint8
|
||||
|
||||
const (
|
||||
_ VarKind = iota // (not meaningful)
|
||||
PackageVar // a package-level variable
|
||||
LocalVar // a local variable
|
||||
RecvVar // a method receiver variable
|
||||
ParamVar // a function parameter variable
|
||||
ResultVar // a function result variable
|
||||
FieldVar // a struct field
|
||||
)
|
||||
|
||||
func (kind VarKind) String() string {
|
||||
return [...]string{
|
||||
0: "VarKind(0)",
|
||||
PackageVar: "PackageVar",
|
||||
LocalVar: "LocalVar",
|
||||
RecvVar: "RecvVar",
|
||||
ParamVar: "ParamVar",
|
||||
ResultVar: "ResultVar",
|
||||
FieldVar: "FieldVar",
|
||||
}[kind]
|
||||
}
|
||||
|
||||
// GetVarKind returns an invalid VarKind.
|
||||
func GetVarKind(v *types.Var) VarKind { return 0 }
|
||||
|
||||
// SetVarKind has no effect.
|
||||
func SetVarKind(v *types.Var, kind VarKind) {}
|
||||
17
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
generated
vendored
17
src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go
generated
vendored
|
|
@ -204,23 +204,12 @@ func ZeroExpr(t types.Type, qual types.Qualifier) (_ ast.Expr, isValid bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// IsZeroExpr uses simple syntactic heuristics to report whether expr
|
||||
// is a obvious zero value, such as 0, "", nil, or false.
|
||||
// It cannot do better without type information.
|
||||
func IsZeroExpr(expr ast.Expr) bool {
|
||||
switch e := expr.(type) {
|
||||
case *ast.BasicLit:
|
||||
return e.Value == "0" || e.Value == `""`
|
||||
case *ast.Ident:
|
||||
return e.Name == "nil" || e.Name == "false"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// TypeExpr returns syntax for the specified type. References to named types
|
||||
// are qualified by an appropriate (optional) qualifier function.
|
||||
// It may panic for types such as Tuple or Union.
|
||||
//
|
||||
// See also https://go.dev/issues/75604, which will provide a robust
|
||||
// Type-to-valid-Go-syntax formatter.
|
||||
func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
|
|
|
|||
13
src/cmd/vendor/modules.txt
vendored
13
src/cmd/vendor/modules.txt
vendored
|
|
@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
|||
# golang.org/x/build v0.0.0-20250806225920-b7c66c047964
|
||||
## explicit; go 1.23.0
|
||||
golang.org/x/build/relnote
|
||||
# golang.org/x/mod v0.28.0
|
||||
# golang.org/x/mod v0.29.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
|
@ -43,12 +43,12 @@ golang.org/x/mod/zip
|
|||
## explicit; go 1.24.0
|
||||
golang.org/x/sync/errgroup
|
||||
golang.org/x/sync/semaphore
|
||||
# golang.org/x/sys v0.36.0
|
||||
# golang.org/x/sys v0.37.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/sys/plan9
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053
|
||||
# golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/telemetry
|
||||
golang.org/x/telemetry/counter
|
||||
|
|
@ -63,7 +63,7 @@ golang.org/x/telemetry/internal/upload
|
|||
# golang.org/x/term v0.34.0
|
||||
## explicit; go 1.23.0
|
||||
golang.org/x/term
|
||||
# golang.org/x/text v0.29.0
|
||||
# golang.org/x/text v0.30.0
|
||||
## explicit; go 1.24.0
|
||||
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.37.1-0.20250924232827-4df13e317ce4
|
||||
# golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/tools/cmd/bisect
|
||||
golang.org/x/tools/cover
|
||||
|
|
@ -97,7 +97,6 @@ golang.org/x/tools/go/analysis/passes/hostport
|
|||
golang.org/x/tools/go/analysis/passes/httpresponse
|
||||
golang.org/x/tools/go/analysis/passes/ifaceassert
|
||||
golang.org/x/tools/go/analysis/passes/inspect
|
||||
golang.org/x/tools/go/analysis/passes/internal/analysisutil
|
||||
golang.org/x/tools/go/analysis/passes/loopclosure
|
||||
golang.org/x/tools/go/analysis/passes/lostcancel
|
||||
golang.org/x/tools/go/analysis/passes/nilfunc
|
||||
|
|
@ -133,6 +132,8 @@ golang.org/x/tools/internal/diff/lcs
|
|||
golang.org/x/tools/internal/facts
|
||||
golang.org/x/tools/internal/fmtstr
|
||||
golang.org/x/tools/internal/moreiters
|
||||
golang.org/x/tools/internal/packagepath
|
||||
golang.org/x/tools/internal/refactor
|
||||
golang.org/x/tools/internal/stdlib
|
||||
golang.org/x/tools/internal/typeparams
|
||||
golang.org/x/tools/internal/typesinternal
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ module std
|
|||
go 1.26
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.42.0
|
||||
golang.org/x/net v0.44.1-0.20251002015445-edb764c2296f
|
||||
golang.org/x/crypto v0.43.0
|
||||
golang.org/x/net v0.46.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
)
|
||||
|
|
|
|||
16
src/go.sum
16
src/go.sum
|
|
@ -1,8 +1,8 @@
|
|||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/net v0.44.1-0.20251002015445-edb764c2296f h1:vNklv+oJQSYNGsWXHoCPi2MHMcpj9/Q7aBhvvfnJvGg=
|
||||
golang.org/x/net v0.44.1-0.20251002015445-edb764c2296f/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
|
|
|
|||
|
|
@ -11695,6 +11695,12 @@ func (ws *http2priorityWriteSchedulerRFC9218) AdjustStream(streamID uint32, prio
|
|||
q.prev.next = q
|
||||
q.next.prev = q
|
||||
}
|
||||
|
||||
// Update the metadata.
|
||||
ws.streams[streamID] = http2streamMetadata{
|
||||
location: q,
|
||||
priority: priority,
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *http2priorityWriteSchedulerRFC9218) Push(wr http2FrameWriteRequest) {
|
||||
|
|
|
|||
11
src/vendor/golang.org/x/text/unicode/bidi/core.go
generated
vendored
11
src/vendor/golang.org/x/text/unicode/bidi/core.go
generated
vendored
|
|
@ -427,13 +427,6 @@ type isolatingRunSequence struct {
|
|||
|
||||
func (i *isolatingRunSequence) Len() int { return len(i.indexes) }
|
||||
|
||||
func maxLevel(a, b level) level {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Rule X10, second bullet: Determine the start-of-sequence (sos) and end-of-sequence (eos) types,
|
||||
// either L or R, for each isolating run sequence.
|
||||
func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence {
|
||||
|
|
@ -474,8 +467,8 @@ func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence {
|
|||
indexes: indexes,
|
||||
types: types,
|
||||
level: level,
|
||||
sos: typeForLevel(maxLevel(prevLevel, level)),
|
||||
eos: typeForLevel(maxLevel(succLevel, level)),
|
||||
sos: typeForLevel(max(prevLevel, level)),
|
||||
eos: typeForLevel(max(succLevel, level)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
8
src/vendor/modules.txt
vendored
8
src/vendor/modules.txt
vendored
|
|
@ -1,4 +1,4 @@
|
|||
# golang.org/x/crypto v0.42.0
|
||||
# golang.org/x/crypto v0.43.0
|
||||
## explicit; go 1.24.0
|
||||
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.44.1-0.20251002015445-edb764c2296f
|
||||
# golang.org/x/net v0.46.0
|
||||
## explicit; go 1.24.0
|
||||
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.36.0
|
||||
# golang.org/x/sys v0.37.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/sys/cpu
|
||||
# golang.org/x/text v0.29.0
|
||||
# golang.org/x/text v0.30.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/text/secure/bidirule
|
||||
golang.org/x/text/transform
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue