From c93496be2eb7817f59c8123cb45eaa11364525ce Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Thu, 4 Sep 2025 22:28:55 +0800 Subject: [PATCH 1/5] all: replace strings.Split with strings.SplitSeq --- src/go/ast/ast.go | 2 +- src/go/build/build.go | 2 +- src/go/build/constraint/expr.go | 4 ++-- src/internal/buildcfg/cfg.go | 2 +- src/internal/buildcfg/exp.go | 2 +- src/internal/testenv/testenv.go | 2 +- src/internal/trace/traceviewer/mmu.go | 4 ++-- src/os/exec/lp_windows.go | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index a3dc0c3220d19c..2a0d9e686021e8 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -1123,7 +1123,7 @@ func generator(file *File) (string, bool) { // opt: check Contains first to avoid unnecessary array allocation in Split. const prefix = "// Code generated " if strings.Contains(comment.Text, prefix) { - for _, line := range strings.Split(comment.Text, "\n") { + for line := range strings.SplitSeq(comment.Text, "\n") { if rest, ok := strings.CutPrefix(line, prefix); ok { if gen, ok := strings.CutSuffix(rest, " DO NOT EDIT."); ok { return gen, true diff --git a/src/go/build/build.go b/src/go/build/build.go index 50288fcec64141..76866c7487adf4 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -1708,7 +1708,7 @@ Lines: // that affect the way cgo's C code is built. func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { text := cg.Text() - for _, line := range strings.Split(text, "\n") { + for line := range strings.SplitSeq(text, "\n") { orig := line // Line is diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 0f05f8db6a48cb..1f39bb20110adf 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -406,9 +406,9 @@ func parsePlusBuildExpr(text string) (Expr, error) { size := 0 var x Expr - for _, clause := range strings.Fields(text) { + for clause := range strings.FieldsSeq(text) { var y Expr - for _, lit := range strings.Split(clause, ",") { + for lit := range strings.SplitSeq(clause, ",") { var z Expr var neg bool if strings.HasPrefix(lit, "!!") || lit == "!" { diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go index 7e4ee365dfe126..52d1c45afa6fb6 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go @@ -336,7 +336,7 @@ func (f gowasmFeatures) String() string { } func gowasm() (f gowasmFeatures) { - for _, opt := range strings.Split(envOr("GOWASM", ""), ",") { + for opt := range strings.SplitSeq(envOr("GOWASM", ""), ",") { switch opt { case "satconv": f.SatConv = true diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 310226bc0146e5..be9d1f71258caf 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -113,7 +113,7 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) { } // Parse names. - for _, f := range strings.Split(goexp, ",") { + for f := range strings.SplitSeq(goexp, ",") { if f == "" { continue } diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 0f6c9bbdad43de..fc206c737bbf51 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -484,7 +484,7 @@ func WriteImportcfg(t testing.TB, dstPath string, packageFiles map[string]string t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr) } - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { if line == "" { continue } diff --git a/src/internal/trace/traceviewer/mmu.go b/src/internal/trace/traceviewer/mmu.go index 0bc1233b44dee9..190ce5afcad6e1 100644 --- a/src/internal/trace/traceviewer/mmu.go +++ b/src/internal/trace/traceviewer/mmu.go @@ -69,7 +69,7 @@ var utilFlagNames = map[string]trace.UtilFlags{ func requestUtilFlags(r *http.Request) trace.UtilFlags { var flags trace.UtilFlags - for _, flagStr := range strings.Split(r.FormValue("flags"), "|") { + for flagStr := range strings.SplitSeq(r.FormValue("flags"), "|") { flags |= utilFlagNames[flagStr] } return flags @@ -119,7 +119,7 @@ func (m *mmu) HandlePlot(w http.ResponseWriter, r *http.Request) { } var quantiles []float64 - for _, flagStr := range strings.Split(r.FormValue("flags"), "|") { + for flagStr := range strings.SplitSeq(r.FormValue("flags"), "|") { if flagStr == "mut" { quantiles = []float64{0, 1 - .999, 1 - .99, 1 - .95} break diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go index e01e7bbbbabde0..74537dec687c81 100644 --- a/src/os/exec/lp_windows.go +++ b/src/os/exec/lp_windows.go @@ -123,7 +123,7 @@ func pathExt() []string { var exts []string x := os.Getenv(`PATHEXT`) if x != "" { - for _, e := range strings.Split(strings.ToLower(x), `;`) { + for e := range strings.SplitSeq(strings.ToLower(x), `;`) { if e == "" { continue } From f56319cf4cde654a0b9f2e7ea22d0db362b0e1ad Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Fri, 5 Sep 2025 19:38:28 +0800 Subject: [PATCH 2/5] cmd: replace strings.Split with strings.SplitSeq --- misc/ios/go_ios_exec.go | 2 +- src/cmd/cgo/gcc.go | 4 +- src/cmd/cgo/internal/test/testx.go | 2 +- src/cmd/compile/internal/base/flag.go | 2 +- src/cmd/dist/build.go | 6 +- src/cmd/distpack/pack.go | 2 +- src/cmd/fix/main.go | 4 +- src/cmd/go/internal/auth/gitauth.go | 2 +- src/cmd/go/internal/auth/netrc.go | 2 +- src/cmd/go/internal/doc/dirs.go | 2 +- src/cmd/go/internal/doc/pkg.go | 2 +- src/cmd/go/internal/list/list.go | 2 +- src/cmd/go/internal/modfetch/codehost/git.go | 6 +- src/cmd/go/internal/modfetch/codehost/vcs.go | 4 +- src/cmd/go/internal/modindex/build.go | 2 +- src/cmd/go/internal/modindex/scan.go | 2 +- src/cmd/go/internal/modload/buildlist.go | 2 +- src/cmd/go/internal/modload/init.go | 2 +- src/cmd/go/internal/modload/vendor.go | 4 +- src/cmd/go/internal/test/testflag.go | 2 +- src/cmd/go/internal/toolchain/path_windows.go | 2 +- src/cmd/go/internal/vcs/vcs.go | 6 +- src/cmd/go/internal/vcweb/vcweb.go | 2 +- src/cmd/go/internal/work/build.go | 2 +- src/cmd/go/internal/work/exec.go | 4 +- src/cmd/go/internal/work/gccgo.go | 2 +- src/cmd/internal/objabi/flag.go | 2 +- src/cmd/internal/script/cmds.go | 2 +- .../internal/script/scripttest/conditions.go | 2 +- src/strings/iter_test.go | 56 +++++++++++++++++++ 30 files changed, 96 insertions(+), 40 deletions(-) diff --git a/misc/ios/go_ios_exec.go b/misc/ios/go_ios_exec.go index b21ce1aaf3f0cc..e58457d0519948 100644 --- a/misc/ios/go_ios_exec.go +++ b/misc/ios/go_ios_exec.go @@ -212,7 +212,7 @@ func copyLocalData(dstbase string) (pkgpath string, err error) { // Copy all immediate files and testdata directories between // the package being tested and the source root. pkgpath = "" - for _, element := range strings.Split(finalPkgpath, string(filepath.Separator)) { + for element := range strings.SplitSeq(finalPkgpath, string(filepath.Separator)) { if debug { log.Printf("copying %s", pkgpath) } diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index c1530b9f154898..8309af68989a22 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -242,7 +242,7 @@ func (f *File) loadDefines(gccOptions []string) bool { stdout := gccDefines(b.Bytes(), gccOptions) var gccIsClang bool - for _, line := range strings.Split(stdout, "\n") { + for line := range strings.SplitSeq(stdout, "\n") { if len(line) < 9 || line[0:7] != "#define" { continue } @@ -418,7 +418,7 @@ func (p *Package) guessKinds(f *File) []*Name { notDeclared ) sawUnmatchedErrors := false - for _, line := range strings.Split(stderr, "\n") { + for line := range strings.SplitSeq(stderr, "\n") { // Ignore warnings and random comments, with one // exception: newer GCC versions will sometimes emit // an error on a macro #define with a note referring diff --git a/src/cmd/cgo/internal/test/testx.go b/src/cmd/cgo/internal/test/testx.go index 0e2a51a52280ba..9a63b9e10087ad 100644 --- a/src/cmd/cgo/internal/test/testx.go +++ b/src/cmd/cgo/internal/test/testx.go @@ -447,7 +447,7 @@ func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) { runtime.GC() buf := make([]byte, 65536) trace := string(buf[:runtime.Stack(buf, true)]) - for _, goroutine := range strings.Split(trace, "\n\n") { + for goroutine := range strings.SplitSeq(trace, "\n\n") { if strings.Contains(goroutine, "test.issue7978go") { trace := strings.Split(goroutine, "\n") // look for the expected function in the stack diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index e87f57cdaae020..514a00d146e8b5 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -570,7 +570,7 @@ func readEmbedCfg(file string) { // parseSpectre parses the spectre configuration from the string s. func parseSpectre(s string) { - for _, f := range strings.Split(s, ",") { + for f := range strings.SplitSeq(s, ",") { f = strings.TrimSpace(f) switch f { default: diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index fb70047dd0e81c..9a7951726f6f04 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -380,7 +380,7 @@ func findgoversion() string { if i := strings.Index(b, "\n"); i >= 0 { rest := b[i+1:] b = chomp(b[:i]) - for _, line := range strings.Split(rest, "\n") { + for line := range strings.SplitSeq(rest, "\n") { f := strings.Fields(line) if len(f) == 0 { continue @@ -1137,7 +1137,7 @@ func shouldbuild(file, pkg string) bool { } // Check file contents for //go:build lines. - for _, p := range strings.Split(readfile(file), "\n") { + for p := range strings.SplitSeq(readfile(file), "\n") { p = strings.TrimSpace(p) if p == "" { continue @@ -2016,7 +2016,7 @@ func cmdlist() { } func setNoOpt() { - for _, gcflag := range strings.Split(gogcflags, " ") { + for gcflag := range strings.SplitSeq(gogcflags, " ") { if gcflag == "-N" || gcflag == "-l" { noOpt = true break diff --git a/src/cmd/distpack/pack.go b/src/cmd/distpack/pack.go index 27f73e593cf6fb..6bab45f1d3d642 100644 --- a/src/cmd/distpack/pack.go +++ b/src/cmd/distpack/pack.go @@ -271,7 +271,7 @@ func readVERSION(goroot string) (version string, t time.Time) { log.Fatal(err) } version, rest, _ := strings.Cut(string(data), "\n") - for _, line := range strings.Split(rest, "\n") { + for line := range strings.SplitSeq(rest, "\n") { f := strings.Fields(line) if len(f) == 0 { continue diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go index 44ce396e372198..933c32bcd92639 100644 --- a/src/cmd/fix/main.go +++ b/src/cmd/fix/main.go @@ -84,14 +84,14 @@ func main() { if *allowedRewrites != "" { allowed = make(map[string]bool) - for _, f := range strings.Split(*allowedRewrites, ",") { + for f := range strings.SplitSeq(*allowedRewrites, ",") { allowed[f] = true } } if *forceRewrites != "" { force = make(map[string]bool) - for _, f := range strings.Split(*forceRewrites, ",") { + for f := range strings.SplitSeq(*forceRewrites, ",") { force[f] = true } } diff --git a/src/cmd/go/internal/auth/gitauth.go b/src/cmd/go/internal/auth/gitauth.go index 29d2852814b450..f11cd2fbf057d7 100644 --- a/src/cmd/go/internal/auth/gitauth.go +++ b/src/cmd/go/internal/auth/gitauth.go @@ -82,7 +82,7 @@ func runGitAuth(client *http.Client, dir, url string) (string, http.Header, erro // Any of these values may be empty if parsing fails. func parseGitAuth(data []byte) (parsedPrefix, username, password string) { prefix := new(url.URL) - for _, line := range strings.Split(string(data), "\n") { + for line := range strings.SplitSeq(string(data), "\n") { key, value, ok := strings.Cut(strings.TrimSpace(line), "=") if !ok { continue diff --git a/src/cmd/go/internal/auth/netrc.go b/src/cmd/go/internal/auth/netrc.go index 4191ccb29304d6..78c884b31bd541 100644 --- a/src/cmd/go/internal/auth/netrc.go +++ b/src/cmd/go/internal/auth/netrc.go @@ -24,7 +24,7 @@ func parseNetrc(data string) []netrcLine { var nrc []netrcLine var l netrcLine inMacro := false - for _, line := range strings.Split(data, "\n") { + for line := range strings.SplitSeq(data, "\n") { if inMacro { if line == "" { inMacro = false diff --git a/src/cmd/go/internal/doc/dirs.go b/src/cmd/go/internal/doc/dirs.go index 8b1670f61c253c..5efd40b1d5a48b 100644 --- a/src/cmd/go/internal/doc/dirs.go +++ b/src/cmd/go/internal/doc/dirs.go @@ -241,7 +241,7 @@ func findCodeRoots() []Dir { cmd := exec.Command(goCmd(), "list", "-m", "-f={{.Path}}\t{{.Dir}}", "all") cmd.Stderr = os.Stderr out, _ := cmd.Output() - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { path, dir, _ := strings.Cut(line, "\t") if dir != "" { list = append(list, Dir{importPath: path, dir: dir, inModule: true}) diff --git a/src/cmd/go/internal/doc/pkg.go b/src/cmd/go/internal/doc/pkg.go index 953b0d9a2840ab..7b5e00365d04a1 100644 --- a/src/cmd/go/internal/doc/pkg.go +++ b/src/cmd/go/internal/doc/pkg.go @@ -920,7 +920,7 @@ func trimUnexportedFields(fields *ast.FieldList, isInterface bool) *ast.FieldLis start := doc.List[0].Slash doc.List = doc.List[:0] - for _, line := range strings.Split(text, "\n") { + for line := range strings.SplitSeq(text, "\n") { prefix := "// " if len(line) > 0 && line[0] == '\t' { prefix = "//" diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 86a6b1792c5016..bee7dc8053ee6f 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -381,7 +381,7 @@ func (v *jsonFlag) Set(s string) error { if *v == nil { *v = make(map[string]bool) } - for _, f := range strings.Split(s, ",") { + for f := range strings.SplitSeq(s, ",") { (*v)[f] = true } return nil diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 8a1c12b90a5c07..74c4c646cdc582 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -173,7 +173,7 @@ func (r *gitRepo) loadLocalTags(ctx context.Context) { return } - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { if line != "" { r.localTags.Store(line, true) } @@ -273,7 +273,7 @@ func (r *gitRepo) loadRefs(ctx context.Context) (map[string]string, error) { } refs := make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { f := strings.Fields(line) if len(f) != 2 { continue @@ -745,7 +745,7 @@ func (r *gitRepo) RecentTag(ctx context.Context, rev, prefix string, allowed fun // prefixed tags aren't valid semver tags so compare without prefix, but only tags with correct prefix var highest string - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { 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. diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go index 8e59479339be7f..d80397502b422d 100644 --- a/src/cmd/go/internal/modfetch/codehost/vcs.go +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -561,7 +561,7 @@ func bzrParseStat(rev, out string) (*RevInfo, error) { var revno int64 var tm time.Time var tags []string - for _, line := range strings.Split(out, "\n") { + for line := range strings.SplitSeq(out, "\n") { if line == "" || line[0] == ' ' || line[0] == '\t' { // End of header, start of commit message. break @@ -614,7 +614,7 @@ func bzrParseStat(rev, out string) (*RevInfo, error) { } func fossilParseStat(rev, out string) (*RevInfo, error) { - for _, line := range strings.Split(out, "\n") { + for line := range strings.SplitSeq(out, "\n") { if strings.HasPrefix(line, "uuid:") || strings.HasPrefix(line, "hash:") { f := strings.Fields(line) if len(f) != 5 || len(f[1]) != 40 || f[4] != "UTC" { diff --git a/src/cmd/go/internal/modindex/build.go b/src/cmd/go/internal/modindex/build.go index 761bda8d39b158..0fa78afe2c08ef 100644 --- a/src/cmd/go/internal/modindex/build.go +++ b/src/cmd/go/internal/modindex/build.go @@ -426,7 +426,7 @@ Lines: // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives // that affect the way cgo's C code is built. func (ctxt *Context) saveCgo(filename string, di *build.Package, text string) error { - for _, line := range strings.Split(text, "\n") { + for line := range strings.SplitSeq(text, "\n") { orig := line // Line is diff --git a/src/cmd/go/internal/modindex/scan.go b/src/cmd/go/internal/modindex/scan.go index 90be154e8ea69a..af2c0abe046d72 100644 --- a/src/cmd/go/internal/modindex/scan.go +++ b/src/cmd/go/internal/modindex/scan.go @@ -275,7 +275,7 @@ func importRaw(modroot, reldir string) *rawPackage { // which is the comment on import "C". func extractCgoDirectives(doc string) []string { var out []string - for _, line := range strings.Split(doc, "\n") { + for line := range strings.SplitSeq(doc, "\n") { // Line is // #cgo [GOOS/GOARCH...] LDFLAGS: stuff // diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index cd3ec4f102473b..2ba04f707b5472 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -329,7 +329,7 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio // so it wouldn't be useful to log when that occurs (because it happens in // normal operation all the time). readModGraphDebugOnce.Do(func() { - for _, f := range strings.Split(os.Getenv("GODEBUG"), ",") { + for f := range strings.SplitSeq(os.Getenv("GODEBUG"), ",") { switch f { case "lazymod=log": debug.PrintStack() diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 25151103edb579..498ff7433ea6fe 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -1597,7 +1597,7 @@ func modulesTextIsForWorkspace(vendorDir string) (bool, error) { } line, _, _ := strings.Cut(string(buf[:n]), "\n") if annotations, ok := strings.CutPrefix(line, "## "); ok { - for _, entry := range strings.Split(annotations, ";") { + for entry := range strings.SplitSeq(annotations, ";") { entry = strings.TrimSpace(entry) if entry == "workspace" { return true, nil diff --git a/src/cmd/go/internal/modload/vendor.go b/src/cmd/go/internal/modload/vendor.go index b2cb44100ec4d2..c7fe73193582ab 100644 --- a/src/cmd/go/internal/modload/vendor.go +++ b/src/cmd/go/internal/modload/vendor.go @@ -53,7 +53,7 @@ func readVendorList(vendorDir string) { } var mod module.Version - for _, line := range strings.Split(string(data), "\n") { + for line := range strings.SplitSeq(string(data), "\n") { if strings.HasPrefix(line, "# ") { f := strings.Fields(line) @@ -103,7 +103,7 @@ func readVendorList(vendorDir string) { if annotations, ok := strings.CutPrefix(line, "## "); ok { // Metadata. Take the union of annotations across multiple lines, if present. meta := vendorMeta[mod] - for _, entry := range strings.Split(annotations, ";") { + for entry := range strings.SplitSeq(annotations, ";") { entry = strings.TrimSpace(entry) if entry == "explicit" { meta.Explicit = true diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go index 09e41533b6ccba..983e8f56e9af09 100644 --- a/src/cmd/go/internal/test/testflag.go +++ b/src/cmd/go/internal/test/testflag.go @@ -149,7 +149,7 @@ func (f *vetFlag) Set(value string) error { *f = vetFlag{explicit: true} var single string - for _, arg := range strings.Split(value, ",") { + for arg := range strings.SplitSeq(value, ",") { switch arg { case "": return fmt.Errorf("-vet argument contains empty list element") diff --git a/src/cmd/go/internal/toolchain/path_windows.go b/src/cmd/go/internal/toolchain/path_windows.go index d88945ddc8ecea..dfb2238a4dbb97 100644 --- a/src/cmd/go/internal/toolchain/path_windows.go +++ b/src/cmd/go/internal/toolchain/path_windows.go @@ -21,7 +21,7 @@ var pathExts = sync.OnceValue(func() []string { } var exts []string - for _, e := range strings.Split(strings.ToLower(x), `;`) { + for e := range strings.SplitSeq(strings.ToLower(x), `;`) { if e == "" { continue } diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 7e081eb41a1c4e..edbc5734401737 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -110,7 +110,7 @@ func (v *Cmd) isSecureScheme(scheme string) bool { // colon-separated list of schemes that are allowed to be used with git // fetch/clone. Any scheme not mentioned will be considered insecure. if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" { - for _, s := range strings.Split(allow, ":") { + for s := range strings.SplitSeq(allow, ":") { if s == scheme { return true } @@ -440,7 +440,7 @@ func bzrStatus(vcsBzr *Cmd, rootDir string) (Status, error) { var rev string var commitTime time.Time - for _, line := range strings.Split(out, "\n") { + for line := range strings.SplitSeq(out, "\n") { i := strings.IndexByte(line, ':') if i < 0 { continue @@ -974,7 +974,7 @@ func parseGOVCS(s string) (govcsConfig, error) { } var cfg govcsConfig have := make(map[string]string) - for _, item := range strings.Split(s, ",") { + for item := range strings.SplitSeq(s, ",") { item = strings.TrimSpace(item) if item == "" { return nil, fmt.Errorf("empty entry in GOVCS") diff --git a/src/cmd/go/internal/vcweb/vcweb.go b/src/cmd/go/internal/vcweb/vcweb.go index 757a595808c7b7..b81ff5e63de72a 100644 --- a/src/cmd/go/internal/vcweb/vcweb.go +++ b/src/cmd/go/internal/vcweb/vcweb.go @@ -224,7 +224,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { // uniqueness: if a path exists as a directory, then it cannot exist as a // ".txt" script (because the search would ignore that file). scriptPath := "." - for _, part := range strings.Split(clean, "/") { + for part := range strings.SplitSeq(clean, "/") { scriptPath = filepath.Join(scriptPath, part) dir := filepath.Join(s.scriptDir, scriptPath) if _, err := os.Stat(dir); err != nil { diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 742efe6490f347..6741b39f051cd6 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -384,7 +384,7 @@ func (v *tagsFlag) Set(s string) error { // Split on commas, ignore empty strings. *v = []string{} - for _, s := range strings.Split(s, ",") { + for s := range strings.SplitSeq(s, ",") { if s != "" { *v = append(*v, s) } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 9959dc804d0f4d..74cf3b01db045e 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1084,7 +1084,7 @@ func (b *Builder) loadCachedVet(a *Action) error { return fmt.Errorf("reading srcfiles list: %w", err) } var srcfiles []string - for _, name := range strings.Split(string(list), "\n") { + for name := range strings.SplitSeq(string(list), "\n") { if name == "" { // end of list continue } @@ -1108,7 +1108,7 @@ func (b *Builder) loadCachedCompiledGoFiles(a *Action) error { return fmt.Errorf("reading srcfiles list: %w", err) } var gofiles []string - for _, name := range strings.Split(string(list), "\n") { + for name := range strings.SplitSeq(string(list), "\n") { if name == "" { // end of list continue } else if !strings.HasSuffix(name, ".go") { diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go index b42e92ea690981..276e082b71ba55 100644 --- a/src/cmd/go/internal/work/gccgo.go +++ b/src/cmd/go/internal/work/gccgo.go @@ -278,7 +278,7 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string return err } const ldflagsPrefix = "_CGO_LDFLAGS=" - for _, line := range strings.Split(string(flags), "\n") { + for line := range strings.SplitSeq(string(flags), "\n") { if strings.HasPrefix(line, ldflagsPrefix) { flag := line[len(ldflagsPrefix):] // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go index 1bb46e3bcdc01b..8709c4e5cf530e 100644 --- a/src/cmd/internal/objabi/flag.go +++ b/src/cmd/internal/objabi/flag.go @@ -277,7 +277,7 @@ func (f *DebugFlag) Set(debugstr string) error { if debugstr == "" { return nil } - for _, name := range strings.Split(debugstr, ",") { + for name := range strings.SplitSeq(debugstr, ",") { if name == "" { continue } diff --git a/src/cmd/internal/script/cmds.go b/src/cmd/internal/script/cmds.go index 7a930caf355d66..a682d9b3f66863 100644 --- a/src/cmd/internal/script/cmds.go +++ b/src/cmd/internal/script/cmds.go @@ -513,7 +513,7 @@ func lookPath(s *State, command string) (string, error) { } pathEnv, _ := s.LookupEnv(pathEnvName()) - for _, dir := range strings.Split(pathEnv, string(filepath.ListSeparator)) { + for dir := range strings.SplitSeq(pathEnv, string(filepath.ListSeparator)) { if dir == "" { continue } diff --git a/src/cmd/internal/script/scripttest/conditions.go b/src/cmd/internal/script/scripttest/conditions.go index e35ac2ddb7412f..6702e9279b106b 100644 --- a/src/cmd/internal/script/scripttest/conditions.go +++ b/src/cmd/internal/script/scripttest/conditions.go @@ -88,7 +88,7 @@ func pieLinkExt(s *script.State) (bool, error) { func hasGodebug(s *script.State, value string) (bool, error) { godebug, _ := s.LookupEnv("GODEBUG") - for _, p := range strings.Split(godebug, ",") { + for p := range strings.SplitSeq(godebug, ",") { if strings.TrimSpace(p) == value { return true, nil } diff --git a/src/strings/iter_test.go b/src/strings/iter_test.go index 2db599377f0fc0..403b4d4dced0af 100644 --- a/src/strings/iter_test.go +++ b/src/strings/iter_test.go @@ -50,3 +50,59 @@ func BenchmarkSplitAfterSeqMultiByteSeparator(b *testing.B) { } } } + +func findKvBySplit(s string, k string) string { + for _, kv := range Split(s, ",") { + if HasPrefix(kv, k) { + return kv + } + } + return "" +} + +func findKvBySplitSeq(s string, k string) string { + for kv := range SplitSeq(s, ",") { + if HasPrefix(kv, k) { + return kv + } + } + return "" +} + +var testSplitString = "k1=v1,k2=v2,k3=v3,k4=v4" + +func BenchmarkSplitAndSplitSeqKeyFound(b *testing.B) { + b.Run("findKvBySplit", func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplit(testSplitString, "k3") + } + }) + + b.Run("findKvBySplitSeq", func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplitSeq(testSplitString, "k3") + } + }) +} + +func BenchmarkSplitAndSplitSeqKeyNotFound(b *testing.B) { + b.Run("findKvBySplit", func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplit(testSplitString, "notFoundKey") + } + }) + + b.Run("findKvBySplitSeq", func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplitSeq(testSplitString, "notFoundKey") + } + }) +} From 9e9bd04bd71df926304ffa5313cd19e55b85a28d Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Sat, 6 Sep 2025 15:57:06 +0800 Subject: [PATCH 3/5] cmd: add some benchmarks for strings.SplitSeq replacement --- src/cmd/compile/internal/base/flag_test.go | 57 ++++++++++++++++ src/cmd/go/internal/auth/gitauth_test.go | 75 ++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 src/cmd/compile/internal/base/flag_test.go diff --git a/src/cmd/compile/internal/base/flag_test.go b/src/cmd/compile/internal/base/flag_test.go new file mode 100644 index 00000000000000..71485ccfaa6065 --- /dev/null +++ b/src/cmd/compile/internal/base/flag_test.go @@ -0,0 +1,57 @@ +// 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 base + +import ( + "cmd/internal/obj" + "strings" + "testing" +) + +func BenchmarkParseSpectreNew(b *testing.B) { + if Ctxt == nil { + Ctxt = &obj.Link{} + } + + testCases := []struct { + name string + input string + }{{ + name: "empty", + input: "", + }, { + name: "index", + input: "index", + }, { + name: "ret", + input: "ret", + }, { + name: "index_ret", + input: "index,ret", + }, { + name: "all", + input: "all", + }, { + name: "multiple_indices_ret", + input: strings.Repeat("index,", 10) + "ret", + }} + + for _, tc := range testCases { + b.Run(tc.name, func(b *testing.B) { + // Reset variables before each run + oldFlagCfgSpectreIndex := Flag.Cfg.SpectreIndex + oldCtxtRetpoline := Ctxt.Retpoline + defer func() { + Flag.Cfg.SpectreIndex = oldFlagCfgSpectreIndex + Ctxt.Retpoline = oldCtxtRetpoline + }() + + b.ResetTimer() + for b.Loop() { + parseSpectre(tc.input) + } + }) + } +} diff --git a/src/cmd/go/internal/auth/gitauth_test.go b/src/cmd/go/internal/auth/gitauth_test.go index 1ddd48fa7a889a..2ba93ad2c25f17 100644 --- a/src/cmd/go/internal/auth/gitauth_test.go +++ b/src/cmd/go/internal/auth/gitauth_test.go @@ -5,6 +5,7 @@ package auth import ( + "strings" "testing" ) @@ -82,3 +83,77 @@ password:secr3t } } } + +func BenchmarkParseGitAuth(b *testing.B) { + // Define different test scenarios to benchmark + testCases := []struct { + name string + data []byte + }{{ + // Standard scenario with all basic fields present + name: "standard", + data: []byte(` +protocol=https +host=example.com +username=bob +password=secr3t +`), + }, { + // Scenario with URL field included + name: "with_url", + data: []byte(` +protocol=https +host=example.com +username=bob +password=secr3t +url=https://example.com/repo +`), + }, { + // Minimal scenario with only required fields + name: "minimal", + data: []byte(` +protocol=https +host=example.com +`), + }, { + // Complex scenario with longer values and extra fields + name: "complex", + data: func() []byte { + var builder strings.Builder + builder.WriteString("protocol=https\n") + builder.WriteString("host=example.com\n") + builder.WriteString("username=longusernamenamename\n") + builder.WriteString("password=longpasswordwithmanycharacters123456789\n") + builder.WriteString("url=https://example.com/very/long/path/to/repository\n") + builder.WriteString("extra1=value1\n") + builder.WriteString("extra2=value2\n") + return []byte(builder.String()) + }(), + }, { + // Scenario with empty input + name: "empty", + data: []byte(``), + }, { + // Scenario with malformed input (using colon instead of equals) + name: "malformed", + data: []byte(` +protocol:https +host:example.com +username:bob +password:secr3t +`), + }} + + for _, tc := range testCases { + b.Run(tc.name, func(b *testing.B) { + b.ResetTimer() + for b.Loop() { + prefix, username, password := parseGitAuth(tc.data) + + _ = prefix + _ = username + _ = password + } + }) + } +} From 4db66ee1461671f045766dc31a4632949411f2ab Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Sat, 6 Sep 2025 16:34:06 +0800 Subject: [PATCH 4/5] strings: improve BenchmarkSplitAndSplitSeq readability --- src/strings/iter_test.go | 65 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/strings/iter_test.go b/src/strings/iter_test.go index 403b4d4dced0af..963349b1f41441 100644 --- a/src/strings/iter_test.go +++ b/src/strings/iter_test.go @@ -69,40 +69,37 @@ func findKvBySplitSeq(s string, k string) string { return "" } -var testSplitString = "k1=v1,k2=v2,k3=v3,k4=v4" - -func BenchmarkSplitAndSplitSeqKeyFound(b *testing.B) { - b.Run("findKvBySplit", func(b *testing.B) { - b.ResetTimer() - b.ReportAllocs() - for b.Loop() { - findKvBySplit(testSplitString, "k3") - } - }) - - b.Run("findKvBySplitSeq", func(b *testing.B) { - b.ResetTimer() - b.ReportAllocs() - for b.Loop() { - findKvBySplitSeq(testSplitString, "k3") - } - }) -} +func BenchmarkSplitAndSplitSeq(b *testing.B) { + testSplitString := "k1=v1,k2=v2,k3=v3,k4=v4" + testCases := []struct { + name string + input string + }{ + { + name: "Key found", + input: "k3", + }, + { + name: "Key not found", + input: "k100", + }, + } -func BenchmarkSplitAndSplitSeqKeyNotFound(b *testing.B) { - b.Run("findKvBySplit", func(b *testing.B) { - b.ResetTimer() - b.ReportAllocs() - for b.Loop() { - findKvBySplit(testSplitString, "notFoundKey") - } - }) + for _, testCase := range testCases { + b.Run("bySplit "+testCase.name, func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplit(testSplitString, testCase.input) + } + }) - b.Run("findKvBySplitSeq", func(b *testing.B) { - b.ResetTimer() - b.ReportAllocs() - for b.Loop() { - findKvBySplitSeq(testSplitString, "notFoundKey") - } - }) + b.Run("bySplitSeq "+testCase.name, func(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for b.Loop() { + findKvBySplitSeq(testSplitString, testCase.input) + } + }) + } } From 392b315e122f2c9ef8703ca2dbce8f82ec198556 Mon Sep 17 00:00:00 2001 From: 1911860538 Date: Mon, 15 Sep 2025 19:22:36 +0800 Subject: [PATCH 5/5] cmd/compile/internal/base: remove BenchmarkParseSpectreNew --- src/cmd/compile/internal/base/flag_test.go | 57 ---------------------- 1 file changed, 57 deletions(-) delete mode 100644 src/cmd/compile/internal/base/flag_test.go diff --git a/src/cmd/compile/internal/base/flag_test.go b/src/cmd/compile/internal/base/flag_test.go deleted file mode 100644 index 71485ccfaa6065..00000000000000 --- a/src/cmd/compile/internal/base/flag_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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 base - -import ( - "cmd/internal/obj" - "strings" - "testing" -) - -func BenchmarkParseSpectreNew(b *testing.B) { - if Ctxt == nil { - Ctxt = &obj.Link{} - } - - testCases := []struct { - name string - input string - }{{ - name: "empty", - input: "", - }, { - name: "index", - input: "index", - }, { - name: "ret", - input: "ret", - }, { - name: "index_ret", - input: "index,ret", - }, { - name: "all", - input: "all", - }, { - name: "multiple_indices_ret", - input: strings.Repeat("index,", 10) + "ret", - }} - - for _, tc := range testCases { - b.Run(tc.name, func(b *testing.B) { - // Reset variables before each run - oldFlagCfgSpectreIndex := Flag.Cfg.SpectreIndex - oldCtxtRetpoline := Ctxt.Retpoline - defer func() { - Flag.Cfg.SpectreIndex = oldFlagCfgSpectreIndex - Ctxt.Retpoline = oldCtxtRetpoline - }() - - b.ResetTimer() - for b.Loop() { - parseSpectre(tc.input) - } - }) - } -}