From df05b9ea209d70e64451a54306b5708153182ddb Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Sat, 17 May 2025 16:32:19 +0800 Subject: [PATCH 1/2] all: replace HasPrefix and slicing with CutPrefix --- src/archive/zip/reader.go | 4 ++-- src/cmd/cgo/ast.go | 4 ++-- src/cmd/dist/buildtool.go | 4 ++-- src/cmd/go/internal/gover/gomod.go | 4 ++-- src/cmd/go/internal/load/godebug.go | 5 +++-- src/cmd/go/internal/modfetch/codehost/git.go | 12 +++++------ src/cmd/go/internal/modfetch/coderepo.go | 4 ++-- src/cmd/go/internal/modindex/build.go | 5 +++-- src/cmd/go/internal/modindex/scan.go | 4 ++-- src/cmd/internal/script/scripttest/run.go | 4 ++-- src/cmd/link/internal/loadpe/ldpe.go | 4 ++-- src/encoding/json/v2/fields.go | 8 ++++---- src/go/build/constraint/expr.go | 12 +++++------ src/internal/buildcfg/cfg.go | 21 ++++++++++++++------ src/internal/trace/raw/textreader.go | 5 +++-- src/mime/mediatype.go | 13 ++++++------ src/net/http/fs.go | 5 +++-- src/net/http/h2_bundle.go | 4 ++-- src/net/http/httptest/recorder.go | 5 +++-- 19 files changed, 71 insertions(+), 56 deletions(-) diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go index 6b57f767fc849d..21a71ca81068fb 100644 --- a/src/archive/zip/reader.go +++ b/src/archive/zip/reader.go @@ -796,8 +796,8 @@ func toValidName(name string) string { p = strings.TrimPrefix(p, "/") - for strings.HasPrefix(p, "../") { - p = p[len("../"):] + for cut := true; cut; { + p, cut = strings.CutPrefix(p, "../") } return p diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 861479db7acf5b..dc3bd50d369875 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -288,11 +288,11 @@ func (f *File) saveExport(x interface{}, context astContext) { return } for _, c := range n.Doc.List { - if !strings.HasPrefix(c.Text, "//export ") { + name, cut := strings.CutPrefix(c.Text, "//export ") + if !cut { continue } - name := strings.TrimSpace(c.Text[9:]) if name == "" { error_(c.Pos(), "export missing name") } diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 013b769b90f0e2..582a38e091d5b9 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -255,10 +255,10 @@ func bootstrapBuildTools() { // Copy binaries into tool binary directory. for _, name := range bootstrapDirs { - if !strings.HasPrefix(name, "cmd/") { + name, cut := strings.CutPrefix(name, "cmd/") + if !cut { continue } - name = name[len("cmd/"):] if !strings.Contains(name, "/") { copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec) } diff --git a/src/cmd/go/internal/gover/gomod.go b/src/cmd/go/internal/gover/gomod.go index 4a4ae5302908b5..9af8b50e880fe2 100644 --- a/src/cmd/go/internal/gover/gomod.go +++ b/src/cmd/go/internal/gover/gomod.go @@ -31,10 +31,10 @@ func GoModLookup(gomod []byte, key string) string { } func parseKey(line []byte, key string) (string, bool) { - if !strings.HasPrefix(string(line), key) { + s, cut := strings.CutPrefix(string(line), key) + if !cut { return "", false } - s := strings.TrimPrefix(string(line), key) if len(s) == 0 || (s[0] != ' ' && s[0] != '\t') { return "", false } diff --git a/src/cmd/go/internal/load/godebug.go b/src/cmd/go/internal/load/godebug.go index 8ea8ffab1aea1f..6719fc96f15029 100644 --- a/src/cmd/go/internal/load/godebug.go +++ b/src/cmd/go/internal/load/godebug.go @@ -132,10 +132,11 @@ func godebugForGoVersion(v string) map[string]string { v = v[:j] } - if !strings.HasPrefix(v, "1.") { + nv, cut := strings.CutPrefix(v, "1.") + if !cut { return nil } - n, err := strconv.Atoi(v[len("1."):]) + n, err := strconv.Atoi(nv) if err != nil { return nil } diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index dfb366788967f7..7984db35927750 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -290,10 +290,10 @@ func (r *gitRepo) Tags(ctx context.Context, prefix string) (*Tags, error) { List: []Tag{}, } for ref, hash := range refs { - if !strings.HasPrefix(ref, "refs/tags/") { + tag, cut := strings.CutPrefix(ref, "refs/tags/") + if !cut { continue } - tag := ref[len("refs/tags/"):] if !strings.HasPrefix(tag, prefix) { continue } @@ -721,19 +721,19 @@ func (r *gitRepo) RecentTag(ctx context.Context, rev, prefix string, allowed fun line = strings.TrimSpace(line) // git do support lstrip in for-each-ref format, but it was added in v2.13.0. Stripping here // instead gives support for git v2.7.0. - if !strings.HasPrefix(line, "refs/tags/") { + line, cut := strings.CutPrefix(line, "refs/tags/") + if !cut { continue } - line = line[len("refs/tags/"):] - if !strings.HasPrefix(line, prefix) { + semtag, cut := strings.CutPrefix(line, prefix) + if !cut { continue } if !allowed(line) { continue } - semtag := line[len(prefix):] if semver.Compare(semtag, highest) > 0 { highest = semtag } diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index afed35c970975e..728e02fcbb1d93 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -565,10 +565,10 @@ func (r *codeRepo) convert(ctx context.Context, info *codehost.RevInfo, statVers // If the tag is invalid, retracted, or a pseudo-version, tagToVersion returns // an empty version. tagToVersion := func(tag string) (v string, tagIsCanonical bool) { - if !strings.HasPrefix(tag, tagPrefix) { + trimmed, cut := strings.CutPrefix(tag, tagPrefix) + if !cut { return "", false } - trimmed := tag[len(tagPrefix):] // Tags that look like pseudo-versions would be confusing. Ignore them. if module.IsPseudoVersion(tag) { return "", false diff --git a/src/cmd/go/internal/modindex/build.go b/src/cmd/go/internal/modindex/build.go index d7e09fed25f43a..9d291a8e170426 100644 --- a/src/cmd/go/internal/modindex/build.go +++ b/src/cmd/go/internal/modindex/build.go @@ -171,10 +171,11 @@ func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) { func hasSubdir(root, dir string) (rel string, ok bool) { root = str.WithFilePathSeparator(filepath.Clean(root)) dir = filepath.Clean(dir) - if !strings.HasPrefix(dir, root) { + path, cut := strings.CutPrefix(dir, root) + if !cut { return "", false } - return filepath.ToSlash(dir[len(root):]), true + return filepath.ToSlash(path), true } // gopath returns the list of Go path directories. diff --git a/src/cmd/go/internal/modindex/scan.go b/src/cmd/go/internal/modindex/scan.go index 90be154e8ea69a..f013111a8a6e83 100644 --- a/src/cmd/go/internal/modindex/scan.go +++ b/src/cmd/go/internal/modindex/scan.go @@ -65,10 +65,10 @@ func indexModule(modroot string) ([]byte, error) { if !d.IsDir() { return nil } - if !strings.HasPrefix(path, root) { + rel, cut := strings.CutPrefix(path, root) + if !cut { panic(fmt.Errorf("path %v in walk doesn't have modroot %v as prefix", path, modroot)) } - rel := path[len(root):] packages = append(packages, importRaw(modroot, rel)) return nil }) diff --git a/src/cmd/internal/script/scripttest/run.go b/src/cmd/internal/script/scripttest/run.go index 8dff13e22edfc4..431ee0d25a2109 100644 --- a/src/cmd/internal/script/scripttest/run.go +++ b/src/cmd/internal/script/scripttest/run.go @@ -75,10 +75,10 @@ func RunToolScriptTest(t *testing.T, repls []ToolReplacement, scriptsdir string, found := false for k := range env { ev := env[k] - if !strings.HasPrefix(ev, "PATH=") { + oldpath, cut := strings.CutPrefix(ev, "PATH=") + if !cut { continue } - oldpath := ev[5:] env[k] = "PATH=" + dir + string(filepath.ListSeparator) + oldpath found = true break diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go index b895ac41494110..ec86ac3f8d0250 100644 --- a/src/cmd/link/internal/loadpe/ldpe.go +++ b/src/cmd/link/internal/loadpe/ldpe.go @@ -807,10 +807,10 @@ func (state *peLoaderState) preprocessSymbols() error { // "__imp_XYZ" but no XYZ can be found. func LookupBaseFromImport(s loader.Sym, ldr *loader.Loader, arch *sys.Arch) (loader.Sym, error) { sname := ldr.SymName(s) - if !strings.HasPrefix(sname, "__imp_") { + basename, cut := strings.CutPrefix(sname, "__imp_") + if !cut { return 0, nil } - basename := sname[len("__imp_"):] if arch.Family == sys.I386 && basename[0] == '_' { basename = basename[1:] // _Name => Name } diff --git a/src/encoding/json/v2/fields.go b/src/encoding/json/v2/fields.go index 9413189c0850da..857c4df63648a6 100644 --- a/src/encoding/json/v2/fields.go +++ b/src/encoding/json/v2/fields.go @@ -493,11 +493,11 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, } switch opt { case "case": - if !strings.HasPrefix(tag, ":") { + tag, cut := strings.CutPrefix(tag, ":") + if !cut { err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `case` tag option; specify `case:ignore` or `case:strict` instead", sf.Name)) break } - tag = tag[len(":"):] opt, n, err2 := consumeTagOption(tag) if err2 != nil { err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `case` tag option: %v", sf.Name, err2)) @@ -527,11 +527,11 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, case "string": out.string = true case "format": - if !strings.HasPrefix(tag, ":") { + tag, cut := strings.CutPrefix(tag, ":") + if !cut { err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)) break } - tag = tag[len(":"):] opt, n, err2 := consumeTagOption(tag) if err2 != nil { err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err2)) diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 0f05f8db6a48cb..f2b83a86f27760 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -178,12 +178,12 @@ func splitGoBuild(line string) (expr string, ok bool) { return "", false } - if !strings.HasPrefix(line, "//go:build") { + line, cut := strings.CutPrefix(line, "//go:build") + if !cut { return "", false } line = strings.TrimSpace(line) - line = line[len("//go:build"):] // If strings.TrimSpace finds more to trim after removing the //go:build prefix, // it means that the prefix was followed by a space, making this a //go:build line @@ -373,17 +373,17 @@ func splitPlusBuild(line string) (expr string, ok bool) { return "", false } - if !strings.HasPrefix(line, "//") { + line, cut := strings.CutPrefix(line, "//") + if !cut { return "", false } - line = line[len("//"):] // Note the space is optional; "//+build" is recognized too. line = strings.TrimSpace(line) - if !strings.HasPrefix(line, "+build") { + line, cut = strings.CutPrefix(line, "+build") + if !cut { return "", false } - line = line[len("+build"):] // If strings.TrimSpace finds more to trim after removing the +build prefix, // it means that the prefix was followed by a space, making this a +build line diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go index 5ae4c0c7adc8fe..f7b86bc58afcf2 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go @@ -87,18 +87,27 @@ func gofips140() string { // isFIPSVersion reports whether v is a valid FIPS version, // of the form vX.Y.Z. func isFIPSVersion(v string) bool { - if !strings.HasPrefix(v, "v") { + v, cut := strings.CutPrefix(v, "v") + if !cut { return false } - v, ok := skipNum(v[len("v"):]) - if !ok || !strings.HasPrefix(v, ".") { + v, ok := skipNum(v) + if !ok { return false } - v, ok = skipNum(v[len("."):]) - if !ok || !strings.HasPrefix(v, ".") { + v, cut = strings.CutPrefix(v, ".") + if !cut { return false } - v, ok = skipNum(v[len("."):]) + v, ok = skipNum(v) + if !ok { + return false + } + v, cut = strings.CutPrefix(v, ".") + if !cut { + return false + } + v, ok = skipNum(v) return ok && v == "" } diff --git a/src/internal/trace/raw/textreader.go b/src/internal/trace/raw/textreader.go index adb111550d1ee7..42775934e4e93a 100644 --- a/src/internal/trace/raw/textreader.go +++ b/src/internal/trace/raw/textreader.go @@ -37,10 +37,11 @@ func NewTextReader(r io.Reader) (*TextReader, error) { return nil, fmt.Errorf("failed to parse header") } gover, line := readToken(line) - if !strings.HasPrefix(gover, "Go1.") { + ver, cut := strings.CutPrefix(gover, "Go1.") + if !cut { return nil, fmt.Errorf("failed to parse header Go version") } - rawv, err := strconv.ParseUint(gover[len("Go1."):], 10, 64) + rawv, err := strconv.ParseUint(ver, 10, 64) if err != nil { return nil, fmt.Errorf("failed to parse header Go version: %v", err) } diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 66684a68b23961..112319707b2ad4 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -103,10 +103,11 @@ func checkMediaTypeDisposition(s string) error { if rest == "" { return nil } - if !strings.HasPrefix(rest, "/") { + rest, cut := strings.CutPrefix(rest, "/") + if !cut { return errors.New("mime: expected slash after first token") } - subtype, rest := consumeToken(rest[1:]) + subtype, rest := consumeToken(rest) if subtype == "" { return errors.New("mime: expected token after slash") } @@ -309,11 +310,11 @@ func consumeValue(v string) (value, rest string) { func consumeMediaParam(v string) (param, value, rest string) { rest = strings.TrimLeftFunc(v, unicode.IsSpace) - if !strings.HasPrefix(rest, ";") { + rest, cut := strings.CutPrefix(rest, ";") + if !cut { return "", "", v } - rest = rest[1:] // consume semicolon rest = strings.TrimLeftFunc(rest, unicode.IsSpace) param, rest = consumeToken(rest) param = strings.ToLower(param) @@ -322,10 +323,10 @@ func consumeMediaParam(v string) (param, value, rest string) { } rest = strings.TrimLeftFunc(rest, unicode.IsSpace) - if !strings.HasPrefix(rest, "=") { + rest, cut = strings.CutPrefix(rest, "=") + if !cut { return "", "", v } - rest = rest[1:] // consume equals sign rest = strings.TrimLeftFunc(rest, unicode.IsSpace) value, rest2 := consumeValue(rest) if value == "" && rest2 == rest { diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 92bd94f72dfb68..637a4bcce18ed4 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -1017,12 +1017,13 @@ func parseRange(s string, size int64) ([]httpRange, error) { return nil, nil // header not present } const b = "bytes=" - if !strings.HasPrefix(s, b) { + s, cut := strings.CutPrefix(s, b) + if !cut { return nil, errors.New("invalid range") } var ranges []httpRange noOverlap := false - for ra := range strings.SplitSeq(s[len(b):], ",") { + for ra := range strings.SplitSeq(s, ",") { ra = textproto.TrimString(ra) if ra == "" { continue diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index a55fa8ac63d128..8a83abd3562654 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -6760,10 +6760,10 @@ const http2TrailerPrefix = "Trailer:" // fields to be trailers. func (rws *http2responseWriterState) promoteUndeclaredTrailers() { for k, vv := range rws.handlerHeader { - if !strings.HasPrefix(k, http2TrailerPrefix) { + trailerKey, cut := strings.CutPrefix(k, http2TrailerPrefix) + if !cut { continue } - trailerKey := strings.TrimPrefix(k, http2TrailerPrefix) rws.declareTrailer(trailerKey) rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv } diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go index 17aa70f06760a2..4fead3e410380a 100644 --- a/src/net/http/httptest/recorder.go +++ b/src/net/http/httptest/recorder.go @@ -224,14 +224,15 @@ func (rw *ResponseRecorder) Result() *http.Response { } } for k, vv := range rw.HeaderMap { - if !strings.HasPrefix(k, http.TrailerPrefix) { + k, cut := strings.CutPrefix(k, http.TrailerPrefix) + if !cut { continue } if res.Trailer == nil { res.Trailer = make(http.Header) } for _, v := range vv { - res.Trailer.Add(strings.TrimPrefix(k, http.TrailerPrefix), v) + res.Trailer.Add(k, v) } } return res From a4bc4a5dc5d1882e32ef2d3b9343b046272396de Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Sat, 17 May 2025 16:51:01 +0800 Subject: [PATCH 2/2] cmd/cgo: restore TrimSpace removed in saveExport --- src/cmd/cgo/ast.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index dc3bd50d369875..73cedfe99992af 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -293,6 +293,7 @@ func (f *File) saveExport(x interface{}, context astContext) { continue } + name = strings.TrimSpace(name) if name == "" { error_(c.Pos(), "export missing name") }