mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd: update x/tools to 59ff18c
$ go get golang.org/x/tools@59ff18c $ GOWORK=off go mod tidy $ GOWORK=off go mod vendor This implies golang.org/x/sys@v0.38.0, for which I have also updated src/go.mod for consistency. I also upgraded x/mod@3f03020 to bring in some fixes to code that go vet would otherwise have flagged in this CL. This brings in a number of fixes and improvements to the analysis tools within cmd/fix, which I will apply to std and cmd presently. For golang/go#71859 Change-Id: I56c49e7ab28eb6ba55408a3721e9a898ee3067a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/719760 Auto-Submit: Alan Donovan <adonovan@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
50128a2154
commit
410ef44f00
136 changed files with 3430 additions and 1509 deletions
|
|
@ -6,12 +6,12 @@ require (
|
|||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
|
||||
golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938
|
||||
golang.org/x/build v0.0.0-20250806225920-b7c66c047964
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/sys v0.37.0
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8
|
||||
golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54
|
||||
golang.org/x/term v0.34.0
|
||||
golang.org/x/tools v0.38.1-0.20251015192825-7d9453ccc0f5
|
||||
golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938 h1:VJ182b/ajNehMFRltVfCh
|
|||
golang.org/x/arch v0.22.1-0.20251016010524-fea4a9ec4938/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
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.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.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/mod v0.30.1-0.20251114215501-3f03020ad526 h1:LPpBM4CGUFMC47OqgAr2YIUxEUjH1Ur+D3KR/1LiuuQ=
|
||||
golang.org/x/mod v0.30.1-0.20251114215501-3f03020ad526/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
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.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=
|
||||
golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883 h1:aeO0AW8d+a+5+hNQx9f4J5egD89zftrY2x42KGQjLzI=
|
||||
golang.org/x/tools v0.39.1-0.20251114194111-59ff18ce4883/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8=
|
||||
rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ=
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/mod/modfile/print.go
generated
vendored
2
src/cmd/vendor/golang.org/x/mod/modfile/print.go
generated
vendored
|
|
@ -33,7 +33,7 @@ type printer struct {
|
|||
}
|
||||
|
||||
// printf prints to the buffer.
|
||||
func (p *printer) printf(format string, args ...interface{}) {
|
||||
func (p *printer) printf(format string, args ...any) {
|
||||
fmt.Fprintf(p, format, args...)
|
||||
}
|
||||
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/mod/modfile/read.go
generated
vendored
4
src/cmd/vendor/golang.org/x/mod/modfile/read.go
generated
vendored
|
|
@ -94,7 +94,7 @@ func (x *FileSyntax) Span() (start, end Position) {
|
|||
// line, the new line is added at the end of the block containing hint,
|
||||
// extracting hint into a new block if it is not yet in one.
|
||||
//
|
||||
// If the hint is non-nil buts its first token does not match,
|
||||
// If the hint is non-nil but its first token does not match,
|
||||
// the new line is added after the block containing hint
|
||||
// (or hint itself, if not in a block).
|
||||
//
|
||||
|
|
@ -600,7 +600,7 @@ func (in *input) readToken() {
|
|||
|
||||
// Checked all punctuation. Must be identifier token.
|
||||
if c := in.peekRune(); !isIdent(c) {
|
||||
in.Error(fmt.Sprintf("unexpected input character %#q", c))
|
||||
in.Error(fmt.Sprintf("unexpected input character %#q", rune(c)))
|
||||
}
|
||||
|
||||
// Scan over identifier.
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
8
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
|
|
@ -368,7 +368,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
|||
Err: err,
|
||||
})
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
errorf := func(format string, args ...any) {
|
||||
wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
|
|
@ -574,7 +574,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V
|
|||
Err: err,
|
||||
}
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) *Error {
|
||||
errorf := func(format string, args ...any) *Error {
|
||||
return wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
|
|
@ -685,7 +685,7 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string,
|
|||
Err: err,
|
||||
})
|
||||
}
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
errorf := func(format string, args ...any) {
|
||||
wrapError(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
|
|
@ -1594,7 +1594,7 @@ func (f *File) AddRetract(vi VersionInterval, rationale string) error {
|
|||
r.Syntax = f.Syntax.addLine(nil, "retract", "[", AutoQuote(vi.Low), ",", AutoQuote(vi.High), "]")
|
||||
}
|
||||
if rationale != "" {
|
||||
for _, line := range strings.Split(rationale, "\n") {
|
||||
for line := range strings.SplitSeq(rationale, "\n") {
|
||||
com := Comment{Token: "// " + line}
|
||||
r.Syntax.Comment().Before = append(r.Syntax.Comment().Before, com)
|
||||
}
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/mod/module/module.go
generated
vendored
6
src/cmd/vendor/golang.org/x/mod/module/module.go
generated
vendored
|
|
@ -261,7 +261,7 @@ func modPathOK(r rune) bool {
|
|||
|
||||
// importPathOK reports whether r can appear in a package import path element.
|
||||
//
|
||||
// Import paths are intermediate between module paths and file paths: we allow
|
||||
// Import paths are intermediate between module paths and file paths: we
|
||||
// disallow characters that would be confusing or ambiguous as arguments to
|
||||
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
|
||||
// otherwise-unambiguous on the command line and historically used for some
|
||||
|
|
@ -802,8 +802,8 @@ func MatchPrefixPatterns(globs, target string) bool {
|
|||
for globs != "" {
|
||||
// Extract next non-empty glob in comma-separated list.
|
||||
var glob string
|
||||
if i := strings.Index(globs, ","); i >= 0 {
|
||||
glob, globs = globs[:i], globs[i+1:]
|
||||
if before, after, ok := strings.Cut(globs, ","); ok {
|
||||
glob, globs = before, after
|
||||
} else {
|
||||
glob, globs = globs, ""
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/mod/semver/semver.go
generated
vendored
4
src/cmd/vendor/golang.org/x/mod/semver/semver.go
generated
vendored
|
|
@ -45,8 +45,8 @@ func IsValid(v string) bool {
|
|||
|
||||
// Canonical returns the canonical formatting of the semantic version v.
|
||||
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
||||
// Two semantic versions compare equal only if their canonical formattings
|
||||
// are identical strings.
|
||||
// Two semantic versions compare equal only if their canonical formatting
|
||||
// is an identical string.
|
||||
// The canonical invalid semantic version is the empty string.
|
||||
func Canonical(v string) string {
|
||||
p, ok := parse(v)
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/mod/sumdb/cache.go
generated
vendored
6
src/cmd/vendor/golang.org/x/mod/sumdb/cache.go
generated
vendored
|
|
@ -20,13 +20,13 @@ type parCache struct {
|
|||
type cacheEntry struct {
|
||||
done uint32
|
||||
mu sync.Mutex
|
||||
result interface{}
|
||||
result any
|
||||
}
|
||||
|
||||
// Do calls the function f if and only if Do is being called for the first time with this key.
|
||||
// No call to Do with a given key returns until the one call to f returns.
|
||||
// Do returns the value returned by the one call to f.
|
||||
func (c *parCache) Do(key interface{}, f func() interface{}) interface{} {
|
||||
func (c *parCache) Do(key any, f func() any) any {
|
||||
entryIface, ok := c.m.Load(key)
|
||||
if !ok {
|
||||
entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry))
|
||||
|
|
@ -46,7 +46,7 @@ func (c *parCache) Do(key interface{}, f func() interface{}) interface{} {
|
|||
// Get returns the cached result associated with key.
|
||||
// It returns nil if there is no such result.
|
||||
// If the result for key is being computed, Get does not wait for the computation to finish.
|
||||
func (c *parCache) Get(key interface{}) interface{} {
|
||||
func (c *parCache) Get(key any) any {
|
||||
entryIface, ok := c.m.Load(key)
|
||||
if !ok {
|
||||
return nil
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/mod/sumdb/client.go
generated
vendored
6
src/cmd/vendor/golang.org/x/mod/sumdb/client.go
generated
vendored
|
|
@ -244,7 +244,7 @@ func (c *Client) Lookup(path, vers string) (lines []string, err error) {
|
|||
data []byte
|
||||
err error
|
||||
}
|
||||
result := c.record.Do(file, func() interface{} {
|
||||
result := c.record.Do(file, func() any {
|
||||
// Try the on-disk cache, or else get from web.
|
||||
writeCache := false
|
||||
data, err := c.ops.ReadCache(file)
|
||||
|
|
@ -284,7 +284,7 @@ func (c *Client) Lookup(path, vers string) (lines []string, err error) {
|
|||
// (with or without /go.mod).
|
||||
prefix := path + " " + vers + " "
|
||||
var hashes []string
|
||||
for _, line := range strings.Split(string(result.data), "\n") {
|
||||
for line := range strings.SplitSeq(string(result.data), "\n") {
|
||||
if strings.HasPrefix(line, prefix) {
|
||||
hashes = append(hashes, line)
|
||||
}
|
||||
|
|
@ -552,7 +552,7 @@ func (c *Client) readTile(tile tlog.Tile) ([]byte, error) {
|
|||
err error
|
||||
}
|
||||
|
||||
result := c.tileCache.Do(tile, func() interface{} {
|
||||
result := c.tileCache.Do(tile, func() any {
|
||||
// Try the requested tile in on-disk cache.
|
||||
data, err := c.ops.ReadCache(c.tileCacheKey(tile))
|
||||
if err == nil {
|
||||
|
|
|
|||
22
src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go
generated
vendored
22
src/cmd/vendor/golang.org/x/mod/sumdb/note/note.go
generated
vendored
|
|
@ -240,8 +240,8 @@ func isValidName(name string) bool {
|
|||
|
||||
// NewVerifier construct a new [Verifier] from an encoded verifier key.
|
||||
func NewVerifier(vkey string) (Verifier, error) {
|
||||
name, vkey := chop(vkey, "+")
|
||||
hash16, key64 := chop(vkey, "+")
|
||||
name, vkey, _ := strings.Cut(vkey, "+")
|
||||
hash16, key64, _ := strings.Cut(vkey, "+")
|
||||
hash, err1 := strconv.ParseUint(hash16, 16, 32)
|
||||
key, err2 := base64.StdEncoding.DecodeString(key64)
|
||||
if len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
|
||||
|
|
@ -276,12 +276,8 @@ func NewVerifier(vkey string) (Verifier, error) {
|
|||
// chop chops s at the first instance of sep, if any,
|
||||
// and returns the text before and after sep.
|
||||
// If sep is not present, chop returns before is s and after is empty.
|
||||
func chop(s, sep string) (before, after string) {
|
||||
i := strings.Index(s, sep)
|
||||
if i < 0 {
|
||||
return s, ""
|
||||
}
|
||||
return s[:i], s[i+len(sep):]
|
||||
func chop(s, sep string) (before, after string, ok bool) {
|
||||
return strings.Cut(s, sep)
|
||||
}
|
||||
|
||||
// verifier is a trivial Verifier implementation.
|
||||
|
|
@ -297,10 +293,10 @@ func (v *verifier) Verify(msg, sig []byte) bool { return v.verify(msg, sig) }
|
|||
|
||||
// NewSigner constructs a new [Signer] from an encoded signer key.
|
||||
func NewSigner(skey string) (Signer, error) {
|
||||
priv1, skey := chop(skey, "+")
|
||||
priv2, skey := chop(skey, "+")
|
||||
name, skey := chop(skey, "+")
|
||||
hash16, key64 := chop(skey, "+")
|
||||
priv1, skey, _ := strings.Cut(skey, "+")
|
||||
priv2, skey, _ := strings.Cut(skey, "+")
|
||||
name, skey, _ := strings.Cut(skey, "+")
|
||||
hash16, key64, _ := strings.Cut(skey, "+")
|
||||
hash, err1 := strconv.ParseUint(hash16, 16, 32)
|
||||
key, err2 := base64.StdEncoding.DecodeString(key64)
|
||||
if priv1 != "PRIVATE" || priv2 != "KEY" || len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
|
||||
|
|
@ -557,7 +553,7 @@ func Open(msg []byte, known Verifiers) (*Note, error) {
|
|||
return nil, errMalformedNote
|
||||
}
|
||||
line = line[len(sigPrefix):]
|
||||
name, b64 := chop(string(line), " ")
|
||||
name, b64, _ := chop(string(line), " ")
|
||||
sig, err := base64.StdEncoding.DecodeString(b64)
|
||||
if err != nil || !isValidName(name) || b64 == "" || len(sig) < 5 {
|
||||
return nil, errMalformedNote
|
||||
|
|
|
|||
3
src/cmd/vendor/golang.org/x/mod/sumdb/server.go
generated
vendored
3
src/cmd/vendor/golang.org/x/mod/sumdb/server.go
generated
vendored
|
|
@ -76,8 +76,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, "invalid module@version syntax", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
i := strings.Index(mod, "@")
|
||||
escPath, escVers := mod[:i], mod[i+1:]
|
||||
escPath, escVers, _ := strings.Cut(mod, "@")
|
||||
path, err := module.UnescapePath(escPath)
|
||||
if err != nil {
|
||||
reportError(w, err)
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/mod/sumdb/test.go
generated
vendored
2
src/cmd/vendor/golang.org/x/mod/sumdb/test.go
generated
vendored
|
|
@ -66,7 +66,7 @@ func (s *TestServer) ReadRecords(ctx context.Context, id, n int64) ([][]byte, er
|
|||
defer s.mu.Unlock()
|
||||
|
||||
var list [][]byte
|
||||
for i := int64(0); i < n; i++ {
|
||||
for i := range n {
|
||||
if id+i >= int64(len(s.records)) {
|
||||
return nil, fmt.Errorf("missing records")
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go
generated
vendored
4
src/cmd/vendor/golang.org/x/mod/sumdb/tlog/note.go
generated
vendored
|
|
@ -35,7 +35,7 @@ type Tree struct {
|
|||
// A future backwards-incompatible encoding would use a different
|
||||
// first line (for example, "go.sum database tree v2").
|
||||
func FormatTree(tree Tree) []byte {
|
||||
return []byte(fmt.Sprintf("go.sum database tree\n%d\n%s\n", tree.N, tree.Hash))
|
||||
return fmt.Appendf(nil, "go.sum database tree\n%d\n%s\n", tree.N, tree.Hash)
|
||||
}
|
||||
|
||||
var errMalformedTree = errors.New("malformed tree note")
|
||||
|
|
@ -87,7 +87,7 @@ func FormatRecord(id int64, text []byte) (msg []byte, err error) {
|
|||
if !isValidRecordText(text) {
|
||||
return nil, errMalformedRecord
|
||||
}
|
||||
msg = []byte(fmt.Sprintf("%d\n", id))
|
||||
msg = fmt.Appendf(nil, "%d\n", id)
|
||||
msg = append(msg, text...)
|
||||
msg = append(msg, '\n')
|
||||
return msg, nil
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
generated
vendored
4
src/cmd/vendor/golang.org/x/mod/sumdb/tlog/tlog.go
generated
vendored
|
|
@ -194,7 +194,7 @@ func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) {
|
|||
// and consumes a hash from an adjacent subtree.
|
||||
m := int(bits.TrailingZeros64(uint64(n + 1)))
|
||||
indexes := make([]int64, m)
|
||||
for i := 0; i < m; i++ {
|
||||
for i := range m {
|
||||
// We arrange indexes in sorted order.
|
||||
// Note that n>>i is always odd.
|
||||
indexes[m-1-i] = StoredHashIndex(i, n>>uint(i)-1)
|
||||
|
|
@ -210,7 +210,7 @@ func StoredHashesForRecordHash(n int64, h Hash, r HashReader) ([]Hash, error) {
|
|||
}
|
||||
|
||||
// Build new hashes.
|
||||
for i := 0; i < m; i++ {
|
||||
for i := range m {
|
||||
h = NodeHash(old[m-1-i], h)
|
||||
hashes = append(hashes, h)
|
||||
}
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/mod/zip/zip.go
generated
vendored
2
src/cmd/vendor/golang.org/x/mod/zip/zip.go
generated
vendored
|
|
@ -780,7 +780,7 @@ func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) }
|
|||
func (fi dataFileInfo) Mode() os.FileMode { return 0644 }
|
||||
func (fi dataFileInfo) ModTime() time.Time { return time.Time{} }
|
||||
func (fi dataFileInfo) IsDir() bool { return false }
|
||||
func (fi dataFileInfo) Sys() interface{} { return nil }
|
||||
func (fi dataFileInfo) Sys() any { return nil }
|
||||
|
||||
// isVendoredPackage attempts to report whether the given filename is contained
|
||||
// in a package whose import path contains (but does not end with) the component
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
2
src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package errgroup provides synchronization, error propagation, and Context
|
||||
// cancelation for groups of goroutines working on subtasks of a common task.
|
||||
// cancellation for groups of goroutines working on subtasks of a common task.
|
||||
//
|
||||
// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
|
||||
// returning errors.
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
2
src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
|
|
@ -226,6 +226,7 @@ struct ltchars {
|
|||
#include <linux/cryptouser.h>
|
||||
#include <linux/devlink.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/falloc.h>
|
||||
|
|
@ -529,6 +530,7 @@ ccflags="$@"
|
|||
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
|
||||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
|
||||
$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
|
||||
$2 ~ /^(DT|EI|ELF|EV|NN|NT|PF|SHF|SHN|SHT|STB|STT|VER)_/ ||
|
||||
$2 ~ /^O?XTABS$/ ||
|
||||
$2 ~ /^TC[IO](ON|OFF)$/ ||
|
||||
$2 ~ /^IN_/ ||
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
6
src/cmd/vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
|
|
@ -2643,3 +2643,9 @@ func SchedGetAttr(pid int, flags uint) (*SchedAttr, error) {
|
|||
|
||||
//sys Cachestat(fd uint, crange *CachestatRange, cstat *Cachestat_t, flags uint) (err error)
|
||||
//sys Mseal(b []byte, flags uint) (err error)
|
||||
|
||||
//sys setMemPolicy(mode int, mask *CPUSet, size int) (err error) = SYS_SET_MEMPOLICY
|
||||
|
||||
func SetMemPolicy(mode int, mask *CPUSet) error {
|
||||
return setMemPolicy(mode, mask, _CPU_SETSIZE)
|
||||
}
|
||||
|
|
|
|||
359
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
359
src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
|
|
@ -853,20 +853,86 @@ const (
|
|||
DM_VERSION_MAJOR = 0x4
|
||||
DM_VERSION_MINOR = 0x32
|
||||
DM_VERSION_PATCHLEVEL = 0x0
|
||||
DT_ADDRRNGHI = 0x6ffffeff
|
||||
DT_ADDRRNGLO = 0x6ffffe00
|
||||
DT_BLK = 0x6
|
||||
DT_CHR = 0x2
|
||||
DT_DEBUG = 0x15
|
||||
DT_DIR = 0x4
|
||||
DT_ENCODING = 0x20
|
||||
DT_FIFO = 0x1
|
||||
DT_FINI = 0xd
|
||||
DT_FLAGS_1 = 0x6ffffffb
|
||||
DT_GNU_HASH = 0x6ffffef5
|
||||
DT_HASH = 0x4
|
||||
DT_HIOS = 0x6ffff000
|
||||
DT_HIPROC = 0x7fffffff
|
||||
DT_INIT = 0xc
|
||||
DT_JMPREL = 0x17
|
||||
DT_LNK = 0xa
|
||||
DT_LOOS = 0x6000000d
|
||||
DT_LOPROC = 0x70000000
|
||||
DT_NEEDED = 0x1
|
||||
DT_NULL = 0x0
|
||||
DT_PLTGOT = 0x3
|
||||
DT_PLTREL = 0x14
|
||||
DT_PLTRELSZ = 0x2
|
||||
DT_REG = 0x8
|
||||
DT_REL = 0x11
|
||||
DT_RELA = 0x7
|
||||
DT_RELACOUNT = 0x6ffffff9
|
||||
DT_RELAENT = 0x9
|
||||
DT_RELASZ = 0x8
|
||||
DT_RELCOUNT = 0x6ffffffa
|
||||
DT_RELENT = 0x13
|
||||
DT_RELSZ = 0x12
|
||||
DT_RPATH = 0xf
|
||||
DT_SOCK = 0xc
|
||||
DT_SONAME = 0xe
|
||||
DT_STRSZ = 0xa
|
||||
DT_STRTAB = 0x5
|
||||
DT_SYMBOLIC = 0x10
|
||||
DT_SYMENT = 0xb
|
||||
DT_SYMTAB = 0x6
|
||||
DT_TEXTREL = 0x16
|
||||
DT_UNKNOWN = 0x0
|
||||
DT_VALRNGHI = 0x6ffffdff
|
||||
DT_VALRNGLO = 0x6ffffd00
|
||||
DT_VERDEF = 0x6ffffffc
|
||||
DT_VERDEFNUM = 0x6ffffffd
|
||||
DT_VERNEED = 0x6ffffffe
|
||||
DT_VERNEEDNUM = 0x6fffffff
|
||||
DT_VERSYM = 0x6ffffff0
|
||||
DT_WHT = 0xe
|
||||
ECHO = 0x8
|
||||
ECRYPTFS_SUPER_MAGIC = 0xf15f
|
||||
EFD_SEMAPHORE = 0x1
|
||||
EFIVARFS_MAGIC = 0xde5e81e4
|
||||
EFS_SUPER_MAGIC = 0x414a53
|
||||
EI_CLASS = 0x4
|
||||
EI_DATA = 0x5
|
||||
EI_MAG0 = 0x0
|
||||
EI_MAG1 = 0x1
|
||||
EI_MAG2 = 0x2
|
||||
EI_MAG3 = 0x3
|
||||
EI_NIDENT = 0x10
|
||||
EI_OSABI = 0x7
|
||||
EI_PAD = 0x8
|
||||
EI_VERSION = 0x6
|
||||
ELFCLASS32 = 0x1
|
||||
ELFCLASS64 = 0x2
|
||||
ELFCLASSNONE = 0x0
|
||||
ELFCLASSNUM = 0x3
|
||||
ELFDATA2LSB = 0x1
|
||||
ELFDATA2MSB = 0x2
|
||||
ELFDATANONE = 0x0
|
||||
ELFMAG = "\177ELF"
|
||||
ELFMAG0 = 0x7f
|
||||
ELFMAG1 = 'E'
|
||||
ELFMAG2 = 'L'
|
||||
ELFMAG3 = 'F'
|
||||
ELFOSABI_LINUX = 0x3
|
||||
ELFOSABI_NONE = 0x0
|
||||
EM_386 = 0x3
|
||||
EM_486 = 0x6
|
||||
EM_68K = 0x4
|
||||
|
|
@ -1152,14 +1218,24 @@ const (
|
|||
ETH_P_WCCP = 0x883e
|
||||
ETH_P_X25 = 0x805
|
||||
ETH_P_XDSA = 0xf8
|
||||
ET_CORE = 0x4
|
||||
ET_DYN = 0x3
|
||||
ET_EXEC = 0x2
|
||||
ET_HIPROC = 0xffff
|
||||
ET_LOPROC = 0xff00
|
||||
ET_NONE = 0x0
|
||||
ET_REL = 0x1
|
||||
EV_ABS = 0x3
|
||||
EV_CNT = 0x20
|
||||
EV_CURRENT = 0x1
|
||||
EV_FF = 0x15
|
||||
EV_FF_STATUS = 0x17
|
||||
EV_KEY = 0x1
|
||||
EV_LED = 0x11
|
||||
EV_MAX = 0x1f
|
||||
EV_MSC = 0x4
|
||||
EV_NONE = 0x0
|
||||
EV_NUM = 0x2
|
||||
EV_PWR = 0x16
|
||||
EV_REL = 0x2
|
||||
EV_REP = 0x14
|
||||
|
|
@ -2276,7 +2352,167 @@ const (
|
|||
NLM_F_REPLACE = 0x100
|
||||
NLM_F_REQUEST = 0x1
|
||||
NLM_F_ROOT = 0x100
|
||||
NN_386_IOPERM = "LINUX"
|
||||
NN_386_TLS = "LINUX"
|
||||
NN_ARC_V2 = "LINUX"
|
||||
NN_ARM_FPMR = "LINUX"
|
||||
NN_ARM_GCS = "LINUX"
|
||||
NN_ARM_HW_BREAK = "LINUX"
|
||||
NN_ARM_HW_WATCH = "LINUX"
|
||||
NN_ARM_PACA_KEYS = "LINUX"
|
||||
NN_ARM_PACG_KEYS = "LINUX"
|
||||
NN_ARM_PAC_ENABLED_KEYS = "LINUX"
|
||||
NN_ARM_PAC_MASK = "LINUX"
|
||||
NN_ARM_POE = "LINUX"
|
||||
NN_ARM_SSVE = "LINUX"
|
||||
NN_ARM_SVE = "LINUX"
|
||||
NN_ARM_SYSTEM_CALL = "LINUX"
|
||||
NN_ARM_TAGGED_ADDR_CTRL = "LINUX"
|
||||
NN_ARM_TLS = "LINUX"
|
||||
NN_ARM_VFP = "LINUX"
|
||||
NN_ARM_ZA = "LINUX"
|
||||
NN_ARM_ZT = "LINUX"
|
||||
NN_AUXV = "CORE"
|
||||
NN_FILE = "CORE"
|
||||
NN_GNU_PROPERTY_TYPE_0 = "GNU"
|
||||
NN_LOONGARCH_CPUCFG = "LINUX"
|
||||
NN_LOONGARCH_CSR = "LINUX"
|
||||
NN_LOONGARCH_HW_BREAK = "LINUX"
|
||||
NN_LOONGARCH_HW_WATCH = "LINUX"
|
||||
NN_LOONGARCH_LASX = "LINUX"
|
||||
NN_LOONGARCH_LBT = "LINUX"
|
||||
NN_LOONGARCH_LSX = "LINUX"
|
||||
NN_MIPS_DSP = "LINUX"
|
||||
NN_MIPS_FP_MODE = "LINUX"
|
||||
NN_MIPS_MSA = "LINUX"
|
||||
NN_PPC_DEXCR = "LINUX"
|
||||
NN_PPC_DSCR = "LINUX"
|
||||
NN_PPC_EBB = "LINUX"
|
||||
NN_PPC_HASHKEYR = "LINUX"
|
||||
NN_PPC_PKEY = "LINUX"
|
||||
NN_PPC_PMU = "LINUX"
|
||||
NN_PPC_PPR = "LINUX"
|
||||
NN_PPC_SPE = "LINUX"
|
||||
NN_PPC_TAR = "LINUX"
|
||||
NN_PPC_TM_CDSCR = "LINUX"
|
||||
NN_PPC_TM_CFPR = "LINUX"
|
||||
NN_PPC_TM_CGPR = "LINUX"
|
||||
NN_PPC_TM_CPPR = "LINUX"
|
||||
NN_PPC_TM_CTAR = "LINUX"
|
||||
NN_PPC_TM_CVMX = "LINUX"
|
||||
NN_PPC_TM_CVSX = "LINUX"
|
||||
NN_PPC_TM_SPR = "LINUX"
|
||||
NN_PPC_VMX = "LINUX"
|
||||
NN_PPC_VSX = "LINUX"
|
||||
NN_PRFPREG = "CORE"
|
||||
NN_PRPSINFO = "CORE"
|
||||
NN_PRSTATUS = "CORE"
|
||||
NN_PRXFPREG = "LINUX"
|
||||
NN_RISCV_CSR = "LINUX"
|
||||
NN_RISCV_TAGGED_ADDR_CTRL = "LINUX"
|
||||
NN_RISCV_VECTOR = "LINUX"
|
||||
NN_S390_CTRS = "LINUX"
|
||||
NN_S390_GS_BC = "LINUX"
|
||||
NN_S390_GS_CB = "LINUX"
|
||||
NN_S390_HIGH_GPRS = "LINUX"
|
||||
NN_S390_LAST_BREAK = "LINUX"
|
||||
NN_S390_PREFIX = "LINUX"
|
||||
NN_S390_PV_CPU_DATA = "LINUX"
|
||||
NN_S390_RI_CB = "LINUX"
|
||||
NN_S390_SYSTEM_CALL = "LINUX"
|
||||
NN_S390_TDB = "LINUX"
|
||||
NN_S390_TIMER = "LINUX"
|
||||
NN_S390_TODCMP = "LINUX"
|
||||
NN_S390_TODPREG = "LINUX"
|
||||
NN_S390_VXRS_HIGH = "LINUX"
|
||||
NN_S390_VXRS_LOW = "LINUX"
|
||||
NN_SIGINFO = "CORE"
|
||||
NN_TASKSTRUCT = "CORE"
|
||||
NN_VMCOREDD = "LINUX"
|
||||
NN_X86_SHSTK = "LINUX"
|
||||
NN_X86_XSAVE_LAYOUT = "LINUX"
|
||||
NN_X86_XSTATE = "LINUX"
|
||||
NSFS_MAGIC = 0x6e736673
|
||||
NT_386_IOPERM = 0x201
|
||||
NT_386_TLS = 0x200
|
||||
NT_ARC_V2 = 0x600
|
||||
NT_ARM_FPMR = 0x40e
|
||||
NT_ARM_GCS = 0x410
|
||||
NT_ARM_HW_BREAK = 0x402
|
||||
NT_ARM_HW_WATCH = 0x403
|
||||
NT_ARM_PACA_KEYS = 0x407
|
||||
NT_ARM_PACG_KEYS = 0x408
|
||||
NT_ARM_PAC_ENABLED_KEYS = 0x40a
|
||||
NT_ARM_PAC_MASK = 0x406
|
||||
NT_ARM_POE = 0x40f
|
||||
NT_ARM_SSVE = 0x40b
|
||||
NT_ARM_SVE = 0x405
|
||||
NT_ARM_SYSTEM_CALL = 0x404
|
||||
NT_ARM_TAGGED_ADDR_CTRL = 0x409
|
||||
NT_ARM_TLS = 0x401
|
||||
NT_ARM_VFP = 0x400
|
||||
NT_ARM_ZA = 0x40c
|
||||
NT_ARM_ZT = 0x40d
|
||||
NT_AUXV = 0x6
|
||||
NT_FILE = 0x46494c45
|
||||
NT_GNU_PROPERTY_TYPE_0 = 0x5
|
||||
NT_LOONGARCH_CPUCFG = 0xa00
|
||||
NT_LOONGARCH_CSR = 0xa01
|
||||
NT_LOONGARCH_HW_BREAK = 0xa05
|
||||
NT_LOONGARCH_HW_WATCH = 0xa06
|
||||
NT_LOONGARCH_LASX = 0xa03
|
||||
NT_LOONGARCH_LBT = 0xa04
|
||||
NT_LOONGARCH_LSX = 0xa02
|
||||
NT_MIPS_DSP = 0x800
|
||||
NT_MIPS_FP_MODE = 0x801
|
||||
NT_MIPS_MSA = 0x802
|
||||
NT_PPC_DEXCR = 0x111
|
||||
NT_PPC_DSCR = 0x105
|
||||
NT_PPC_EBB = 0x106
|
||||
NT_PPC_HASHKEYR = 0x112
|
||||
NT_PPC_PKEY = 0x110
|
||||
NT_PPC_PMU = 0x107
|
||||
NT_PPC_PPR = 0x104
|
||||
NT_PPC_SPE = 0x101
|
||||
NT_PPC_TAR = 0x103
|
||||
NT_PPC_TM_CDSCR = 0x10f
|
||||
NT_PPC_TM_CFPR = 0x109
|
||||
NT_PPC_TM_CGPR = 0x108
|
||||
NT_PPC_TM_CPPR = 0x10e
|
||||
NT_PPC_TM_CTAR = 0x10d
|
||||
NT_PPC_TM_CVMX = 0x10a
|
||||
NT_PPC_TM_CVSX = 0x10b
|
||||
NT_PPC_TM_SPR = 0x10c
|
||||
NT_PPC_VMX = 0x100
|
||||
NT_PPC_VSX = 0x102
|
||||
NT_PRFPREG = 0x2
|
||||
NT_PRPSINFO = 0x3
|
||||
NT_PRSTATUS = 0x1
|
||||
NT_PRXFPREG = 0x46e62b7f
|
||||
NT_RISCV_CSR = 0x900
|
||||
NT_RISCV_TAGGED_ADDR_CTRL = 0x902
|
||||
NT_RISCV_VECTOR = 0x901
|
||||
NT_S390_CTRS = 0x304
|
||||
NT_S390_GS_BC = 0x30c
|
||||
NT_S390_GS_CB = 0x30b
|
||||
NT_S390_HIGH_GPRS = 0x300
|
||||
NT_S390_LAST_BREAK = 0x306
|
||||
NT_S390_PREFIX = 0x305
|
||||
NT_S390_PV_CPU_DATA = 0x30e
|
||||
NT_S390_RI_CB = 0x30d
|
||||
NT_S390_SYSTEM_CALL = 0x307
|
||||
NT_S390_TDB = 0x308
|
||||
NT_S390_TIMER = 0x301
|
||||
NT_S390_TODCMP = 0x302
|
||||
NT_S390_TODPREG = 0x303
|
||||
NT_S390_VXRS_HIGH = 0x30a
|
||||
NT_S390_VXRS_LOW = 0x309
|
||||
NT_SIGINFO = 0x53494749
|
||||
NT_TASKSTRUCT = 0x4
|
||||
NT_VMCOREDD = 0x700
|
||||
NT_X86_SHSTK = 0x204
|
||||
NT_X86_XSAVE_LAYOUT = 0x205
|
||||
NT_X86_XSTATE = 0x202
|
||||
OCFS2_SUPER_MAGIC = 0x7461636f
|
||||
OCRNL = 0x8
|
||||
OFDEL = 0x80
|
||||
|
|
@ -2463,6 +2699,59 @@ const (
|
|||
PERF_RECORD_MISC_USER = 0x2
|
||||
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
|
||||
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
|
||||
PF_ALG = 0x26
|
||||
PF_APPLETALK = 0x5
|
||||
PF_ASH = 0x12
|
||||
PF_ATMPVC = 0x8
|
||||
PF_ATMSVC = 0x14
|
||||
PF_AX25 = 0x3
|
||||
PF_BLUETOOTH = 0x1f
|
||||
PF_BRIDGE = 0x7
|
||||
PF_CAIF = 0x25
|
||||
PF_CAN = 0x1d
|
||||
PF_DECnet = 0xc
|
||||
PF_ECONET = 0x13
|
||||
PF_FILE = 0x1
|
||||
PF_IB = 0x1b
|
||||
PF_IEEE802154 = 0x24
|
||||
PF_INET = 0x2
|
||||
PF_INET6 = 0xa
|
||||
PF_IPX = 0x4
|
||||
PF_IRDA = 0x17
|
||||
PF_ISDN = 0x22
|
||||
PF_IUCV = 0x20
|
||||
PF_KCM = 0x29
|
||||
PF_KEY = 0xf
|
||||
PF_LLC = 0x1a
|
||||
PF_LOCAL = 0x1
|
||||
PF_MAX = 0x2e
|
||||
PF_MCTP = 0x2d
|
||||
PF_MPLS = 0x1c
|
||||
PF_NETBEUI = 0xd
|
||||
PF_NETLINK = 0x10
|
||||
PF_NETROM = 0x6
|
||||
PF_NFC = 0x27
|
||||
PF_PACKET = 0x11
|
||||
PF_PHONET = 0x23
|
||||
PF_PPPOX = 0x18
|
||||
PF_QIPCRTR = 0x2a
|
||||
PF_R = 0x4
|
||||
PF_RDS = 0x15
|
||||
PF_ROSE = 0xb
|
||||
PF_ROUTE = 0x10
|
||||
PF_RXRPC = 0x21
|
||||
PF_SECURITY = 0xe
|
||||
PF_SMC = 0x2b
|
||||
PF_SNA = 0x16
|
||||
PF_TIPC = 0x1e
|
||||
PF_UNIX = 0x1
|
||||
PF_UNSPEC = 0x0
|
||||
PF_VSOCK = 0x28
|
||||
PF_W = 0x2
|
||||
PF_WANPIPE = 0x19
|
||||
PF_X = 0x1
|
||||
PF_X25 = 0x9
|
||||
PF_XDP = 0x2c
|
||||
PID_FS_MAGIC = 0x50494446
|
||||
PIPEFS_MAGIC = 0x50495045
|
||||
PPPIOCGNPMODE = 0xc008744c
|
||||
|
|
@ -2758,6 +3047,23 @@ const (
|
|||
PTRACE_SYSCALL_INFO_NONE = 0x0
|
||||
PTRACE_SYSCALL_INFO_SECCOMP = 0x3
|
||||
PTRACE_TRACEME = 0x0
|
||||
PT_AARCH64_MEMTAG_MTE = 0x70000002
|
||||
PT_DYNAMIC = 0x2
|
||||
PT_GNU_EH_FRAME = 0x6474e550
|
||||
PT_GNU_PROPERTY = 0x6474e553
|
||||
PT_GNU_RELRO = 0x6474e552
|
||||
PT_GNU_STACK = 0x6474e551
|
||||
PT_HIOS = 0x6fffffff
|
||||
PT_HIPROC = 0x7fffffff
|
||||
PT_INTERP = 0x3
|
||||
PT_LOAD = 0x1
|
||||
PT_LOOS = 0x60000000
|
||||
PT_LOPROC = 0x70000000
|
||||
PT_NOTE = 0x4
|
||||
PT_NULL = 0x0
|
||||
PT_PHDR = 0x6
|
||||
PT_SHLIB = 0x5
|
||||
PT_TLS = 0x7
|
||||
P_ALL = 0x0
|
||||
P_PGID = 0x2
|
||||
P_PID = 0x1
|
||||
|
|
@ -3091,6 +3397,47 @@ const (
|
|||
SEEK_MAX = 0x4
|
||||
SEEK_SET = 0x0
|
||||
SELINUX_MAGIC = 0xf97cff8c
|
||||
SHF_ALLOC = 0x2
|
||||
SHF_EXCLUDE = 0x8000000
|
||||
SHF_EXECINSTR = 0x4
|
||||
SHF_GROUP = 0x200
|
||||
SHF_INFO_LINK = 0x40
|
||||
SHF_LINK_ORDER = 0x80
|
||||
SHF_MASKOS = 0xff00000
|
||||
SHF_MASKPROC = 0xf0000000
|
||||
SHF_MERGE = 0x10
|
||||
SHF_ORDERED = 0x4000000
|
||||
SHF_OS_NONCONFORMING = 0x100
|
||||
SHF_RELA_LIVEPATCH = 0x100000
|
||||
SHF_RO_AFTER_INIT = 0x200000
|
||||
SHF_STRINGS = 0x20
|
||||
SHF_TLS = 0x400
|
||||
SHF_WRITE = 0x1
|
||||
SHN_ABS = 0xfff1
|
||||
SHN_COMMON = 0xfff2
|
||||
SHN_HIPROC = 0xff1f
|
||||
SHN_HIRESERVE = 0xffff
|
||||
SHN_LIVEPATCH = 0xff20
|
||||
SHN_LOPROC = 0xff00
|
||||
SHN_LORESERVE = 0xff00
|
||||
SHN_UNDEF = 0x0
|
||||
SHT_DYNAMIC = 0x6
|
||||
SHT_DYNSYM = 0xb
|
||||
SHT_HASH = 0x5
|
||||
SHT_HIPROC = 0x7fffffff
|
||||
SHT_HIUSER = 0xffffffff
|
||||
SHT_LOPROC = 0x70000000
|
||||
SHT_LOUSER = 0x80000000
|
||||
SHT_NOBITS = 0x8
|
||||
SHT_NOTE = 0x7
|
||||
SHT_NULL = 0x0
|
||||
SHT_NUM = 0xc
|
||||
SHT_PROGBITS = 0x1
|
||||
SHT_REL = 0x9
|
||||
SHT_RELA = 0x4
|
||||
SHT_SHLIB = 0xa
|
||||
SHT_STRTAB = 0x3
|
||||
SHT_SYMTAB = 0x2
|
||||
SHUT_RD = 0x0
|
||||
SHUT_RDWR = 0x2
|
||||
SHUT_WR = 0x1
|
||||
|
|
@ -3317,6 +3664,16 @@ const (
|
|||
STATX_UID = 0x8
|
||||
STATX_WRITE_ATOMIC = 0x10000
|
||||
STATX__RESERVED = 0x80000000
|
||||
STB_GLOBAL = 0x1
|
||||
STB_LOCAL = 0x0
|
||||
STB_WEAK = 0x2
|
||||
STT_COMMON = 0x5
|
||||
STT_FILE = 0x4
|
||||
STT_FUNC = 0x2
|
||||
STT_NOTYPE = 0x0
|
||||
STT_OBJECT = 0x1
|
||||
STT_SECTION = 0x3
|
||||
STT_TLS = 0x6
|
||||
SYNC_FILE_RANGE_WAIT_AFTER = 0x4
|
||||
SYNC_FILE_RANGE_WAIT_BEFORE = 0x1
|
||||
SYNC_FILE_RANGE_WRITE = 0x2
|
||||
|
|
@ -3553,6 +3910,8 @@ const (
|
|||
UTIME_OMIT = 0x3ffffffe
|
||||
V9FS_MAGIC = 0x1021997
|
||||
VERASE = 0x2
|
||||
VER_FLG_BASE = 0x1
|
||||
VER_FLG_WEAK = 0x2
|
||||
VINTR = 0x0
|
||||
VKILL = 0x3
|
||||
VLNEXT = 0xf
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
10
src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
|
|
@ -2238,3 +2238,13 @@ func Mseal(b []byte, flags uint) (err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func setMemPolicy(mode int, mask *CPUSet, size int) (err error) {
|
||||
_, _, e1 := Syscall(SYS_SET_MEMPOLICY, uintptr(mode), uintptr(unsafe.Pointer(mask)), uintptr(size))
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
31
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
31
src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go
generated
vendored
|
|
@ -3590,6 +3590,8 @@ type Nhmsg struct {
|
|||
Flags uint32
|
||||
}
|
||||
|
||||
const SizeofNhmsg = 0x8
|
||||
|
||||
type NexthopGrp struct {
|
||||
Id uint32
|
||||
Weight uint8
|
||||
|
|
@ -3597,6 +3599,8 @@ type NexthopGrp struct {
|
|||
Resvd2 uint16
|
||||
}
|
||||
|
||||
const SizeofNexthopGrp = 0x8
|
||||
|
||||
const (
|
||||
NHA_UNSPEC = 0x0
|
||||
NHA_ID = 0x1
|
||||
|
|
@ -6332,3 +6336,30 @@ type SockDiagReq struct {
|
|||
}
|
||||
|
||||
const RTM_NEWNVLAN = 0x70
|
||||
|
||||
const (
|
||||
MPOL_BIND = 0x2
|
||||
MPOL_DEFAULT = 0x0
|
||||
MPOL_F_ADDR = 0x2
|
||||
MPOL_F_MEMS_ALLOWED = 0x4
|
||||
MPOL_F_MOF = 0x8
|
||||
MPOL_F_MORON = 0x10
|
||||
MPOL_F_NODE = 0x1
|
||||
MPOL_F_NUMA_BALANCING = 0x2000
|
||||
MPOL_F_RELATIVE_NODES = 0x4000
|
||||
MPOL_F_SHARED = 0x1
|
||||
MPOL_F_STATIC_NODES = 0x8000
|
||||
MPOL_INTERLEAVE = 0x3
|
||||
MPOL_LOCAL = 0x4
|
||||
MPOL_MAX = 0x7
|
||||
MPOL_MF_INTERNAL = 0x10
|
||||
MPOL_MF_LAZY = 0x8
|
||||
MPOL_MF_MOVE_ALL = 0x4
|
||||
MPOL_MF_MOVE = 0x2
|
||||
MPOL_MF_STRICT = 0x1
|
||||
MPOL_MF_VALID = 0x7
|
||||
MPOL_MODE_FLAGS = 0xe000
|
||||
MPOL_PREFERRED = 0x1
|
||||
MPOL_PREFERRED_MANY = 0x5
|
||||
MPOL_WEIGHTED_INTERLEAVE = 0x6
|
||||
)
|
||||
|
|
|
|||
15
src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
15
src/cmd/vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
|
|
@ -892,8 +892,12 @@ const socket_error = uintptr(^uint32(0))
|
|||
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||
//sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
|
||||
//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
|
||||
//sys GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) = iphlpapi.GetIpForwardEntry2
|
||||
//sys GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) = iphlpapi.GetIpForwardTable2
|
||||
//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
|
||||
//sys FreeMibTable(memory unsafe.Pointer) = iphlpapi.FreeMibTable
|
||||
//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
|
||||
//sys NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyRouteChange2
|
||||
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
|
||||
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
|
||||
|
||||
|
|
@ -916,6 +920,17 @@ type RawSockaddrInet6 struct {
|
|||
Scope_id uint32
|
||||
}
|
||||
|
||||
// RawSockaddrInet is a union that contains an IPv4, an IPv6 address, or an address family. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-sockaddr_inet.
|
||||
//
|
||||
// A [*RawSockaddrInet] may be converted to a [*RawSockaddrInet4] or [*RawSockaddrInet6] using
|
||||
// unsafe, depending on the address family.
|
||||
type RawSockaddrInet struct {
|
||||
Family uint16
|
||||
Port uint16
|
||||
Data [6]uint32
|
||||
}
|
||||
|
||||
type RawSockaddr struct {
|
||||
Family uint16
|
||||
Data [14]int8
|
||||
|
|
|
|||
76
src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
76
src/cmd/vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
|
|
@ -2320,6 +2320,82 @@ type MibIfRow2 struct {
|
|||
OutQLen uint64
|
||||
}
|
||||
|
||||
// IP_ADDRESS_PREFIX stores an IP address prefix. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-ip_address_prefix.
|
||||
type IpAddressPrefix struct {
|
||||
Prefix RawSockaddrInet
|
||||
PrefixLength uint8
|
||||
}
|
||||
|
||||
// NL_ROUTE_ORIGIN enumeration from nldef.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_origin.
|
||||
const (
|
||||
NlroManual = 0
|
||||
NlroWellKnown = 1
|
||||
NlroDHCP = 2
|
||||
NlroRouterAdvertisement = 3
|
||||
Nlro6to4 = 4
|
||||
)
|
||||
|
||||
// NL_ROUTE_ORIGIN enumeration from nldef.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_route_protocol.
|
||||
const (
|
||||
MIB_IPPROTO_OTHER = 1
|
||||
MIB_IPPROTO_LOCAL = 2
|
||||
MIB_IPPROTO_NETMGMT = 3
|
||||
MIB_IPPROTO_ICMP = 4
|
||||
MIB_IPPROTO_EGP = 5
|
||||
MIB_IPPROTO_GGP = 6
|
||||
MIB_IPPROTO_HELLO = 7
|
||||
MIB_IPPROTO_RIP = 8
|
||||
MIB_IPPROTO_IS_IS = 9
|
||||
MIB_IPPROTO_ES_IS = 10
|
||||
MIB_IPPROTO_CISCO = 11
|
||||
MIB_IPPROTO_BBN = 12
|
||||
MIB_IPPROTO_OSPF = 13
|
||||
MIB_IPPROTO_BGP = 14
|
||||
MIB_IPPROTO_IDPR = 15
|
||||
MIB_IPPROTO_EIGRP = 16
|
||||
MIB_IPPROTO_DVMRP = 17
|
||||
MIB_IPPROTO_RPL = 18
|
||||
MIB_IPPROTO_DHCP = 19
|
||||
MIB_IPPROTO_NT_AUTOSTATIC = 10002
|
||||
MIB_IPPROTO_NT_STATIC = 10006
|
||||
MIB_IPPROTO_NT_STATIC_NON_DOD = 10007
|
||||
)
|
||||
|
||||
// MIB_IPFORWARD_ROW2 stores information about an IP route entry. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_row2.
|
||||
type MibIpForwardRow2 struct {
|
||||
InterfaceLuid uint64
|
||||
InterfaceIndex uint32
|
||||
DestinationPrefix IpAddressPrefix
|
||||
NextHop RawSockaddrInet
|
||||
SitePrefixLength uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Metric uint32
|
||||
Protocol uint32
|
||||
Loopback uint8
|
||||
AutoconfigureAddress uint8
|
||||
Publish uint8
|
||||
Immortal uint8
|
||||
Age uint32
|
||||
Origin uint32
|
||||
}
|
||||
|
||||
// MIB_IPFORWARD_TABLE2 contains a table of IP route entries. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipforward_table2.
|
||||
type MibIpForwardTable2 struct {
|
||||
NumEntries uint32
|
||||
Table [1]MibIpForwardRow2
|
||||
}
|
||||
|
||||
// Rows returns the IP route entries in the table.
|
||||
func (t *MibIpForwardTable2) Rows() []MibIpForwardRow2 {
|
||||
return unsafe.Slice(&t.Table[0], t.NumEntries)
|
||||
}
|
||||
|
||||
// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
|
||||
type MibUnicastIpAddressRow struct {
|
||||
|
|
|
|||
37
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
37
src/cmd/vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
|
|
@ -182,13 +182,17 @@ var (
|
|||
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
|
||||
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
|
||||
procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2")
|
||||
procFreeMibTable = modiphlpapi.NewProc("FreeMibTable")
|
||||
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
|
||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||
procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx")
|
||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||
procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex")
|
||||
procGetIpForwardEntry2 = modiphlpapi.NewProc("GetIpForwardEntry2")
|
||||
procGetIpForwardTable2 = modiphlpapi.NewProc("GetIpForwardTable2")
|
||||
procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
|
||||
procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
|
||||
procNotifyRouteChange2 = modiphlpapi.NewProc("NotifyRouteChange2")
|
||||
procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
|
||||
procAddDllDirectory = modkernel32.NewProc("AddDllDirectory")
|
||||
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
|
||||
|
|
@ -1624,6 +1628,11 @@ func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
|
|||
return
|
||||
}
|
||||
|
||||
func FreeMibTable(memory unsafe.Pointer) {
|
||||
syscall.SyscallN(procFreeMibTable.Addr(), uintptr(memory))
|
||||
return
|
||||
}
|
||||
|
||||
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetAdaptersAddresses.Addr(), uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)))
|
||||
if r0 != 0 {
|
||||
|
|
@ -1664,6 +1673,22 @@ func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
|
|||
return
|
||||
}
|
||||
|
||||
func GetIpForwardEntry2(row *MibIpForwardRow2) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetIpForwardEntry2.Addr(), uintptr(unsafe.Pointer(row)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetIpForwardTable2(family uint16, table **MibIpForwardTable2) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetIpForwardTable2.Addr(), uintptr(family), uintptr(unsafe.Pointer(table)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
|
||||
r0, _, _ := syscall.SyscallN(procGetUnicastIpAddressEntry.Addr(), uintptr(unsafe.Pointer(row)))
|
||||
if r0 != 0 {
|
||||
|
|
@ -1684,6 +1709,18 @@ func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsa
|
|||
return
|
||||
}
|
||||
|
||||
func NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procNotifyRouteChange2.Addr(), uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)))
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
|
|
|
|||
1
src/cmd/vendor/golang.org/x/telemetry/codereview.cfg
generated
vendored
Normal file
1
src/cmd/vendor/golang.org/x/telemetry/codereview.cfg
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
issuerepo: golang/go
|
||||
5
src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
5
src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
generated
vendored
|
|
@ -33,8 +33,9 @@ type Diagnostic struct {
|
|||
URL string
|
||||
|
||||
// SuggestedFixes is an optional list of fixes to address the
|
||||
// problem described by the diagnostic. Each one represents
|
||||
// an alternative strategy; at most one may be applied.
|
||||
// problem described by the diagnostic. Each one represents an
|
||||
// alternative strategy, and should have a distinct and
|
||||
// descriptive message; at most one may be applied.
|
||||
//
|
||||
// Fixes for different diagnostics should be treated as
|
||||
// independent changes to the same baseline file state,
|
||||
|
|
|
|||
159
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
generated
vendored
159
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
generated
vendored
|
|
@ -13,22 +13,20 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
)
|
||||
|
||||
// flags common to all {single,multi,unit}checkers.
|
||||
var (
|
||||
JSON = false // -json
|
||||
Context = -1 // -c=N: if N>0, display offending line plus N lines of context
|
||||
Fix bool // -fix
|
||||
diffFlag bool // -diff (changes [ApplyFixes] behavior)
|
||||
JSON = false // -json
|
||||
Context = -1 // -c=N: if N>0, display offending line plus N lines of context
|
||||
Fix bool // -fix
|
||||
Diff bool // -diff
|
||||
)
|
||||
|
||||
// Parse creates a flag for each of the analyzer's flags,
|
||||
|
|
@ -78,7 +76,7 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
|
|||
flag.BoolVar(&JSON, "json", JSON, "emit JSON output")
|
||||
flag.IntVar(&Context, "c", Context, `display offending line with this many lines of context`)
|
||||
flag.BoolVar(&Fix, "fix", false, "apply all suggested fixes")
|
||||
flag.BoolVar(&diffFlag, "diff", false, "with -fix, don't update the files, but print a unified diff")
|
||||
flag.BoolVar(&Diff, "diff", false, "with -fix, don't update the files, but print a unified diff")
|
||||
|
||||
// Add shims for legacy vet flags to enable existing
|
||||
// scripts that run vet to continue to work.
|
||||
|
|
@ -310,150 +308,3 @@ var vetLegacyFlags = map[string]string{
|
|||
"unusedfuncs": "unusedresult.funcs",
|
||||
"unusedstringmethods": "unusedresult.stringmethods",
|
||||
}
|
||||
|
||||
// ---- output helpers common to all drivers ----
|
||||
//
|
||||
// These functions should not depend on global state (flags)!
|
||||
// Really they belong in a different package.
|
||||
|
||||
// TODO(adonovan): don't accept an io.Writer if we don't report errors.
|
||||
// Either accept a bytes.Buffer (infallible), or return a []byte.
|
||||
|
||||
// PrintPlain prints a diagnostic in plain text form.
|
||||
// If contextLines is nonnegative, it also prints the
|
||||
// offending line plus this many lines of context.
|
||||
func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) {
|
||||
print := func(pos, end token.Pos, message string) {
|
||||
posn := fset.Position(pos)
|
||||
fmt.Fprintf(out, "%s: %s\n", posn, message)
|
||||
|
||||
// show offending line plus N lines of context.
|
||||
if contextLines >= 0 {
|
||||
end := fset.Position(end)
|
||||
if !end.IsValid() {
|
||||
end = posn
|
||||
}
|
||||
// TODO(adonovan): highlight the portion of the line indicated
|
||||
// by pos...end using ASCII art, terminal colors, etc?
|
||||
data, _ := os.ReadFile(posn.Filename)
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ {
|
||||
if 1 <= i && i <= len(lines) {
|
||||
fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print(diag.Pos, diag.End, diag.Message)
|
||||
for _, rel := range diag.Related {
|
||||
print(rel.Pos, rel.End, "\t"+rel.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// A JSONTree is a mapping from package ID to analysis name to result.
|
||||
// Each result is either a jsonError or a list of JSONDiagnostic.
|
||||
type JSONTree map[string]map[string]any
|
||||
|
||||
// A TextEdit describes the replacement of a portion of a file.
|
||||
// Start and End are zero-based half-open indices into the original byte
|
||||
// sequence of the file, and New is the new text.
|
||||
type JSONTextEdit struct {
|
||||
Filename string `json:"filename"`
|
||||
Start int `json:"start"`
|
||||
End int `json:"end"`
|
||||
New string `json:"new"`
|
||||
}
|
||||
|
||||
// A JSONSuggestedFix describes an edit that should be applied as a whole or not
|
||||
// at all. It might contain multiple TextEdits/text_edits if the SuggestedFix
|
||||
// consists of multiple non-contiguous edits.
|
||||
type JSONSuggestedFix struct {
|
||||
Message string `json:"message"`
|
||||
Edits []JSONTextEdit `json:"edits"`
|
||||
}
|
||||
|
||||
// A JSONDiagnostic describes the JSON schema of an analysis.Diagnostic.
|
||||
//
|
||||
// TODO(matloob): include End position if present.
|
||||
type JSONDiagnostic struct {
|
||||
Category string `json:"category,omitempty"`
|
||||
Posn string `json:"posn"` // e.g. "file.go:line:column"
|
||||
Message string `json:"message"`
|
||||
SuggestedFixes []JSONSuggestedFix `json:"suggested_fixes,omitempty"`
|
||||
Related []JSONRelatedInformation `json:"related,omitempty"`
|
||||
}
|
||||
|
||||
// A JSONRelated describes a secondary position and message related to
|
||||
// a primary diagnostic.
|
||||
//
|
||||
// TODO(adonovan): include End position if present.
|
||||
type JSONRelatedInformation struct {
|
||||
Posn string `json:"posn"` // e.g. "file.go:line:column"
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Add adds the result of analysis 'name' on package 'id'.
|
||||
// The result is either a list of diagnostics or an error.
|
||||
func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
|
||||
var v any
|
||||
if err != nil {
|
||||
type jsonError struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
v = jsonError{err.Error()}
|
||||
} else if len(diags) > 0 {
|
||||
diagnostics := make([]JSONDiagnostic, 0, len(diags))
|
||||
for _, f := range diags {
|
||||
var fixes []JSONSuggestedFix
|
||||
for _, fix := range f.SuggestedFixes {
|
||||
var edits []JSONTextEdit
|
||||
for _, edit := range fix.TextEdits {
|
||||
edits = append(edits, JSONTextEdit{
|
||||
Filename: fset.Position(edit.Pos).Filename,
|
||||
Start: fset.Position(edit.Pos).Offset,
|
||||
End: fset.Position(edit.End).Offset,
|
||||
New: string(edit.NewText),
|
||||
})
|
||||
}
|
||||
fixes = append(fixes, JSONSuggestedFix{
|
||||
Message: fix.Message,
|
||||
Edits: edits,
|
||||
})
|
||||
}
|
||||
var related []JSONRelatedInformation
|
||||
for _, r := range f.Related {
|
||||
related = append(related, JSONRelatedInformation{
|
||||
Posn: fset.Position(r.Pos).String(),
|
||||
Message: r.Message,
|
||||
})
|
||||
}
|
||||
jdiag := JSONDiagnostic{
|
||||
Category: f.Category,
|
||||
Posn: fset.Position(f.Pos).String(),
|
||||
Message: f.Message,
|
||||
SuggestedFixes: fixes,
|
||||
Related: related,
|
||||
}
|
||||
diagnostics = append(diagnostics, jdiag)
|
||||
}
|
||||
v = diagnostics
|
||||
}
|
||||
if v != nil {
|
||||
m, ok := tree[id]
|
||||
if !ok {
|
||||
m = make(map[string]any)
|
||||
tree[id] = m
|
||||
}
|
||||
m[name] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (tree JSONTree) Print(out io.Writer) error {
|
||||
data, err := json.MarshalIndent(tree, "", "\t")
|
||||
if err != nil {
|
||||
log.Panicf("internal error: JSON marshaling failed: %v", err)
|
||||
}
|
||||
_, err = fmt.Fprintf(out, "%s\n", data)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
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
|
|
@ -15,7 +15,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -23,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "appends",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "appends"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "appends"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/appends",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
generated
vendored
4
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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
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 := analysisinternal.ReadFile(pass, fname)
|
||||
content, tf, err := analyzerutil.ReadFile(pass, fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
generated
vendored
|
|
@ -18,7 +18,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
|
|
@ -29,7 +29,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "assign",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "assign"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "assign"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
|
@ -23,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "atomic",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "atomic"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "atomic"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
RunDespiteErrors: true,
|
||||
|
|
|
|||
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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
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 := analysisinternal.ReadFile(pass, filename)
|
||||
content, tf, err := analyzerutil.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
|
|
@ -350,8 +350,8 @@ func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
|
|||
case *types.Array:
|
||||
return typeOKForCgoCall(t.Elem(), m)
|
||||
case *types.Struct:
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
if !typeOKForCgoCall(t.Field(i).Type(), m) {
|
||||
for field := range t.Fields() {
|
||||
if !typeOKForCgoCall(field.Type(), m) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
generated
vendored
|
|
@ -328,8 +328,8 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
|
|||
|
||||
ttyp, ok := typ.Underlying().(*types.Tuple)
|
||||
if ok {
|
||||
for i := 0; i < ttyp.Len(); i++ {
|
||||
subpath := lockPath(tpkg, ttyp.At(i).Type(), seen)
|
||||
for v := range ttyp.Variables() {
|
||||
subpath := lockPath(tpkg, v.Type(), seen)
|
||||
if subpath != nil {
|
||||
return append(subpath, typ.String())
|
||||
}
|
||||
|
|
|
|||
90
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go
generated
vendored
90
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go
generated
vendored
|
|
@ -16,9 +16,12 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/go/cfg"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/cfginternal"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
|
|
@ -26,7 +29,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
Doc: "build a control-flow graph",
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ctrlflow",
|
||||
Run: run,
|
||||
ResultType: reflect.TypeOf(new(CFGs)),
|
||||
ResultType: reflect.TypeFor[*CFGs](),
|
||||
FactTypes: []analysis.Fact{new(noReturn)},
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
}
|
||||
|
|
@ -44,7 +47,20 @@ type CFGs struct {
|
|||
defs map[*ast.Ident]types.Object // from Pass.TypesInfo.Defs
|
||||
funcDecls map[*types.Func]*declInfo
|
||||
funcLits map[*ast.FuncLit]*litInfo
|
||||
pass *analysis.Pass // transient; nil after construction
|
||||
noReturn map[*types.Func]bool // functions lacking a reachable return statement
|
||||
pass *analysis.Pass // transient; nil after construction
|
||||
}
|
||||
|
||||
// TODO(adonovan): add (*CFGs).NoReturn to public API.
|
||||
func (c *CFGs) isNoReturn(fn *types.Func) bool {
|
||||
return c.noReturn[fn]
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Expose the hidden method to callers in x/tools.
|
||||
ctrlflowinternal.NoReturn = func(c any, fn *types.Func) bool {
|
||||
return c.(*CFGs).isNoReturn(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// CFGs has two maps: funcDecls for named functions and funcLits for
|
||||
|
|
@ -54,15 +70,14 @@ type CFGs struct {
|
|||
// *types.Func but not the other way.
|
||||
|
||||
type declInfo struct {
|
||||
decl *ast.FuncDecl
|
||||
cfg *cfg.CFG // iff decl.Body != nil
|
||||
started bool // to break cycles
|
||||
noReturn bool
|
||||
decl *ast.FuncDecl
|
||||
cfg *cfg.CFG // iff decl.Body != nil
|
||||
started bool // to break cycles
|
||||
}
|
||||
|
||||
type litInfo struct {
|
||||
cfg *cfg.CFG
|
||||
noReturn bool
|
||||
noReturn bool // (currently unused)
|
||||
}
|
||||
|
||||
// FuncDecl returns the control-flow graph for a named function.
|
||||
|
|
@ -118,6 +133,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
defs: pass.TypesInfo.Defs,
|
||||
funcDecls: funcDecls,
|
||||
funcLits: funcLits,
|
||||
noReturn: make(map[*types.Func]bool),
|
||||
pass: pass,
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +154,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
li := funcLits[lit]
|
||||
if li.cfg == nil {
|
||||
li.cfg = cfg.New(lit.Body, c.callMayReturn)
|
||||
if !hasReachableReturn(li.cfg) {
|
||||
if cfginternal.IsNoReturn(li.cfg) {
|
||||
li.noReturn = true
|
||||
}
|
||||
}
|
||||
|
|
@ -158,27 +174,28 @@ func (c *CFGs) buildDecl(fn *types.Func, di *declInfo) {
|
|||
// The buildDecl call tree thus resembles the static call graph.
|
||||
// We mark each node when we start working on it to break cycles.
|
||||
|
||||
if !di.started { // break cycle
|
||||
di.started = true
|
||||
if di.started {
|
||||
return // break cycle
|
||||
}
|
||||
di.started = true
|
||||
|
||||
if isIntrinsicNoReturn(fn) {
|
||||
di.noReturn = true
|
||||
}
|
||||
if di.decl.Body != nil {
|
||||
di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
|
||||
if !hasReachableReturn(di.cfg) {
|
||||
di.noReturn = true
|
||||
}
|
||||
}
|
||||
if di.noReturn {
|
||||
c.pass.ExportObjectFact(fn, new(noReturn))
|
||||
}
|
||||
noreturn := isIntrinsicNoReturn(fn)
|
||||
|
||||
// debugging
|
||||
if false {
|
||||
log.Printf("CFG for %s:\n%s (noreturn=%t)\n", fn, di.cfg.Format(c.pass.Fset), di.noReturn)
|
||||
if di.decl.Body != nil {
|
||||
di.cfg = cfg.New(di.decl.Body, c.callMayReturn)
|
||||
if cfginternal.IsNoReturn(di.cfg) {
|
||||
noreturn = true
|
||||
}
|
||||
}
|
||||
if noreturn {
|
||||
c.pass.ExportObjectFact(fn, new(noReturn))
|
||||
c.noReturn[fn] = true
|
||||
}
|
||||
|
||||
// debugging
|
||||
if false {
|
||||
log.Printf("CFG for %s:\n%s (noreturn=%t)\n", fn, di.cfg.Format(c.pass.Fset), noreturn)
|
||||
}
|
||||
}
|
||||
|
||||
// callMayReturn reports whether the called function may return.
|
||||
|
|
@ -201,31 +218,26 @@ func (c *CFGs) callMayReturn(call *ast.CallExpr) (r bool) {
|
|||
// Function or method declared in this package?
|
||||
if di, ok := c.funcDecls[fn]; ok {
|
||||
c.buildDecl(fn, di)
|
||||
return !di.noReturn
|
||||
return !c.noReturn[fn]
|
||||
}
|
||||
|
||||
// Not declared in this package.
|
||||
// Is there a fact from another package?
|
||||
return !c.pass.ImportObjectFact(fn, new(noReturn))
|
||||
if c.pass.ImportObjectFact(fn, new(noReturn)) {
|
||||
c.noReturn[fn] = true
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var panicBuiltin = types.Universe.Lookup("panic").(*types.Builtin)
|
||||
|
||||
func hasReachableReturn(g *cfg.CFG) bool {
|
||||
for _, b := range g.Blocks {
|
||||
if b.Live && b.Return() != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isIntrinsicNoReturn reports whether a function intrinsically never
|
||||
// returns because it stops execution of the calling thread.
|
||||
// It is the base case in the recursion.
|
||||
func isIntrinsicNoReturn(fn *types.Func) bool {
|
||||
// Add functions here as the need arises, but don't allocate memory.
|
||||
path, name := fn.Pkg().Path(), fn.Name()
|
||||
return path == "syscall" && (name == "Exit" || name == "ExitProcess" || name == "ExitThread") ||
|
||||
path == "runtime" && name == "Goexit"
|
||||
return typesinternal.IsFunctionNamed(fn, "syscall", "Exit", "ExitProcess", "ExitThread") ||
|
||||
typesinternal.IsFunctionNamed(fn, "runtime", "Goexit")
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
generated
vendored
|
|
@ -12,7 +12,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ var doc string
|
|||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "defers",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "defers"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "defers"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
|
||||
Run: run,
|
||||
}
|
||||
|
|
|
|||
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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
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 := analysisinternal.ReadFile(pass, filename)
|
||||
content, tf, err := analyzerutil.ReadFile(pass, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
generated
vendored
|
|
@ -12,7 +12,7 @@ import (
|
|||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
)
|
||||
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go
generated
vendored
4
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/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
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 := analysisinternal.ReadFile(pass, fname)
|
||||
content, tf, err := analyzerutil.ReadFile(pass, fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/hostport/hostport.go
generated
vendored
|
|
@ -17,7 +17,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
)
|
||||
|
||||
|
|
|
|||
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
|
|
@ -12,7 +12,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "ifaceassert",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "ifaceassert"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "ifaceassert"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@ import (
|
|||
"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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/diff"
|
||||
"golang.org/x/tools/internal/moreiters"
|
||||
"golang.org/x/tools/internal/packagepath"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/refactor/inline"
|
||||
|
|
@ -34,7 +35,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "inline",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "inline"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "inline"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inline",
|
||||
Run: run,
|
||||
FactTypes: []analysis.Fact{
|
||||
|
|
@ -132,8 +133,6 @@ func (a *analyzer) HandleConst(nameIdent, rhsIdent *ast.Ident) {
|
|||
|
||||
// inline inlines each static call to an inlinable function
|
||||
// and each reference to an inlinable constant or type alias.
|
||||
//
|
||||
// TODO(adonovan): handle multiple diffs that each add the same import.
|
||||
func (a *analyzer) inline() {
|
||||
for cur := range a.root.Preorder((*ast.CallExpr)(nil), (*ast.Ident)(nil)) {
|
||||
switch n := cur.Node().(type) {
|
||||
|
|
@ -167,6 +166,10 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
|
|||
return // nope
|
||||
}
|
||||
|
||||
if a.withinTestOf(cur, fn) {
|
||||
return // don't inline a function from within its own test
|
||||
}
|
||||
|
||||
// Inline the call.
|
||||
content, err := a.readFile(call)
|
||||
if err != nil {
|
||||
|
|
@ -229,6 +232,44 @@ func (a *analyzer) inlineCall(call *ast.CallExpr, cur inspector.Cursor) {
|
|||
}
|
||||
}
|
||||
|
||||
// withinTestOf reports whether cur is within a dedicated test
|
||||
// function for the inlinable target function.
|
||||
// A call within its dedicated test should not be inlined.
|
||||
func (a *analyzer) withinTestOf(cur inspector.Cursor, target *types.Func) bool {
|
||||
curFuncDecl, ok := moreiters.First(cur.Enclosing((*ast.FuncDecl)(nil)))
|
||||
if !ok {
|
||||
return false // not in a function
|
||||
}
|
||||
funcDecl := curFuncDecl.Node().(*ast.FuncDecl)
|
||||
if funcDecl.Recv != nil {
|
||||
return false // not a test func
|
||||
}
|
||||
if strings.TrimSuffix(a.pass.Pkg.Path(), "_test") != target.Pkg().Path() {
|
||||
return false // different package
|
||||
}
|
||||
if !strings.HasSuffix(a.pass.Fset.File(funcDecl.Pos()).Name(), "_test.go") {
|
||||
return false // not a test file
|
||||
}
|
||||
|
||||
// Computed expected SYMBOL portion of "TestSYMBOL_comment"
|
||||
// for the target symbol.
|
||||
symbol := target.Name()
|
||||
if recv := target.Signature().Recv(); recv != nil {
|
||||
_, named := typesinternal.ReceiverNamed(recv)
|
||||
symbol = named.Obj().Name() + "_" + symbol
|
||||
}
|
||||
|
||||
// TODO(adonovan): use a proper Test function parser.
|
||||
fname := funcDecl.Name.Name
|
||||
for _, pre := range []string{"Test", "Example", "Bench"} {
|
||||
if fname == pre+symbol || strings.HasPrefix(fname, pre+symbol+"_") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// If tn is the TypeName of an inlinable alias, suggest inlining its use at cur.
|
||||
func (a *analyzer) inlineAlias(tn *types.TypeName, curId inspector.Cursor) {
|
||||
inalias, ok := a.inlinableAliases[tn]
|
||||
|
|
@ -375,8 +416,8 @@ func typenames(t types.Type) []*types.TypeName {
|
|||
visit(t.Key())
|
||||
visit(t.Elem())
|
||||
case *types.Struct:
|
||||
for i := range t.NumFields() {
|
||||
visit(t.Field(i).Type())
|
||||
for field := range t.Fields() {
|
||||
visit(field.Type())
|
||||
}
|
||||
case *types.Signature:
|
||||
// Ignore the receiver: although it may be present, it has no meaning
|
||||
|
|
@ -389,11 +430,11 @@ func typenames(t types.Type) []*types.TypeName {
|
|||
visit(t.Params())
|
||||
visit(t.Results())
|
||||
case *types.Interface:
|
||||
for i := range t.NumEmbeddeds() {
|
||||
visit(t.EmbeddedType(i))
|
||||
for etyp := range t.EmbeddedTypes() {
|
||||
visit(etyp)
|
||||
}
|
||||
for i := range t.NumExplicitMethods() {
|
||||
visit(t.ExplicitMethod(i).Type())
|
||||
for method := range t.ExplicitMethods() {
|
||||
visit(method.Type())
|
||||
}
|
||||
case *types.Tuple:
|
||||
for v := range t.Variables() {
|
||||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
generated
vendored
|
|
@ -41,7 +41,7 @@ var Analyzer = &analysis.Analyzer{
|
|||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inspect",
|
||||
Run: run,
|
||||
RunDespiteErrors: true,
|
||||
ResultType: reflect.TypeOf(new(inspector.Inspector)),
|
||||
ResultType: reflect.TypeFor[*inspector.Inspector](),
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (any, error) {
|
||||
|
|
|
|||
17
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go
generated
vendored
Normal file
17
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/ctrlflowinternal/ctrlflowinternal.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// 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 ctrlflowinternal exposes internals of ctrlflow.
|
||||
// It cannot actually depend on symbols from ctrlflow.
|
||||
package ctrlflowinternal
|
||||
|
||||
import "go/types"
|
||||
|
||||
// NoReturn exposes the (*ctrlflow.CFGs).NoReturn method to the buildssa analyzer.
|
||||
//
|
||||
// You must link [golang.org/x/tools/go/analysis/passes/ctrlflow] into your
|
||||
// application for it to be non-nil.
|
||||
var NoReturn = func(cfgs any, fn *types.Func) bool {
|
||||
panic("x/tools/go/analysis/passes/ctrlflow is not linked into this application")
|
||||
}
|
||||
43
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
43
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
|
@ -23,7 +23,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "loopclosure",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "loopclosure"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "loopclosure"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -55,8 +55,8 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
switch n := n.(type) {
|
||||
case *ast.File:
|
||||
// Only traverse the file if its goversion is strictly before go1.22.
|
||||
goversion := versions.FileVersion(pass.TypesInfo, n)
|
||||
return versions.Before(goversion, versions.Go1_22)
|
||||
return !analyzerutil.FileUsesGoVersion(pass, n, versions.Go1_22)
|
||||
|
||||
case *ast.RangeStmt:
|
||||
body = n.Body
|
||||
addVar(n.Key)
|
||||
|
|
@ -308,12 +308,11 @@ func parallelSubtest(info *types.Info, call *ast.CallExpr) []ast.Stmt {
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
expr := exprStmt.X
|
||||
if isMethodCall(info, expr, "testing", "T", "Parallel") {
|
||||
call, _ := expr.(*ast.CallExpr)
|
||||
if call == nil {
|
||||
continue
|
||||
}
|
||||
call, ok := exprStmt.X.(*ast.CallExpr)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if isMethodCall(info, call, "testing", "T", "Parallel") {
|
||||
x, _ := call.Fun.(*ast.SelectorExpr)
|
||||
if x == nil {
|
||||
continue
|
||||
|
|
@ -347,26 +346,6 @@ func unlabel(stmt ast.Stmt) (ast.Stmt, bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// isMethodCall reports whether expr is a method call of
|
||||
// <pkgPath>.<typeName>.<method>.
|
||||
func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method string) bool {
|
||||
call, ok := expr.(*ast.CallExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that we are calling a method <method>
|
||||
f := typeutil.StaticCallee(info, call)
|
||||
if f == nil || f.Name() != method {
|
||||
return false
|
||||
}
|
||||
recv := f.Type().(*types.Signature).Recv()
|
||||
if recv == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that the receiver is a <pkgPath>.<typeName> or
|
||||
// *<pkgPath>.<typeName>.
|
||||
_, named := typesinternal.ReceiverNamed(recv)
|
||||
return typesinternal.IsTypeNamed(named, pkgPath, typeName)
|
||||
func isMethodCall(info *types.Info, call *ast.CallExpr, pkgPath, typeName, method string) bool {
|
||||
return typesinternal.IsMethodNamed(typeutil.Callee(info, call), pkgPath, typeName, method)
|
||||
}
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
generated
vendored
|
|
@ -15,7 +15,7 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/go/cfg"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
|
@ -25,7 +25,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "lostcancel",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "lostcancel"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "lostcancel"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
|
||||
Run: run,
|
||||
Requires: []*analysis.Analyzer{
|
||||
|
|
@ -316,8 +316,8 @@ outer:
|
|||
}
|
||||
|
||||
func tupleContains(tuple *types.Tuple, v *types.Var) bool {
|
||||
for i := 0; i < tuple.Len(); i++ {
|
||||
if tuple.At(i) == v {
|
||||
for v0 := range tuple.Variables() {
|
||||
if v0 == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go
generated
vendored
24
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/any.go
generated
vendored
|
|
@ -9,29 +9,21 @@ 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/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var AnyAnalyzer = &analysis.Analyzer{
|
||||
Name: "any",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "any"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: runAny,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#any",
|
||||
Name: "any",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "any"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: runAny,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#any",
|
||||
}
|
||||
|
||||
// The any pass replaces interface{} with go1.18's 'any'.
|
||||
func runAny(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
||||
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.18") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_18) {
|
||||
for curIface := range curFile.Preorder((*ast.InterfaceType)(nil)) {
|
||||
iface := curIface.Node().(*ast.InterfaceType)
|
||||
|
||||
|
|
|
|||
36
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go
generated
vendored
36
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/bloop.go
generated
vendored
|
|
@ -15,20 +15,19 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/moreiters"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var BLoopAnalyzer = &analysis.Analyzer{
|
||||
Name: "bloop",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "bloop"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "bloop"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -45,16 +44,13 @@ var BLoopAnalyzer = &analysis.Analyzer{
|
|||
// for i := 0; i < b.N; i++ {} => for b.Loop() {}
|
||||
// for range b.N {}
|
||||
func bloop(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
if !typesinternal.Imports(pass.Pkg, "testing") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
)
|
||||
|
||||
// edits computes the text edits for a matched for/range loop
|
||||
|
|
@ -102,7 +98,7 @@ func bloop(pass *analysis.Pass) (any, error) {
|
|||
(*ast.ForStmt)(nil),
|
||||
(*ast.RangeStmt)(nil),
|
||||
}
|
||||
for curFile := range filesUsing(inspect, info, "go1.24") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
|
||||
for curLoop := range curFile.Preorder(loops...) {
|
||||
switch n := curLoop.Node().(type) {
|
||||
case *ast.ForStmt:
|
||||
|
|
@ -189,6 +185,7 @@ func enclosingFunc(c inspector.Cursor) (inspector.Cursor, bool) {
|
|||
// 2. The only b.N loop in that benchmark function
|
||||
// - b.Loop() can only be called once per benchmark execution
|
||||
// - Multiple calls result in "B.Loop called with timer stopped" error
|
||||
// - Multiple loops may have complex interdependencies that are hard to analyze
|
||||
func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
|
||||
// Find the enclosing benchmark function
|
||||
curFunc, ok := enclosingFunc(c)
|
||||
|
|
@ -205,17 +202,14 @@ func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Count b.N references in this benchmark function
|
||||
// Count all b.N references in this benchmark function (including nested functions)
|
||||
bnRefCount := 0
|
||||
filter := []ast.Node{(*ast.SelectorExpr)(nil), (*ast.FuncLit)(nil)}
|
||||
filter := []ast.Node{(*ast.SelectorExpr)(nil)}
|
||||
curFunc.Inspect(filter, func(cur inspector.Cursor) bool {
|
||||
switch n := cur.Node().(type) {
|
||||
case *ast.FuncLit:
|
||||
return false // don't descend into nested function literals
|
||||
case *ast.SelectorExpr:
|
||||
if n.Sel.Name == "N" && typesinternal.IsPointerToNamed(info.TypeOf(n.X), "testing", "B") {
|
||||
bnRefCount++
|
||||
}
|
||||
sel := cur.Node().(*ast.SelectorExpr)
|
||||
if sel.Sel.Name == "N" &&
|
||||
typesinternal.IsPointerToNamed(info.TypeOf(sel.X), "testing", "B") {
|
||||
bnRefCount++
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
|
@ -240,7 +234,7 @@ func isIncrementLoop(info *types.Info, loop *ast.ForStmt) *types.Var {
|
|||
if assign, ok := loop.Init.(*ast.AssignStmt); ok &&
|
||||
assign.Tok == token.DEFINE &&
|
||||
len(assign.Rhs) == 1 &&
|
||||
isZeroIntLiteral(info, assign.Rhs[0]) &&
|
||||
isZeroIntConst(info, assign.Rhs[0]) &&
|
||||
is[*ast.IncDecStmt](loop.Post) &&
|
||||
loop.Post.(*ast.IncDecStmt).Tok == token.INC &&
|
||||
astutil.EqualSyntax(loop.Post.(*ast.IncDecStmt).X, assign.Lhs[0]) {
|
||||
|
|
|
|||
46
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go
generated
vendored
46
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/doc.go
generated
vendored
|
|
@ -176,8 +176,12 @@ This analyzer finds declarations of functions of this form:
|
|||
and suggests a fix to turn them into inlinable wrappers around
|
||||
go1.26's built-in new(expr) function:
|
||||
|
||||
//go:fix inline
|
||||
func varOf(x int) *int { return new(x) }
|
||||
|
||||
(The directive comment causes the 'inline' analyzer to suggest
|
||||
that calls to such functions are inlined.)
|
||||
|
||||
In addition, this analyzer suggests a fix for each call
|
||||
to one of the functions before it is transformed, so that
|
||||
|
||||
|
|
@ -187,9 +191,9 @@ is replaced by:
|
|||
|
||||
use(new(123))
|
||||
|
||||
(Wrapper functions such as varOf are common when working with Go
|
||||
Wrapper functions such as varOf are common when working with Go
|
||||
serialization packages such as for JSON or protobuf, where pointers
|
||||
are often used to express optionality.)
|
||||
are often used to express optionality.
|
||||
|
||||
# Analyzer omitzero
|
||||
|
||||
|
|
@ -327,6 +331,44 @@ iterator offered by the same data type:
|
|||
|
||||
where x is one of various well-known types in the standard library.
|
||||
|
||||
# Analyzer stringscut
|
||||
|
||||
stringscut: replace strings.Index etc. with strings.Cut
|
||||
|
||||
This analyzer replaces certain patterns of use of [strings.Index] and string slicing by [strings.Cut], added in go1.18.
|
||||
|
||||
For example:
|
||||
|
||||
idx := strings.Index(s, substr)
|
||||
if idx >= 0 {
|
||||
return s[:idx]
|
||||
}
|
||||
|
||||
is replaced by:
|
||||
|
||||
before, _, ok := strings.Cut(s, substr)
|
||||
if ok {
|
||||
return before
|
||||
}
|
||||
|
||||
And:
|
||||
|
||||
idx := strings.Index(s, substr)
|
||||
if idx >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
is replaced by:
|
||||
|
||||
found := strings.Contains(s, substr)
|
||||
if found {
|
||||
return
|
||||
}
|
||||
|
||||
It also handles variants using [strings.IndexByte] instead of Index, or the bytes package instead of strings.
|
||||
|
||||
Fixes are offered only in cases in which there are no potential modifications of the idx, s, or substr expressions between their definition and use.
|
||||
|
||||
# Analyzer stringscutprefix
|
||||
|
||||
stringscutprefix: replace HasPrefix/TrimPrefix with CutPrefix
|
||||
|
|
|
|||
16
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go
generated
vendored
16
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/errorsastype.go
generated
vendored
|
|
@ -14,21 +14,21 @@ import (
|
|||
"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/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/goplsexport"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var errorsastypeAnalyzer = &analysis.Analyzer{
|
||||
Name: "errorsastype",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "errorsastype"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "errorsastype"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#errorsastype",
|
||||
Requires: []*analysis.Analyzer{generated.Analyzer, typeindexanalyzer.Analyzer},
|
||||
Requires: []*analysis.Analyzer{typeindexanalyzer.Analyzer},
|
||||
Run: errorsastype,
|
||||
}
|
||||
|
||||
|
|
@ -78,8 +78,6 @@ func init() {
|
|||
//
|
||||
// - if errors.As(err, myerr) && othercond { ... }
|
||||
func errorsastype(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
|
@ -97,7 +95,7 @@ func errorsastype(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
file := astutil.EnclosingFile(curDeclStmt)
|
||||
if !fileUses(info, file, "go1.26") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
|
||||
continue // errors.AsType is too new
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +125,8 @@ func errorsastype(pass *analysis.Pass) (any, error) {
|
|||
errtype := types.TypeString(v.Type(), qual)
|
||||
|
||||
// Choose a name for the "ok" variable.
|
||||
// TODO(adonovan): this pattern also appears in stditerators,
|
||||
// and is wanted elsewhere; factor.
|
||||
okName := "ok"
|
||||
if okVar := lookup(info, curCall, "ok"); okVar != nil {
|
||||
// The name 'ok' is already declared, but
|
||||
|
|
|
|||
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go
generated
vendored
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/fmtappendf.go
generated
vendored
|
|
@ -13,18 +13,17 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var FmtAppendfAnalyzer = &analysis.Analyzer{
|
||||
Name: "fmtappendf",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "fmtappendf"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "fmtappendf"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -35,8 +34,6 @@ var FmtAppendfAnalyzer = &analysis.Analyzer{
|
|||
// The fmtappend function replaces []byte(fmt.Sprintf(...)) by
|
||||
// fmt.Appendf(nil, ...), and similarly for Sprint, Sprintln.
|
||||
func fmtappendf(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
index := pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
for _, fn := range []types.Object{
|
||||
index.Object("fmt", "Sprintf"),
|
||||
|
|
@ -50,7 +47,7 @@ func fmtappendf(pass *analysis.Pass) (any, error) {
|
|||
conv := curCall.Parent().Node().(*ast.CallExpr)
|
||||
tv := pass.TypesInfo.Types[conv.Fun]
|
||||
if tv.IsType() && types.Identical(tv.Type, byteSliceType) &&
|
||||
fileUses(pass.TypesInfo, astutil.EnclosingFile(curCall), "go1.19") {
|
||||
analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_19) {
|
||||
// Have: []byte(fmt.SprintX(...))
|
||||
|
||||
// Find "Sprint" identifier.
|
||||
|
|
|
|||
99
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go
generated
vendored
99
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/forvar.go
generated
vendored
|
|
@ -10,22 +10,18 @@ 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/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var ForVarAnalyzer = &analysis.Analyzer{
|
||||
Name: "forvar",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "forvar"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: forvar,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#forvar",
|
||||
Name: "forvar",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "forvar"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: forvar,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#forvar",
|
||||
}
|
||||
|
||||
// forvar offers to fix unnecessary copying of a for variable
|
||||
|
|
@ -39,54 +35,77 @@ var ForVarAnalyzer = &analysis.Analyzer{
|
|||
// where the two idents are the same,
|
||||
// and the ident is defined (:=) as a variable in the for statement.
|
||||
// (Note that this 'fix' does not work for three clause loops
|
||||
// because the Go specification says "The variable used by each subsequent iteration
|
||||
// because the Go specfilesUsingGoVersionsays "The variable used by each subsequent iteration
|
||||
// is declared implicitly before executing the post statement and initialized to the
|
||||
// value of the previous iteration's variable at that moment.")
|
||||
//
|
||||
// Variant: same thing in an IfStmt.Init, when the IfStmt is the sole
|
||||
// loop body statement:
|
||||
//
|
||||
// for _, x := range foo {
|
||||
// if x := x; cond { ... }
|
||||
// }
|
||||
//
|
||||
// (The restriction is necessary to avoid potential problems arising
|
||||
// from merging two distinct variables.)
|
||||
//
|
||||
// This analyzer is synergistic with stditerators,
|
||||
// which may create redundant "x := x" statements.
|
||||
func forvar(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.22") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_22) {
|
||||
for curLoop := range curFile.Preorder((*ast.RangeStmt)(nil)) {
|
||||
loop := curLoop.Node().(*ast.RangeStmt)
|
||||
if loop.Tok != token.DEFINE {
|
||||
continue
|
||||
}
|
||||
isLoopVarRedecl := func(assign *ast.AssignStmt) bool {
|
||||
for i, lhs := range assign.Lhs {
|
||||
if !(astutil.EqualSyntax(lhs, assign.Rhs[i]) &&
|
||||
(astutil.EqualSyntax(lhs, loop.Key) || astutil.EqualSyntax(lhs, loop.Value))) {
|
||||
return false
|
||||
isLoopVarRedecl := func(stmt ast.Stmt) bool {
|
||||
if assign, ok := stmt.(*ast.AssignStmt); ok &&
|
||||
assign.Tok == token.DEFINE &&
|
||||
len(assign.Lhs) == len(assign.Rhs) {
|
||||
|
||||
for i, lhs := range assign.Lhs {
|
||||
if !(astutil.EqualSyntax(lhs, assign.Rhs[i]) &&
|
||||
(astutil.EqualSyntax(lhs, loop.Key) ||
|
||||
astutil.EqualSyntax(lhs, loop.Value))) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
// Have: for k, v := range x { stmts }
|
||||
//
|
||||
// Delete the prefix of stmts that are
|
||||
// of the form k := k; v := v; k, v := k, v; v, k := v, k.
|
||||
for _, stmt := range loop.Body.List {
|
||||
if assign, ok := stmt.(*ast.AssignStmt); ok &&
|
||||
assign.Tok == token.DEFINE &&
|
||||
len(assign.Lhs) == len(assign.Rhs) &&
|
||||
isLoopVarRedecl(assign) {
|
||||
|
||||
curStmt, _ := curLoop.FindNode(stmt)
|
||||
edits := refactor.DeleteStmt(pass.Fset.File(stmt.Pos()), curStmt)
|
||||
if len(edits) > 0 {
|
||||
pass.Report(analysis.Diagnostic{
|
||||
Pos: stmt.Pos(),
|
||||
End: stmt.End(),
|
||||
Message: "copying variable is unneeded",
|
||||
SuggestedFixes: []analysis.SuggestedFix{{
|
||||
Message: "Remove unneeded redeclaration",
|
||||
TextEdits: edits,
|
||||
}},
|
||||
})
|
||||
}
|
||||
if isLoopVarRedecl(stmt) {
|
||||
// { x := x; ... }
|
||||
// ------
|
||||
} else if ifstmt, ok := stmt.(*ast.IfStmt); ok &&
|
||||
ifstmt.Init != nil &&
|
||||
len(loop.Body.List) == 1 && // must be sole statement in loop body
|
||||
isLoopVarRedecl(ifstmt.Init) {
|
||||
// if x := x; cond {
|
||||
// ------
|
||||
stmt = ifstmt.Init
|
||||
} else {
|
||||
break // stop at first other statement
|
||||
}
|
||||
|
||||
curStmt, _ := curLoop.FindNode(stmt)
|
||||
edits := refactor.DeleteStmt(pass.Fset.File(stmt.Pos()), curStmt)
|
||||
if len(edits) > 0 {
|
||||
pass.Report(analysis.Diagnostic{
|
||||
Pos: stmt.Pos(),
|
||||
End: stmt.End(),
|
||||
Message: "copying variable is unneeded",
|
||||
SuggestedFixes: []analysis.SuggestedFix{{
|
||||
Message: "Remove unneeded redeclaration",
|
||||
TextEdits: edits,
|
||||
}},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go
generated
vendored
22
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/maps.go
generated
vendored
|
|
@ -15,23 +15,20 @@ 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/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var MapsLoopAnalyzer = &analysis.Analyzer{
|
||||
Name: "mapsloop",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "mapsloop"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: mapsloop,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#mapsloop",
|
||||
Name: "mapsloop",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "mapsloop"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: mapsloop,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#mapsloop",
|
||||
}
|
||||
|
||||
// The mapsloop pass offers to simplify a loop of map insertions:
|
||||
|
|
@ -55,8 +52,6 @@ var MapsLoopAnalyzer = &analysis.Analyzer{
|
|||
// m = make(M)
|
||||
// m = M{}
|
||||
func mapsloop(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "maps", "bytes", "runtime") {
|
||||
|
|
@ -223,8 +218,7 @@ func mapsloop(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
// Find all range loops around m[k] = v.
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.23") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_23) {
|
||||
file := curFile.Node().(*ast.File)
|
||||
|
||||
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
|
||||
|
|
|
|||
14
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go
generated
vendored
14
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/minmax.go
generated
vendored
|
|
@ -15,19 +15,18 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var MinMaxAnalyzer = &analysis.Analyzer{
|
||||
Name: "minmax",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "minmax"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "minmax"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -56,8 +55,6 @@ var MinMaxAnalyzer = &analysis.Analyzer{
|
|||
// - "x := a" or "x = a" or "var x = a" in pattern 2
|
||||
// - "x < b" or "a < b" in pattern 2
|
||||
func minmax(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Check for user-defined min/max functions that can be removed
|
||||
checkUserDefinedMinMax(pass)
|
||||
|
||||
|
|
@ -201,8 +198,7 @@ func minmax(pass *analysis.Pass) (any, error) {
|
|||
|
||||
// Find all "if a < b { lhs = rhs }" statements.
|
||||
info := pass.TypesInfo
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
for curFile := range filesUsing(inspect, info, "go1.21") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
|
||||
astFile := curFile.Node().(*ast.File)
|
||||
for curIfStmt := range curFile.Preorder((*ast.IfStmt)(nil)) {
|
||||
ifStmt := curIfStmt.Node().(*ast.IfStmt)
|
||||
|
|
|
|||
49
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go
generated
vendored
49
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/modernize.go
generated
vendored
|
|
@ -16,15 +16,15 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/moreiters"
|
||||
"golang.org/x/tools/internal/packagepath"
|
||||
"golang.org/x/tools/internal/stdlib"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -48,6 +48,7 @@ var Suite = []*analysis.Analyzer{
|
|||
// SlicesDeleteAnalyzer, // not nil-preserving!
|
||||
SlicesSortAnalyzer,
|
||||
stditeratorsAnalyzer,
|
||||
stringscutAnalyzer,
|
||||
StringsCutPrefixAnalyzer,
|
||||
StringsSeqAnalyzer,
|
||||
StringsBuilderAnalyzer,
|
||||
|
|
@ -57,18 +58,6 @@ var Suite = []*analysis.Analyzer{
|
|||
|
||||
// -- helpers --
|
||||
|
||||
// skipGenerated decorates pass.Report to suppress diagnostics in generated files.
|
||||
func skipGenerated(pass *analysis.Pass) {
|
||||
report := pass.Report
|
||||
pass.Report = func(diag analysis.Diagnostic) {
|
||||
generated := pass.ResultOf[generated.Analyzer].(*generated.Result)
|
||||
if generated.IsGenerated(diag.Pos) {
|
||||
return // skip
|
||||
}
|
||||
report(diag)
|
||||
}
|
||||
}
|
||||
|
||||
// formatExprs formats a comma-separated list of expressions.
|
||||
func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
|
||||
var buf strings.Builder
|
||||
|
|
@ -81,8 +70,8 @@ func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// isZeroIntLiteral reports whether e is an integer whose value is 0.
|
||||
func isZeroIntLiteral(info *types.Info, e ast.Expr) bool {
|
||||
// isZeroIntConst reports whether e is an integer whose value is 0.
|
||||
func isZeroIntConst(info *types.Info, e ast.Expr) bool {
|
||||
return isIntLiteral(info, e, 0)
|
||||
}
|
||||
|
||||
|
|
@ -91,36 +80,28 @@ func isIntLiteral(info *types.Info, e ast.Expr, n int64) bool {
|
|||
return info.Types[e].Value == constant.MakeInt64(n)
|
||||
}
|
||||
|
||||
// filesUsing returns a cursor for each *ast.File in the inspector
|
||||
// filesUsingGoVersion returns a cursor for each *ast.File in the inspector
|
||||
// that uses at least the specified version of Go (e.g. "go1.24").
|
||||
//
|
||||
// The pass's analyzer must require [inspect.Analyzer].
|
||||
//
|
||||
// TODO(adonovan): opt: eliminate this function, instead following the
|
||||
// approach of [fmtappendf], which uses typeindex and [fileUses].
|
||||
// See "Tip" at [fileUses] for motivation.
|
||||
func filesUsing(inspect *inspector.Inspector, info *types.Info, version string) iter.Seq[inspector.Cursor] {
|
||||
// approach of [fmtappendf], which uses typeindex and
|
||||
// [analyzerutil.FileUsesGoVersion]; see "Tip" documented at the
|
||||
// latter function for motivation.
|
||||
func filesUsingGoVersion(pass *analysis.Pass, version string) iter.Seq[inspector.Cursor] {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
||||
return func(yield func(inspector.Cursor) bool) {
|
||||
for curFile := range inspect.Root().Children() {
|
||||
file := curFile.Node().(*ast.File)
|
||||
if !versions.Before(info.FileVersions[file], version) && !yield(curFile) {
|
||||
if analyzerutil.FileUsesGoVersion(pass, file, version) && !yield(curFile) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fileUses reports whether the specified file uses at least the
|
||||
// specified version of Go (e.g. "go1.24").
|
||||
//
|
||||
// Tip: we recommend using this check "late", just before calling
|
||||
// pass.Report, rather than "early" (when entering each ast.File, or
|
||||
// each candidate node of interest, during the traversal), because the
|
||||
// operation is not free, yet is not a highly selective filter: the
|
||||
// fraction of files that pass most version checks is high and
|
||||
// increases over time.
|
||||
func fileUses(info *types.Info, file *ast.File, version string) bool {
|
||||
return !versions.Before(info.FileVersions[file], version)
|
||||
}
|
||||
|
||||
// within reports whether the current pass is analyzing one of the
|
||||
// specified standard packages or their dependencies.
|
||||
func within(pass *analysis.Pass, pkgs ...string) bool {
|
||||
|
|
|
|||
38
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go
generated
vendored
38
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/newexpr.go
generated
vendored
|
|
@ -17,13 +17,14 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var NewExprAnalyzer = &analysis.Analyzer{
|
||||
Name: "newexpr",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "newexpr"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "newexpr"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize#newexpr",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -60,7 +61,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
|
||||
// Check file version.
|
||||
file := astutil.EnclosingFile(curFuncDecl)
|
||||
if !fileUses(info, file, "go1.26") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
|
||||
continue // new(expr) not available in this file
|
||||
}
|
||||
|
||||
|
|
@ -87,25 +88,18 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Disabled until we resolve https://go.dev/issue/75726
|
||||
// (Go version skew between caller and callee in inliner.)
|
||||
// TODO(adonovan): fix and reenable.
|
||||
// Add a //go:fix inline annotation, if not already present.
|
||||
//
|
||||
// Also, restore these lines to our section of doc.go:
|
||||
// //go:fix inline
|
||||
// ...
|
||||
// (The directive comment causes the inline analyzer to suggest
|
||||
// that calls to such functions are inlined.)
|
||||
if false {
|
||||
// Add a //go:fix inline annotation, if not already present.
|
||||
// TODO(adonovan): use ast.ParseDirective when go1.26 is assured.
|
||||
if !strings.Contains(decl.Doc.Text(), "go:fix inline") {
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: decl.Pos(),
|
||||
End: decl.Pos(),
|
||||
NewText: []byte("//go:fix inline\n"),
|
||||
})
|
||||
}
|
||||
// The inliner will not inline a newer callee body into an
|
||||
// older Go file; see https://go.dev/issue/75726.
|
||||
//
|
||||
// TODO(adonovan): use ast.ParseDirective when go1.26 is assured.
|
||||
if !strings.Contains(decl.Doc.Text(), "go:fix inline") {
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: decl.Pos(),
|
||||
End: decl.Pos(),
|
||||
NewText: []byte("//go:fix inline\n"),
|
||||
})
|
||||
}
|
||||
|
||||
if len(edits) > 0 {
|
||||
|
|
@ -140,7 +134,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
|
||||
// Check file version.
|
||||
file := astutil.EnclosingFile(curCall)
|
||||
if !fileUses(info, file, "go1.26") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_26) {
|
||||
continue // new(expr) not available in this file
|
||||
}
|
||||
|
||||
|
|
|
|||
49
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go
generated
vendored
49
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/omitzero.go
generated
vendored
|
|
@ -12,21 +12,17 @@ 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/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var OmitZeroAnalyzer = &analysis.Analyzer{
|
||||
Name: "omitzero",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "omitzero"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: omitzero,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#omitzero",
|
||||
Name: "omitzero",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "omitzero"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: omitzero,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#omitzero",
|
||||
}
|
||||
|
||||
func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Field) {
|
||||
|
|
@ -48,25 +44,20 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
|
|||
// No omitempty in json tag
|
||||
return
|
||||
}
|
||||
omitEmptyPos, omitEmptyEnd, err := astutil.RangeInStringLiteral(curField.Tag, match[2], match[3])
|
||||
omitEmpty, err := astutil.RangeInStringLiteral(curField.Tag, match[2], match[3])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
removePos, removeEnd := omitEmptyPos, omitEmptyEnd
|
||||
var remove analysis.Range = omitEmpty
|
||||
|
||||
jsonTag := reflect.StructTag(tagconv).Get("json")
|
||||
if jsonTag == ",omitempty" {
|
||||
// Remove the entire struct tag if json is the only package used
|
||||
if match[1]-match[0] == len(tagconv) {
|
||||
removePos = curField.Tag.Pos()
|
||||
removeEnd = curField.Tag.End()
|
||||
remove = curField.Tag
|
||||
} else {
|
||||
// Remove the json tag if omitempty is the only field
|
||||
removePos, err = astutil.PosInStringLiteral(curField.Tag, match[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
removeEnd, err = astutil.PosInStringLiteral(curField.Tag, match[1])
|
||||
remove, err = astutil.RangeInStringLiteral(curField.Tag, match[0], match[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -81,8 +72,8 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
|
|||
Message: "Remove redundant omitempty tag",
|
||||
TextEdits: []analysis.TextEdit{
|
||||
{
|
||||
Pos: removePos,
|
||||
End: removeEnd,
|
||||
Pos: remove.Pos(),
|
||||
End: remove.End(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -90,8 +81,8 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
|
|||
Message: "Replace omitempty with omitzero (behavior change)",
|
||||
TextEdits: []analysis.TextEdit{
|
||||
{
|
||||
Pos: omitEmptyPos,
|
||||
End: omitEmptyEnd,
|
||||
Pos: omitEmpty.Pos(),
|
||||
End: omitEmpty.End(),
|
||||
NewText: []byte(",omitzero"),
|
||||
},
|
||||
},
|
||||
|
|
@ -100,18 +91,14 @@ func checkOmitEmptyField(pass *analysis.Pass, info *types.Info, curField *ast.Fi
|
|||
}
|
||||
|
||||
// The omitzero pass searches for instances of "omitempty" in a json field tag on a
|
||||
// struct. Since "omitempty" does not have any effect when applied to a struct field,
|
||||
// struct. Since "omitfilesUsingGoVersions not have any effect when applied to a struct field,
|
||||
// it suggests either deleting "omitempty" or replacing it with "omitzero", which
|
||||
// correctly excludes structs from a json encoding.
|
||||
func omitzero(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
info := pass.TypesInfo
|
||||
for curFile := range filesUsing(inspect, info, "go1.24") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
|
||||
for curStruct := range curFile.Preorder((*ast.StructType)(nil)) {
|
||||
for _, curField := range curStruct.Node().(*ast.StructType).Fields.List {
|
||||
checkOmitEmptyField(pass, info, curField)
|
||||
checkOmitEmptyField(pass, pass.TypesInfo, curField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go
generated
vendored
7
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/plusbuild.go
generated
vendored
|
|
@ -10,13 +10,14 @@ import (
|
|||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/goplsexport"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var plusBuildAnalyzer = &analysis.Analyzer{
|
||||
Name: "plusbuild",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "plusbuild"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "plusbuild"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#plusbuild",
|
||||
Run: plusbuild,
|
||||
}
|
||||
|
|
@ -28,7 +29,7 @@ func init() {
|
|||
|
||||
func plusbuild(pass *analysis.Pass) (any, error) {
|
||||
check := func(f *ast.File) {
|
||||
if !fileUses(pass.TypesInfo, f, "go1.18") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, f, versions.Go1_18) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
23
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go
generated
vendored
23
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/rangeint.go
generated
vendored
|
|
@ -15,19 +15,18 @@ import (
|
|||
"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/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var RangeIntAnalyzer = &analysis.Analyzer{
|
||||
Name: "rangeint",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "rangeint"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "rangeint"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -66,21 +65,19 @@ var RangeIntAnalyzer = &analysis.Analyzer{
|
|||
// - a constant; or
|
||||
// - len(s), where s has the above properties.
|
||||
func rangeint(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
var (
|
||||
info = pass.TypesInfo
|
||||
typeindex = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
)
|
||||
|
||||
info := pass.TypesInfo
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
typeindex := pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
|
||||
for curFile := range filesUsing(inspect, info, "go1.22") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_22) {
|
||||
nextLoop:
|
||||
for curLoop := range curFile.Preorder((*ast.ForStmt)(nil)) {
|
||||
loop := curLoop.Node().(*ast.ForStmt)
|
||||
if init, ok := loop.Init.(*ast.AssignStmt); ok &&
|
||||
isSimpleAssign(init) &&
|
||||
is[*ast.Ident](init.Lhs[0]) &&
|
||||
isZeroIntLiteral(info, init.Rhs[0]) {
|
||||
isZeroIntConst(info, init.Rhs[0]) {
|
||||
// Have: for i = 0; ... (or i := 0)
|
||||
index := init.Lhs[0].(*ast.Ident)
|
||||
|
||||
|
|
|
|||
12
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go
generated
vendored
12
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/reflect.go
generated
vendored
|
|
@ -14,9 +14,8 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
|
|
@ -26,9 +25,8 @@ import (
|
|||
|
||||
var ReflectTypeForAnalyzer = &analysis.Analyzer{
|
||||
Name: "reflecttypefor",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "reflecttypefor"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "reflecttypefor"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -37,8 +35,6 @@ var ReflectTypeForAnalyzer = &analysis.Analyzer{
|
|||
}
|
||||
|
||||
func reflecttypefor(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
|
@ -89,7 +85,7 @@ func reflecttypefor(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
file := astutil.EnclosingFile(curCall)
|
||||
if versions.Before(info.FileVersions[file], "go1.22") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_22) {
|
||||
continue // TypeFor requires go1.22
|
||||
}
|
||||
tokFile := pass.Fset.File(file.Pos())
|
||||
|
|
|
|||
25
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go
generated
vendored
25
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slices.go
generated
vendored
|
|
@ -13,25 +13,21 @@ 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/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
// Warning: this analyzer is not safe to enable by default.
|
||||
var AppendClippedAnalyzer = &analysis.Analyzer{
|
||||
Name: "appendclipped",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "appendclipped"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: appendclipped,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#appendclipped",
|
||||
Name: "appendclipped",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "appendclipped"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: appendclipped,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#appendclipped",
|
||||
}
|
||||
|
||||
// The appendclipped pass offers to simplify a tower of append calls:
|
||||
|
|
@ -59,8 +55,6 @@ var AppendClippedAnalyzer = &analysis.Analyzer{
|
|||
// The fix does not always preserve nilness the of base slice when the
|
||||
// addends (a, b, c) are all empty (see #73557).
|
||||
func appendclipped(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "slices", "bytes", "runtime") {
|
||||
|
|
@ -205,8 +199,7 @@ func appendclipped(pass *analysis.Pass) (any, error) {
|
|||
skip := make(map[*ast.CallExpr]bool)
|
||||
|
||||
// Visit calls of form append(x, y...).
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
for curFile := range filesUsing(inspect, info, "go1.21") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
|
||||
file := curFile.Node().(*ast.File)
|
||||
|
||||
for curCall := range curFile.Preorder((*ast.CallExpr)(nil)) {
|
||||
|
|
@ -266,7 +259,7 @@ func clippedSlice(info *types.Info, e ast.Expr) (res ast.Expr, empty bool) {
|
|||
// x[:0:0], x[:len(x):len(x)], x[:k:k]
|
||||
if e.Slice3 && e.High != nil && e.Max != nil && astutil.EqualSyntax(e.High, e.Max) { // x[:k:k]
|
||||
res = e
|
||||
empty = isZeroIntLiteral(info, e.High) // x[:0:0]
|
||||
empty = isZeroIntConst(info, e.High) // x[:0:0]
|
||||
if call, ok := e.High.(*ast.CallExpr); ok &&
|
||||
typeutil.Callee(info, call) == builtinLen &&
|
||||
astutil.EqualSyntax(call.Args[0], e.X) {
|
||||
|
|
|
|||
52
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
generated
vendored
52
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicescontains.go
generated
vendored
|
|
@ -14,20 +14,19 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var SlicesContainsAnalyzer = &analysis.Analyzer{
|
||||
Name: "slicescontains",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "slicescontains"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "slicescontains"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -66,8 +65,6 @@ var SlicesContainsAnalyzer = &analysis.Analyzer{
|
|||
// TODO(adonovan): Add a check that needle/predicate expression from
|
||||
// if-statement has no effects. Now the program behavior may change.
|
||||
func slicescontains(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "slices", "runtime") {
|
||||
|
|
@ -75,9 +72,8 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
)
|
||||
|
||||
// check is called for each RangeStmt of this form:
|
||||
|
|
@ -312,7 +308,7 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
|
||||
// Special case:
|
||||
// prev="lhs = false" body={ lhs = true; break }
|
||||
// => lhs = slices.Contains(...) (or negation)
|
||||
// => lhs = slices.Contains(...) (or its negation)
|
||||
if assign, ok := body.List[0].(*ast.AssignStmt); ok &&
|
||||
len(body.List) == 2 &&
|
||||
assign.Tok == token.ASSIGN &&
|
||||
|
|
@ -320,13 +316,12 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
len(assign.Rhs) == 1 {
|
||||
|
||||
// Have: body={ lhs = rhs; break }
|
||||
|
||||
if prevAssign, ok := prevStmt.(*ast.AssignStmt); ok &&
|
||||
len(prevAssign.Lhs) == 1 &&
|
||||
len(prevAssign.Rhs) == 1 &&
|
||||
astutil.EqualSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
|
||||
is[*ast.Ident](assign.Rhs[0]) &&
|
||||
info.Uses[assign.Rhs[0].(*ast.Ident)] == builtinTrue {
|
||||
isTrueOrFalse(info, assign.Rhs[0]) ==
|
||||
-isTrueOrFalse(info, prevAssign.Rhs[0]) {
|
||||
|
||||
// Have:
|
||||
// lhs = false
|
||||
|
|
@ -336,15 +331,14 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
//
|
||||
// TODO(adonovan):
|
||||
// - support "var lhs bool = false" and variants.
|
||||
// - support negation.
|
||||
// Both these variants seem quite significant.
|
||||
// - allow the break to be omitted.
|
||||
neg := cond(isTrueOrFalse(info, assign.Rhs[0]) < 0, "!", "")
|
||||
report([]analysis.TextEdit{
|
||||
// Replace "rhs" of previous assignment by slices.Contains(...)
|
||||
// Replace "rhs" of previous assignment by [!]slices.Contains(...)
|
||||
{
|
||||
Pos: prevAssign.Rhs[0].Pos(),
|
||||
End: prevAssign.Rhs[0].End(),
|
||||
NewText: []byte(contains),
|
||||
NewText: []byte(neg + contains),
|
||||
},
|
||||
// Delete the loop and preceding space.
|
||||
{
|
||||
|
|
@ -388,7 +382,7 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
}
|
||||
|
||||
for curFile := range filesUsing(inspect, info, "go1.21") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
|
||||
file := curFile.Node().(*ast.File)
|
||||
|
||||
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
|
||||
|
|
@ -420,13 +414,19 @@ func slicescontains(pass *analysis.Pass) (any, error) {
|
|||
// isReturnTrueOrFalse returns nonzero if stmt returns true (+1) or false (-1).
|
||||
func isReturnTrueOrFalse(info *types.Info, stmt ast.Stmt) int {
|
||||
if ret, ok := stmt.(*ast.ReturnStmt); ok && len(ret.Results) == 1 {
|
||||
if id, ok := ret.Results[0].(*ast.Ident); ok {
|
||||
switch info.Uses[id] {
|
||||
case builtinTrue:
|
||||
return +1
|
||||
case builtinFalse:
|
||||
return -1
|
||||
}
|
||||
return isTrueOrFalse(info, ret.Results[0])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// isTrueOrFalse returns nonzero if expr is literally true (+1) or false (-1).
|
||||
func isTrueOrFalse(info *types.Info, expr ast.Expr) int {
|
||||
if id, ok := expr.(*ast.Ident); ok {
|
||||
switch info.Uses[id] {
|
||||
case builtinTrue:
|
||||
return +1
|
||||
case builtinFalse:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
|
|
|||
25
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go
generated
vendored
25
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesdelete.go
generated
vendored
|
|
@ -12,24 +12,20 @@ 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/analysisinternal/generated"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
// Warning: this analyzer is not safe to enable by default (not nil-preserving).
|
||||
var SlicesDeleteAnalyzer = &analysis.Analyzer{
|
||||
Name: "slicesdelete",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "slicesdelete"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
},
|
||||
Run: slicesdelete,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#slicesdelete",
|
||||
Name: "slicesdelete",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "slicesdelete"),
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: slicesdelete,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/modernize#slicesdelete",
|
||||
}
|
||||
|
||||
// The slicesdelete pass attempts to replace instances of append(s[:i], s[i+k:]...)
|
||||
|
|
@ -37,15 +33,12 @@ var SlicesDeleteAnalyzer = &analysis.Analyzer{
|
|||
// Other variations that will also have suggested replacements include:
|
||||
// append(s[:i-1], s[i:]...) and append(s[:i+k1], s[i+k2:]) where k2 > k1.
|
||||
func slicesdelete(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "slices", "runtime") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
info := pass.TypesInfo
|
||||
report := func(file *ast.File, call *ast.CallExpr, slice1, slice2 *ast.SliceExpr) {
|
||||
insert := func(pos token.Pos, text string) analysis.TextEdit {
|
||||
|
|
@ -55,7 +48,7 @@ func slicesdelete(pass *analysis.Pass) (any, error) {
|
|||
return types.Identical(types.Default(info.TypeOf(e)), builtinInt.Type())
|
||||
}
|
||||
isIntShadowed := func() bool {
|
||||
scope := pass.TypesInfo.Scopes[file].Innermost(call.Lparen)
|
||||
scope := info.Scopes[file].Innermost(call.Lparen)
|
||||
if _, obj := scope.LookupParent("int", call.Lparen); obj != builtinInt {
|
||||
return true // int type is shadowed
|
||||
}
|
||||
|
|
@ -130,7 +123,7 @@ func slicesdelete(pass *analysis.Pass) (any, error) {
|
|||
}},
|
||||
})
|
||||
}
|
||||
for curFile := range filesUsing(inspect, info, "go1.21") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_21) {
|
||||
file := curFile.Node().(*ast.File)
|
||||
for curCall := range curFile.Preorder((*ast.CallExpr)(nil)) {
|
||||
call := curCall.Node().(*ast.CallExpr)
|
||||
|
|
|
|||
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go
generated
vendored
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/sortslice.go
generated
vendored
|
|
@ -11,20 +11,19 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
// (Not to be confused with go/analysis/passes/sortslice.)
|
||||
var SlicesSortAnalyzer = &analysis.Analyzer{
|
||||
Name: "slicessort",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "slicessort"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "slicessort"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -52,8 +51,6 @@ var SlicesSortAnalyzer = &analysis.Analyzer{
|
|||
// - sort.Sort(x) where x has a named slice type whose Less method is the natural order.
|
||||
// -> sort.Slice(x)
|
||||
func slicessort(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "slices", "sort", "runtime") {
|
||||
|
|
@ -87,7 +84,7 @@ func slicessort(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
file := astutil.EnclosingFile(curCall)
|
||||
if isIndex(compare.X, i) && isIndex(compare.Y, j) &&
|
||||
fileUses(info, file, "go1.21") {
|
||||
analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_21) {
|
||||
// Have: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
|
||||
|
||||
prefix, importEdits := refactor.AddImport(
|
||||
|
|
|
|||
67
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go
generated
vendored
67
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stditerators.go
generated
vendored
|
|
@ -14,9 +14,8 @@ import (
|
|||
"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/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/goplsexport"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
|
|
@ -26,9 +25,8 @@ import (
|
|||
|
||||
var stditeratorsAnalyzer = &analysis.Analyzer{
|
||||
Name: "stditerators",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stditerators"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stditerators"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
Run: stditerators,
|
||||
|
|
@ -89,8 +87,6 @@ var stditeratorsTable = [...]struct {
|
|||
// iterator for that reason? We don't want to go fix to
|
||||
// undo optimizations. Do we need a suppression mechanism?
|
||||
func stditerators(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
|
@ -116,6 +112,10 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
//
|
||||
// for ... { e := x.At(i); use(e) }
|
||||
//
|
||||
// or
|
||||
//
|
||||
// for ... { if e := x.At(i); cond { use(e) } }
|
||||
//
|
||||
// then chooseName prefers the name e and additionally
|
||||
// returns the var's symbol. We'll transform this to:
|
||||
//
|
||||
|
|
@ -124,10 +124,11 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
// which leaves a redundant assignment that a
|
||||
// subsequent 'forvar' pass will eliminate.
|
||||
chooseName := func(curBody inspector.Cursor, x ast.Expr, i *types.Var) (string, *types.Var) {
|
||||
// Is body { elem := x.At(i); ... } ?
|
||||
body := curBody.Node().(*ast.BlockStmt)
|
||||
if len(body.List) > 0 {
|
||||
if assign, ok := body.List[0].(*ast.AssignStmt); ok &&
|
||||
|
||||
// isVarAssign reports whether stmt has the form v := x.At(i)
|
||||
// and returns the variable if so.
|
||||
isVarAssign := func(stmt ast.Stmt) *types.Var {
|
||||
if assign, ok := stmt.(*ast.AssignStmt); ok &&
|
||||
assign.Tok == token.DEFINE &&
|
||||
len(assign.Lhs) == 1 &&
|
||||
len(assign.Rhs) == 1 &&
|
||||
|
|
@ -138,15 +139,47 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
astutil.EqualSyntax(ast.Unparen(call.Fun).(*ast.SelectorExpr).X, x) &&
|
||||
is[*ast.Ident](call.Args[0]) &&
|
||||
info.Uses[call.Args[0].(*ast.Ident)] == i {
|
||||
// Have: { elem := x.At(i); ... }
|
||||
// Have: elem := x.At(i)
|
||||
id := assign.Lhs[0].(*ast.Ident)
|
||||
return id.Name, info.Defs[id].(*types.Var)
|
||||
return info.Defs[id].(*types.Var)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
body := curBody.Node().(*ast.BlockStmt)
|
||||
if len(body.List) > 0 {
|
||||
// Is body { elem := x.At(i); ... } ?
|
||||
if v := isVarAssign(body.List[0]); v != nil {
|
||||
return v.Name(), v
|
||||
}
|
||||
|
||||
// Or { if elem := x.At(i); cond { ... } } ?
|
||||
if ifstmt, ok := body.List[0].(*ast.IfStmt); ok && ifstmt.Init != nil {
|
||||
if v := isVarAssign(ifstmt.Init); v != nil {
|
||||
return v.Name(), v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loop := curBody.Parent().Node()
|
||||
return refactor.FreshName(info.Scopes[loop], loop.Pos(), row.elemname), nil
|
||||
|
||||
// Choose a fresh name only if
|
||||
// (a) the preferred name is already declared here, and
|
||||
// (b) there are references to it from the loop body.
|
||||
// TODO(adonovan): this pattern also appears in errorsastype,
|
||||
// and is wanted elsewhere; factor.
|
||||
name := row.elemname
|
||||
if v := lookup(info, curBody, name); v != nil {
|
||||
// is it free in body?
|
||||
for curUse := range index.Uses(v) {
|
||||
if curBody.Contains(curUse) {
|
||||
name = refactor.FreshName(info.Scopes[loop], loop.Pos(), name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Process each call of x.Len().
|
||||
|
|
@ -191,7 +224,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
// Have: for i := 0; i < x.Len(); i++ { ... }.
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
rng = analysisinternal.Range(loop.For, loop.Post.End())
|
||||
rng = astutil.RangeOf(loop.For, loop.Post.End())
|
||||
indexVar = v
|
||||
curBody = curFor.ChildAt(edge.ForStmt_Body, -1)
|
||||
elem, elemVar = chooseName(curBody, lenSel.X, indexVar)
|
||||
|
|
@ -234,7 +267,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
// Have: for i := range x.Len() { ... }
|
||||
// ~~~~~~~~~~~~~
|
||||
|
||||
rng = analysisinternal.Range(loop.Range, loop.X.End())
|
||||
rng = astutil.RangeOf(loop.Range, loop.X.End())
|
||||
indexVar = info.Defs[id].(*types.Var)
|
||||
curBody = curRange.ChildAt(edge.RangeStmt_Body, -1)
|
||||
elem, elemVar = chooseName(curBody, lenSel.X, indexVar)
|
||||
|
|
@ -313,7 +346,7 @@ func stditerators(pass *analysis.Pass) (any, error) {
|
|||
// may be somewhat expensive.)
|
||||
if v, ok := methodGoVersion(row.pkgpath, row.typename, row.itermethod); !ok {
|
||||
panic("no version found")
|
||||
} else if file := astutil.EnclosingFile(curLenCall); !fileUses(info, file, v.String()) {
|
||||
} else if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curLenCall), v.String()) {
|
||||
continue nextCall
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go
generated
vendored
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsbuilder.go
generated
vendored
|
|
@ -15,9 +15,8 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
|
|
@ -26,9 +25,8 @@ import (
|
|||
|
||||
var StringsBuilderAnalyzer = &analysis.Analyzer{
|
||||
Name: "stringsbuilder",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stringsbuilder"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stringsbuilder"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -38,8 +36,6 @@ var StringsBuilderAnalyzer = &analysis.Analyzer{
|
|||
|
||||
// stringsbuilder replaces string += string in a loop by strings.Builder.
|
||||
func stringsbuilder(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
// Skip the analyzer in packages where its
|
||||
// fixes would create an import cycle.
|
||||
if within(pass, "strings", "runtime") {
|
||||
|
|
|
|||
580
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
generated
vendored
Normal file
580
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscut.go
generated
vendored
Normal file
|
|
@ -0,0 +1,580 @@
|
|||
// 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 modernize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"iter"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"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/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/goplsexport"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var stringscutAnalyzer = &analysis.Analyzer{
|
||||
Name: "stringscut",
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stringscut"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
Run: stringscut,
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize#stringscut",
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Export to gopls until this is a published modernizer.
|
||||
goplsexport.StringsCutModernizer = stringscutAnalyzer
|
||||
}
|
||||
|
||||
// stringscut offers a fix to replace an occurrence of strings.Index{,Byte} with
|
||||
// strings.{Cut,Contains}, and similar fixes for functions in the bytes package.
|
||||
// Consider some candidate for replacement i := strings.Index(s, substr).
|
||||
// The following must hold for a replacement to occur:
|
||||
//
|
||||
// 1. All instances of i and s must be in one of these forms.
|
||||
// Binary expressions:
|
||||
// (a): establishing that i < 0: e.g.: i < 0, 0 > i, i == -1, -1 == i
|
||||
// (b): establishing that i > -1: e.g.: i >= 0, 0 <= i, i == 0, 0 == i
|
||||
//
|
||||
// Slice expressions:
|
||||
// a: s[:i], s[0:i]
|
||||
// b: s[i+len(substr):], s[len(substr) + i:], s[i + const], s[k + i] (where k = len(substr))
|
||||
//
|
||||
// 2. There can be no uses of s, substr, or i where they are
|
||||
// potentially modified (i.e. in assignments, or function calls with unknown side
|
||||
// effects).
|
||||
//
|
||||
// Then, the replacement involves the following substitutions:
|
||||
//
|
||||
// 1. Replace "i := strings.Index(s, substr)" with "before, after, ok := strings.Cut(s, substr)"
|
||||
//
|
||||
// 2. Replace instances of binary expressions (a) with !ok and binary expressions (b) with ok.
|
||||
//
|
||||
// 3. Replace slice expressions (a) with "before" and slice expressions (b) with after.
|
||||
//
|
||||
// 4. The assignments to before, after, and ok may use the blank identifier "_" if they are unused.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// i := strings.Index(s, substr)
|
||||
// if i >= 0 {
|
||||
// use(s[:i], s[i+len(substr):])
|
||||
// }
|
||||
//
|
||||
// Would become:
|
||||
//
|
||||
// before, after, ok := strings.Cut(s, substr)
|
||||
// if ok {
|
||||
// use(before, after)
|
||||
// }
|
||||
//
|
||||
// If the condition involving `i` establishes that i > -1, then we replace it with
|
||||
// `if ok“. Variants listed above include i >= 0, i > 0, and i == 0.
|
||||
// If the condition is negated (e.g. establishes `i < 0`), we use `if !ok` instead.
|
||||
// If the slices of `s` match `s[:i]` or `s[i+len(substr):]` or their variants listed above,
|
||||
// then we replace them with before and after.
|
||||
//
|
||||
// When the index `i` is used only to check for the presence of the substring or byte slice,
|
||||
// the suggested fix uses Contains() instead of Cut.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// i := strings.Index(s, substr)
|
||||
// if i >= 0 {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// Would become:
|
||||
//
|
||||
// found := strings.Contains(s, substr)
|
||||
// if found {
|
||||
// return
|
||||
// }
|
||||
func stringscut(pass *analysis.Pass) (any, error) {
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
||||
stringsIndex = index.Object("strings", "Index")
|
||||
stringsIndexByte = index.Object("strings", "IndexByte")
|
||||
bytesIndex = index.Object("bytes", "Index")
|
||||
bytesIndexByte = index.Object("bytes", "IndexByte")
|
||||
)
|
||||
|
||||
for _, obj := range []types.Object{
|
||||
stringsIndex,
|
||||
stringsIndexByte,
|
||||
bytesIndex,
|
||||
bytesIndexByte,
|
||||
} {
|
||||
// (obj may be nil)
|
||||
nextcall:
|
||||
for curCall := range index.Calls(obj) {
|
||||
// Check file version.
|
||||
if !analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(curCall), versions.Go1_18) {
|
||||
continue // strings.Index not available in this file
|
||||
}
|
||||
indexCall := curCall.Node().(*ast.CallExpr) // the call to strings.Index, etc.
|
||||
obj := typeutil.Callee(info, indexCall)
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var iIdent *ast.Ident // defining identifier of i var
|
||||
switch ek, idx := curCall.ParentEdge(); ek {
|
||||
case edge.ValueSpec_Values:
|
||||
// Have: var i = strings.Index(...)
|
||||
curName := curCall.Parent().ChildAt(edge.ValueSpec_Names, idx)
|
||||
iIdent = curName.Node().(*ast.Ident)
|
||||
case edge.AssignStmt_Rhs:
|
||||
// Have: i := strings.Index(...)
|
||||
// (Must be i's definition.)
|
||||
curLhs := curCall.Parent().ChildAt(edge.AssignStmt_Lhs, idx)
|
||||
iIdent, _ = curLhs.Node().(*ast.Ident) // may be nil
|
||||
}
|
||||
|
||||
if iIdent == nil {
|
||||
continue
|
||||
}
|
||||
// Inv: iIdent is i's definition. The following would be skipped: 'var i int; i = strings.Index(...)'
|
||||
// Get uses of i.
|
||||
iObj := info.ObjectOf(iIdent)
|
||||
if iObj == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
s = indexCall.Args[0]
|
||||
substr = indexCall.Args[1]
|
||||
)
|
||||
|
||||
// Check that there are no statements that alter the value of s
|
||||
// or substr after the call to Index().
|
||||
if !indexArgValid(info, index, s, indexCall.Pos()) ||
|
||||
!indexArgValid(info, index, substr, indexCall.Pos()) {
|
||||
continue nextcall
|
||||
}
|
||||
|
||||
// Next, examine all uses of i. If the only uses are of the
|
||||
// forms mentioned above (e.g. i < 0, i >= 0, s[:i] and s[i +
|
||||
// len(substr)]), then we can replace the call to Index()
|
||||
// with a call to Cut() and use the returned ok, before,
|
||||
// and after variables accordingly.
|
||||
lessZero, greaterNegOne, beforeSlice, afterSlice := checkIdxUses(pass.TypesInfo, index.Uses(iObj), s, substr)
|
||||
|
||||
// Either there are no uses of before, after, or ok, or some use
|
||||
// of i does not match our criteria - don't suggest a fix.
|
||||
if lessZero == nil && greaterNegOne == nil && beforeSlice == nil && afterSlice == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the only uses are ok and !ok, don't suggest a Cut() fix - these should be using Contains()
|
||||
isContains := (len(lessZero) > 0 || len(greaterNegOne) > 0) && len(beforeSlice) == 0 && len(afterSlice) == 0
|
||||
|
||||
scope := iObj.Parent()
|
||||
var (
|
||||
// TODO(adonovan): avoid FreshName when not needed; see errorsastype.
|
||||
okVarName = refactor.FreshName(scope, iIdent.Pos(), "ok")
|
||||
beforeVarName = refactor.FreshName(scope, iIdent.Pos(), "before")
|
||||
afterVarName = refactor.FreshName(scope, iIdent.Pos(), "after")
|
||||
foundVarName = refactor.FreshName(scope, iIdent.Pos(), "found") // for Contains()
|
||||
)
|
||||
|
||||
// If there will be no uses of ok, before, or after, use the
|
||||
// blank identifier instead.
|
||||
if len(lessZero) == 0 && len(greaterNegOne) == 0 {
|
||||
okVarName = "_"
|
||||
}
|
||||
if len(beforeSlice) == 0 {
|
||||
beforeVarName = "_"
|
||||
}
|
||||
if len(afterSlice) == 0 {
|
||||
afterVarName = "_"
|
||||
}
|
||||
|
||||
var edits []analysis.TextEdit
|
||||
replace := func(exprs []ast.Expr, new string) {
|
||||
for _, expr := range exprs {
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: expr.Pos(),
|
||||
End: expr.End(),
|
||||
NewText: []byte(new),
|
||||
})
|
||||
}
|
||||
}
|
||||
// Get the ident for the call to strings.Index, which could just be
|
||||
// "Index" if the strings package is dot imported.
|
||||
indexCallId := typesinternal.UsedIdent(info, indexCall.Fun)
|
||||
replacedFunc := "Cut"
|
||||
if isContains {
|
||||
replacedFunc = "Contains"
|
||||
replace(lessZero, "!"+foundVarName) // idx < 0 -> !found
|
||||
replace(greaterNegOne, foundVarName) // idx > -1 -> found
|
||||
|
||||
// Replace the assignment with found, and replace the call to
|
||||
// Index or IndexByte with a call to Contains.
|
||||
// i := strings.Index (...)
|
||||
// ----- --------
|
||||
// found := strings.Contains(...)
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: iIdent.Pos(),
|
||||
End: iIdent.End(),
|
||||
NewText: []byte(foundVarName),
|
||||
}, analysis.TextEdit{
|
||||
Pos: indexCallId.Pos(),
|
||||
End: indexCallId.End(),
|
||||
NewText: []byte("Contains"),
|
||||
})
|
||||
} else {
|
||||
replace(lessZero, "!"+okVarName) // idx < 0 -> !ok
|
||||
replace(greaterNegOne, okVarName) // idx > -1 -> ok
|
||||
replace(beforeSlice, beforeVarName) // s[:idx] -> before
|
||||
replace(afterSlice, afterVarName) // s[idx+k:] -> after
|
||||
|
||||
// Replace the assignment with before, after, ok, and replace
|
||||
// the call to Index or IndexByte with a call to Cut.
|
||||
// i := strings.Index(...)
|
||||
// ----------------- -----
|
||||
// before, after, ok := strings.Cut (...)
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: iIdent.Pos(),
|
||||
End: iIdent.End(),
|
||||
NewText: fmt.Appendf(nil, "%s, %s, %s", beforeVarName, afterVarName, okVarName),
|
||||
}, analysis.TextEdit{
|
||||
Pos: indexCallId.Pos(),
|
||||
End: indexCallId.End(),
|
||||
NewText: []byte("Cut"),
|
||||
})
|
||||
}
|
||||
|
||||
// Calls to IndexByte have a byte as their second arg, which
|
||||
// must be converted to a string or []byte to be a valid arg for Cut/Contains.
|
||||
if obj.Name() == "IndexByte" {
|
||||
switch obj.Pkg().Name() {
|
||||
case "strings":
|
||||
searchByteVal := info.Types[substr].Value
|
||||
if searchByteVal == nil {
|
||||
// substr is a variable, e.g. substr := byte('b')
|
||||
// use string(substr)
|
||||
edits = append(edits, []analysis.TextEdit{
|
||||
{
|
||||
Pos: substr.Pos(),
|
||||
NewText: []byte("string("),
|
||||
},
|
||||
{
|
||||
Pos: substr.End(),
|
||||
NewText: []byte(")"),
|
||||
},
|
||||
}...)
|
||||
} else {
|
||||
// substr is a byte constant
|
||||
val, _ := constant.Int64Val(searchByteVal) // inv: must be a valid byte
|
||||
// strings.Cut/Contains requires a string, so convert byte literal to string literal; e.g. 'a' -> "a", 55 -> "7"
|
||||
edits = append(edits, analysis.TextEdit{
|
||||
Pos: substr.Pos(),
|
||||
End: substr.End(),
|
||||
NewText: strconv.AppendQuote(nil, string(byte(val))),
|
||||
})
|
||||
}
|
||||
case "bytes":
|
||||
// bytes.Cut/Contains requires a []byte, so wrap substr in a []byte{}
|
||||
edits = append(edits, []analysis.TextEdit{
|
||||
{
|
||||
Pos: substr.Pos(),
|
||||
NewText: []byte("[]byte{"),
|
||||
},
|
||||
{
|
||||
Pos: substr.End(),
|
||||
NewText: []byte("}"),
|
||||
},
|
||||
}...)
|
||||
}
|
||||
}
|
||||
pass.Report(analysis.Diagnostic{
|
||||
Pos: indexCall.Fun.Pos(),
|
||||
End: indexCall.Fun.End(),
|
||||
Message: fmt.Sprintf("%s.%s can be simplified using %s.%s",
|
||||
obj.Pkg().Name(), obj.Name(), obj.Pkg().Name(), replacedFunc),
|
||||
Category: "stringscut",
|
||||
SuggestedFixes: []analysis.SuggestedFix{{
|
||||
Message: fmt.Sprintf("Simplify %s.%s call using %s.%s", obj.Pkg().Name(), obj.Name(), obj.Pkg().Name(), replacedFunc),
|
||||
TextEdits: edits,
|
||||
}},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// indexArgValid reports whether expr is a valid strings.Index(_, _) arg
|
||||
// for the transformation. An arg is valid iff it is:
|
||||
// - constant;
|
||||
// - a local variable with no modifying uses after the Index() call; or
|
||||
// - []byte(x) where x is also valid by this definition.
|
||||
// All other expressions are assumed not referentially transparent,
|
||||
// so we cannot be sure that all uses are safe to replace.
|
||||
func indexArgValid(info *types.Info, index *typeindex.Index, expr ast.Expr, afterPos token.Pos) bool {
|
||||
tv := info.Types[expr]
|
||||
if tv.Value != nil {
|
||||
return true // constant
|
||||
}
|
||||
switch expr := expr.(type) {
|
||||
case *ast.CallExpr:
|
||||
return types.Identical(tv.Type, byteSliceType) &&
|
||||
indexArgValid(info, index, expr.Args[0], afterPos) // check s in []byte(s)
|
||||
case *ast.Ident:
|
||||
sObj := info.Uses[expr]
|
||||
sUses := index.Uses(sObj)
|
||||
return !hasModifyingUses(info, sUses, afterPos)
|
||||
default:
|
||||
// For now, skip instances where s or substr are not
|
||||
// identifers, basic lits, or call expressions of the form
|
||||
// []byte(s).
|
||||
// TODO(mkalil): Handle s and substr being expressions like ptr.field[i].
|
||||
// From adonovan: We'd need to analyze s and substr to see
|
||||
// whether they are referentially transparent, and if not,
|
||||
// analyze all code between declaration and use and see if
|
||||
// there are statements or expressions with potential side
|
||||
// effects.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// checkIdxUses inspects the uses of i to make sure they match certain criteria that
|
||||
// allows us to suggest a modernization. If all uses of i, s and substr match
|
||||
// one of the following four valid formats, it returns a list of occurrences for
|
||||
// each format. If any of the uses do not match one of the formats, return nil
|
||||
// for all values, since we should not offer a replacement.
|
||||
// 1. lessZero - a condition involving i establishing that i is negative (e.g. i < 0, 0 > i, i == -1, -1 == i)
|
||||
// 2. greaterNegOne - a condition involving i establishing that i is non-negative (e.g. i >= 0, 0 <= i, i == 0, 0 == i)
|
||||
// 3. beforeSlice - a slice of `s` that matches either s[:i], s[0:i]
|
||||
// 4. afterSlice - a slice of `s` that matches one of: s[i+len(substr):], s[len(substr) + i:], s[i + const], s[k + i] (where k = len(substr))
|
||||
func checkIdxUses(info *types.Info, uses iter.Seq[inspector.Cursor], s, substr ast.Expr) (lessZero, greaterNegOne, beforeSlice, afterSlice []ast.Expr) {
|
||||
use := func(cur inspector.Cursor) bool {
|
||||
ek, _ := cur.ParentEdge()
|
||||
n := cur.Parent().Node()
|
||||
switch ek {
|
||||
case edge.BinaryExpr_X, edge.BinaryExpr_Y:
|
||||
check := n.(*ast.BinaryExpr)
|
||||
switch checkIdxComparison(info, check) {
|
||||
case -1:
|
||||
lessZero = append(lessZero, check)
|
||||
return true
|
||||
case 1:
|
||||
greaterNegOne = append(greaterNegOne, check)
|
||||
return true
|
||||
}
|
||||
// Check does not establish that i < 0 or i > -1.
|
||||
// Might be part of an outer slice expression like s[i + k]
|
||||
// which requires a different check.
|
||||
// Check that the thing being sliced is s and that the slice
|
||||
// doesn't have a max index.
|
||||
if slice, ok := cur.Parent().Parent().Node().(*ast.SliceExpr); ok &&
|
||||
sameObject(info, s, slice.X) &&
|
||||
slice.Max == nil {
|
||||
if isBeforeSlice(info, ek, slice) {
|
||||
beforeSlice = append(beforeSlice, slice)
|
||||
return true
|
||||
} else if isAfterSlice(info, ek, slice, substr) {
|
||||
afterSlice = append(afterSlice, slice)
|
||||
return true
|
||||
}
|
||||
}
|
||||
case edge.SliceExpr_Low, edge.SliceExpr_High:
|
||||
slice := n.(*ast.SliceExpr)
|
||||
// Check that the thing being sliced is s and that the slice doesn't
|
||||
// have a max index.
|
||||
if sameObject(info, s, slice.X) && slice.Max == nil {
|
||||
if isBeforeSlice(info, ek, slice) {
|
||||
beforeSlice = append(beforeSlice, slice)
|
||||
return true
|
||||
} else if isAfterSlice(info, ek, slice, substr) {
|
||||
afterSlice = append(afterSlice, slice)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for curIdent := range uses {
|
||||
if !use(curIdent) {
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
}
|
||||
return lessZero, greaterNegOne, beforeSlice, afterSlice
|
||||
}
|
||||
|
||||
// hasModifyingUses reports whether any of the uses involve potential
|
||||
// modifications. Uses involving assignments before the "afterPos" won't be
|
||||
// considered.
|
||||
func hasModifyingUses(info *types.Info, uses iter.Seq[inspector.Cursor], afterPos token.Pos) bool {
|
||||
for curUse := range uses {
|
||||
ek, _ := curUse.ParentEdge()
|
||||
if ek == edge.AssignStmt_Lhs {
|
||||
if curUse.Node().Pos() <= afterPos {
|
||||
continue
|
||||
}
|
||||
assign := curUse.Parent().Node().(*ast.AssignStmt)
|
||||
if sameObject(info, assign.Lhs[0], curUse.Node().(*ast.Ident)) {
|
||||
// Modifying use because we are reassigning the value of the object.
|
||||
return true
|
||||
}
|
||||
} else if ek == edge.UnaryExpr_X &&
|
||||
curUse.Parent().Node().(*ast.UnaryExpr).Op == token.AND {
|
||||
// Modifying use because we might be passing the object by reference (an explicit &).
|
||||
// We can ignore the case where we have a method call on the expression (which
|
||||
// has an implicit &) because we know the type of s and substr are strings
|
||||
// which cannot have methods on them.
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// checkIdxComparison reports whether the check establishes that i is negative
|
||||
// or non-negative. It returns -1 in the first case, 1 in the second, and 0 if
|
||||
// we can confirm neither condition. We assume that a check passed to
|
||||
// checkIdxComparison has i as one of its operands.
|
||||
func checkIdxComparison(info *types.Info, check *ast.BinaryExpr) int {
|
||||
// Check establishes that i is negative.
|
||||
// e.g.: i < 0, 0 > i, i == -1, -1 == i
|
||||
if check.Op == token.LSS && (isNegativeConst(info, check.Y) || isZeroIntConst(info, check.Y)) || //i < (0 or neg)
|
||||
check.Op == token.GTR && (isNegativeConst(info, check.X) || isZeroIntConst(info, check.X)) || // (0 or neg) > i
|
||||
check.Op == token.LEQ && (isNegativeConst(info, check.Y)) || //i <= (neg)
|
||||
check.Op == token.GEQ && (isNegativeConst(info, check.X)) || // (neg) >= i
|
||||
check.Op == token.EQL &&
|
||||
(isNegativeConst(info, check.X) || isNegativeConst(info, check.Y)) { // i == neg; neg == i
|
||||
return -1
|
||||
}
|
||||
// Check establishes that i is non-negative.
|
||||
// e.g.: i >= 0, 0 <= i, i == 0, 0 == i
|
||||
if check.Op == token.GTR && (isNonNegativeConst(info, check.Y) || isIntLiteral(info, check.Y, -1)) || // i > (non-neg or -1)
|
||||
check.Op == token.LSS && (isNonNegativeConst(info, check.X) || isIntLiteral(info, check.X, -1)) || // (non-neg or -1) < i
|
||||
check.Op == token.GEQ && isNonNegativeConst(info, check.Y) || // i >= (non-neg)
|
||||
check.Op == token.LEQ && isNonNegativeConst(info, check.X) || // (non-neg) <= i
|
||||
check.Op == token.EQL &&
|
||||
(isNonNegativeConst(info, check.X) || isNonNegativeConst(info, check.Y)) { // i == non-neg; non-neg == i
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// isNegativeConst returns true if the expr is a const int with value < zero.
|
||||
func isNegativeConst(info *types.Info, expr ast.Expr) bool {
|
||||
if tv, ok := info.Types[expr]; ok && tv.Value != nil && tv.Value.Kind() == constant.Int {
|
||||
if v, ok := constant.Int64Val(tv.Value); ok {
|
||||
return v < 0
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isNoneNegativeConst returns true if the expr is a const int with value >= zero.
|
||||
func isNonNegativeConst(info *types.Info, expr ast.Expr) bool {
|
||||
if tv, ok := info.Types[expr]; ok && tv.Value != nil && tv.Value.Kind() == constant.Int {
|
||||
if v, ok := constant.Int64Val(tv.Value); ok {
|
||||
return v >= 0
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isBeforeSlice reports whether the SliceExpr is of the form s[:i] or s[0:i].
|
||||
func isBeforeSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr) bool {
|
||||
return ek == edge.SliceExpr_High && (slice.Low == nil || isZeroIntConst(info, slice.Low))
|
||||
}
|
||||
|
||||
// isAfterSlice reports whether the SliceExpr is of the form s[i+len(substr):],
|
||||
// or s[i + k:] where k is a const is equal to len(substr).
|
||||
func isAfterSlice(info *types.Info, ek edge.Kind, slice *ast.SliceExpr, substr ast.Expr) bool {
|
||||
lowExpr, ok := slice.Low.(*ast.BinaryExpr)
|
||||
if !ok || slice.High != nil {
|
||||
return false
|
||||
}
|
||||
// Returns true if the expression is a call to len(substr).
|
||||
isLenCall := func(expr ast.Expr) bool {
|
||||
call, ok := expr.(*ast.CallExpr)
|
||||
if !ok || len(call.Args) != 1 {
|
||||
return false
|
||||
}
|
||||
return sameObject(info, substr, call.Args[0]) && typeutil.Callee(info, call) == builtinLen
|
||||
}
|
||||
|
||||
// Handle len([]byte(substr))
|
||||
if is[*ast.CallExpr](substr) {
|
||||
call := substr.(*ast.CallExpr)
|
||||
tv := info.Types[call.Fun]
|
||||
if tv.IsType() && types.Identical(tv.Type, byteSliceType) {
|
||||
// Only one arg in []byte conversion.
|
||||
substr = call.Args[0]
|
||||
}
|
||||
}
|
||||
substrLen := -1
|
||||
substrVal := info.Types[substr].Value
|
||||
if substrVal != nil {
|
||||
switch substrVal.Kind() {
|
||||
case constant.String:
|
||||
substrLen = len(constant.StringVal(substrVal))
|
||||
case constant.Int:
|
||||
// constant.Value is a byte literal, e.g. bytes.IndexByte(_, 'a')
|
||||
// or a numeric byte literal, e.g. bytes.IndexByte(_, 65)
|
||||
substrLen = 1
|
||||
}
|
||||
}
|
||||
|
||||
switch ek {
|
||||
case edge.BinaryExpr_X:
|
||||
kVal := info.Types[lowExpr.Y].Value
|
||||
if kVal == nil {
|
||||
// i + len(substr)
|
||||
return lowExpr.Op == token.ADD && isLenCall(lowExpr.Y)
|
||||
} else {
|
||||
// i + k
|
||||
kInt, ok := constant.Int64Val(kVal)
|
||||
return ok && substrLen == int(kInt)
|
||||
}
|
||||
case edge.BinaryExpr_Y:
|
||||
kVal := info.Types[lowExpr.X].Value
|
||||
if kVal == nil {
|
||||
// len(substr) + i
|
||||
return lowExpr.Op == token.ADD && isLenCall(lowExpr.X)
|
||||
} else {
|
||||
// k + i
|
||||
kInt, ok := constant.Int64Val(kVal)
|
||||
return ok && substrLen == int(kInt)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// sameObject reports whether we know that the expressions resolve to the same object.
|
||||
func sameObject(info *types.Info, expr1, expr2 ast.Expr) bool {
|
||||
if ident1, ok := expr1.(*ast.Ident); ok {
|
||||
if ident2, ok := expr2.(*ast.Ident); ok {
|
||||
uses1, ok1 := info.Uses[ident1]
|
||||
uses2, ok2 := info.Uses[ident2]
|
||||
return ok1 && ok2 && uses1 == uses2
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
20
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go
generated
vendored
20
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringscutprefix.go
generated
vendored
|
|
@ -12,22 +12,20 @@ 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/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var StringsCutPrefixAnalyzer = &analysis.Analyzer{
|
||||
Name: "stringscutprefix",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stringscutprefix"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stringscutprefix"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -56,12 +54,9 @@ var StringsCutPrefixAnalyzer = &analysis.Analyzer{
|
|||
// Variants:
|
||||
// - bytes.HasPrefix/HasSuffix usage as pattern 1.
|
||||
func stringscutprefix(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
||||
stringsTrimPrefix = index.Object("strings", "TrimPrefix")
|
||||
bytesTrimPrefix = index.Object("bytes", "TrimPrefix")
|
||||
|
|
@ -72,7 +67,7 @@ func stringscutprefix(pass *analysis.Pass) (any, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
for curFile := range filesUsing(inspect, pass.TypesInfo, "go1.20") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_20) {
|
||||
for curIfStmt := range curFile.Preorder((*ast.IfStmt)(nil)) {
|
||||
ifStmt := curIfStmt.Node().(*ast.IfStmt)
|
||||
|
||||
|
|
@ -206,6 +201,7 @@ func stringscutprefix(pass *analysis.Pass) (any, error) {
|
|||
|
||||
if astutil.EqualSyntax(lhs, bin.X) && astutil.EqualSyntax(call.Args[0], bin.Y) ||
|
||||
(astutil.EqualSyntax(lhs, bin.Y) && astutil.EqualSyntax(call.Args[0], bin.X)) {
|
||||
// TODO(adonovan): avoid FreshName when not needed; see errorsastype.
|
||||
okVarName := refactor.FreshName(info.Scopes[ifStmt], ifStmt.Pos(), "ok")
|
||||
// Have one of:
|
||||
// if rest := TrimPrefix(s, prefix); rest != s { (ditto Suffix)
|
||||
|
|
|
|||
19
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go
generated
vendored
19
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/stringsseq.go
generated
vendored
|
|
@ -13,19 +13,17 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"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/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var StringsSeqAnalyzer = &analysis.Analyzer{
|
||||
Name: "stringsseq",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stringsseq"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stringsseq"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -48,12 +46,9 @@ var StringsSeqAnalyzer = &analysis.Analyzer{
|
|||
// - bytes.SplitSeq
|
||||
// - bytes.FieldsSeq
|
||||
func stringsseq(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
inspect = pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
||||
stringsSplit = index.Object("strings", "Split")
|
||||
stringsFields = index.Object("strings", "Fields")
|
||||
|
|
@ -64,7 +59,7 @@ func stringsseq(pass *analysis.Pass) (any, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
for curFile := range filesUsing(inspect, info, "go1.24") {
|
||||
for curFile := range filesUsingGoVersion(pass, versions.Go1_24) {
|
||||
for curRange := range curFile.Preorder((*ast.RangeStmt)(nil)) {
|
||||
rng := curRange.Node().(*ast.RangeStmt)
|
||||
|
||||
|
|
|
|||
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go
generated
vendored
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/testingcontext.go
generated
vendored
|
|
@ -17,19 +17,18 @@ import (
|
|||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/edge"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var TestingContextAnalyzer = &analysis.Analyzer{
|
||||
Name: "testingcontext",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "testingcontext"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "testingcontext"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -56,8 +55,6 @@ var TestingContextAnalyzer = &analysis.Analyzer{
|
|||
// - the call is within a test or subtest function
|
||||
// - the relevant testing.{T,B,F} is named and not shadowed at the call
|
||||
func testingContext(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
|
@ -137,7 +134,7 @@ calls:
|
|||
testObj = isTestFn(info, n)
|
||||
}
|
||||
}
|
||||
if testObj != nil && fileUses(info, astutil.EnclosingFile(cur), "go1.24") {
|
||||
if testObj != nil && analyzerutil.FileUsesGoVersion(pass, astutil.EnclosingFile(cur), versions.Go1_24) {
|
||||
// Have a test function. Check that we can resolve the relevant
|
||||
// testing.{T,B,F} at the current position.
|
||||
if _, obj := lhs[0].Parent().LookupParent(testObj.Name(), lhs[0].Pos()); obj == testObj {
|
||||
|
|
|
|||
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go
generated
vendored
13
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/modernize/waitgroup.go
generated
vendored
|
|
@ -14,19 +14,18 @@ import (
|
|||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysisinternal/generated"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
typeindexanalyzer "golang.org/x/tools/internal/analysis/typeindex"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
"golang.org/x/tools/internal/typesinternal/typeindex"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
var WaitGroupAnalyzer = &analysis.Analyzer{
|
||||
Name: "waitgroup",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "waitgroup"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "waitgroup"),
|
||||
Requires: []*analysis.Analyzer{
|
||||
generated.Analyzer,
|
||||
inspect.Analyzer,
|
||||
typeindexanalyzer.Analyzer,
|
||||
},
|
||||
|
|
@ -61,8 +60,6 @@ var WaitGroupAnalyzer = &analysis.Analyzer{
|
|||
// other effects, or blocked, or if WaitGroup.Go propagated panics
|
||||
// from child to parent goroutine, the argument would be different.)
|
||||
func waitgroup(pass *analysis.Pass) (any, error) {
|
||||
skipGenerated(pass)
|
||||
|
||||
var (
|
||||
index = pass.ResultOf[typeindexanalyzer.Analyzer].(*typeindex.Index)
|
||||
info = pass.TypesInfo
|
||||
|
|
@ -128,7 +125,7 @@ func waitgroup(pass *analysis.Pass) (any, error) {
|
|||
}
|
||||
|
||||
file := astutil.EnclosingFile(curAddCall)
|
||||
if !fileUses(info, file, "go1.25") {
|
||||
if !analyzerutil.FileUsesGoVersion(pass, file, versions.Go1_25) {
|
||||
continue
|
||||
}
|
||||
tokFile := pass.Fset.File(file.Pos())
|
||||
|
|
|
|||
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
|
|
@ -15,7 +15,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "nilfunc",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "nilfunc"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "nilfunc"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
24
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
24
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
generated
vendored
|
|
@ -21,7 +21,7 @@ import (
|
|||
"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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/fmtstr"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
|
|
@ -38,7 +38,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "printf",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "printf"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "printf"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -612,7 +612,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
|
|||
// breaking existing tests and CI scripts.
|
||||
if idx == len(call.Args)-1 &&
|
||||
fileVersion != "" && // fail open
|
||||
versions.AtLeast(fileVersion, "go1.24") {
|
||||
versions.AtLeast(fileVersion, versions.Go1_24) {
|
||||
|
||||
pass.Report(analysis.Diagnostic{
|
||||
Pos: formatArg.Pos(),
|
||||
|
|
@ -662,7 +662,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
|
|||
anyIndex = true
|
||||
}
|
||||
rng := opRange(formatArg, op)
|
||||
if !okPrintfArg(pass, call, rng, &maxArgIndex, firstArg, name, op) {
|
||||
if !okPrintfArg(pass, fileVersion, call, rng, &maxArgIndex, firstArg, name, op) {
|
||||
// One error per format is enough.
|
||||
return
|
||||
}
|
||||
|
|
@ -694,9 +694,9 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C
|
|||
// such as the position of the %v substring of "...%v...".
|
||||
func opRange(formatArg ast.Expr, op *fmtstr.Operation) analysis.Range {
|
||||
if lit, ok := formatArg.(*ast.BasicLit); ok {
|
||||
start, end, err := astutil.RangeInStringLiteral(lit, op.Range.Start, op.Range.End)
|
||||
rng, err := astutil.RangeInStringLiteral(lit, op.Range.Start, op.Range.End)
|
||||
if err == nil {
|
||||
return analysisinternal.Range(start, end) // position of "%v"
|
||||
return rng // position of "%v"
|
||||
}
|
||||
}
|
||||
return formatArg // entire format string
|
||||
|
|
@ -707,6 +707,7 @@ type printfArgType int
|
|||
|
||||
const (
|
||||
argBool printfArgType = 1 << iota
|
||||
argByte
|
||||
argInt
|
||||
argRune
|
||||
argString
|
||||
|
|
@ -751,7 +752,7 @@ var printVerbs = []printVerb{
|
|||
{'o', sharpNumFlag, argInt | argPointer},
|
||||
{'O', sharpNumFlag, argInt | argPointer},
|
||||
{'p', "-#", argPointer},
|
||||
{'q', " -+.0#", argRune | argInt | argString},
|
||||
{'q', " -+.0#", argRune | argInt | argString}, // note: when analyzing go1.26 code, argInt => argByte
|
||||
{'s', " -+.0", argString},
|
||||
{'t', "-", argBool},
|
||||
{'T', "-", anyType},
|
||||
|
|
@ -765,7 +766,7 @@ var printVerbs = []printVerb{
|
|||
// okPrintfArg compares the operation to the arguments actually present,
|
||||
// reporting any discrepancies it can discern, maxArgIndex was the index of the highest used index.
|
||||
// If the final argument is ellipsissed, there's little it can do for that.
|
||||
func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) {
|
||||
func okPrintfArg(pass *analysis.Pass, fileVersion string, call *ast.CallExpr, rng analysis.Range, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) {
|
||||
verb := operation.Verb.Verb
|
||||
var v printVerb
|
||||
found := false
|
||||
|
|
@ -777,6 +778,13 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, rng analysis.Range, ma
|
|||
}
|
||||
}
|
||||
|
||||
// When analyzing go1.26 code, rune and byte are the only %q integers (#72850).
|
||||
if verb == 'q' &&
|
||||
fileVersion != "" && // fail open
|
||||
versions.AtLeast(fileVersion, versions.Go1_26) {
|
||||
v.typ = argRune | argByte | argString
|
||||
}
|
||||
|
||||
// Could verb's arg implement fmt.Formatter?
|
||||
// Skip check for the %w verb, which requires an error.
|
||||
formatter := false
|
||||
|
|
|
|||
16
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
generated
vendored
16
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/types.go
generated
vendored
|
|
@ -204,8 +204,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
|
|||
case *types.Struct:
|
||||
// report whether all the elements of the struct match the expected type. For
|
||||
// instance, with "%d" all the elements must be printable with the "%d" format.
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
typf := typ.Field(i)
|
||||
for typf := range typ.Fields() {
|
||||
if !m.match(typf.Type(), false) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -228,14 +227,20 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
|
|||
types.Bool:
|
||||
return m.t&argBool != 0
|
||||
|
||||
case types.Byte:
|
||||
return m.t&(argInt|argByte) != 0
|
||||
|
||||
case types.Rune, types.UntypedRune:
|
||||
return m.t&(argInt|argRune) != 0
|
||||
|
||||
case types.UntypedInt,
|
||||
types.Int,
|
||||
types.Int8,
|
||||
types.Int16,
|
||||
types.Int32,
|
||||
// see case Rune for int32
|
||||
types.Int64,
|
||||
types.Uint,
|
||||
types.Uint8,
|
||||
// see case Byte for uint8
|
||||
types.Uint16,
|
||||
types.Uint32,
|
||||
types.Uint64,
|
||||
|
|
@ -259,9 +264,6 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
|
|||
case types.UnsafePointer:
|
||||
return m.t&(argPointer|argInt) != 0
|
||||
|
||||
case types.UntypedRune:
|
||||
return m.t&(argInt|argRune) != 0
|
||||
|
||||
case types.UntypedNil:
|
||||
return false
|
||||
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go
generated
vendored
|
|
@ -19,7 +19,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ var doc string
|
|||
// Analyzer describes sigchanyzer analysis function detector.
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "sigchanyzer",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "sigchanyzer"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "sigchanyzer"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sigchanyzer",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
generated
vendored
|
|
@ -19,7 +19,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"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: analysisinternal.MustExtractDoc(doc, "slog"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "slog"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/slog",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -168,7 +168,7 @@ func isAttr(t types.Type) bool {
|
|||
// "slog.Logger.With" (instead of "(*log/slog.Logger).With")
|
||||
func shortName(fn *types.Func) string {
|
||||
var r string
|
||||
if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
|
||||
if recv := fn.Signature().Recv(); recv != nil {
|
||||
if _, named := typesinternal.ReceiverNamed(recv); named != nil {
|
||||
r = named.Obj().Name()
|
||||
} else {
|
||||
|
|
@ -188,7 +188,7 @@ func kvFuncSkipArgs(fn *types.Func) (int, bool) {
|
|||
return 0, false
|
||||
}
|
||||
var recvName string // by default a slog package function
|
||||
if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
|
||||
if recv := fn.Signature().Recv(); recv != nil {
|
||||
_, named := typesinternal.ReceiverNamed(recv)
|
||||
if named == nil {
|
||||
return 0, false // anon struct/interface
|
||||
|
|
|
|||
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
generated
vendored
10
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
generated
vendored
|
|
@ -13,7 +13,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/analysis/analyzerutil"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -21,7 +21,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "stdmethods",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "stdmethods"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stdmethods"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -131,12 +131,12 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) {
|
|||
}
|
||||
|
||||
// Do the =s (if any) all match?
|
||||
if !matchParams(pass, expect.args, args, "=") || !matchParams(pass, expect.results, results, "=") {
|
||||
if !matchParams(expect.args, args, "=") || !matchParams(expect.results, results, "=") {
|
||||
return
|
||||
}
|
||||
|
||||
// Everything must match.
|
||||
if !matchParams(pass, expect.args, args, "") || !matchParams(pass, expect.results, results, "") {
|
||||
if !matchParams(expect.args, args, "") || !matchParams(expect.results, results, "") {
|
||||
expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
|
||||
if len(expect.results) == 1 {
|
||||
expectFmt += " " + argjoin(expect.results)
|
||||
|
|
@ -168,7 +168,7 @@ func argjoin(x []string) string {
|
|||
}
|
||||
|
||||
// Does each type in expect with the given prefix match the corresponding type in actual?
|
||||
func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, prefix string) bool {
|
||||
func matchParams(expect []string, actual *types.Tuple, prefix string) bool {
|
||||
for i, x := range expect {
|
||||
if !strings.HasPrefix(x, prefix) {
|
||||
continue
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
|
|
@ -14,7 +14,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/analysis/analyzerutil"
|
||||
"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: analysisinternal.MustExtractDoc(doc, "stringintconv"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "stringintconv"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ func init() {
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "testinggoroutine",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "testinggoroutine"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "testinggoroutine"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
generated
vendored
|
|
@ -36,7 +36,7 @@ func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *
|
|||
// isMethodNamed returns true if f is a method defined
|
||||
// in package with the path pkgPath with a name in names.
|
||||
//
|
||||
// (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.)
|
||||
// (Unlike [analysis.IsMethodNamed], it ignores the receiver type name.)
|
||||
func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
|
||||
if f == nil {
|
||||
return false
|
||||
|
|
@ -44,7 +44,7 @@ func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
|
|||
if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
|
||||
return false
|
||||
}
|
||||
if f.Type().(*types.Signature).Recv() == nil {
|
||||
if f.Signature().Recv() == nil {
|
||||
return false
|
||||
}
|
||||
return slices.Contains(names, f.Name())
|
||||
|
|
|
|||
7
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
generated
vendored
7
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
generated
vendored
|
|
@ -15,7 +15,8 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "tests",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "tests"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "tests"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
|
||||
Run: run,
|
||||
}
|
||||
|
|
@ -464,7 +465,7 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) {
|
|||
if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 {
|
||||
// Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters.
|
||||
// We have currently decided to also warn before compilation/package loading. This can help users in IDEs.
|
||||
pass.ReportRangef(analysisinternal.Range(tparams.Opening, tparams.Closing),
|
||||
pass.ReportRangef(astutil.RangeOf(tparams.Opening, tparams.Closing),
|
||||
"%s has type parameters: it will not be run by go test as a %sXXX function",
|
||||
fn.Name.Name, prefix)
|
||||
}
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
generated
vendored
6
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
generated
vendored
|
|
@ -18,7 +18,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "timeformat",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "timeformat"),
|
||||
Doc: analyzerutil.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 !analysisinternal.Imports(pass.Pkg, "time").
|
||||
// when !analysis.Imports(pass.Pkg, "time").
|
||||
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
|
|
|||
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
generated
vendored
8
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unmarshal",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unmarshal"),
|
||||
Doc: analyzerutil.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 !analysisinternal.Imports(pass.Pkg, "encoding/...").
|
||||
// when !analysis.Imports(pass.Pkg, "encoding/...").
|
||||
// TODO(taking): Consider using a prepass to collect typeutil.Callees.
|
||||
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
|
|
@ -57,7 +57,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
// Classify the callee (without allocating memory).
|
||||
argidx := -1
|
||||
|
||||
recv := fn.Type().(*types.Signature).Recv()
|
||||
recv := fn.Signature().Recv()
|
||||
if fn.Name() == "Unmarshal" && recv == nil {
|
||||
// "encoding/json".Unmarshal
|
||||
// "encoding/xml".Unmarshal
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
generated
vendored
|
|
@ -15,7 +15,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/refactor"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unreachable",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unreachable"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "unreachable"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
RunDespiteErrors: true,
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
generated
vendored
|
|
@ -15,7 +15,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/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unsafeptr",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unsafeptr"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "unsafeptr"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
11
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
generated
vendored
11
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
generated
vendored
|
|
@ -25,7 +25,8 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/astutil"
|
||||
)
|
||||
|
||||
//go:embed doc.go
|
||||
|
|
@ -33,7 +34,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "unusedresult",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "unusedresult"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "unusedresult"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
@ -149,11 +150,11 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
if !ok {
|
||||
return // e.g. var or builtin
|
||||
}
|
||||
if sig := fn.Type().(*types.Signature); sig.Recv() != nil {
|
||||
if sig := fn.Signature(); sig.Recv() != nil {
|
||||
// method (e.g. foo.String())
|
||||
if types.Identical(sig, sigNoArgsStringResult) {
|
||||
if stringMethods[fn.Name()] {
|
||||
pass.ReportRangef(analysisinternal.Range(call.Pos(), call.Lparen),
|
||||
pass.ReportRangef(astutil.RangeOf(call.Pos(), call.Lparen),
|
||||
"result of (%s).%s call not used",
|
||||
sig.Recv().Type(), fn.Name())
|
||||
}
|
||||
|
|
@ -161,7 +162,7 @@ func run(pass *analysis.Pass) (any, error) {
|
|||
} else {
|
||||
// package-level function (e.g. fmt.Errorf)
|
||||
if pkgFuncs[[2]string{fn.Pkg().Path(), fn.Name()}] {
|
||||
pass.ReportRangef(analysisinternal.Range(call.Pos(), call.Lparen),
|
||||
pass.ReportRangef(astutil.RangeOf(call.Pos(), call.Lparen),
|
||||
"result of %s.%s call not used",
|
||||
fn.Pkg().Path(), fn.Name())
|
||||
}
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/waitgroup/waitgroup.go
generated
vendored
|
|
@ -15,7 +15,7 @@ import (
|
|||
"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"
|
||||
"golang.org/x/tools/internal/analysis/analyzerutil"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ var doc string
|
|||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "waitgroup",
|
||||
Doc: analysisinternal.MustExtractDoc(doc, "waitgroup"),
|
||||
Doc: analyzerutil.MustExtractDoc(doc, "waitgroup"),
|
||||
URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/waitgroup",
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
|
|
|
|||
28
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
28
src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
|
|
@ -49,7 +49,7 @@ import (
|
|||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/internal/analysisflags"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/analysis/driverutil"
|
||||
"golang.org/x/tools/internal/facts"
|
||||
)
|
||||
|
||||
|
|
@ -183,16 +183,18 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
|
|||
// but apply all fixes from the root actions.
|
||||
|
||||
// Convert results to form needed by ApplyFixes.
|
||||
fixActions := make([]analysisflags.FixAction, len(results))
|
||||
fixActions := make([]driverutil.FixAction, len(results))
|
||||
for i, res := range results {
|
||||
fixActions[i] = analysisflags.FixAction{
|
||||
fixActions[i] = driverutil.FixAction{
|
||||
Name: res.a.Name,
|
||||
Pkg: res.pkg,
|
||||
Files: res.files,
|
||||
FileSet: fset,
|
||||
ReadFileFunc: os.ReadFile,
|
||||
ReadFileFunc: os.ReadFile, // TODO(adonovan): respect overlays
|
||||
Diagnostics: res.diagnostics,
|
||||
}
|
||||
}
|
||||
if err := analysisflags.ApplyFixes(fixActions, false); err != nil {
|
||||
if err := driverutil.ApplyFixes(fixActions, analysisflags.Diff, false); err != nil {
|
||||
// Fail when applying fixes failed.
|
||||
log.Print(err)
|
||||
exit = 1
|
||||
|
|
@ -209,7 +211,7 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
|
|||
|
||||
if analysisflags.JSON {
|
||||
// JSON output
|
||||
tree := make(analysisflags.JSONTree)
|
||||
tree := make(driverutil.JSONTree)
|
||||
for _, res := range results {
|
||||
tree.Add(fset, id, res.a.Name, res.diagnostics, res.err)
|
||||
}
|
||||
|
|
@ -225,7 +227,7 @@ func processResults(fset *token.FileSet, id string, results []result) (exit int)
|
|||
}
|
||||
for _, res := range results {
|
||||
for _, diag := range res.diagnostics {
|
||||
analysisflags.PrintPlain(os.Stderr, fset, analysisflags.Context, diag)
|
||||
driverutil.PrintPlain(os.Stderr, fset, analysisflags.Context, diag)
|
||||
exit = 1
|
||||
}
|
||||
}
|
||||
|
|
@ -428,7 +430,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
|
|||
ResultOf: inputs,
|
||||
Report: func(d analysis.Diagnostic) {
|
||||
// Unitchecker doesn't apply fixes, but it does report them in the JSON output.
|
||||
if err := analysisinternal.ValidateFixes(fset, a, d.SuggestedFixes); err != nil {
|
||||
if err := driverutil.ValidateFixes(fset, a, d.SuggestedFixes); err != nil {
|
||||
// Since we have diagnostics, the exit code will be nonzero,
|
||||
// so logging these errors is sufficient.
|
||||
log.Println(err)
|
||||
|
|
@ -444,14 +446,14 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
|
|||
AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) },
|
||||
Module: module,
|
||||
}
|
||||
pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile)
|
||||
pass.ReadFile = driverutil.CheckedReadFile(pass, os.ReadFile)
|
||||
|
||||
t0 := time.Now()
|
||||
act.result, act.err = a.Run(pass)
|
||||
|
||||
if act.err == nil { // resolve URLs on diagnostics.
|
||||
for i := range act.diagnostics {
|
||||
if url, uerr := analysisflags.ResolveURL(a, act.diagnostics[i]); uerr == nil {
|
||||
if url, uerr := driverutil.ResolveURL(a, act.diagnostics[i]); uerr == nil {
|
||||
act.diagnostics[i].URL = url
|
||||
} else {
|
||||
act.err = uerr // keep the last error
|
||||
|
|
@ -482,9 +484,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
|
|||
results := make([]result, len(analyzers))
|
||||
for i, a := range analyzers {
|
||||
act := actions[a]
|
||||
results[i].a = a
|
||||
results[i].err = act.err
|
||||
results[i].diagnostics = act.diagnostics
|
||||
results[i] = result{pkg, files, a, act.diagnostics, act.err}
|
||||
}
|
||||
|
||||
data := facts.Encode()
|
||||
|
|
@ -499,6 +499,8 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
|
|||
}
|
||||
|
||||
type result struct {
|
||||
pkg *types.Package
|
||||
files []*ast.File
|
||||
a *analysis.Analyzer
|
||||
diagnostics []analysis.Diagnostic
|
||||
err error
|
||||
|
|
|
|||
17
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
generated
vendored
17
src/cmd/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
generated
vendored
|
|
@ -467,7 +467,9 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
|
|||
// This algorithm could be implemented using c.Inspect,
|
||||
// but it is about 2.5x slower.
|
||||
|
||||
best := int32(-1) // push index of latest (=innermost) node containing range
|
||||
// best is the push-index of the latest (=innermost) node containing range.
|
||||
// (Beware: latest is not always innermost because FuncDecl.{Name,Type} overlap.)
|
||||
best := int32(-1)
|
||||
for i, limit := c.indices(); i < limit; i++ {
|
||||
ev := events[i]
|
||||
if ev.index > i { // push?
|
||||
|
|
@ -481,6 +483,19 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
|
|||
continue
|
||||
}
|
||||
} else {
|
||||
// Edge case: FuncDecl.Name and .Type overlap:
|
||||
// Don't update best from Name to FuncDecl.Type.
|
||||
//
|
||||
// The condition can be read as:
|
||||
// - n is FuncType
|
||||
// - n.parent is FuncDecl
|
||||
// - best is strictly beneath the FuncDecl
|
||||
if ev.typ == 1<<nFuncType &&
|
||||
events[ev.parent].typ == 1<<nFuncDecl &&
|
||||
best > ev.parent {
|
||||
continue
|
||||
}
|
||||
|
||||
nodeEnd = n.End()
|
||||
if n.Pos() > start {
|
||||
break // disjoint, after; stop
|
||||
|
|
|
|||
16
src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go
generated
vendored
16
src/cmd/vendor/golang.org/x/tools/go/cfg/builder.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
type builder struct {
|
||||
cfg *CFG
|
||||
blocks []*Block
|
||||
mayReturn func(*ast.CallExpr) bool
|
||||
current *Block
|
||||
lblocks map[string]*lblock // labeled blocks
|
||||
|
|
@ -32,12 +32,18 @@ start:
|
|||
*ast.SendStmt,
|
||||
*ast.IncDecStmt,
|
||||
*ast.GoStmt,
|
||||
*ast.DeferStmt,
|
||||
*ast.EmptyStmt,
|
||||
*ast.AssignStmt:
|
||||
// No effect on control flow.
|
||||
b.add(s)
|
||||
|
||||
case *ast.DeferStmt:
|
||||
b.add(s)
|
||||
// Assume conservatively that this behaves like:
|
||||
// defer func() { recover() }
|
||||
// so any subsequent panic may act like a return.
|
||||
b.current.returns = true
|
||||
|
||||
case *ast.ExprStmt:
|
||||
b.add(s)
|
||||
if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
|
||||
|
|
@ -64,6 +70,7 @@ start:
|
|||
goto start // effectively: tailcall stmt(g, s.Stmt, label)
|
||||
|
||||
case *ast.ReturnStmt:
|
||||
b.current.returns = true
|
||||
b.add(s)
|
||||
b.current = b.newBlock(KindUnreachable, s)
|
||||
|
||||
|
|
@ -483,14 +490,13 @@ func (b *builder) labeledBlock(label *ast.Ident, stmt *ast.LabeledStmt) *lblock
|
|||
// It does not automatically become the current block.
|
||||
// comment is an optional string for more readable debugging output.
|
||||
func (b *builder) newBlock(kind BlockKind, stmt ast.Stmt) *Block {
|
||||
g := b.cfg
|
||||
block := &Block{
|
||||
Index: int32(len(g.Blocks)),
|
||||
Index: int32(len(b.blocks)),
|
||||
Kind: kind,
|
||||
Stmt: stmt,
|
||||
}
|
||||
block.Succs = block.succs2[:0]
|
||||
g.Blocks = append(g.Blocks, block)
|
||||
b.blocks = append(b.blocks, block)
|
||||
return block
|
||||
}
|
||||
|
||||
|
|
|
|||
54
src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go
generated
vendored
54
src/cmd/vendor/golang.org/x/tools/go/cfg/cfg.go
generated
vendored
|
|
@ -47,13 +47,16 @@ import (
|
|||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
|
||||
"golang.org/x/tools/internal/cfginternal"
|
||||
)
|
||||
|
||||
// A CFG represents the control-flow graph of a single function.
|
||||
//
|
||||
// The entry point is Blocks[0]; there may be multiple return blocks.
|
||||
type CFG struct {
|
||||
Blocks []*Block // block[0] is entry; order otherwise undefined
|
||||
Blocks []*Block // block[0] is entry; order otherwise undefined
|
||||
noreturn bool // function body lacks a reachable return statement
|
||||
}
|
||||
|
||||
// A Block represents a basic block: a list of statements and
|
||||
|
|
@ -67,12 +70,13 @@ type CFG struct {
|
|||
// an [ast.Expr], Succs[0] is the successor if the condition is true, and
|
||||
// Succs[1] is the successor if the condition is false.
|
||||
type Block struct {
|
||||
Nodes []ast.Node // statements, expressions, and ValueSpecs
|
||||
Succs []*Block // successor nodes in the graph
|
||||
Index int32 // index within CFG.Blocks
|
||||
Live bool // block is reachable from entry
|
||||
Kind BlockKind // block kind
|
||||
Stmt ast.Stmt // statement that gave rise to this block (see BlockKind for details)
|
||||
Nodes []ast.Node // statements, expressions, and ValueSpecs
|
||||
Succs []*Block // successor nodes in the graph
|
||||
Index int32 // index within CFG.Blocks
|
||||
Live bool // block is reachable from entry
|
||||
returns bool // block contains return or defer (which may recover and return)
|
||||
Kind BlockKind // block kind
|
||||
Stmt ast.Stmt // statement that gave rise to this block (see BlockKind for details)
|
||||
|
||||
succs2 [2]*Block // underlying array for Succs
|
||||
}
|
||||
|
|
@ -141,14 +145,14 @@ func (kind BlockKind) String() string {
|
|||
func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
|
||||
b := builder{
|
||||
mayReturn: mayReturn,
|
||||
cfg: new(CFG),
|
||||
}
|
||||
b.current = b.newBlock(KindBody, body)
|
||||
b.stmt(body)
|
||||
|
||||
// Compute liveness (reachability from entry point), breadth-first.
|
||||
q := make([]*Block, 0, len(b.cfg.Blocks))
|
||||
q = append(q, b.cfg.Blocks[0]) // entry point
|
||||
// Compute liveness (reachability from entry point),
|
||||
// breadth-first, marking Block.Live flags.
|
||||
q := make([]*Block, 0, len(b.blocks))
|
||||
q = append(q, b.blocks[0]) // entry point
|
||||
for len(q) > 0 {
|
||||
b := q[len(q)-1]
|
||||
q = q[:len(q)-1]
|
||||
|
|
@ -162,12 +166,30 @@ func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
|
|||
// Does control fall off the end of the function's body?
|
||||
// Make implicit return explicit.
|
||||
if b.current != nil && b.current.Live {
|
||||
b.current.returns = true
|
||||
b.add(&ast.ReturnStmt{
|
||||
Return: body.End() - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return b.cfg
|
||||
// Is any return (or defer+recover) block reachable?
|
||||
noreturn := true
|
||||
for _, bl := range b.blocks {
|
||||
if bl.Live && bl.returns {
|
||||
noreturn = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &CFG{Blocks: b.blocks, noreturn: noreturn}
|
||||
}
|
||||
|
||||
// isNoReturn reports whether the function has no reachable return.
|
||||
// TODO(adonovan): add (*CFG).NoReturn to public API.
|
||||
func isNoReturn(_cfg any) bool { return _cfg.(*CFG).noreturn }
|
||||
|
||||
func init() {
|
||||
cfginternal.IsNoReturn = isNoReturn // expose to ctrlflow analyzer
|
||||
}
|
||||
|
||||
func (b *Block) String() string {
|
||||
|
|
@ -187,6 +209,14 @@ func (b *Block) comment(fset *token.FileSet) string {
|
|||
//
|
||||
// When control falls off the end of the function, the ReturnStmt is synthetic
|
||||
// and its [ast.Node.End] position may be beyond the end of the file.
|
||||
//
|
||||
// A function that contains no return statement (explicit or implied)
|
||||
// may yet return normally, and may even return a nonzero value. For example:
|
||||
//
|
||||
// func() (res any) {
|
||||
// defer func() { res = recover() }()
|
||||
// panic(123)
|
||||
// }
|
||||
func (b *Block) Return() (ret *ast.ReturnStmt) {
|
||||
if len(b.Nodes) > 0 {
|
||||
ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
|
||||
|
|
|
|||
4
src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
4
src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
generated
vendored
|
|
@ -249,7 +249,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
|
|||
|
||||
case *types.Func:
|
||||
// A func, if not package-level, must be a method.
|
||||
if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
|
||||
if recv := obj.Signature().Recv(); recv == nil {
|
||||
return "", fmt.Errorf("func is not a method: %v", obj)
|
||||
}
|
||||
|
||||
|
|
@ -405,7 +405,7 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
|
|||
return "", false
|
||||
}
|
||||
|
||||
_, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv())
|
||||
_, named := typesinternal.ReceiverNamed(meth.Signature().Recv())
|
||||
if named == nil {
|
||||
return "", false
|
||||
}
|
||||
|
|
|
|||
3
src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
3
src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
|
|
@ -304,8 +304,7 @@ func (h hasher) hash(t types.Type) uint32 {
|
|||
case *types.Named:
|
||||
hash := h.hashTypeName(t.Obj())
|
||||
targs := t.TypeArgs()
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
targ := targs.At(i)
|
||||
for targ := range targs.Types() {
|
||||
hash += 2 * h.hash(targ)
|
||||
}
|
||||
return hash
|
||||
|
|
|
|||
6
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go
generated
vendored
Normal file
6
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// 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 analyzerutil provides implementation helpers for analyzers.
|
||||
package analyzerutil
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package analysisinternal
|
||||
package analyzerutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -35,7 +35,7 @@ import (
|
|||
//
|
||||
// var Analyzer = &analysis.Analyzer{
|
||||
// Name: "halting",
|
||||
// Doc: analysisinternal.MustExtractDoc(doc, "halting"),
|
||||
// Doc: analyzerutil.MustExtractDoc(doc, "halting"),
|
||||
// ...
|
||||
// }
|
||||
func MustExtractDoc(content, name string) string {
|
||||
30
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go
generated
vendored
Normal file
30
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/readfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// 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 analyzerutil
|
||||
|
||||
// This file defines helpers for calling [analysis.Pass.ReadFile].
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
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
|
||||
}
|
||||
42
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
generated
vendored
Normal file
42
src/cmd/vendor/golang.org/x/tools/internal/analysis/analyzerutil/version.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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 analyzerutil
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/packagepath"
|
||||
"golang.org/x/tools/internal/stdlib"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
// FileUsesGoVersion reports whether the specified file may use features of the
|
||||
// specified version of Go (e.g. "go1.24").
|
||||
//
|
||||
// Tip: we recommend using this check "late", just before calling
|
||||
// pass.Report, rather than "early" (when entering each ast.File, or
|
||||
// each candidate node of interest, during the traversal), because the
|
||||
// operation is not free, yet is not a highly selective filter: the
|
||||
// fraction of files that pass most version checks is high and
|
||||
// increases over time.
|
||||
func FileUsesGoVersion(pass *analysis.Pass, file *ast.File, version string) (_res bool) {
|
||||
fileVersion := pass.TypesInfo.FileVersions[file]
|
||||
|
||||
// Standard packages that are part of toolchain bootstrapping
|
||||
// are not considered to use a version of Go later than the
|
||||
// current bootstrap toolchain version.
|
||||
// The bootstrap rule does not cover tests,
|
||||
// and some tests (e.g. debug/elf/file_test.go) rely on this.
|
||||
pkgpath := pass.Pkg.Path()
|
||||
if packagepath.IsStdPackage(pkgpath) &&
|
||||
stdlib.IsBootstrapPackage(pkgpath) && // (excludes "*_test" external test packages)
|
||||
!strings.HasSuffix(pass.Fset.File(file.Pos()).Name(), "_test.go") { // (excludes all tests)
|
||||
fileVersion = stdlib.BootstrapVersion.String() // package must bootstrap
|
||||
}
|
||||
|
||||
return !versions.Before(fileVersion, version)
|
||||
}
|
||||
|
|
@ -2,37 +2,48 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package analysisflags
|
||||
// Package driverutil defines implementation helper functions for
|
||||
// analysis drivers such as unitchecker, {single,multi}checker, and
|
||||
// analysistest.
|
||||
package driverutil
|
||||
|
||||
// This file defines the -fix logic common to unitchecker and
|
||||
// {single,multi}checker.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/astutil/free"
|
||||
"golang.org/x/tools/internal/diff"
|
||||
)
|
||||
|
||||
// FixAction abstracts a checker action (running one analyzer on one
|
||||
// package) for the purposes of applying its diagnostics' fixes.
|
||||
type FixAction struct {
|
||||
Name string // e.g. "analyzer@package"
|
||||
Name string // e.g. "analyzer@package"
|
||||
Pkg *types.Package // (for import removal)
|
||||
Files []*ast.File
|
||||
FileSet *token.FileSet
|
||||
ReadFileFunc analysisinternal.ReadFileFunc
|
||||
ReadFileFunc ReadFileFunc
|
||||
Diagnostics []analysis.Diagnostic
|
||||
}
|
||||
|
||||
// ApplyFixes attempts to apply the first suggested fix associated
|
||||
// with each diagnostic reported by the specified actions.
|
||||
// All fixes must have been validated by [analysisinternal.ValidateFixes].
|
||||
// All fixes must have been validated by [ValidateFixes].
|
||||
//
|
||||
// Each fix is treated as an independent change; fixes are merged in
|
||||
// an arbitrary deterministic order as if by a three-way diff tool
|
||||
|
|
@ -58,15 +69,15 @@ type FixAction struct {
|
|||
// composition of the two fixes is semantically correct. Coalescing
|
||||
// identical edits is appropriate for imports, but not for, say,
|
||||
// increments to a counter variable; the correct resolution in that
|
||||
// case might be to increment it twice. Or consider two fixes that
|
||||
// each delete the penultimate reference to an import or local
|
||||
// variable: each fix is sound individually, and they may be textually
|
||||
// distant from each other, but when both are applied, the program is
|
||||
// no longer valid because it has an unreferenced import or local
|
||||
// variable.
|
||||
// TODO(adonovan): investigate replacing the final "gofmt" step with a
|
||||
// formatter that applies the unused-import deletion logic of
|
||||
// "goimports".
|
||||
// case might be to increment it twice.
|
||||
//
|
||||
// Or consider two fixes that each delete the penultimate reference to
|
||||
// a local variable: each fix is sound individually, and they may be
|
||||
// textually distant from each other, but when both are applied, the
|
||||
// program is no longer valid because it has an unreferenced local
|
||||
// variable. (ApplyFixes solves the analogous problem for imports by
|
||||
// eliminating imports whose name is unreferenced in the remainder of
|
||||
// the fixed file.)
|
||||
//
|
||||
// Merging depends on both the order of fixes and they order of edits
|
||||
// within them. For example, if three fixes add import "a" twice and
|
||||
|
|
@ -80,12 +91,15 @@ type FixAction struct {
|
|||
// applyFixes returns success if all fixes are valid, could be cleanly
|
||||
// merged, and the corresponding files were successfully updated.
|
||||
//
|
||||
// If the -diff flag was set, instead of updating the files it display the final
|
||||
// patch composed of all the cleanly merged fixes.
|
||||
// If printDiff (from the -diff flag) is set, instead of updating the
|
||||
// files it display the final patch composed of all the cleanly merged
|
||||
// fixes.
|
||||
//
|
||||
// TODO(adonovan): handle file-system level aliases such as symbolic
|
||||
// links using robustio.FileID.
|
||||
func ApplyFixes(actions []FixAction, verbose bool) error {
|
||||
func ApplyFixes(actions []FixAction, printDiff, verbose bool) error {
|
||||
generated := make(map[*token.File]bool)
|
||||
|
||||
// Select fixes to apply.
|
||||
//
|
||||
// If there are several for a given Diagnostic, choose the first.
|
||||
|
|
@ -96,6 +110,15 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
|
|||
}
|
||||
var fixes []*fixact
|
||||
for _, act := range actions {
|
||||
for _, file := range act.Files {
|
||||
tokFile := act.FileSet.File(file.FileStart)
|
||||
// Memoize, since there may be many actions
|
||||
// for the same package (list of files).
|
||||
if _, seen := generated[tokFile]; !seen {
|
||||
generated[tokFile] = ast.IsGenerated(file)
|
||||
}
|
||||
}
|
||||
|
||||
for _, diag := range act.Diagnostics {
|
||||
for i := range diag.SuggestedFixes {
|
||||
fix := &diag.SuggestedFixes[i]
|
||||
|
|
@ -119,7 +142,7 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
|
|||
// packages are not disjoint, due to test variants, so this
|
||||
// would not really address the issue.)
|
||||
baselineContent := make(map[string][]byte)
|
||||
getBaseline := func(readFile analysisinternal.ReadFileFunc, filename string) ([]byte, error) {
|
||||
getBaseline := func(readFile ReadFileFunc, filename string) ([]byte, error) {
|
||||
content, ok := baselineContent[filename]
|
||||
if !ok {
|
||||
var err error
|
||||
|
|
@ -134,16 +157,32 @@ func ApplyFixes(actions []FixAction, verbose bool) error {
|
|||
|
||||
// Apply each fix, updating the current state
|
||||
// only if the entire fix can be cleanly merged.
|
||||
accumulatedEdits := make(map[string][]diff.Edit)
|
||||
goodFixes := 0
|
||||
var (
|
||||
accumulatedEdits = make(map[string][]diff.Edit)
|
||||
filePkgs = make(map[string]*types.Package) // maps each file to an arbitrary package that includes it
|
||||
|
||||
goodFixes = 0 // number of fixes cleanly applied
|
||||
skippedFixes = 0 // number of fixes skipped (because e.g. edits a generated file)
|
||||
)
|
||||
fixloop:
|
||||
for _, fixact := range fixes {
|
||||
// Skip a fix if any of its edits touch a generated file.
|
||||
for _, edit := range fixact.fix.TextEdits {
|
||||
file := fixact.act.FileSet.File(edit.Pos)
|
||||
if generated[file] {
|
||||
skippedFixes++
|
||||
continue fixloop
|
||||
}
|
||||
}
|
||||
|
||||
// Convert analysis.TextEdits to diff.Edits, grouped by file.
|
||||
// Precondition: a prior call to validateFix succeeded.
|
||||
fileEdits := make(map[string][]diff.Edit)
|
||||
for _, edit := range fixact.fix.TextEdits {
|
||||
file := fixact.act.FileSet.File(edit.Pos)
|
||||
|
||||
filePkgs[file.Name()] = fixact.act.Pkg
|
||||
|
||||
baseline, err := getBaseline(fixact.act.ReadFileFunc, file.Name())
|
||||
if err != nil {
|
||||
log.Printf("skipping fix to file %s: %v", file.Name(), err)
|
||||
|
|
@ -191,7 +230,7 @@ fixloop:
|
|||
log.Printf("%s: fix %s applied", fixact.act.Name, fixact.fix.Message)
|
||||
}
|
||||
}
|
||||
badFixes := len(fixes) - goodFixes
|
||||
badFixes := len(fixes) - goodFixes - skippedFixes // number of fixes that could not be applied
|
||||
|
||||
// Show diff or update files to final state.
|
||||
var files []string
|
||||
|
|
@ -214,11 +253,11 @@ fixloop:
|
|||
}
|
||||
|
||||
// Attempt to format each file.
|
||||
if formatted, err := format.Source(final); err == nil {
|
||||
if formatted, err := FormatSourceRemoveImports(filePkgs[file], final); err == nil {
|
||||
final = formatted
|
||||
}
|
||||
|
||||
if diffFlag {
|
||||
if printDiff {
|
||||
// Since we formatted the file, we need to recompute the diff.
|
||||
unified := diff.Unified(file+" (old)", file+" (new)", string(baseline), string(final))
|
||||
// TODO(adonovan): abstract the I/O.
|
||||
|
|
@ -262,23 +301,149 @@ fixloop:
|
|||
// These numbers are potentially misleading:
|
||||
// The denominator includes duplicate conflicting fixes due to
|
||||
// common files in packages "p" and "p [p.test]", which may
|
||||
// have been fixed fixed and won't appear in the re-run.
|
||||
// have been fixed and won't appear in the re-run.
|
||||
// TODO(adonovan): eliminate identical fixes as an initial
|
||||
// filtering step.
|
||||
//
|
||||
// TODO(adonovan): should we log that n files were updated in case of total victory?
|
||||
if badFixes > 0 || filesUpdated < totalFiles {
|
||||
if diffFlag {
|
||||
return fmt.Errorf("%d of %d fixes skipped (e.g. due to conflicts)", badFixes, len(fixes))
|
||||
if printDiff {
|
||||
return fmt.Errorf("%d of %s skipped (e.g. due to conflicts)",
|
||||
badFixes,
|
||||
plural(len(fixes), "fix", "fixes"))
|
||||
} else {
|
||||
return fmt.Errorf("applied %d of %d fixes; %d files updated. (Re-run the command to apply more.)",
|
||||
goodFixes, len(fixes), filesUpdated)
|
||||
return fmt.Errorf("applied %d of %s; %s updated. (Re-run the command to apply more.)",
|
||||
goodFixes,
|
||||
plural(len(fixes), "fix", "fixes"),
|
||||
plural(filesUpdated, "file", "files"))
|
||||
}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
log.Printf("applied %d fixes, updated %d files", len(fixes), filesUpdated)
|
||||
if skippedFixes > 0 {
|
||||
log.Printf("skipped %s that would edit generated files",
|
||||
plural(skippedFixes, "fix", "fixes"))
|
||||
}
|
||||
log.Printf("applied %s, updated %s",
|
||||
plural(len(fixes), "fix", "fixes"),
|
||||
plural(filesUpdated, "file", "files"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatSourceRemoveImports is a variant of [format.Source] that
|
||||
// removes imports that became redundant when fixes were applied.
|
||||
//
|
||||
// Import removal is necessarily heuristic since we do not have type
|
||||
// information for the fixed file and thus cannot accurately tell
|
||||
// whether k is among the free names of T{k: 0}, which requires
|
||||
// knowledge of whether T is a struct type.
|
||||
func FormatSourceRemoveImports(pkg *types.Package, src []byte) ([]byte, error) {
|
||||
// This function was reduced from the "strict entire file"
|
||||
// path through [format.Source].
|
||||
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "fixed.go", src, parser.ParseComments|parser.SkipObjectResolution)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ast.SortImports(fset, file)
|
||||
|
||||
removeUnneededImports(fset, pkg, file)
|
||||
|
||||
// printerNormalizeNumbers means to canonicalize number literal prefixes
|
||||
// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
|
||||
//
|
||||
// This value is defined in go/printer specifically for go/format and cmd/gofmt.
|
||||
const printerNormalizeNumbers = 1 << 30
|
||||
cfg := &printer.Config{
|
||||
Mode: printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers,
|
||||
Tabwidth: 8,
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := cfg.Fprint(&buf, fset, file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// removeUnneededImports removes import specs that are not referenced
|
||||
// within the fixed file. It uses [free.Names] to heuristically
|
||||
// approximate the set of imported names needed by the body of the
|
||||
// file based only on syntax.
|
||||
//
|
||||
// pkg provides type information about the unmodified package, in
|
||||
// particular the name that would implicitly be declared by a
|
||||
// non-renaming import of a given existing dependency.
|
||||
func removeUnneededImports(fset *token.FileSet, pkg *types.Package, file *ast.File) {
|
||||
// Map each existing dependency to its default import name.
|
||||
// (We'll need this to interpret non-renaming imports.)
|
||||
packageNames := make(map[string]string)
|
||||
for _, imp := range pkg.Imports() {
|
||||
packageNames[imp.Path()] = imp.Name()
|
||||
}
|
||||
|
||||
// Compute the set of free names of the file,
|
||||
// ignoring its import decls.
|
||||
freenames := make(map[string]bool)
|
||||
for _, decl := range file.Decls {
|
||||
if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
|
||||
continue // skip import
|
||||
}
|
||||
|
||||
// TODO(adonovan): we could do better than includeComplitIdents=false
|
||||
// since we have type information about the unmodified package,
|
||||
// which is a good source of heuristics.
|
||||
const includeComplitIdents = false
|
||||
maps.Copy(freenames, free.Names(decl, includeComplitIdents))
|
||||
}
|
||||
|
||||
// Check whether each import's declared name is free (referenced) by the file.
|
||||
var deletions []func()
|
||||
for _, spec := range file.Imports {
|
||||
path, err := strconv.Unquote(spec.Path.Value)
|
||||
if err != nil {
|
||||
continue // malformed import; ignore
|
||||
}
|
||||
explicit := "" // explicit PkgName, if any
|
||||
if spec.Name != nil {
|
||||
explicit = spec.Name.Name
|
||||
}
|
||||
name := explicit // effective PkgName
|
||||
if name == "" {
|
||||
// Non-renaming import: use package's default name.
|
||||
name = packageNames[path]
|
||||
}
|
||||
switch name {
|
||||
case "":
|
||||
continue // assume it's a new import
|
||||
case ".":
|
||||
continue // dot imports are tricky
|
||||
case "_":
|
||||
continue // keep blank imports
|
||||
}
|
||||
if !freenames[name] {
|
||||
// Import's effective name is not free in (not used by) the file.
|
||||
// Enqueue it for deletion after the loop.
|
||||
deletions = append(deletions, func() {
|
||||
astutil.DeleteNamedImport(fset, file, explicit, path)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the deletions.
|
||||
for _, del := range deletions {
|
||||
del()
|
||||
}
|
||||
}
|
||||
|
||||
// plural returns "n nouns", selecting the plural form as approriate.
|
||||
func plural(n int, singular, plural string) string {
|
||||
if n == 1 {
|
||||
return "1 " + singular
|
||||
} else {
|
||||
return fmt.Sprintf("%d %s", n, plural)
|
||||
}
|
||||
}
|
||||
161
src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go
generated
vendored
Normal file
161
src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/print.go
generated
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// 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 driverutil
|
||||
|
||||
// This file defined output helpers common to all drivers.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
)
|
||||
|
||||
// TODO(adonovan): don't accept an io.Writer if we don't report errors.
|
||||
// Either accept a bytes.Buffer (infallible), or return a []byte.
|
||||
|
||||
// PrintPlain prints a diagnostic in plain text form.
|
||||
// If contextLines is nonnegative, it also prints the
|
||||
// offending line plus this many lines of context.
|
||||
func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) {
|
||||
print := func(pos, end token.Pos, message string) {
|
||||
posn := fset.Position(pos)
|
||||
fmt.Fprintf(out, "%s: %s\n", posn, message)
|
||||
|
||||
// show offending line plus N lines of context.
|
||||
if contextLines >= 0 {
|
||||
end := fset.Position(end)
|
||||
if !end.IsValid() {
|
||||
end = posn
|
||||
}
|
||||
// TODO(adonovan): highlight the portion of the line indicated
|
||||
// by pos...end using ASCII art, terminal colors, etc?
|
||||
data, _ := os.ReadFile(posn.Filename)
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ {
|
||||
if 1 <= i && i <= len(lines) {
|
||||
fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print(diag.Pos, diag.End, diag.Message)
|
||||
for _, rel := range diag.Related {
|
||||
print(rel.Pos, rel.End, "\t"+rel.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// A JSONTree is a mapping from package ID to analysis name to result.
|
||||
// Each result is either a jsonError or a list of JSONDiagnostic.
|
||||
type JSONTree map[string]map[string]any
|
||||
|
||||
// A TextEdit describes the replacement of a portion of a file.
|
||||
// Start and End are zero-based half-open indices into the original byte
|
||||
// sequence of the file, and New is the new text.
|
||||
type JSONTextEdit struct {
|
||||
Filename string `json:"filename"`
|
||||
Start int `json:"start"`
|
||||
End int `json:"end"`
|
||||
New string `json:"new"`
|
||||
}
|
||||
|
||||
// A JSONSuggestedFix describes an edit that should be applied as a whole or not
|
||||
// at all. It might contain multiple TextEdits/text_edits if the SuggestedFix
|
||||
// consists of multiple non-contiguous edits.
|
||||
type JSONSuggestedFix struct {
|
||||
Message string `json:"message"`
|
||||
Edits []JSONTextEdit `json:"edits"`
|
||||
}
|
||||
|
||||
// A JSONDiagnostic describes the JSON schema of an analysis.Diagnostic.
|
||||
//
|
||||
// TODO(matloob): include End position if present.
|
||||
type JSONDiagnostic struct {
|
||||
Category string `json:"category,omitempty"`
|
||||
Posn string `json:"posn"` // e.g. "file.go:line:column"
|
||||
Message string `json:"message"`
|
||||
SuggestedFixes []JSONSuggestedFix `json:"suggested_fixes,omitempty"`
|
||||
Related []JSONRelatedInformation `json:"related,omitempty"`
|
||||
}
|
||||
|
||||
// A JSONRelated describes a secondary position and message related to
|
||||
// a primary diagnostic.
|
||||
//
|
||||
// TODO(adonovan): include End position if present.
|
||||
type JSONRelatedInformation struct {
|
||||
Posn string `json:"posn"` // e.g. "file.go:line:column"
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Add adds the result of analysis 'name' on package 'id'.
|
||||
// The result is either a list of diagnostics or an error.
|
||||
func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
|
||||
var v any
|
||||
if err != nil {
|
||||
type jsonError struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
v = jsonError{err.Error()}
|
||||
} else if len(diags) > 0 {
|
||||
diagnostics := make([]JSONDiagnostic, 0, len(diags))
|
||||
for _, f := range diags {
|
||||
var fixes []JSONSuggestedFix
|
||||
for _, fix := range f.SuggestedFixes {
|
||||
var edits []JSONTextEdit
|
||||
for _, edit := range fix.TextEdits {
|
||||
edits = append(edits, JSONTextEdit{
|
||||
Filename: fset.Position(edit.Pos).Filename,
|
||||
Start: fset.Position(edit.Pos).Offset,
|
||||
End: fset.Position(edit.End).Offset,
|
||||
New: string(edit.NewText),
|
||||
})
|
||||
}
|
||||
fixes = append(fixes, JSONSuggestedFix{
|
||||
Message: fix.Message,
|
||||
Edits: edits,
|
||||
})
|
||||
}
|
||||
var related []JSONRelatedInformation
|
||||
for _, r := range f.Related {
|
||||
related = append(related, JSONRelatedInformation{
|
||||
Posn: fset.Position(r.Pos).String(),
|
||||
Message: r.Message,
|
||||
})
|
||||
}
|
||||
jdiag := JSONDiagnostic{
|
||||
Category: f.Category,
|
||||
Posn: fset.Position(f.Pos).String(),
|
||||
Message: f.Message,
|
||||
SuggestedFixes: fixes,
|
||||
Related: related,
|
||||
}
|
||||
diagnostics = append(diagnostics, jdiag)
|
||||
}
|
||||
v = diagnostics
|
||||
}
|
||||
if v != nil {
|
||||
m, ok := tree[id]
|
||||
if !ok {
|
||||
m = make(map[string]any)
|
||||
tree[id] = m
|
||||
}
|
||||
m[name] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (tree JSONTree) Print(out io.Writer) error {
|
||||
data, err := json.MarshalIndent(tree, "", "\t")
|
||||
if err != nil {
|
||||
log.Panicf("internal error: JSON marshaling failed: %v", err)
|
||||
}
|
||||
_, err = fmt.Fprintf(out, "%s\n", data)
|
||||
return err
|
||||
}
|
||||
43
src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go
generated
vendored
Normal file
43
src/cmd/vendor/golang.org/x/tools/internal/analysis/driverutil/readfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package driverutil
|
||||
|
||||
// This file defines helpers for implementing [analysis.Pass.ReadFile].
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
)
|
||||
|
||||
// A ReadFileFunc is a function that returns the
|
||||
// contents of a file, such as [os.ReadFile].
|
||||
type ReadFileFunc = func(filename string) ([]byte, error)
|
||||
|
||||
// CheckedReadFile returns a wrapper around a Pass.ReadFile
|
||||
// function that performs the appropriate checks.
|
||||
func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc {
|
||||
return func(filename string) ([]byte, error) {
|
||||
if err := CheckReadable(pass, filename); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return readFile(filename)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass].
|
||||
func CheckReadable(pass *analysis.Pass, filename string) error {
|
||||
if slices.Contains(pass.OtherFiles, filename) ||
|
||||
slices.Contains(pass.IgnoredFiles, filename) {
|
||||
return nil
|
||||
}
|
||||
for _, f := range pass.Files {
|
||||
if pass.Fset.File(f.FileStart).Name() == filename {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue